forked from qt-creator/qt-creator
CompilerExplorer: Implement saving documents
Change-Id: Iccfd300a9f0fc25bafae9892c14f172874a99ce1 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -133,11 +133,11 @@ struct CompileParameters
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Options &libraries(const CompilerExplorer::LibrarySelectionAspect &aspect)
|
Options &libraries(const QMap<QString, QString> &libraries)
|
||||||
{
|
{
|
||||||
Libraries result;
|
Libraries result;
|
||||||
for (const auto &key : aspect.value().keys()) {
|
for (const auto &key : libraries.keys()) {
|
||||||
result.add(key, aspect.value()[key]);
|
result.add(key, libraries[key]);
|
||||||
}
|
}
|
||||||
obj["libraries"] = result.array;
|
obj["libraries"] = result.array;
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QItemSelectionModel>
|
#include <QItemSelectionModel>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
namespace CompilerExplorer {
|
namespace CompilerExplorer {
|
||||||
@@ -67,4 +70,138 @@ private:
|
|||||||
QStandardItemModel *m_model{nullptr};
|
QStandardItemModel *m_model{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class AspectListAspect : public Utils::BaseAspect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using ToBaseAspectPtr = std::function<Utils::BaseAspect *(const T &)>;
|
||||||
|
using CreateItem = std::function<T()>;
|
||||||
|
using ItemCallback = std::function<void(const T &)>;
|
||||||
|
using IsDirty = std::function<bool(const T &)>;
|
||||||
|
using Apply = std::function<void(const T &)>;
|
||||||
|
|
||||||
|
AspectListAspect(Utils::AspectContainer *container = nullptr)
|
||||||
|
: Utils::BaseAspect(container)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void fromMap(const QVariantMap &map) override
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!settingsKey().isEmpty(), return);
|
||||||
|
|
||||||
|
QVariantList list = map[settingsKey()].toList();
|
||||||
|
for (const auto &entry : list) {
|
||||||
|
T item = m_createItem();
|
||||||
|
m_toBaseAspect(item)->fromMap(entry.toMap());
|
||||||
|
m_volatileItems.append(item);
|
||||||
|
}
|
||||||
|
m_items = m_volatileItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList toList(bool v) const
|
||||||
|
{
|
||||||
|
QVariantList list;
|
||||||
|
const auto &items = v ? m_volatileItems : m_items;
|
||||||
|
|
||||||
|
for (const auto &item : items) {
|
||||||
|
QVariantMap childMap;
|
||||||
|
if (v)
|
||||||
|
m_toBaseAspect(item)->volatileToMap(childMap);
|
||||||
|
else
|
||||||
|
m_toBaseAspect(item)->toMap(childMap);
|
||||||
|
|
||||||
|
list.append(childMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toMap(Utils::Store &map) const override
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!settingsKey().isEmpty(), return);
|
||||||
|
const QString key = settingsKey();
|
||||||
|
map[key] = toList(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void volatileToMap(Utils::Store &map) const override
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!settingsKey().isEmpty(), return);
|
||||||
|
const QString key = settingsKey();
|
||||||
|
map[key] = toList(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
T addItem(T item)
|
||||||
|
{
|
||||||
|
m_volatileItems.append(item);
|
||||||
|
if (m_itemAdded)
|
||||||
|
m_itemAdded(item);
|
||||||
|
emit volatileValueChanged();
|
||||||
|
if (isAutoApply())
|
||||||
|
apply();
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeItem(T item)
|
||||||
|
{
|
||||||
|
m_volatileItems.removeOne(item);
|
||||||
|
if (m_itemRemoved)
|
||||||
|
m_itemRemoved(item);
|
||||||
|
emit volatileValueChanged();
|
||||||
|
if (isAutoApply())
|
||||||
|
apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply() override
|
||||||
|
{
|
||||||
|
m_items = m_volatileItems;
|
||||||
|
if (m_apply)
|
||||||
|
forEachItem(m_apply);
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setToBaseAspectFunction(ToBaseAspectPtr toBaseAspect) { m_toBaseAspect = toBaseAspect; }
|
||||||
|
void setCreateItemFunction(CreateItem createItem) { m_createItem = createItem; }
|
||||||
|
void setIsDirtyFunction(IsDirty isDirty) { m_isDirty = isDirty; }
|
||||||
|
void setApplyFunction(Apply apply) { m_apply = apply; }
|
||||||
|
|
||||||
|
void forEachItem(std::function<void(const T &)> callback)
|
||||||
|
{
|
||||||
|
for (const auto &item : m_volatileItems)
|
||||||
|
callback(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forEachItem(std::function<void(const T &, int)> callback)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
for (const auto &item : m_volatileItems)
|
||||||
|
callback(item, idx++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setItemAddedCallback(const ItemCallback &callback) { m_itemAdded = callback; }
|
||||||
|
void setItemRemovedCallback(const ItemCallback &callback) { m_itemRemoved = callback; }
|
||||||
|
|
||||||
|
qsizetype size() { return m_volatileItems.size(); }
|
||||||
|
bool isDirty() override
|
||||||
|
{
|
||||||
|
if (m_isDirty) {
|
||||||
|
for (const auto &item : m_volatileItems) {
|
||||||
|
if (m_isDirty(item))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant volatileVariantValue() const override { return {}; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<T> m_items;
|
||||||
|
QList<T> m_volatileItems;
|
||||||
|
ToBaseAspectPtr m_toBaseAspect;
|
||||||
|
CreateItem m_createItem;
|
||||||
|
IsDirty m_isDirty;
|
||||||
|
Apply m_apply;
|
||||||
|
ItemCallback m_itemAdded;
|
||||||
|
ItemCallback m_itemRemoved;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace CompilerExplorer
|
} // namespace CompilerExplorer
|
||||||
|
|||||||
@@ -20,10 +20,11 @@
|
|||||||
|
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/mimeutils.h>
|
|
||||||
#include <utils/mimetypes2/mimetype.h>
|
#include <utils/mimetypes2/mimetype.h>
|
||||||
|
#include <utils/mimeutils.h>
|
||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
#include <QCompleter>
|
#include <QCompleter>
|
||||||
@@ -49,7 +50,7 @@ namespace CompilerExplorer {
|
|||||||
class CodeEditorWidget : public TextEditorWidget
|
class CodeEditorWidget : public TextEditorWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CodeEditorWidget(Settings *settings)
|
CodeEditorWidget(const std::shared_ptr<SourceSettings> &settings)
|
||||||
: m_settings(settings){};
|
: m_settings(settings){};
|
||||||
|
|
||||||
void updateHighlighter()
|
void updateHighlighter()
|
||||||
@@ -62,26 +63,195 @@ public:
|
|||||||
configureGenericHighlighter(mimeType);
|
configureGenericHighlighter(mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
std::shared_ptr<SourceSettings> m_settings;
|
||||||
Settings *m_settings;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CompilerWidget::CompilerWidget()
|
class SourceTextDocument : public TextDocument
|
||||||
: m_compilerSettings(&settings())
|
{
|
||||||
|
public:
|
||||||
|
SourceTextDocument(const std::shared_ptr<SourceSettings> &settings)
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JsonSettingsDocument::JsonSettingsDocument(CompilerExplorerSettings *ceSettings)
|
||||||
|
: m_ceSettings(ceSettings)
|
||||||
|
{
|
||||||
|
setId(Constants::CE_EDITOR_ID);
|
||||||
|
|
||||||
|
connect(m_ceSettings, &CompilerExplorerSettings::changed, this, [this] { emit changed(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::IDocument::OpenResult JsonSettingsDocument::open(QString *errorString,
|
||||||
|
const Utils::FilePath &filePath,
|
||||||
|
const Utils::FilePath &realFilePath)
|
||||||
|
{
|
||||||
|
if (!filePath.isReadableFile())
|
||||||
|
return OpenResult::ReadError;
|
||||||
|
|
||||||
|
auto contents = realFilePath.fileContents();
|
||||||
|
if (!contents) {
|
||||||
|
if (errorString)
|
||||||
|
*errorString = contents.error();
|
||||||
|
return OpenResult::ReadError;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(*contents, &error);
|
||||||
|
if (error.error != QJsonParseError::NoError) {
|
||||||
|
if (errorString)
|
||||||
|
*errorString = error.errorString();
|
||||||
|
return OpenResult::CannotHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doc.isObject()) {
|
||||||
|
if (errorString)
|
||||||
|
*errorString = Tr::tr("Not a valid JSON object.");
|
||||||
|
return OpenResult::CannotHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ceSettings->fromMap(doc.toVariant().toMap());
|
||||||
|
emit settingsChanged();
|
||||||
|
return OpenResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JsonSettingsDocument::saveImpl(QString *errorString,
|
||||||
|
const Utils::FilePath &newFilePath,
|
||||||
|
bool autoSave)
|
||||||
|
{
|
||||||
|
QVariantMap map;
|
||||||
|
|
||||||
|
if (autoSave) {
|
||||||
|
if (m_windowStateCallback)
|
||||||
|
m_ceSettings->windowState.setVolatileValue(m_windowStateCallback());
|
||||||
|
|
||||||
|
m_ceSettings->volatileToMap(map);
|
||||||
|
} else {
|
||||||
|
if (m_windowStateCallback)
|
||||||
|
m_ceSettings->windowState.setValue(m_windowStateCallback());
|
||||||
|
|
||||||
|
m_ceSettings->apply();
|
||||||
|
m_ceSettings->toMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument doc = QJsonDocument::fromVariant(map);
|
||||||
|
|
||||||
|
Utils::FilePath path = newFilePath.isEmpty() ? filePath() : newFilePath;
|
||||||
|
|
||||||
|
if (!newFilePath.isEmpty() && !autoSave)
|
||||||
|
setFilePath(newFilePath);
|
||||||
|
|
||||||
|
auto result = path.writeFileContents(doc.toJson(QJsonDocument::Indented));
|
||||||
|
if (!result && errorString) {
|
||||||
|
*errorString = result.error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JsonSettingsDocument::isModified() const
|
||||||
|
{
|
||||||
|
bool isDirty = m_ceSettings->isDirty();
|
||||||
|
return isDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JsonSettingsDocument::setContents(const QByteArray &contents)
|
||||||
|
{
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(contents, &error);
|
||||||
|
QTC_ASSERT(error.error == QJsonParseError::NoError, return false);
|
||||||
|
|
||||||
|
QTC_ASSERT(doc.isObject(), return false);
|
||||||
|
|
||||||
|
m_ceSettings->fromMap(doc.toVariant().toMap());
|
||||||
|
|
||||||
|
emit settingsChanged();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceEditorWidget::SourceEditorWidget(const std::shared_ptr<SourceSettings> &settings)
|
||||||
|
: m_sourceSettings(settings)
|
||||||
|
{
|
||||||
|
m_codeEditor = new CodeEditorWidget(m_sourceSettings);
|
||||||
|
|
||||||
|
TextDocumentPtr document = TextDocumentPtr(new SourceTextDocument(m_sourceSettings));
|
||||||
|
|
||||||
|
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"));
|
||||||
|
connect(addCompilerButton, &QPushButton::clicked, this, [this] {
|
||||||
|
auto newCompiler = std::make_shared<CompilerSettings>(m_sourceSettings->apiConfigFunction());
|
||||||
|
newCompiler->setLanguageId(m_sourceSettings->languageId());
|
||||||
|
m_sourceSettings->compilers.addItem(newCompiler);
|
||||||
|
});
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
using namespace Layouting;
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Row {
|
||||||
|
settings->languageId,
|
||||||
|
addCompilerButton,
|
||||||
|
},
|
||||||
|
m_codeEditor,
|
||||||
|
}.attachTo(this);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
setWindowTitle("Source code");
|
||||||
|
setObjectName("source_code");
|
||||||
|
|
||||||
|
Aggregate *agg = Aggregate::parentAggregate(m_codeEditor);
|
||||||
|
if (!agg) {
|
||||||
|
agg = new Aggregate;
|
||||||
|
agg->add(m_codeEditor);
|
||||||
|
}
|
||||||
|
agg->add(this);
|
||||||
|
|
||||||
|
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;
|
using namespace Layouting;
|
||||||
QVariantMap map;
|
QVariantMap map;
|
||||||
|
|
||||||
m_compilerSettings.setAutoApply(true);
|
|
||||||
|
|
||||||
m_delayTimer = new QTimer(this);
|
m_delayTimer = new QTimer(this);
|
||||||
m_delayTimer->setSingleShot(true);
|
m_delayTimer->setSingleShot(true);
|
||||||
m_delayTimer->setInterval(500ms);
|
m_delayTimer->setInterval(500ms);
|
||||||
connect(m_delayTimer, &QTimer::timeout, this, &CompilerWidget::doCompile);
|
connect(m_delayTimer, &QTimer::timeout, this, &CompilerWidget::doCompile);
|
||||||
|
|
||||||
for (const auto &aspect : m_compilerSettings.aspects())
|
connect(m_compilerSettings.get(),
|
||||||
QTC_CHECK(
|
&CompilerSettings::changed,
|
||||||
connect(aspect, &Utils::BaseAspect::changed, m_delayTimer, qOverload<>(&QTimer::start)));
|
m_delayTimer,
|
||||||
|
qOverload<>(&QTimer::start));
|
||||||
|
|
||||||
m_asmEditor = new TextEditorWidget;
|
m_asmEditor = new TextEditorWidget;
|
||||||
m_asmDocument = QSharedPointer<TextDocument>(new TextDocument);
|
m_asmDocument = QSharedPointer<TextDocument>(new TextDocument);
|
||||||
@@ -96,7 +266,7 @@ CompilerWidget::CompilerWidget()
|
|||||||
advDlg->setIcon(Utils::Icons::SETTINGS_TOOLBAR.icon());
|
advDlg->setIcon(Utils::Icons::SETTINGS_TOOLBAR.icon());
|
||||||
advDlg->setIconText(Tr::tr("Advanced Options"));
|
advDlg->setIconText(Tr::tr("Advanced Options"));
|
||||||
connect(advDlg, &QAction::triggered, this, [advButton, this] {
|
connect(advDlg, &QAction::triggered, this, [advButton, this] {
|
||||||
CompilerExplorerOptions *dlg = new CompilerExplorerOptions(m_compilerSettings, advButton);
|
CompilerExplorerOptions *dlg = new CompilerExplorerOptions(*m_compilerSettings, advButton);
|
||||||
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
dlg->setWindowFlag(Qt::WindowType::Popup);
|
dlg->setWindowFlag(Qt::WindowType::Popup);
|
||||||
dlg->show();
|
dlg->show();
|
||||||
@@ -108,10 +278,16 @@ CompilerWidget::CompilerWidget()
|
|||||||
connect(advButton, &QPushButton::clicked, advDlg, &QAction::trigger);
|
connect(advButton, &QPushButton::clicked, advDlg, &QAction::trigger);
|
||||||
advButton->setIcon(advDlg->icon());
|
advButton->setIcon(advDlg->icon());
|
||||||
|
|
||||||
|
compile(m_sourceSettings->source());
|
||||||
|
|
||||||
|
connect(&m_sourceSettings->source, &Utils::StringAspect::volatileValueChanged, this, [this] {
|
||||||
|
compile(m_sourceSettings->source.volatileValue());
|
||||||
|
});
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
Column {
|
Column {
|
||||||
Row {
|
Row {
|
||||||
m_compilerSettings.compiler,
|
m_compilerSettings->compiler,
|
||||||
advButton,
|
advButton,
|
||||||
},
|
},
|
||||||
Splitter {
|
Splitter {
|
||||||
@@ -125,6 +301,11 @@ CompilerWidget::CompilerWidget()
|
|||||||
m_spinner = new SpinnerSolution::Spinner(SpinnerSolution::SpinnerSize::Large, this);
|
m_spinner = new SpinnerSolution::Spinner(SpinnerSolution::SpinnerSize::Large, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompilerWidget::~CompilerWidget()
|
||||||
|
{
|
||||||
|
qDebug() << "Good bye!";
|
||||||
|
}
|
||||||
|
|
||||||
Core::SearchableTerminal *CompilerWidget::createTerminal()
|
Core::SearchableTerminal *CompilerWidget::createTerminal()
|
||||||
{
|
{
|
||||||
m_resultTerminal = new Core::SearchableTerminal();
|
m_resultTerminal = new Core::SearchableTerminal();
|
||||||
@@ -166,33 +347,34 @@ void CompilerWidget::doCompile()
|
|||||||
{
|
{
|
||||||
using namespace Api;
|
using namespace Api;
|
||||||
|
|
||||||
QString compilerId = m_compilerSettings.compiler();
|
QString compilerId = m_compilerSettings->compiler();
|
||||||
if (compilerId.isEmpty())
|
if (compilerId.isEmpty())
|
||||||
compilerId = "clang_trunk";
|
compilerId = "clang_trunk";
|
||||||
|
|
||||||
m_spinner->setVisible(true);
|
m_spinner->setVisible(true);
|
||||||
m_asmEditor->setEnabled(false);
|
m_asmEditor->setEnabled(false);
|
||||||
|
|
||||||
CompileParameters params = CompileParameters(compilerId)
|
CompileParameters params
|
||||||
.source(m_source)
|
= CompileParameters(compilerId)
|
||||||
.language(settings().languageId())
|
.source(m_source)
|
||||||
.options(CompileParameters::Options()
|
.language(m_sourceSettings->languageId.volatileValue())
|
||||||
.userArguments(m_compilerSettings.compilerOptions())
|
.options(CompileParameters::Options()
|
||||||
.compilerOptions({false, false})
|
.userArguments(m_compilerSettings->compilerOptions.volatileValue())
|
||||||
.filters({false,
|
.compilerOptions({false, false})
|
||||||
m_compilerSettings.compileToBinaryObject(),
|
.filters({false,
|
||||||
true,
|
m_compilerSettings->compileToBinaryObject.volatileValue(),
|
||||||
m_compilerSettings.demangleIdentifiers(),
|
true,
|
||||||
true,
|
m_compilerSettings->demangleIdentifiers.volatileValue(),
|
||||||
m_compilerSettings.executeCode(),
|
true,
|
||||||
m_compilerSettings.intelAsmSyntax(),
|
m_compilerSettings->executeCode.volatileValue(),
|
||||||
true,
|
m_compilerSettings->intelAsmSyntax.volatileValue(),
|
||||||
false,
|
true,
|
||||||
false,
|
false,
|
||||||
false})
|
false,
|
||||||
.libraries(m_compilerSettings.libraries));
|
false})
|
||||||
|
.libraries(m_compilerSettings->libraries.volatileValue()));
|
||||||
|
|
||||||
auto f = Api::compile(settings().apiConfig(), params);
|
auto f = Api::compile(m_sourceSettings->apiConfigFunction()(), params);
|
||||||
|
|
||||||
m_compileWatcher.reset(new QFutureWatcher<CompileResult>);
|
m_compileWatcher.reset(new QFutureWatcher<CompileResult>);
|
||||||
|
|
||||||
@@ -273,105 +455,170 @@ void CompilerWidget::doCompile()
|
|||||||
m_compileWatcher->setFuture(f);
|
m_compileWatcher->setFuture(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorWidget::EditorWidget(TextDocumentPtr document, QWidget *parent)
|
EditorWidget::EditorWidget(QSharedPointer<JsonSettingsDocument> document, QWidget *parent)
|
||||||
: Utils::FancyMainWindow(parent)
|
: Utils::FancyMainWindow(parent)
|
||||||
|
, m_document(document)
|
||||||
{
|
{
|
||||||
setAutoHideTitleBars(false);
|
setAutoHideTitleBars(false);
|
||||||
setDockNestingEnabled(true);
|
setDockNestingEnabled(true);
|
||||||
setDocumentMode(true);
|
setDocumentMode(true);
|
||||||
setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::TabPosition::South);
|
setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::TabPosition::South);
|
||||||
|
|
||||||
using namespace Layouting;
|
document->setWindowStateCallback([this] {
|
||||||
|
auto settings = saveSettings();
|
||||||
|
QVariantMap result;
|
||||||
|
|
||||||
m_codeEditor = new CodeEditorWidget(&settings());
|
for (const auto &key : settings.keys()) {
|
||||||
m_codeEditor->setTextDocument(document);
|
// QTBUG-116339
|
||||||
m_codeEditor->updateHighlighter();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto addCompilerButton = new QPushButton;
|
return result;
|
||||||
addCompilerButton->setText(Tr::tr("Add compiler"));
|
});
|
||||||
connect(addCompilerButton, &QPushButton::clicked, this, &EditorWidget::addCompiler);
|
|
||||||
|
|
||||||
// clang-format off
|
auto addCompiler = [this](const std::shared_ptr<SourceSettings> &sourceSettings,
|
||||||
auto source =
|
const std::shared_ptr<CompilerSettings> &compilerSettings,
|
||||||
Column {
|
int idx) {
|
||||||
Row {
|
auto compiler = new CompilerWidget(sourceSettings, compilerSettings);
|
||||||
settings().languageId,
|
compiler->setWindowTitle("Compiler #" + QString::number(idx));
|
||||||
settings().compilerExplorerUrl,
|
compiler->setObjectName("compiler_" + QString::number(idx));
|
||||||
addCompilerButton,
|
QDockWidget *dockWidget = addDockForWidget(compiler);
|
||||||
},
|
addDockWidget(Qt::RightDockWidgetArea, dockWidget);
|
||||||
m_codeEditor,
|
m_compilerWidgets.append(dockWidget);
|
||||||
}.emerge();
|
};
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
source->setWindowTitle("Source code");
|
auto addSourceEditor = [this, document, addCompiler](
|
||||||
source->setObjectName("source_code");
|
const std::shared_ptr<SourceSettings> &sourceSettings) {
|
||||||
addDockWidget(Qt::LeftDockWidgetArea, addDockForWidget(source));
|
auto sourceEditor = new SourceEditorWidget(sourceSettings);
|
||||||
|
sourceEditor->setWindowTitle("Source Code #" + QString::number(m_sourceWidgets.size() + 1));
|
||||||
|
sourceEditor->setObjectName("source_code_editor_"
|
||||||
|
+ QString::number(m_sourceWidgets.size() + 1));
|
||||||
|
|
||||||
addCompiler();
|
QDockWidget *dockWidget = addDockForWidget(sourceEditor);
|
||||||
|
connect(dockWidget,
|
||||||
|
&QDockWidget::visibilityChanged,
|
||||||
|
this,
|
||||||
|
[document, sourceSettings = sourceSettings.get(), dockWidget] {
|
||||||
|
if (!dockWidget->isVisible())
|
||||||
|
document->settings()->m_sources.removeItem(
|
||||||
|
sourceSettings->shared_from_this());
|
||||||
|
});
|
||||||
|
|
||||||
Aggregate *agg = Aggregate::parentAggregate(m_codeEditor);
|
addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
|
||||||
if (!agg) {
|
|
||||||
agg = new Aggregate;
|
sourceSettings->compilers.forEachItem(
|
||||||
agg->add(m_codeEditor);
|
[addCompiler, sourceSettings](const std::shared_ptr<CompilerSettings> &compilerSettings,
|
||||||
}
|
int idx) {
|
||||||
agg->add(this);
|
addCompiler(sourceSettings, compilerSettings, idx + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
sourceSettings->compilers.setItemAddedCallback(
|
||||||
|
[addCompiler, sourceSettings = sourceSettings.get()](
|
||||||
|
const std::shared_ptr<CompilerSettings> &compilerSettings) {
|
||||||
|
addCompiler(sourceSettings->shared_from_this(),
|
||||||
|
compilerSettings,
|
||||||
|
sourceSettings->compilers.size());
|
||||||
|
});
|
||||||
|
|
||||||
|
sourceSettings->compilers.setItemRemovedCallback(
|
||||||
|
[this](const std::shared_ptr<CompilerSettings> &compilerSettings) {
|
||||||
|
m_compilerWidgets.removeIf([compilerSettings](const QDockWidget *c) {
|
||||||
|
return static_cast<CompilerWidget *>(c->widget())->m_compilerSettings
|
||||||
|
== compilerSettings;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Aggregate *agg = Aggregate::parentAggregate(sourceEditor);
|
||||||
|
if (!agg) {
|
||||||
|
agg = new Aggregate;
|
||||||
|
agg->add(sourceEditor);
|
||||||
|
}
|
||||||
|
agg->add(this);
|
||||||
|
|
||||||
|
setFocusProxy(sourceEditor);
|
||||||
|
|
||||||
|
m_sourceWidgets.append(dockWidget);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto removeSourceEditor = [this](const std::shared_ptr<SourceSettings> &sourceSettings) {
|
||||||
|
m_sourceWidgets.removeIf([sourceSettings = sourceSettings.get()](const QDockWidget *c) {
|
||||||
|
return static_cast<SourceEditorWidget *>(c->widget())->m_sourceSettings
|
||||||
|
== sourceSettings->shared_from_this();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
auto recreateEditors = [this, addSourceEditor]() {
|
||||||
|
qDeleteAll(m_sourceWidgets);
|
||||||
|
qDeleteAll(m_compilerWidgets);
|
||||||
|
|
||||||
|
m_sourceWidgets.clear();
|
||||||
|
m_compilerWidgets.clear();
|
||||||
|
|
||||||
|
m_document->settings()->m_sources.forEachItem(addSourceEditor);
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreSettings(hashMap);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document->settings()->m_sources.setItemAddedCallback(addSourceEditor);
|
||||||
|
document->settings()->m_sources.setItemRemovedCallback(removeSourceEditor);
|
||||||
|
connect(document.get(), &JsonSettingsDocument::settingsChanged, this, recreateEditors);
|
||||||
|
|
||||||
m_context = new Core::IContext(this);
|
m_context = new Core::IContext(this);
|
||||||
m_context->setWidget(this);
|
m_context->setWidget(this);
|
||||||
m_context->setContext(Core::Context(Constants::CE_EDITOR_CONTEXT_ID));
|
m_context->setContext(Core::Context(Constants::CE_EDITOR_CONTEXT_ID));
|
||||||
Core::ICore::addContextObject(m_context);
|
Core::ICore::addContextObject(m_context);
|
||||||
|
|
||||||
connect(m_codeEditor, &QPlainTextEdit::textChanged, this, &EditorWidget::sourceCodeChanged);
|
|
||||||
|
|
||||||
connect(&settings(),
|
|
||||||
&Settings::languagesChanged,
|
|
||||||
m_codeEditor,
|
|
||||||
&CodeEditorWidget::updateHighlighter);
|
|
||||||
|
|
||||||
connect(&settings().languageId,
|
|
||||||
&StringSelectionAspect::changed,
|
|
||||||
this,
|
|
||||||
&EditorWidget::onLanguageChanged);
|
|
||||||
|
|
||||||
setFocusProxy(m_codeEditor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidget::onLanguageChanged()
|
EditorWidget::~EditorWidget()
|
||||||
{
|
{
|
||||||
m_codeEditor->updateHighlighter();
|
m_compilerWidgets.clear();
|
||||||
}
|
m_sourceWidgets.clear();
|
||||||
|
|
||||||
void EditorWidget::addCompiler()
|
|
||||||
{
|
|
||||||
m_compilerCount++;
|
|
||||||
|
|
||||||
auto compiler = new CompilerWidget;
|
|
||||||
compiler->setWindowTitle("Compiler #" + QString::number(m_compilerCount));
|
|
||||||
compiler->setObjectName("compiler_" + QString::number(m_compilerCount));
|
|
||||||
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, addDockForWidget(compiler));
|
|
||||||
|
|
||||||
if (m_codeEditor && m_codeEditor->textDocument())
|
|
||||||
compiler->compile(QString::fromUtf8(m_codeEditor->textDocument()->contents()));
|
|
||||||
|
|
||||||
connect(this, &EditorWidget::sourceCodeChanged, compiler, [this, compiler] {
|
|
||||||
compiler->compile(QString::fromUtf8(m_codeEditor->textDocument()->contents()));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Editor : public Core::IEditor
|
class Editor : public Core::IEditor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Editor()
|
Editor()
|
||||||
: m_document(new TextDocument(Constants::CE_EDITOR_ID))
|
: m_document(new JsonSettingsDocument(&m_settings))
|
||||||
{
|
{
|
||||||
setWidget(new EditorWidget(m_document));
|
setWidget(new EditorWidget(m_document));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~Editor() { delete widget(); }
|
||||||
|
|
||||||
Core::IDocument *document() const override { return m_document.data(); }
|
Core::IDocument *document() const override { return m_document.data(); }
|
||||||
QWidget *toolBar() override { return nullptr; }
|
QWidget *toolBar() override { return nullptr; }
|
||||||
|
|
||||||
TextDocumentPtr m_document;
|
CompilerExplorerSettings m_settings;
|
||||||
|
QSharedPointer<JsonSettingsDocument> m_document;
|
||||||
};
|
};
|
||||||
|
|
||||||
EditorFactory::EditorFactory()
|
EditorFactory::EditorFactory()
|
||||||
|
|||||||
@@ -27,18 +27,76 @@ class CppEditorWidget;
|
|||||||
|
|
||||||
namespace CompilerExplorer {
|
namespace CompilerExplorer {
|
||||||
|
|
||||||
|
class JsonSettingsDocument;
|
||||||
|
class SourceEditorWidget;
|
||||||
class CodeEditorWidget;
|
class CodeEditorWidget;
|
||||||
|
|
||||||
|
class JsonSettingsDocument : public Core::IDocument
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
JsonSettingsDocument(CompilerExplorerSettings *ceSettings);
|
||||||
|
OpenResult open(QString *errorString,
|
||||||
|
const Utils::FilePath &filePath,
|
||||||
|
const Utils::FilePath &realFilePath) override;
|
||||||
|
|
||||||
|
bool saveImpl(QString *errorString,
|
||||||
|
const Utils::FilePath &filePath = Utils::FilePath(),
|
||||||
|
bool autoSave = false) override;
|
||||||
|
|
||||||
|
bool setContents(const QByteArray &contents) override;
|
||||||
|
|
||||||
|
bool shouldAutoSave() const override { return !filePath().isEmpty(); }
|
||||||
|
bool isModified() const override;
|
||||||
|
bool isSaveAsAllowed() const override { return true; }
|
||||||
|
|
||||||
|
CompilerExplorerSettings *settings() { return m_ceSettings; }
|
||||||
|
|
||||||
|
void setWindowStateCallback(std::function<QVariantMap()> callback)
|
||||||
|
{
|
||||||
|
m_windowStateCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void settingsChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CompilerExplorerSettings *m_ceSettings;
|
||||||
|
std::function<QVariantMap()> m_windowStateCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SourceEditorWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SourceEditorWidget(const std::shared_ptr<SourceSettings> &settings);
|
||||||
|
|
||||||
|
QString sourceCode();
|
||||||
|
|
||||||
|
std::shared_ptr<SourceSettings> m_sourceSettings;
|
||||||
|
signals:
|
||||||
|
void sourceCodeChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CodeEditorWidget *m_codeEditor{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
class CompilerWidget : public QWidget
|
class CompilerWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
CompilerWidget();
|
CompilerWidget(const std::shared_ptr<SourceSettings> &sourceSettings,
|
||||||
|
const std::shared_ptr<CompilerSettings> &compilerSettings);
|
||||||
|
|
||||||
|
~CompilerWidget();
|
||||||
|
|
||||||
Core::SearchableTerminal *createTerminal();
|
Core::SearchableTerminal *createTerminal();
|
||||||
|
|
||||||
void compile(const QString &source);
|
void compile(const QString &source);
|
||||||
|
|
||||||
|
std::shared_ptr<SourceSettings> m_sourceSettings;
|
||||||
|
std::shared_ptr<CompilerSettings> m_compilerSettings;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void doCompile();
|
void doCompile();
|
||||||
|
|
||||||
@@ -51,8 +109,6 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<QFutureWatcher<Api::CompileResult>> m_compileWatcher;
|
std::unique_ptr<QFutureWatcher<Api::CompileResult>> m_compileWatcher;
|
||||||
|
|
||||||
CompilerExplorer::CompilerSettings m_compilerSettings;
|
|
||||||
|
|
||||||
QString m_source;
|
QString m_source;
|
||||||
QTimer *m_delayTimer{nullptr};
|
QTimer *m_delayTimer{nullptr};
|
||||||
QList<TextEditor::TextMark *> m_marks;
|
QList<TextEditor::TextMark *> m_marks;
|
||||||
@@ -62,25 +118,21 @@ class EditorWidget : public Utils::FancyMainWindow
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
EditorWidget(QSharedPointer<TextEditor::TextDocument> document = nullptr, QWidget *parent = nullptr);
|
EditorWidget(QSharedPointer<JsonSettingsDocument> document = nullptr, QWidget *parent = nullptr);
|
||||||
|
~EditorWidget() override;
|
||||||
void addCompiler();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Core::SearchableTerminal *createTerminal();
|
|
||||||
|
|
||||||
void onLanguageChanged();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sourceCodeChanged();
|
void sourceCodeChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CodeEditorWidget *m_codeEditor;
|
|
||||||
CompilerExplorer::Settings m_currentSettings;
|
|
||||||
QSplitter *m_mainSplitter;
|
QSplitter *m_mainSplitter;
|
||||||
int m_compilerCount{0};
|
int m_compilerCount{0};
|
||||||
|
QSharedPointer<JsonSettingsDocument> m_document;
|
||||||
|
|
||||||
Core::IContext *m_context;
|
Core::IContext *m_context;
|
||||||
|
|
||||||
|
QList<QDockWidget *> m_compilerWidgets;
|
||||||
|
QList<QDockWidget *> m_sourceWidgets;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditorFactory : public Core::IEditorFactory
|
class EditorFactory : public Core::IEditorFactory
|
||||||
|
|||||||
@@ -34,11 +34,10 @@ public:
|
|||||||
|
|
||||||
auto action = new QAction(Tr::tr("Open Compiler Explorer"), this);
|
auto action = new QAction(Tr::tr("Open Compiler Explorer"), this);
|
||||||
connect(action, &QAction::triggered, this, [] {
|
connect(action, &QAction::triggered, this, [] {
|
||||||
CompilerExplorer::Settings settings;
|
|
||||||
|
|
||||||
const QString src = settings.source();
|
|
||||||
QString name("Compiler Explorer");
|
QString name("Compiler Explorer");
|
||||||
EditorManager::openEditorWithContents(Constants::CE_EDITOR_ID, &name, src.toUtf8());
|
Core::EditorManager::openEditorWithContents(Constants::CE_EDITOR_ID,
|
||||||
|
&name,
|
||||||
|
settings().defaultDocument().toUtf8());
|
||||||
});
|
});
|
||||||
|
|
||||||
ActionContainer *mtools = ActionManager::actionContainer(Core::Constants::M_TOOLS);
|
ActionContainer *mtools = ActionManager::actionContainer(Core::Constants::M_TOOLS);
|
||||||
@@ -47,11 +46,12 @@ public:
|
|||||||
menu->setTitle(Tr::tr("Compiler Explorer"));
|
menu->setTitle(Tr::tr("Compiler Explorer"));
|
||||||
mtools->addMenu(mCompilerExplorer);
|
mtools->addMenu(mCompilerExplorer);
|
||||||
|
|
||||||
Command *cmd = ActionManager::registerAction(action, "CompilerExplorer.CompilerExplorerAction");
|
Command *cmd = ActionManager::registerAction(action,
|
||||||
|
"CompilerExplorer.CompilerExplorerAction");
|
||||||
mCompilerExplorer->addAction(cmd);
|
mCompilerExplorer->addAction(cmd);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // CompilerExplorer::Internl
|
} // namespace CompilerExplorer::Internal
|
||||||
|
|
||||||
#include "compilerexplorerplugin.moc"
|
#include "compilerexplorerplugin.moc"
|
||||||
|
|||||||
@@ -14,12 +14,29 @@
|
|||||||
|
|
||||||
namespace CompilerExplorer {
|
namespace CompilerExplorer {
|
||||||
|
|
||||||
Settings &settings()
|
PluginSettings &settings()
|
||||||
{
|
{
|
||||||
static Settings instance;
|
static PluginSettings instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PluginSettings::PluginSettings()
|
||||||
|
{
|
||||||
|
defaultDocument.setSettingsKey("DefaultDocument");
|
||||||
|
defaultDocument.setDefaultValue(R"(
|
||||||
|
{
|
||||||
|
"Sources": [{
|
||||||
|
"LanguageId": "c++",
|
||||||
|
"Source": "int main() {\n return 0;\n}",
|
||||||
|
"Compilers": [{
|
||||||
|
"Id": "clang_trunk",
|
||||||
|
"Options": "-O3"
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
static Api::Languages &cachedLanguages()
|
static Api::Languages &cachedLanguages()
|
||||||
{
|
{
|
||||||
static Api::Languages instance;
|
static Api::Languages instance;
|
||||||
@@ -43,41 +60,58 @@ static QMap<QString, QMap<QString, QString>> &cachedCompilers()
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::Settings()
|
SourceSettings::SourceSettings(const ApiConfigFunction &apiConfigFunction)
|
||||||
|
: m_apiConfigFunction(apiConfigFunction)
|
||||||
{
|
{
|
||||||
static QNetworkAccessManager networkManager;
|
setAutoApply(false);
|
||||||
m_networkAccessManager = &networkManager;
|
|
||||||
|
|
||||||
setSettingsGroup("CompilerExplorer");
|
source.setSettingsKey("Source");
|
||||||
|
|
||||||
source.setDefaultValue(R"(
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
)");
|
|
||||||
|
|
||||||
compilerExplorerUrl.setLabelText(Tr::tr("Compiler Explorer URL:"));
|
|
||||||
compilerExplorerUrl.setToolTip(Tr::tr("URL of the Compiler Explorer instance to use"));
|
|
||||||
compilerExplorerUrl.setDefaultValue("https://godbolt.org/");
|
|
||||||
compilerExplorerUrl.setDisplayStyle(Utils::StringAspect::DisplayStyle::LineEditDisplay);
|
|
||||||
compilerExplorerUrl.setHistoryCompleter("CompilerExplorer.Url.History");
|
|
||||||
|
|
||||||
|
languageId.setSettingsKey("LanguageId");
|
||||||
languageId.setDefaultValue("c++");
|
languageId.setDefaultValue("c++");
|
||||||
languageId.setLabelText(Tr::tr("Language:"));
|
languageId.setLabelText(Tr::tr("Language:"));
|
||||||
languageId.setFillCallback([this](auto cb) { fillLanguageIdModel(cb); });
|
languageId.setFillCallback([this](auto cb) { fillLanguageIdModel(cb); });
|
||||||
|
|
||||||
connect(&compilerExplorerUrl, &Utils::StringAspect::changed, this, [this] {
|
compilers.setSettingsKey("Compilers");
|
||||||
languageId.setValue(languageId.defaultValue());
|
compilers.setCreateItemFunction([this, apiConfigFunction] {
|
||||||
cachedLanguages().clear();
|
auto result = std::make_shared<CompilerSettings>(apiConfigFunction);
|
||||||
languageId.refill();
|
connect(this, &SourceSettings::languagesChanged, result.get(), &CompilerSettings::refresh);
|
||||||
|
connect(&languageId,
|
||||||
|
&StringSelectionAspect::changed,
|
||||||
|
result.get(),
|
||||||
|
[this, result = result.get()] { result->setLanguageId(languageId()); });
|
||||||
|
|
||||||
|
connect(result.get(), &Utils::AspectContainer::changed, this, &SourceSettings::changed);
|
||||||
|
|
||||||
|
result->setLanguageId(languageId());
|
||||||
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
readSettings();
|
compilers.setToBaseAspectFunction([](const std::shared_ptr<CompilerSettings> &item) {
|
||||||
|
return static_cast<Utils::BaseAspect *>(item.get());
|
||||||
|
});
|
||||||
|
compilers.setIsDirtyFunction(
|
||||||
|
[](const std::shared_ptr<CompilerSettings> &settings) { return settings->isDirty(); });
|
||||||
|
compilers.setApplyFunction(
|
||||||
|
[](const std::shared_ptr<CompilerSettings> &settings) { settings->apply(); });
|
||||||
|
|
||||||
|
for (const auto &aspect : this->aspects())
|
||||||
|
connect(aspect,
|
||||||
|
&Utils::BaseAspect::volatileValueChanged,
|
||||||
|
this,
|
||||||
|
&CompilerExplorerSettings::changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Settings::languageExtension() const
|
void SourceSettings::refresh()
|
||||||
|
{
|
||||||
|
languageId.setValue(languageId.defaultValue());
|
||||||
|
cachedLanguages().clear();
|
||||||
|
languageId.refill();
|
||||||
|
|
||||||
|
compilers.forEachItem(&CompilerSettings::refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SourceSettings::languageExtension() const
|
||||||
{
|
{
|
||||||
auto it = std::find_if(std::begin(cachedLanguages()),
|
auto it = std::find_if(std::begin(cachedLanguages()),
|
||||||
std::end(cachedLanguages()),
|
std::end(cachedLanguages()),
|
||||||
@@ -89,50 +123,70 @@ QString Settings::languageExtension() const
|
|||||||
return ".cpp";
|
return ".cpp";
|
||||||
}
|
}
|
||||||
|
|
||||||
CompilerSettings::CompilerSettings(Settings *settings)
|
CompilerSettings::CompilerSettings(const ApiConfigFunction &apiConfigFunction)
|
||||||
: m_parent(settings)
|
: m_apiConfigFunction(apiConfigFunction)
|
||||||
{
|
{
|
||||||
setAutoApply(true);
|
setAutoApply(false);
|
||||||
compilerOptions.setDefaultValue("-O3");
|
compiler.setSettingsKey("Id");
|
||||||
|
compiler.setLabelText(Tr::tr("Compiler:"));
|
||||||
|
compiler.setFillCallback([this](auto cb) { fillCompilerModel(cb); });
|
||||||
|
|
||||||
|
compilerOptions.setSettingsKey("Options");
|
||||||
compilerOptions.setLabelText(Tr::tr("Compiler options:"));
|
compilerOptions.setLabelText(Tr::tr("Compiler options:"));
|
||||||
compilerOptions.setToolTip(Tr::tr("Arguments passed to the compiler"));
|
compilerOptions.setToolTip(Tr::tr("Arguments passed to the compiler"));
|
||||||
compilerOptions.setDisplayStyle(Utils::StringAspect::DisplayStyle::LineEditDisplay);
|
compilerOptions.setDisplayStyle(Utils::StringAspect::DisplayStyle::LineEditDisplay);
|
||||||
|
|
||||||
compiler.setDefaultValue("clang_trunk");
|
libraries.setSettingsKey("Libraries");
|
||||||
compiler.setLabelText(Tr::tr("Compiler:"));
|
|
||||||
compiler.setFillCallback([this](auto cb) { fillCompilerModel(cb); });
|
|
||||||
|
|
||||||
libraries.setLabelText(Tr::tr("Libraries:"));
|
libraries.setLabelText(Tr::tr("Libraries:"));
|
||||||
libraries.setFillCallback([this](auto cb) { fillLibraries(cb); });
|
libraries.setFillCallback([this](auto cb) { fillLibraries(cb); });
|
||||||
|
|
||||||
|
executeCode.setSettingsKey("ExecuteCode");
|
||||||
executeCode.setLabelText(Tr::tr("Execute the code"));
|
executeCode.setLabelText(Tr::tr("Execute the code"));
|
||||||
|
|
||||||
|
compileToBinaryObject.setSettingsKey("CompileToBinaryObject");
|
||||||
compileToBinaryObject.setLabelText(Tr::tr("Compile to binary object"));
|
compileToBinaryObject.setLabelText(Tr::tr("Compile to binary object"));
|
||||||
|
|
||||||
|
intelAsmSyntax.setSettingsKey("IntelAsmSyntax");
|
||||||
intelAsmSyntax.setLabelText(Tr::tr("Intel asm syntax"));
|
intelAsmSyntax.setLabelText(Tr::tr("Intel asm syntax"));
|
||||||
intelAsmSyntax.setDefaultValue(true);
|
intelAsmSyntax.setDefaultValue(true);
|
||||||
|
|
||||||
|
demangleIdentifiers.setSettingsKey("DemangleIdentifiers");
|
||||||
demangleIdentifiers.setLabelText(Tr::tr("Demangle identifiers"));
|
demangleIdentifiers.setLabelText(Tr::tr("Demangle identifiers"));
|
||||||
demangleIdentifiers.setDefaultValue(true);
|
demangleIdentifiers.setDefaultValue(true);
|
||||||
|
|
||||||
connect(&settings->compilerExplorerUrl, &Utils::StringAspect::changed, this, [this] {
|
for (const auto &aspect : this->aspects())
|
||||||
cachedCompilers().clear();
|
connect(aspect,
|
||||||
cachedLibraries().clear();
|
&Utils::BaseAspect::volatileValueChanged,
|
||||||
|
this,
|
||||||
|
&CompilerExplorerSettings::changed);
|
||||||
|
}
|
||||||
|
|
||||||
compiler.refill();
|
void CompilerSettings::refresh()
|
||||||
libraries.refill();
|
{
|
||||||
});
|
cachedCompilers().clear();
|
||||||
|
cachedLibraries().clear();
|
||||||
|
|
||||||
connect(&settings->languageId, &StringSelectionAspect::changed, this, [this] {
|
compiler.refill();
|
||||||
compiler.refill();
|
libraries.refill();
|
||||||
libraries.refill();
|
}
|
||||||
if (m_parent->languageId() == "c++")
|
|
||||||
compilerOptions.setValue("-O3");
|
void CompilerSettings::setLanguageId(const QString &languageId)
|
||||||
else
|
{
|
||||||
compilerOptions.setValue("");
|
m_languageId = languageId;
|
||||||
});
|
|
||||||
|
compiler.refill();
|
||||||
|
libraries.refill();
|
||||||
|
|
||||||
|
// TODO: Set real defaults ...
|
||||||
|
if (m_languageId == "c++")
|
||||||
|
compilerOptions.setValue("-O3");
|
||||||
|
else
|
||||||
|
compilerOptions.setValue("");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerSettings::fillLibraries(LibrarySelectionAspect::ResultCallback cb)
|
void CompilerSettings::fillLibraries(LibrarySelectionAspect::ResultCallback cb)
|
||||||
{
|
{
|
||||||
const QString lang = m_parent->languageId();
|
const QString lang = m_languageId;
|
||||||
auto fillFromCache = [cb, lang] {
|
auto fillFromCache = [cb, lang] {
|
||||||
QList<QStandardItem *> items;
|
QList<QStandardItem *> items;
|
||||||
for (const Api::Library &lib : cachedLibraries(lang)) {
|
for (const Api::Library &lib : cachedLibraries(lang)) {
|
||||||
@@ -148,7 +202,7 @@ void CompilerSettings::fillLibraries(LibrarySelectionAspect::ResultCallback cb)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto future = Api::libraries(m_parent->apiConfig(), lang);
|
auto future = Api::libraries(m_apiConfigFunction(), lang);
|
||||||
|
|
||||||
auto watcher = new QFutureWatcher<Api::Libraries>(this);
|
auto watcher = new QFutureWatcher<Api::Libraries>(this);
|
||||||
watcher->setFuture(future);
|
watcher->setFuture(future);
|
||||||
@@ -166,7 +220,7 @@ void CompilerSettings::fillLibraries(LibrarySelectionAspect::ResultCallback cb)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::fillLanguageIdModel(StringSelectionAspect::ResultCallback cb)
|
void SourceSettings::fillLanguageIdModel(StringSelectionAspect::ResultCallback cb)
|
||||||
{
|
{
|
||||||
auto fillFromCache = [cb, this] {
|
auto fillFromCache = [cb, this] {
|
||||||
QList<QStandardItem *> items;
|
QList<QStandardItem *> items;
|
||||||
@@ -190,7 +244,7 @@ void Settings::fillLanguageIdModel(StringSelectionAspect::ResultCallback cb)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto future = Api::languages(apiConfig());
|
auto future = Api::languages(m_apiConfigFunction());
|
||||||
|
|
||||||
auto watcher = new QFutureWatcher<Api::Languages>(this);
|
auto watcher = new QFutureWatcher<Api::Languages>(this);
|
||||||
watcher->setFuture(future);
|
watcher->setFuture(future);
|
||||||
@@ -220,13 +274,13 @@ void CompilerSettings::fillCompilerModel(StringSelectionAspect::ResultCallback c
|
|||||||
cb(items);
|
cb(items);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto it = cachedCompilers().find(m_parent->languageId());
|
auto it = cachedCompilers().find(m_languageId);
|
||||||
if (it != cachedCompilers().end()) {
|
if (it != cachedCompilers().end()) {
|
||||||
fillFromCache(it);
|
fillFromCache(it);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto future = Api::compilers(m_parent->apiConfig(), m_parent->languageId());
|
auto future = Api::compilers(m_apiConfigFunction(), m_languageId);
|
||||||
|
|
||||||
auto watcher = new QFutureWatcher<Api::Compilers>(this);
|
auto watcher = new QFutureWatcher<Api::Compilers>(this);
|
||||||
watcher->setFuture(future);
|
watcher->setFuture(future);
|
||||||
@@ -236,7 +290,7 @@ void CompilerSettings::fillCompilerModel(StringSelectionAspect::ResultCallback c
|
|||||||
[watcher, this, fillFromCache]() {
|
[watcher, this, fillFromCache]() {
|
||||||
try {
|
try {
|
||||||
auto result = watcher->result();
|
auto result = watcher->result();
|
||||||
auto itCache = cachedCompilers().insert(m_parent->languageId(), {});
|
auto itCache = cachedCompilers().insert(m_languageId, {});
|
||||||
|
|
||||||
for (const Api::Compiler &compiler : result)
|
for (const Api::Compiler &compiler : result)
|
||||||
itCache->insert(compiler.name, compiler.id);
|
itCache->insert(compiler.name, compiler.id);
|
||||||
@@ -249,4 +303,50 @@ void CompilerSettings::fillCompilerModel(StringSelectionAspect::ResultCallback c
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompilerExplorerSettings::CompilerExplorerSettings()
|
||||||
|
{
|
||||||
|
setAutoApply(false);
|
||||||
|
setSettingsKey("CompilerExplorer");
|
||||||
|
static QNetworkAccessManager networkManager;
|
||||||
|
m_networkAccessManager = &networkManager;
|
||||||
|
|
||||||
|
compilerExplorerUrl.setSettingsKey("CompilerExplorerUrl");
|
||||||
|
compilerExplorerUrl.setLabelText(Tr::tr("Compiler Explorer URL:"));
|
||||||
|
compilerExplorerUrl.setToolTip(Tr::tr("URL of the Compiler Explorer instance to use"));
|
||||||
|
compilerExplorerUrl.setDefaultValue("https://godbolt.org/");
|
||||||
|
compilerExplorerUrl.setDisplayStyle(Utils::StringAspect::DisplayStyle::LineEditDisplay);
|
||||||
|
compilerExplorerUrl.setHistoryCompleter("CompilerExplorer.Url.History");
|
||||||
|
|
||||||
|
windowState.setSettingsKey("WindowState");
|
||||||
|
|
||||||
|
m_sources.setSettingsKey("Sources");
|
||||||
|
m_sources.setCreateItemFunction([this] {
|
||||||
|
auto newSourceSettings = std::make_shared<SourceSettings>([this] { return apiConfig(); });
|
||||||
|
connect(newSourceSettings.get(),
|
||||||
|
&Utils::AspectContainer::changed,
|
||||||
|
this,
|
||||||
|
&CompilerExplorerSettings::changed);
|
||||||
|
return newSourceSettings;
|
||||||
|
});
|
||||||
|
m_sources.setIsDirtyFunction(
|
||||||
|
[](const std::shared_ptr<SourceSettings> &settings) { return settings->isDirty(); });
|
||||||
|
m_sources.setApplyFunction(
|
||||||
|
[](const std::shared_ptr<SourceSettings> &settings) { settings->apply(); });
|
||||||
|
m_sources.setToBaseAspectFunction([](const std::shared_ptr<SourceSettings> &item) {
|
||||||
|
return static_cast<Utils::BaseAspect *>(item.get());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(&compilerExplorerUrl, &Utils::StringAspect::volatileValueChanged, this, [this] {
|
||||||
|
m_sources.forEachItem(&SourceSettings::refresh);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const auto &aspect : this->aspects())
|
||||||
|
connect(aspect,
|
||||||
|
&Utils::BaseAspect::volatileValueChanged,
|
||||||
|
this,
|
||||||
|
&CompilerExplorerSettings::changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilerExplorerSettings::~CompilerExplorerSettings() = default;
|
||||||
|
|
||||||
} // namespace CompilerExplorer
|
} // namespace CompilerExplorer
|
||||||
|
|||||||
@@ -11,12 +11,76 @@
|
|||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
|
|
||||||
namespace CompilerExplorer {
|
namespace CompilerExplorer {
|
||||||
class Settings;
|
class SourceSettings;
|
||||||
|
class CompilerSettings;
|
||||||
|
|
||||||
|
using ApiConfigFunction = std::function<Api::Config()>;
|
||||||
|
|
||||||
|
class PluginSettings : public Utils::AspectContainer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PluginSettings();
|
||||||
|
Utils::StringAspect defaultDocument{this};
|
||||||
|
};
|
||||||
|
|
||||||
|
PluginSettings &settings();
|
||||||
|
|
||||||
|
class CompilerExplorerSettings : public Utils::AspectContainer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CompilerExplorerSettings();
|
||||||
|
~CompilerExplorerSettings();
|
||||||
|
|
||||||
|
Utils::StringAspect compilerExplorerUrl{this};
|
||||||
|
Utils::TypedAspect<QVariantMap> windowState{this};
|
||||||
|
|
||||||
|
AspectListAspect<std::shared_ptr<SourceSettings>> m_sources{this};
|
||||||
|
|
||||||
|
Api::Config apiConfig() const
|
||||||
|
{
|
||||||
|
return Api::Config(m_networkAccessManager, compilerExplorerUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkAccessManager *networkAccessManager() const { return m_networkAccessManager; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QNetworkAccessManager *m_networkAccessManager{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
class SourceSettings : public Utils::AspectContainer,
|
||||||
|
public std::enable_shared_from_this<SourceSettings>
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SourceSettings(const ApiConfigFunction &apiConfigFunction);
|
||||||
|
|
||||||
|
void refresh();
|
||||||
|
|
||||||
|
ApiConfigFunction apiConfigFunction() const { return m_apiConfigFunction; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringSelectionAspect languageId{this};
|
||||||
|
Utils::StringAspect source{this};
|
||||||
|
AspectListAspect<std::shared_ptr<CompilerSettings>> compilers{this};
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString languageExtension() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void languagesChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fillLanguageIdModel(StringSelectionAspect::ResultCallback cb);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CompilerExplorerSettings *m_parent;
|
||||||
|
ApiConfigFunction m_apiConfigFunction;
|
||||||
|
};
|
||||||
|
|
||||||
class CompilerSettings : public Utils::AspectContainer
|
class CompilerSettings : public Utils::AspectContainer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CompilerSettings(Settings *settings);
|
CompilerSettings(const ApiConfigFunction &apiConfigFunction);
|
||||||
|
|
||||||
StringSelectionAspect compiler{this};
|
StringSelectionAspect compiler{this};
|
||||||
|
|
||||||
@@ -29,42 +93,15 @@ public:
|
|||||||
Utils::BoolAspect intelAsmSyntax{this};
|
Utils::BoolAspect intelAsmSyntax{this};
|
||||||
Utils::BoolAspect demangleIdentifiers{this};
|
Utils::BoolAspect demangleIdentifiers{this};
|
||||||
|
|
||||||
|
void refresh();
|
||||||
|
void setLanguageId(const QString &languageId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillCompilerModel(StringSelectionAspect::ResultCallback cb);
|
void fillCompilerModel(StringSelectionAspect::ResultCallback cb);
|
||||||
void fillLibraries(LibrarySelectionAspect::ResultCallback cb);
|
void fillLibraries(LibrarySelectionAspect::ResultCallback cb);
|
||||||
|
|
||||||
Settings *m_parent;
|
QString m_languageId;
|
||||||
|
ApiConfigFunction m_apiConfigFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Settings : public Utils::AspectContainer
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
Settings();
|
|
||||||
|
|
||||||
StringSelectionAspect languageId{this};
|
|
||||||
Utils::StringAspect compilerExplorerUrl{this};
|
|
||||||
|
|
||||||
Utils::StringAspect source{this};
|
|
||||||
|
|
||||||
QNetworkAccessManager *networkAccessManager() const { return m_networkAccessManager; }
|
|
||||||
|
|
||||||
Api::Config apiConfig() const
|
|
||||||
{
|
|
||||||
return Api::Config(m_networkAccessManager, compilerExplorerUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString languageExtension() const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void languagesChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void fillLanguageIdModel(StringSelectionAspect::ResultCallback cb);
|
|
||||||
|
|
||||||
QNetworkAccessManager *m_networkAccessManager{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
Settings &settings();
|
|
||||||
|
|
||||||
} // namespace CompilerExplorer
|
} // namespace CompilerExplorer
|
||||||
|
|||||||
Reference in New Issue
Block a user