Skip to content

Conversation

@nschimme
Copy link
Contributor

@nschimme nschimme commented Jan 29, 2026

Summary by Sourcery

Add configuration import/export and in-app editing capabilities, and adjust related configuration and connection handling.

New Features:

  • Allow editing the client configuration via a GUI editor opened from the config command.
  • Add UI actions to export the current configuration to an .ini file and import configuration from an external .ini file.

Bug Fixes:

  • Remove obsolete doorhelp command and its mention from help text to avoid referencing unsupported functionality.

Enhancements:

  • Refactor configuration read/write logic into reusable readFrom/writeTo helpers to support file-based import/export.
  • Rename the general preferences signal to a generic config reload signal and reuse it for factory reset and imports.
  • Improve socket error handling by reporting a clear message when SSL connections to MUME fail.

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 29, 2026

Reviewer's Guide

Implements configuration edit/export/import workflows using QSettings and temporary files, refactors Configuration read/write to support external QSettings, wires UI signals to reload config after changes, slightly adjusts help/commands, and improves SSL error handling.

Sequence diagram for config edit console command

sequenceDiagram
    actor User
    participant AbstractParser
    participant QTemporaryFile
    participant QSettings
    participant QFile
    participant RemoteEditWidget
    participant Configuration

    User->>AbstractParser: config edit
    AbstractParser->>AbstractParser: isConnected check
    alt user is connected
        AbstractParser-->>User: error You must disconnect
    else user is disconnected
        AbstractParser-->>User: Opening configuration editor
        AbstractParser->>QTemporaryFile: create temp ini file
        QTemporaryFile-->>AbstractParser: fileName
        AbstractParser->>QSettings: writeTo using getConfig
        AbstractParser->>QFile: open temp ini for read
        QFile-->>AbstractParser: content
        AbstractParser->>QFile: remove temp file
        alt content empty
            AbstractParser-->>User: Configuration is empty or failed to export
        else content ok
            AbstractParser->>RemoteEditWidget: new RemoteEditWidget(true, title, content)
            AbstractParser->>RemoteEditWidget: connect sig_save to lambda
            RemoteEditWidget->>User: show editor window

            User->>RemoteEditWidget: edits and saves
            RemoteEditWidget-->>AbstractParser: sig_save(edited)
            AbstractParser->>QTemporaryFile: create tempRead ini file
            AbstractParser->>QTemporaryFile: write edited content
            AbstractParser->>QSettings: cfg.readFrom(tempRead)
            AbstractParser->>Configuration: write
            AbstractParser-->>User: Configuration imported and persisted
            AbstractParser-->>User: OK response
        end
    end
Loading

Sequence diagram for preferences configuration export and import

sequenceDiagram
    actor User
    participant GeneralPage
    participant QTemporaryFile
    participant QSettings
    participant QFile
    participant QFileDialog
    participant Configuration
    participant ConfigDialog
    participant OtherPages

    rect rgb(230,230,250)
    note over User,GeneralPage: Export workflow
    User->>GeneralPage: clicks configurationExportButton
    GeneralPage->>QTemporaryFile: create temp ini
    QTemporaryFile-->>GeneralPage: fileName
    GeneralPage->>QSettings: getConfig.writeTo
    GeneralPage->>QFile: open temp for read
    QFile-->>GeneralPage: content
    GeneralPage->>QFileDialog: saveFileContent(content, mmapper.ini)
    GeneralPage->>QFile: remove temp file
    end

    rect rgb(230,250,230)
    note over User,GeneralPage: Import workflow
    User->>GeneralPage: clicks configurationImportButton
    GeneralPage->>QFileDialog: getOpenFileContent(callback importFile)
    QFileDialog-->>GeneralPage: fileName, fileContent
    GeneralPage->>QTemporaryFile: create temp import ini
    GeneralPage->>QTemporaryFile: write content
    GeneralPage->>QSettings: cfg.readFrom(tempImport)
    GeneralPage->>Configuration: write
    GeneralPage-->>ConfigDialog: sig_reloadConfig
    ConfigDialog-->>GeneralPage: sig_loadConfig
    ConfigDialog-->>OtherPages: sig_loadConfig
    end
Loading

Class diagram for updated configuration and preferences classes

classDiagram
    class Configuration {
        +GeneralSettings general
        +ColorSettings colorSettings
        +NetworkSettings network
        +void read()
        +void write() const
        +void reset()
        +void readFrom(QSettings &conf)
        +void writeTo(QSettings &conf) const
    }

    class AbstractParser {
        +void doConfig(StringView cmd)
        +bool isConnected() const
        +Configuration & setConfig()
        +const Configuration & getConfig() const
        +void sendToUser(SendToUserSourceEnum source, const char *text)
        +void sendOkToUser()
    }

    class RemoteEditWidget {
        +RemoteEditWidget(bool modal, const QString &title, const QString &content, QWidget *parent)
        +void show()
        +void activateWindow()
        +void setAttribute(Qt::WidgetAttribute attribute)
        <<signal>> void sig_save(const QString &edited)
    }

    class GeneralPage {
        +GeneralPage(QWidget *parent)
        +void slot_loadConfig()
        <<signal>> void sig_reloadConfig()
    }

    class ConfigDialog {
        +ConfigDialog(QWidget *parent)
        <<signal>> void sig_loadConfig()
    }

    class MumeFallbackSocket {
        +void onSocketError(const QString &errorString)
    }

    Configuration <.. AbstractParser : uses
    Configuration <.. GeneralPage : uses
    Configuration <.. ConfigDialog : uses

    AbstractParser --> RemoteEditWidget : creates and connects

    GeneralPage ..> ConfigDialog : emits sig_reloadConfig
    ConfigDialog ..> GeneralPage : emits sig_loadConfig

    MumeFallbackSocket ..> SocketTypeEnum : uses
Loading

File-Level Changes

Change Details Files
Add /config edit command to open a RemoteEditWidget for interactive client-configuration editing and persist edited settings.
  • Add edit subcommand handler under the config command that prevents use while connected and notifies the user.
  • Export current configuration to a temporary INI file via QSettings, load its contents, and pass them into a RemoteEditWidget instance.
  • On sig_save from the editor, write edited content to a temporary INI file, reload it into the Configuration object using QSettings, persist it, and send confirmation back to the user.
  • Introduce required Qt includes (QDir, QFile, QPointer, QSettings, QTemporaryFile and RemoteEditWidget header) in the parser config implementation.
src/parser/AbstractParser-Config.cpp
Add configuration export/import buttons in the General preferences page that round-trip configuration via INI using temporary files and QSettings, and ensure the UI reloads configuration after changes or factory reset.
  • Change factory reset signaling from sig_factoryReset to sig_reloadConfig so the dialog can reuse one signal for any config reload trigger.
  • Wire ConfigDialog to listen to sig_reloadConfig from GeneralPage and propagate sig_loadConfig to all preference sub-pages.
  • Implement configuration export button to write current settings to a temporary INI using QSettings, then offer it for download via QFileDialog::saveFileContent.
  • Implement configuration import button using QFileDialog::getOpenFileContent, writing the selected INI bytes to a temporary file, loading them into Configuration via QSettings, persisting them, and emitting sig_reloadConfig.
  • Update the GeneralPage UI header and UI file to match the new signal and buttons.
src/preferences/generalpage.cpp
src/preferences/generalpage.h
src/preferences/generalpage.ui
src/preferences/configdialog.cpp
Refactor Configuration read/write so they can operate on arbitrary QSettings instances, enabling reuse in export/import paths.
  • Split Configuration::read into a wrapper that constructs default SETTINGS(conf) and a new readFrom(QSettings &) that performs the actual load, keeping color reset and first-time-install logic intact.
  • Split Configuration::write into a wrapper that constructs default SETTINGS(conf) and a new writeTo(QSettings &) that performs the group-wise write.
  • Expose readFrom(QSettings &) and writeTo(QSettings &) in the Configuration header for use by parser and preferences code.
src/configuration/configuration.cpp
src/configuration/configuration.h
Clean up help/command set and slightly improve SSL error handling in the MUME proxy socket.
  • Remove the doorhelp command registration and abbreviation, and drop its mention from the general help text.
  • Adjust MumeFallbackSocket::onSocketError to emit a more user-friendly message and return immediately for SSL failures instead of falling through to assertion handling.
src/parser/AbstractParser-Commands.cpp
src/parser/abstractparser.cpp
src/proxy/mumesocket.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The export/import logic for configuration appears duplicated across the new config edit handler and the GeneralPage buttons (temp-file creation, QSettings write/read, QFile removal); consider extracting small helpers (e.g., exportConfigToByteArray / importConfigFromByteArray) to centralize this behavior and reduce the chance of subtle inconsistencies.
  • The new public Configuration::readFrom(QSettings &conf) and writeTo(QSettings &conf) const methods add a QSettings dependency to the header; ensure configuration.h either includes <QSettings> or forward-declares class QSettings; so that all translation units including this header compile cleanly.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The export/import logic for configuration appears duplicated across the new `config edit` handler and the GeneralPage buttons (temp-file creation, QSettings write/read, QFile removal); consider extracting small helpers (e.g., `exportConfigToByteArray` / `importConfigFromByteArray`) to centralize this behavior and reduce the chance of subtle inconsistencies.
- The new public `Configuration::readFrom(QSettings &conf)` and `writeTo(QSettings &conf) const` methods add a QSettings dependency to the header; ensure `configuration.h` either includes `<QSettings>` or forward-declares `class QSettings;` so that all translation units including this header compile cleanly.

## Individual Comments

### Comment 1
<location> `src/preferences/generalpage.cpp:142-143` </location>
<code_context>
+    });
+
+    connect(ui->configurationImportButton, &QAbstractButton::clicked, this, [this]() {
+        auto importFile = [this](const QString &fileName,
+                                 const std::optional<QByteArray> &fileContent) {
+            if (fileName.isEmpty() || !fileContent.has_value()) {
+                return;
</code_context>

<issue_to_address>
**issue (bug_risk):** Import callback signature using std::optional<QByteArray> may not match QFileDialog::getOpenFileContent expectations.

`QFileDialog::getOpenFileContent` expects a callback `void(const QString &, const QByteArray &)`. A lambda taking `const std::optional<QByteArray> &` will not match this signature and will fail to compile (no implicit conversion from `QByteArray` to `std::optional<QByteArray>`). If you need to represent “no content”, keep the Qt signature and use `content.isEmpty()` instead of `std::optional`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +142 to +143
auto importFile = [this](const QString &fileName,
const std::optional<QByteArray> &fileContent) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Import callback signature using std::optional may not match QFileDialog::getOpenFileContent expectations.

QFileDialog::getOpenFileContent expects a callback void(const QString &, const QByteArray &). A lambda taking const std::optional<QByteArray> & will not match this signature and will fail to compile (no implicit conversion from QByteArray to std::optional<QByteArray>). If you need to represent “no content”, keep the Qt signature and use content.isEmpty() instead of std::optional.

@codecov
Copy link

codecov bot commented Jan 29, 2026

Codecov Report

❌ Patch coverage is 42.85714% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.06%. Comparing base (26d1a9d) to head (1337323).
⚠️ Report is 181 commits behind head on master.

Files with missing lines Patch % Lines
src/configuration/configuration.cpp 42.85% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #444      +/-   ##
==========================================
+ Coverage   66.48%   74.06%   +7.58%     
==========================================
  Files          85       87       +2     
  Lines        4186     4033     -153     
  Branches      255      274      +19     
==========================================
+ Hits         2783     2987     +204     
+ Misses       1403     1046     -357     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nschimme nschimme merged commit 737be29 into MUME:master Jan 29, 2026
20 of 22 checks passed
@nschimme nschimme deleted the config branch January 29, 2026 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant