Skip to content

fix: load pending tab in recoverFile fallback - #676

Open
pengfeixx wants to merge 1 commit into
linuxdeepin:masterfrom
pengfeixx:agent/pms-bug-bot/72b0b4aeaae7
Open

pengfeixx wants to merge 1 commit into
linuxdeepin:masterfrom
pengfeixx:agent/pms-bug-bot/72b0b4aeaae7

Conversation

@pengfeixx

@pengfeixx pengfeixx commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Root Cause Analysis

When the editor reopens with recoverFile() and the focus tab's file has been deleted/moved, the focus tab is skipped via continue. The remaining non-focus tabs are added as pending (lazy-loaded) tabs via addPendingTab(), which internally calls DTabBar::setCurrentIndex(0) with signals blocked. When only 1 pending tab remains (the 2-file scenario), currentIndex is already 0, so the fallback activeTab(0) → setCurrentIndex(0) does not emit currentChanged. As a result, handleCurrentChanged() is never called, loadPendingTab() is never triggered, and the editor area has no EditWrapper — the user cannot edit.

Key evidence: addPendingTab blocks signals while addTabWithIndex sets currentIndex (tabbar.cpp:141); activeTab calls setCurrentIndex which is a no-op when index unchanged (window.cpp:676-683).

Fix

In the fallback branch of recoverFile() (startmanager.cpp:507), before calling activeTab(0), check whether the first tab is still pending. If so, explicitly call loadPendingTab() to load its content, bypassing the currentChanged signal dependency. This is a 7-line addition using existing public interfaces (isPendingTab, loadPendingTab, getTabbar()->fileAt).

Change Safety Assessment

Code Safety

  • Risk Level: Low
  • Target code is in a fallback branch that only runs when the focus tab file is missing; normal recovery paths are unaffected
  • Uses only existing public Window interfaces; loadPendingTab internally handles file-not-found and tab-creation failures gracefully

Business Impact Scope

Affects the file recovery path on editor startup. Specifically fixes the scenario where exactly 2 files were open and the focus tab's file was deleted/moved before restart. No impact on normal tab switching, file opening, or multi-file recovery (3+ files).

Verification Suggestion

Test the 2-file scenario (open 2 files, delete focus file, restart) to confirm editing works. Also verify 3-file and normal recovery scenarios for no regression.


根因分析

编辑器重启时 recoverFile() 恢复标签页,若焦点标签页文件已被删除/移动,则通过 continue 跳过。剩余非焦点标签页通过 addPendingTab() 以待加载(懒加载)方式添加,其内部调用 DTabBar::setCurrentIndex(0) 但信号被 blockSignals(true) 阻止。当仅剩 1 个待加载标签页(2 文件场景)时,currentIndex 已为 0,兜底代码 activeTab(0) → setCurrentIndex(0) 不会发射 currentChanged 信号,导致 handleCurrentChanged() 永不被调用,loadPendingTab() 永不触发,编辑区域无 EditWrapper,用户无法编辑。

关键证据:addPendingTab 阻塞信号时 addTabWithIndex 已设置 currentIndex(tabbar.cpp:141);activeTab 调用 setCurrentIndex 在索引未变时为空操作(window.cpp:676-683)。

修复方案

在 recoverFile() 兜底分支(startmanager.cpp:507)中,调用 activeTab(0) 前检查第一个标签页是否仍为待加载状态,若是则显式调用 loadPendingTab() 加载内容,不依赖 currentChanged 信号触发。新增 7 行代码,使用已有公开接口(isPendingTab、loadPendingTab、getTabbar()->fileAt)。

改动安全评估

代码安全评估

  • 风险等级: 低风险
  • 目标代码位于兜底分支,仅在焦点标签页文件缺失时执行,不影响正常恢复路径
  • 仅使用 Window 已有公开接口;loadPendingTab 内部已处理文件不存在和标签创建失败的情况

业务影响范围

影响编辑器启动时的文件恢复路径。专门修复打开恰好 2 个文件且焦点标签页文件被删除/移动后重启无法编辑的场景。对正常标签切换、文件打开、多文件恢复(3+ 文件)无影响。

验证建议

测试 2 文件场景(打开 2 个文件,删除焦点文件,重启)确认可正常编辑。同时验证 3 文件及正常恢复场景无回归。

Summary by Sourcery

Bug Fixes:

  • Ensure the first recoverable pending tab is loaded when the focused file is unavailable, restoring an editable editor after startup recovery.

1. Root cause: when focus tab file is deleted/moved, recoverFile()
   skips it via continue, leaving only pending tabs added by
   addPendingTab which implicitly sets currentIndex to 0 with
   signals blocked
2. Fix: before calling activeTab(0), check if the first tab is
   still pending and explicitly call loadPendingTab() to load its
   content, bypassing the currentChanged signal dependency
3. Impact: fixes editor being uneditable after restart when exactly
   2 files were open and the focus tab file was deleted; no behavior
   change for normal recovery paths

Log: fix editor uneditable when focus tab file is deleted

Influence:
1. Test opening 2 files, delete the focus file, restart editor
2. Verify editor content loads and is editable after restart
3. Test opening 3 files, delete focus file, restart editor
4. Verify normal file recovery still works correctly

fix: recoverFile兜底分支显式加载待加载标签页

1. 根因:焦点标签页文件被删除/移动后,recoverFile() 通过 continue
   跳过该标签页,仅剩 addPendingTab 添加的待加载标签页,其内部
   隐式将 currentIndex 设为 0 但信号被阻塞
2. 方案:在调用 activeTab(0) 前,检查第一个标签页是否为待加载
   状态,若是则显式调用 loadPendingTab() 加载内容,不依赖
   currentChanged 信号触发
3. 影响:修复打开2个文件且焦点标签页文件被删除后重启编辑器
   无法编辑的问题,不影响正常文件恢复路径

Log: 修复焦点标签页文件被删除后编辑器无法编辑的问题

Influence:
1. 测试打开2个文件,删除焦点文件后重启编辑器
2. 验证重启后编辑器内容正常加载且可编辑
3. 测试打开3个文件,删除焦点文件后重启编辑器
4. 验证正常文件恢复功能不受影响

PMS: BUG-376141
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: pengfeixx

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

@sourcery-ai

sourcery-ai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Fixes the recovery fallback for the two-file case where the focused file is missing: the remaining pending tab is now explicitly loaded before activation, restoring the editor content while leaving normal recovery paths unchanged.

Sequence diagram for loading a pending recovery tab

sequenceDiagram
    participant StartManager
    participant Window
    participant TabBar
    participant EditWrapper

    StartManager->>TabBar: count()
    StartManager->>TabBar: fileAt(0)
    StartManager->>Window: isPendingTab(firstFile)
    alt first tab is pending
        StartManager->>Window: loadPendingTab(firstFile)
        Window->>EditWrapper: load file content
    end
    StartManager->>Window: activeTab(0)
Loading

File-Level Changes

Change Details Files
Explicitly loads the first pending recovery tab before activating it when the focused file cannot be recovered.
  • Reads the first tab’s file path in the recovery fallback.
  • Checks whether that tab remains pending.
  • Calls the existing pending-tab loader before selecting the tab, avoiding reliance on an unchanged-index currentChanged signal.
src/startmanager.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

🤖 AI 代码审查报告

总体评分: 100 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 本次提交修复了 recoverFile 函数中 pending 标签页未被加载的问题。代码逻辑正确,注释详尽地解释了根因与修复方案, 无安全漏洞,无性能问题。四维度均通过,代码质量优秀。

🔍 详细分析

1. 语法逻辑 ✅

评价: 语法正确,逻辑清晰 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: []


2. 代码质量 ✅

评价: 代码结构清晰,注释完整 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: []


3. 代码性能 ✅

评价: 性能良好,资源使用合理 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: []


4. 代码安全 🔒

评价: 存在0个安全漏洞 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: []


💡 改进建议代码示例

// 当前代码已经是正确的修复方案,无需额外修改。 // 修复后的代码逻辑: // 1. 获取第一个标签页文件路径 // 2. 判断是否为 pending 标签页 // 3. 若是则显式加载,确保编辑区域有内容 // 4. 最后激活该标签页 // // QString firstFile = window->getTabbar()->fileAt(0); // if (window->isPendingTab(firstFile)) { //     window->loadPendingTab(firstFile); // } // window->activeTab(0);

本报告由 AI 代码审查工具自动生成

@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.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/startmanager.cpp" line_range="513-515" />
<code_context>
+        // 当仅剩 pending 标签页时,currentIndex 已被 addPendingTab 隐式设为 0,
+        // activeTab(0) 中的 setCurrentIndex(0) 不会触发 currentChanged 信号,
+        // 需显式加载该 pending 标签页,否则编辑区域为空且无法编辑
+        QString firstFile = window->getTabbar()->fileAt(0);
+        if (window->isPendingTab(firstFile)) {
+            window->loadPendingTab(firstFile);
+        }
         window->activeTab(0);
</code_context>
<issue_to_address>
**Earlier windows open without editors**

When the missing focus record leaves recoverable tabs in multiple saved windows, `recoverFile()` adds pending tabs to every recovery window, but this branch loads a tab only from the last `window`; earlier windows receive no `currentChanged` signal and retain unloaded tabs, so they open without file editors.

Iterate over every recovered window and explicitly load its current pending tab.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread src/startmanager.cpp
Comment on lines +513 to +515
QString firstFile = window->getTabbar()->fileAt(0);
if (window->isPendingTab(firstFile)) {
window->loadPendingTab(firstFile);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Earlier windows open without editors

When the missing focus record leaves recoverable tabs in multiple saved windows, recoverFile() adds pending tabs to every recovery window, but this branch loads a tab only from the last window; earlier windows receive no currentChanged signal and retain unloaded tabs, so they open without file editors.

Iterate over every recovered window and explicitly load its current pending tab.

Prompt for AI agents
In `src/startmanager.cpp` at lines 513-515:

**Earlier windows open without editors**

When the missing focus record leaves recoverable tabs in multiple saved windows, `recoverFile()` adds pending tabs to every recovery window, but this branch loads a tab only from the last `window`; earlier windows receive no `currentChanged` signal and retain unloaded tabs, so they open without file editors.

Iterate over every recovered window and explicitly load its current pending tab.

@deepin-bot

deepin-bot Bot commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

TAG Bot

New tag: 6.6.8
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #678

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.

2 participants