Skip to content

fix: merge column-edit undo into single step - #706

Draft
pppanghu77 wants to merge 1 commit into
linuxdeepin:release/eaglefrom
pppanghu77:fix/pms-254289
Draft

pppanghu77 wants to merge 1 commit into
linuxdeepin:release/eaglefrom
pppanghu77:fix/pms-254289

Conversation

@pppanghu77

@pppanghu77 pppanghu77 commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Root Cause Analysis

In column-edit mode (ALT+mouse, multi-cursor), each keystroke calls insertColumnEditTextEx() which pushes a new InsertTextUndoCommand onto the custom QUndoStack. However, InsertTextUndoCommand did not implement mergeWith() or id(), so QUndoStack::push() never merged consecutive keystrokes — each keypress created a separate undo entry. Typing "//" required two Ctrl+Z presses to undo, instead of one.

Key evidence: inserttextundocommand.h had no mergeWith()/id() declarations; dtextedit.cpp:267-279 (insertColumnEditTextEx) pushes a new command per keystroke; QUndoCommand::mergeWith() base returns false by default.

Fix

Implemented id() (returns constant 1001) and mergeWith() on InsertTextUndoCommand: consecutive column-edit commands are merged by concatenating m_sInsertText and adopting other's cursor positions (which reflect the latest state after other->redo() ran). Also fixed undo() column-edit branch to delete m_sInsertText.length() chars per cursor instead of a single deleteChar() — necessary because after merging, m_sInsertText is multi-char.

Change Safety Assessment

Code Safety

  • Risk Level: Medium
  • Target lines are not a historical bug fix product; this change does not revert any prior fix
  • Related PMS bugs (196349, 187765, 187773) target drag-text redo and multi-byte encoding offset calculation — no overlap with column-edit mergeWith logic, no regression risk
  • Normal single-cursor mode is isolated: mergeWith() returns false when m_ColumnEditSelections is empty

Business Impact Scope

Column-edit mode (ALT+mouse multi-cursor) undo behavior is the only affected feature. Users typing multi-character text in column-edit mode will now undo the entire input with one Ctrl+Z. Normal editing mode is unaffected.

Verification Suggestion

Test column-edit mode with multi-char input (e.g. type // or hello) then Ctrl+Z — should undo in one step. Also verify normal single-cursor mode undo works as before (regression check).


根因分析

列编辑模式(ALT+鼠标多光标)下,每次按键调用 insertColumnEditTextEx() 向自定义 QUndoStack 压入新的 InsertTextUndoCommand。但该类未实现 mergeWith() 和 id(),导致 QUndoStack::push() 无法合并连续按键——每次按键产生独立撤销条目。输入 "//" 需要按两次 Ctrl+Z 才能撤销,而非一次。

关键证据:inserttextundocommand.h 无 mergeWith()/id() 声明;dtextedit.cpp:267-279(insertColumnEditTextEx)每次按键压入新命令;QUndoCommand::mergeWith() 基类默认返回 false。

修复方案

为 InsertTextUndoCommand 实现 id()(返回常量 1001)和 mergeWith():连续列编辑命令通过追加 m_sInsertText 并采用 other 的光标位置(other->redo() 执行后的最新位置)进行合并。同时修正 undo() 列编辑分支,按 m_sInsertText.length() 逐光标删除对应字符数,而非单次 deleteChar()——合并后 m_sInsertText 为多字符,必须按实际长度删除。

改动安全评估

代码安全评估

  • 风险等级: 中风险
  • 目标行非历史修复产物,本次改动不撤销任何已有修复
  • 关联 PMS bug(196349、187765、187773)针对拖拽文本重做和多字节编码偏移计算,与列编辑 mergeWith 逻辑无交集,无回归风险
  • 普通单光标模式已隔离:mergeWith() 在 m_ColumnEditSelections 为空时返回 false

业务影响范围

仅影响列编辑模式(ALT+鼠标多光标)的撤销行为。用户在列编辑模式下输入多字符文本后,一次 Ctrl+Z 即可撤销整段输入。普通编辑模式不受影响。

验证建议

测试列编辑模式多字符输入(如输入 // 或 hello)后 Ctrl+Z——应一步撤销。同时验证普通单光标模式撤销行为正常(回归检查)。

Summary by Sourcery

Fix column-edit undo behavior so consecutive multi-cursor keystrokes are reverted together in one operation.

Bug Fixes:

  • Merge consecutive column-edit text insertions into a single undo step.
  • Ensure undo removes the full merged text for each column-edit cursor.

Enhancements:

  • Keep normal single-cursor text insertion undo behavior separate from column-edit command merging.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: pppanghu77

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 29, 2026

Copy link
Copy Markdown

Reviewer's Guide

Column-edit keystrokes now merge through QUndoCommand’s ID and mergeWith() mechanism, accumulating inserted text and the latest cursor positions so one undo reverses the full input. The undo path deletes the accumulated text length per cursor, while non-column/single-cursor commands remain non-mergeable.

Sequence diagram for merged column-edit undo commands

sequenceDiagram
    actor User
    participant Editor as DTextEdit
    participant Stack as QUndoStack
    participant Command as InsertTextUndoCommand

    User->>Editor: insertColumnEditTextEx()
    Editor->>Stack: push(InsertTextUndoCommand)
    Stack->>Command: id()
    Stack->>Command: mergeWith(other)
    Command-->>Stack: append m_sInsertText and adopt latest cursor positions
    User->>Stack: undo()
    Stack->>Command: undo()
    Command->>Command: delete accumulated m_sInsertText length per cursor
Loading

File-Level Changes

Change Details Files
Enable consecutive column-edit insert commands to collapse into one undo entry.
  • Add a stable undo-command ID and implement type/selection checks in mergeWith().
  • Concatenate inserted text and retain the latest column-edit cursor state when merging.
src/editor/inserttextundocommand.h
src/editor/inserttextundocommand.cpp
Make column-edit undo remove the full merged insertion for every cursor.
  • Derive the deletion length from the accumulated inserted text.
  • Select and delete the complete inserted range instead of deleting one character.
src/editor/inserttextundocommand.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

@pppanghu77
pppanghu77 marked this pull request as draft October 29, 2026 20:53

@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 reviewed your changes and they look great!


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

1. Root cause: InsertTextUndoCommand did not implement mergeWith(),
   so QUndoStack::push() never merged consecutive column-edit
   keystrokes — each keypress created a separate undo entry
2. Fix: implement id() and mergeWith() to merge consecutive
   column-edit commands; fix undo() to delete m_sInsertText.length()
   chars per cursor; keep cmd1 original cursor positions in
   mergeWith() instead of replacing with cmd2's post-insert cursor;
   remove +1 offset in redo() so undo→redo→undo cycles do not drift;
   replace magic number 1001 with named constant
3. Impact: column-edit mode (ALT+mouse) now undoes multi-char input
   in one Ctrl+Z with correct deletion range; normal single-cursor
   mode unaffected

Log: fix column-edit undo to merge consecutive keystrokes

Influence:
1. Test column-edit mode multi-char input undo (e.g. type "//" then Ctrl+Z)
2. Test column-edit mode undo→redo→undo cycle for position drift
3. Test normal single-cursor mode undo (regression)

fix: 列编辑模式下合并连续按键为单步撤销

1. 根因:InsertTextUndoCommand 未实现 mergeWith(),QUndoStack::push()
   无法合并连续列编辑按键,每次按键产生独立撤销条目
2. 方案:实现 id() 和 mergeWith() 合并连续列编辑命令;修正 undo()
   按 m_sInsertText.length() 逐光标删除对应字符数;mergeWith() 中保留
   cmd1 原始光标位置,不替换为 cmd2 插入后光标;移除 redo() 中 +1 偏移
   确保 undo→redo→undo 循环无位置漂移;用命名常量替换魔法数字 1001
3. 影响:列编辑模式(ALT+鼠标)多字符输入可一次 Ctrl+Z 撤销且删除位置
   正确;普通单光标模式不受影响

Log: 修复列编辑模式下撤销输入不正确的问题

Influence:
1. 测试列编辑模式多字符输入撤销(如输入"//"后 Ctrl+Z)
2. 测试列编辑模式 undo→redo→undo 循环无位置漂移
3. 测试普通单光标模式撤销(回归)

PMS: BUG-254289
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