From 687fd379fea857bcab2d3b0b27794754e93a4f2a Mon Sep 17 00:00:00 2001 From: liujinchang Date: Fri, 30 Oct 2026 04:48:34 +0800 Subject: [PATCH] fix: merge column-edit undo into single step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/editor/inserttextundocommand.cpp | 33 +++++++++++++++++++++++++--- src/editor/inserttextundocommand.h | 4 +++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/editor/inserttextundocommand.cpp b/src/editor/inserttextundocommand.cpp index b02864ff4..a3cf53a9c 100644 --- a/src/editor/inserttextundocommand.cpp +++ b/src/editor/inserttextundocommand.cpp @@ -1,9 +1,13 @@ -// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2019 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #include "inserttextundocommand.h" +namespace { +constexpr int ColumnEditTextMergeId = 1001; +} + InsertTextUndoCommand::InsertTextUndoCommand(const QTextCursor &textcursor, const QString &text, QPlainTextEdit *edit, QUndoCommand *parent) : QUndoCommand(parent) , m_pEdit(edit) @@ -43,8 +47,13 @@ void InsertTextUndoCommand::undo() } } else { int cnt = m_ColumnEditSelections.size(); + int deleteLen = m_sInsertText.length(); for (int i = 0; i < cnt; i++) { - m_ColumnEditSelections[i].cursor.deleteChar(); + auto &cursor = m_ColumnEditSelections[i].cursor; + int startPos = cursor.selectionStart(); + cursor.setPosition(startPos); + cursor.setPosition(startPos + deleteLen, QTextCursor::KeepAnchor); + cursor.deleteChar(); } if (m_pEdit && !m_ColumnEditSelections.isEmpty()) { @@ -76,7 +85,7 @@ void InsertTextUndoCommand::redo() int cnt = m_ColumnEditSelections.size(); for (int i = 0; i < cnt; i++) { m_ColumnEditSelections[i].cursor.insertText(m_sInsertText); - m_ColumnEditSelections[i].cursor.setPosition(m_ColumnEditSelections[i].cursor.position() - m_sInsertText.length() + 1, + m_ColumnEditSelections[i].cursor.setPosition(m_ColumnEditSelections[i].cursor.position() - m_sInsertText.length(), QTextCursor::KeepAnchor); } @@ -88,6 +97,24 @@ void InsertTextUndoCommand::redo() } } +int InsertTextUndoCommand::id() const +{ + return ColumnEditTextMergeId; +} + +bool InsertTextUndoCommand::mergeWith(const QUndoCommand *other) +{ + if (m_ColumnEditSelections.isEmpty()) + return false; + + const InsertTextUndoCommand *cmd = dynamic_cast(other); + if (!cmd || cmd->m_ColumnEditSelections.isEmpty()) + return false; + + m_sInsertText += cmd->m_sInsertText; + return true; +} + /** * @class MidButtonInsertTextUndoCommand * @brief 用于鼠标中键黏贴的插入撤销项,使用 QClipboard::Selection 类型插入选中的数据, diff --git a/src/editor/inserttextundocommand.h b/src/editor/inserttextundocommand.h index 393dc95c0..7fa5413b9 100644 --- a/src/editor/inserttextundocommand.h +++ b/src/editor/inserttextundocommand.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2019 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -21,6 +21,8 @@ class InsertTextUndoCommand : public QUndoCommand QUndoCommand *parent = nullptr); virtual void undo(); virtual void redo(); + virtual int id() const override; + virtual bool mergeWith(const QUndoCommand *other) override; private: QPlainTextEdit *m_pEdit = nullptr;