Skip to content

fix(editor): persist file encoding across sessions - #491

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:release/eaglefrom
GongHeng2017:agent/bugfix/a13ac752
Jul 28, 2026
Merged

fix(editor): persist file encoding across sessions#491
deepin-bot[bot] merged 1 commit into
linuxdeepin:release/eaglefrom
GongHeng2017:agent/bugfix/a13ac752

Conversation

@GongHeng2017

@GongHeng2017 GongHeng2017 commented Jul 28, 2026

Copy link
Copy Markdown

修复 BUG-365847:切换编码格式并保存后再打开,部分格式无法保存

问题

用户在文本编辑器中切换文件编码格式(如 GB18030、ISO-8859-1、CP1252 等)并保存后,关闭标签页重新打开,编码格式回退为 UTF-8,无法保持用户选择的编码。

根因

deepin-editor 打开文件时完全依赖 DetectCode::GetFileEncodingFormat 对内容做编码探测。对于与 UTF-8/ASCII 字节重叠的编码(ASCII 内容保存为 GB18030 等),探测器无法区分,必然回退为 UTF-8。项目中已有编码历史持久化机制(隐藏配置项 browsing_encode_history + writeEncodeHistoryRecord/readEncodeHistoryRecord),但该机制是死代码,从未接入保存/打开流程。

修复方案

激活已有但未接入的编码历史持久化机制:

  1. FileLoadThread:新增 setPreferredEncode/m_preferredEncode,打开文件时优先使用历史编码,跳过不可靠的内容自动探测
  2. TextEdit:新增 readEncodeHistoryRecord(filepath) 重载,按文件路径查询历史编码;新增 setTextEncode setter
  3. EditWrapper::openFile:读取历史编码并设为 preferred hint
  4. EditWrapper 各保存路径(saveFile/saveTemFile/saveDraftFile/forceSaveInvalidCharFile):保存成功后记录编码历史
  5. Window::saveAsFileToDisk:另存为成功后(路径已更新为新路径)记录编码历史

审查说明

基于用户提供的 fix.patch,审查发现并修复了 saveAsFile(newFilePath, encode) 中的路径键问题:原 patch 在 writeEncodeHistoryRecord()m_sFilePath 仍为旧路径(调用方 saveAsFileToDiskupdateSaveAsFileName 之后才更新为新路径),导致历史记录键到错误路径。已将另存为的历史记录从 saveAsFile 移至 saveAsFileToDiskupdateSaveAsFileName 之后。

PMS: https://pms.uniontech.com/bug-view-365847.html

Summary by Sourcery

Persist user-selected text encoding across file saves and reopen, avoiding incorrect fallback to UTF-8 by reusing stored encoding history when loading files.

Bug Fixes:

  • Ensure files reopen using their last saved encoding by preferring persisted encoding history over automatic detection, especially for encodings overlapping with UTF-8/ASCII.

Enhancements:

  • Add per-file encoding history lookup and use it as a preferred hint when opening files.
  • Record encoding history on successful save, draft save, invalid-character forced save, and save-as operations.
  • Allow the file loading thread to accept a preferred encoding to bypass unreliable automatic detection for known files.

Activate the existing but unused encoding history mechanism
(browsing_encode_history + writeEncodeHistoryRecord/readEncodeHistoryRecord)
to remember the user's chosen encoding per file path. When saving,
record the encoding; when reopening, pass it as a preferred encode hint
to FileLoadThread, skipping unreliable content-based detection that
falls back to UTF-8 for ASCII-compatible encodings (GB18030, ISO-8859-1,
CP1252, BIG5, etc.).

Changes:
- FileLoadThread: add setPreferredEncode/m_preferredEncode; use preferred
  encode to skip auto-detection in both large-file and normal paths
- TextEdit: add readEncodeHistoryRecord(filepath) overload to look up a
  specific file's stored encoding; add setTextEncode setter
- EditWrapper::openFile: read history encoding and set as preferred hint
- EditWrapper::saveFile/saveTemFile/saveDraftFile/forceSaveInvalidCharFile:
  record encoding history after successful save
- Window::saveAsFileToDisk: record encoding history after path is updated
  to the new file path (fixes path-key issue in saveAsFile)

Log: 激活编码历史持久化机制,修复切换编码保存后重新打开编码丢失的问题
Bug: https://pms.uniontech.com/bug-view-365847.html

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @GongHeng2017, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@sourcery-ai

sourcery-ai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Reviewer's Guide

Persists user-selected file encodings by wiring the existing encode history mechanism into file open/save flows, and by allowing FileLoadThread to prefer a stored encoding over automatic detection.

Sequence diagram for opening a file with preferred encoding history

sequenceDiagram
    actor User
    participant Window
    participant EditWrapper
    participant TextEdit
    participant FileLoadThread
    participant DetectCode

    User ->> Window: openFile
    Window ->> EditWrapper: openFile(filepath, qstrTruePath, bNewWindow)
    EditWrapper ->> TextEdit: setFilePath(filepath)
    EditWrapper ->> TextEdit: readEncodeHistoryRecord(filepath)
    TextEdit -->> EditWrapper: historyEncode
    alt [historyEncode not empty]
        EditWrapper ->> FileLoadThread: setPreferredEncode(historyEncode.toLocal8Bit)
    end
    EditWrapper ->> FileLoadThread: start
    FileLoadThread ->> FileLoadThread: run
    alt [m_preferredEncode not empty]
        FileLoadThread ->> FileLoadThread: encode = m_preferredEncode
    else [m_preferredEncode empty]
        FileLoadThread ->> DetectCode: GetFileEncodingFormat(m_strFilePath, indata)
        DetectCode -->> FileLoadThread: encode
    end
Loading

Sequence diagram for saving a file and recording encoding history

sequenceDiagram
    actor User
    participant Window
    participant EditWrapper
    participant TextEdit

    User ->> EditWrapper: saveFile(encode)
    EditWrapper ->> EditWrapper: write file to disk
    EditWrapper ->> TextEdit: setTextEncode(m_sCurEncode)
    EditWrapper ->> TextEdit: writeEncodeHistoryRecord

    User ->> Window: saveAsFileToDisk
    Window ->> EditWrapper: saveAsFile(newFilePath, encode)
    Window ->> Window: updateSaveAsFileName(wrapper->filePath, newFilePath)
    Window ->> TextEdit: setTextEncode(QString::fromUtf8(encode))
    Window ->> TextEdit: writeEncodeHistoryRecord

    User ->> EditWrapper: saveDraftFile(newFilePath)
    EditWrapper ->> EditWrapper: write draft file
    EditWrapper ->> TextEdit: setTextEncode(QString::fromUtf8(encode))
    EditWrapper ->> TextEdit: writeEncodeHistoryRecord
Loading

File-Level Changes

Change Details Files
Persist and read per-file encoding history in TextEdit and use it when opening files.
  • Added TextEdit::readEncodeHistoryRecord(const QString&) to look up a file-specific encoding from the browsing_encode_history setting.
  • Introduced a setTextEncode() inline setter to store the current encoding on TextEdit for history writes.
  • Wired EditWrapper::openFile to set the file path on TextEdit, read any stored encoding, and pass it to FileLoadThread as a preferred encoding hint.
src/editor/dtextedit.cpp
src/editor/dtextedit.h
src/editor/editwrapper.cpp
Allow FileLoadThread to skip unreliable auto-detection when a preferred encoding is available.
  • Added a m_preferredEncode member and setPreferredEncode() API in FileLoadThread.
  • Updated FileLoadThread::run() to use m_preferredEncode when present and only fall back to DetectCode::GetFileEncodingFormat when no preferred encoding is provided, including for large files.
src/common/fileloadthread.cpp
src/common/fileloadthread.h
Record encoding history after all successful save flows, including Save As, drafts, and invalid-char saves.
  • Updated EditWrapper::saveFile, saveDraftFile, and forceSaveInvalidCharFile to set the TextEdit encoding and call writeEncodeHistoryRecord() after successful saves.
  • Updated Window::saveAsFileToDisk to record encoding history after updateSaveAsFileName, ensuring the history key uses the new file path instead of the old one.
src/editor/editwrapper.cpp
src/widgets/window.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

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:100分

■ 【总体评价】

代码实现了基于历史记录的文件编码优先加载机制,有效解决了大文件编码探测不一致导致的乱码问题
逻辑正确且通过跳过自动探测提升了文件打开性能,无安全漏洞,代码质量优秀

■ 【详细分析】

  • 1.语法逻辑(完全正确)✓

代码在 FileLoadThread::run() 中正确增加了对 m_preferredEncode 的判断,在 EditWrapper::openFile() 中正确读取历史记录并传入线程。保存逻辑在 saveFileforceSaveInvalidCharFilesaveDraftFilesaveAsFileToDisk 中均正确调用了记录方法。
潜在问题:TextEdit::readEncodeHistoryRecord(const QString &filepath) 使用字符串匹配解析历史记录,若 filepath 本身包含特殊字符(如 ]*),可能导致解析位置错误,返回错误的编码字符串。
建议:考虑使用 JSON 等结构化格式存储历史编码记录,或对文件路径进行转义/哈希处理后再拼接,以增强解析的健壮性。

  • 2.代码质量(优秀)✓

新增代码遵循了现有的命名规范,变量命名清晰,且在头文件和实现文件中添加了必要的注释说明。代码结构清晰,职责划分明确。
潜在问题:无
建议:无

  • 3.代码性能(高效)✓

通过优先使用历史编码记录,跳过了对大文件头部 1MB 数据的 DetectCode::GetFileEncodingFormat 自动探测过程,减少了不必要的计算开销,显著提升了文件打开速度。
潜在问题:无
建议:无

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
代码主要涉及文件编码历史的读写和线程传参,未引入外部输入直接执行或拼接 SQL/命令的操作,不存在安全风险。

  • 建议:无

■ 【改进建议代码示例】

// 建议改进 TextEdit::readEncodeHistoryRecord 的解析逻辑,使用更安全的 JSON 格式存储和读取
// 假设历史记录存储格式改为 JSON: {"file_path_1": "UTF-8", "file_path_2": "GBK"}

QString TextEdit::readEncodeHistoryRecord(const QString &filepath)
{
    QString history = m_settings->settings->option("advance.editor.browsing_encode_history")->value().toString();
    if (history.isEmpty()) {
        return QString();
    }

    QJsonDocument doc = QJsonDocument::fromJson(history.toUtf8());
    if (doc.isObject()) {
        QJsonObject obj = doc.object();
        if (obj.contains(filepath)) {
            return obj.value(filepath).toString();
        }
    }
    
    return QString();
}

// 对应的 writeEncodeHistoryRecord 也应修改为更新 JSON 对象

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: GongHeng2017, max-lvs

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@GongHeng2017

Copy link
Copy Markdown
Author

/merge

@deepin-bot
deepin-bot Bot merged commit 1d54985 into linuxdeepin:release/eagle Jul 28, 2026
20 checks passed
deepin-bot Bot pushed a commit that referenced this pull request Jul 29, 2026
This reverts commit 1d54985.

需求调整,回退 PR #491(bug-fix-365847)的编码历史持久化改动,
代码恢复到该 PR 合并前的状态。

Log: 回退编码历史持久化机制改动
Bug: https://pms.uniontech.com/bug-view-365847.html
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.

3 participants