File indexing completed on 2024-04-28 05:48:32

0001 /*
0002     SPDX-FileCopyrightText: 2019 Mark Nauwelaerts <mark.nauwelaerts@gmail.com>
0003     SPDX-FileCopyrightText: 2023 Akseli Lahtinen <akselmo@akselmo.dev>
0004 
0005     SPDX-License-Identifier: MIT
0006 */
0007 
0008 #include "debugconfigpage.h"
0009 #include "plugin_kategdb.h"
0010 #include "ui_debugconfig.h"
0011 
0012 #include <KLocalizedString>
0013 
0014 #include <KSyntaxHighlighting/Definition>
0015 #include <KSyntaxHighlighting/Repository>
0016 #include <KSyntaxHighlighting/SyntaxHighlighter>
0017 #include <KSyntaxHighlighting/Theme>
0018 
0019 #include <KTextEditor/Editor>
0020 
0021 #include <QJsonDocument>
0022 #include <QJsonParseError>
0023 #include <QMenu>
0024 #include <QPalette>
0025 
0026 DebugConfigPage::DebugConfigPage(QWidget *parent, KatePluginGDB *plugin)
0027     : KTextEditor::ConfigPage(parent)
0028     , m_plugin(plugin)
0029 {
0030     ui = new Ui::DebugConfigWidget();
0031     ui->setupUi(this);
0032 
0033     // Fix-up our two text edits to be proper JSON file editors
0034     updateHighlighters();
0035 
0036     // Ensure we update the highlighters if the repository is updated or theme is changed
0037     connect(KTextEditor::Editor::instance(), &KTextEditor::Editor::repositoryReloaded, this, &DebugConfigPage::updateHighlighters);
0038     connect(KTextEditor::Editor::instance(), &KTextEditor::Editor::configChanged, this, &DebugConfigPage::updateHighlighters);
0039 
0040     // Setup default JSON settings
0041     QFile defaultConfigFile(QStringLiteral(":/debugger/dap.json"));
0042     defaultConfigFile.open(QIODevice::ReadOnly);
0043     Q_ASSERT(defaultConfigFile.isOpen());
0044     ui->defaultConfig->setPlainText(QString::fromUtf8(defaultConfigFile.readAll()));
0045 
0046     // Setup default config path as placeholder to show user where it is
0047     ui->edtConfigPath->setPlaceholderText(m_plugin->m_defaultConfigPath.toLocalFile());
0048 
0049     reset();
0050 
0051     connect(ui->edtConfigPath, &KUrlRequester::textChanged, this, &DebugConfigPage::configUrlChanged);
0052     connect(ui->edtConfigPath, &KUrlRequester::urlSelected, this, &DebugConfigPage::configUrlChanged);
0053 
0054     auto cfgh = [this](int position, int added, int removed) {
0055         Q_UNUSED(position);
0056         // Discard format change
0057         // (e.g. due to syntax highlighting)
0058         if (added || removed) {
0059             configTextChanged();
0060         }
0061     };
0062     connect(ui->userConfig->document(), &QTextDocument::contentsChange, this, cfgh);
0063 }
0064 
0065 DebugConfigPage::~DebugConfigPage()
0066 {
0067     delete ui;
0068 }
0069 
0070 QString DebugConfigPage::name() const
0071 {
0072     return QString(i18n("Debugger"));
0073 }
0074 
0075 QString DebugConfigPage::fullName() const
0076 {
0077     return QString(i18n("Debugger"));
0078 }
0079 
0080 QIcon DebugConfigPage::icon() const
0081 {
0082     return QIcon::fromTheme(QLatin1String("debug-run"));
0083 }
0084 
0085 void DebugConfigPage::apply()
0086 {
0087     m_plugin->m_configPath = ui->edtConfigPath->url();
0088     // Own scope to ensure file is flushed before we signal below in writeConfig!
0089     {
0090         QFile configFile(m_plugin->configPath().toLocalFile());
0091         configFile.open(QIODevice::WriteOnly);
0092         if (configFile.isOpen()) {
0093             configFile.write(ui->userConfig->toPlainText().toUtf8());
0094         }
0095     }
0096 
0097     m_plugin->writeConfig();
0098 }
0099 
0100 void DebugConfigPage::reset()
0101 {
0102     ui->edtConfigPath->setUrl(m_plugin->m_configPath);
0103     readUserConfig(m_plugin->configPath().toLocalFile());
0104 }
0105 
0106 void DebugConfigPage::defaults()
0107 {
0108     reset();
0109 }
0110 
0111 void DebugConfigPage::readUserConfig(const QString &fileName)
0112 {
0113     QFile configFile(fileName);
0114     configFile.open(QIODevice::ReadOnly);
0115     if (configFile.isOpen()) {
0116         ui->userConfig->setPlainText(QString::fromUtf8(configFile.readAll()));
0117     } else {
0118         ui->userConfig->clear();
0119     }
0120 
0121     updateConfigTextErrorState();
0122 }
0123 
0124 void DebugConfigPage::updateConfigTextErrorState()
0125 {
0126     const auto data = ui->userConfig->toPlainText().toUtf8();
0127     if (data.isEmpty()) {
0128         ui->userConfigError->setText(i18n("No JSON data to validate."));
0129         return;
0130     }
0131 
0132     QJsonParseError error{};
0133     auto json = QJsonDocument::fromJson(data, &error);
0134     if (error.error == QJsonParseError::NoError) {
0135         if (json.isObject()) {
0136             ui->userConfigError->setText(i18n("JSON data is valid."));
0137         } else {
0138             ui->userConfigError->setText(i18n("JSON data is invalid: no JSON object"));
0139         }
0140     } else {
0141         ui->userConfigError->setText(i18n("JSON data is invalid: %1", error.errorString()));
0142     }
0143 }
0144 
0145 void DebugConfigPage::configTextChanged()
0146 {
0147     updateConfigTextErrorState();
0148     changed();
0149 }
0150 
0151 void DebugConfigPage::configUrlChanged()
0152 {
0153     readUserConfig(ui->edtConfigPath->url().isEmpty() ? m_plugin->m_defaultConfigPath.toLocalFile() : ui->edtConfigPath->url().toLocalFile());
0154     changed();
0155 }
0156 
0157 void DebugConfigPage::updateHighlighters()
0158 {
0159     for (auto textEdit : {ui->userConfig, ui->defaultConfig}) {
0160         auto highlighter = new KSyntaxHighlighting::SyntaxHighlighter(textEdit->document());
0161         highlighter->setDefinition(KTextEditor::Editor::instance()->repository().definitionForFileName(QStringLiteral("dap.json")));
0162 
0163         // Use monospace font
0164         textEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
0165 
0166         // Use right color scheme
0167         const auto theme = KTextEditor::Editor::instance()->theme();
0168         auto pal = qApp->palette();
0169         pal.setColor(QPalette::Base, QColor::fromRgba(theme.editorColor(KSyntaxHighlighting::Theme::BackgroundColor)));
0170         pal.setColor(QPalette::Highlight, QColor::fromRgba(theme.editorColor(KSyntaxHighlighting::Theme::TextSelection)));
0171         textEdit->setPalette(pal);
0172         highlighter->setTheme(theme);
0173         highlighter->rehighlight();
0174     }
0175 }
0176 
0177 #include "moc_debugconfigpage.cpp"