From 3fbf315c0319581f18387bf230b21453dce9eaf2 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Sat, 10 Oct 2026 10:30:55 +0800 Subject: [PATCH] fix: distribute multi-line clipboard per selection in column mode paste MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pasting with column (Alt) selections and the clipboard text has the same number of lines as the selections, insert one clipboard line per selection, matching mainstream editors (VS Code, Sublime, Notepad++). Previously the whole multi-line text was inserted into every selection, duplicating the entire clipboard at each cursor. When the line count differs from the selection count, the previous whole-text-per-selection behavior is kept. 列编辑模式下粘贴与列选区数量一致的多行剪贴板时,按行分发到各列选区, 对齐主流编辑器(VS Code/Sublime/Notepad++)的列模式粘贴语义;此前整段 文本会被原样插入每个选区,导致内容在每个选区整段重复。行数与选区数 不一致时保持原有整段插入行为,撤销/重做按各选区实际插入文本还原。 Log: 修复列编辑粘贴多行剪贴板时内容在每个选区整段重复的问题 Influence: 列编辑模式下粘贴多行剪贴板的行为 --- src/editor/inserttextundocommand.cpp | 22 ++++++++++++++++------ src/editor/inserttextundocommand.h | 7 +++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/editor/inserttextundocommand.cpp b/src/editor/inserttextundocommand.cpp index bf56461ab..b233421be 100644 --- a/src/editor/inserttextundocommand.cpp +++ b/src/editor/inserttextundocommand.cpp @@ -31,12 +31,21 @@ InsertTextUndoCommand::InsertTextUndoCommand(QList &s m_sInsertText.replace("\r\n", "\n"); qDebug() << "InsertTextUndoCommand(multi-selection) created"; - for (const auto &selection : m_columnEditSelections) { + // When the clipboard text has the same number of lines as the column + // selections, distribute one line per selection (the semantics of + // mainstream editors); otherwise insert the whole text into every + // selection as before. + const QStringList lines = m_sInsertText.split(QLatin1Char('\n')); + const bool distribute = lines.size() > 1 && lines.size() == m_columnEditSelections.size(); + + for (int i = 0; i < m_columnEditSelections.size(); ++i) { + const auto &selection = m_columnEditSelections.at(i); ColumnReplaceNode replaceNode; replaceNode.startPos = selection.cursor.selectionStart(); replaceNode.endPos = selection.cursor.selectionEnd(); replaceNode.leftToRight = selection.cursor.anchor() <= selection.cursor.position(); replaceNode.originText = selection.cursor.selectedText(); + replaceNode.insertedText = distribute ? lines.at(i) : m_sInsertText; m_replaces.append(replaceNode); } } @@ -72,7 +81,7 @@ void InsertTextUndoCommand::undo() // restore origin text QTextCursor cursor = selection.cursor; cursor.setPosition(replaceNode.startPos); - cursor.setPosition(replaceNode.startPos + m_sInsertText.size(), QTextCursor::KeepAnchor); + cursor.setPosition(replaceNode.startPos + replaceNode.insertedText.size(), QTextCursor::KeepAnchor); cursor.insertText(replaceNode.originText); if (replaceNode.leftToRight) { @@ -130,25 +139,26 @@ void InsertTextUndoCommand::redo() for (int i = 0; i < m_columnEditSelections.size(); i++) { QTextEdit::ExtraSelection &selection = m_columnEditSelections[i]; const ColumnReplaceNode &replaceNode = m_replaces[i]; + const QString &insertedText = replaceNode.insertedText; // remove origin text with replace text QTextCursor cursor = selection.cursor; cursor.setPosition(columnOffset + replaceNode.startPos); cursor.setPosition(columnOffset + replaceNode.endPos, QTextCursor::KeepAnchor); - cursor.insertText(m_sInsertText); + cursor.insertText(insertedText); if (replaceNode.leftToRight) { qDebug() << "InsertTextUndoCommand redo, leftToRight"; cursor.setPosition(columnOffset + replaceNode.startPos); - cursor.setPosition(columnOffset + replaceNode.startPos + m_sInsertText.size(), QTextCursor::KeepAnchor); + cursor.setPosition(columnOffset + replaceNode.startPos + insertedText.size(), QTextCursor::KeepAnchor); } else { qDebug() << "InsertTextUndoCommand redo, rightToLeft"; - cursor.setPosition(columnOffset + replaceNode.startPos + m_sInsertText.size()); + cursor.setPosition(columnOffset + replaceNode.startPos + insertedText.size()); cursor.setPosition(columnOffset + replaceNode.startPos, QTextCursor::KeepAnchor); } selection.cursor = cursor; - columnOffset += m_sInsertText.size() - replaceNode.originText.size(); + columnOffset += insertedText.size() - replaceNode.originText.size(); } if (m_pEdit && !m_columnEditSelections.isEmpty()) { diff --git a/src/editor/inserttextundocommand.h b/src/editor/inserttextundocommand.h index 470e43f00..e4c2c12ff 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 @@ -35,7 +35,10 @@ class InsertTextUndoCommand : public QUndoCommand int startPos{false}; int endPos{false}; bool leftToRight{true}; - QString originText; // replaced text before insert. + QString originText; // replaced text before insert. + QString insertedText; // text inserted into this selection; one clipboard line + // per selection when a multi-line clipboard matches + // the selection count, whole text otherwise. }; TextEdit *m_pEdit = nullptr;