forked from qt-creator/qt-creator
TextEditor: Duplicate selection (Duplicate selection and comment)
New TextEditor action for duplicating current selection. Extended version of this feature creates commented duplications. Possible use cases: 1. No selection, cursor anywhere in text - Duplicity line 2. Simple selection - Duplicity selection 3. Block selection, without columns - Duplicity lines 4. Block selection, with columns - Duplicity selection Cursor position and selection stays unchanged. Works well with Undo action. First use case with no selection looks similar as copyLineDown, but difference is that copyLineDown moves current cursor position and select created line. This feature don't change cursor position. Because of this difference it is not possible to integrate this additions with copyLineDown. Quick intro: https://youtu.be/Fv6WdCnCLpo Change-Id: I7c36fca6e17de030cbd22cfa103c2ed672deabbc Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -256,6 +256,8 @@ public:
|
||||
void print(QPrinter *printer);
|
||||
|
||||
void maybeSelectLine();
|
||||
void duplicateSelection(bool comment);
|
||||
void duplicateBlockSelection(bool comment);
|
||||
void updateCannotDecodeInfo();
|
||||
void collectToCircularClipboard();
|
||||
|
||||
@@ -6165,6 +6167,128 @@ void TextEditorWidget::copyLine()
|
||||
copy();
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::duplicateSelection(bool comment)
|
||||
{
|
||||
if (m_inBlockSelectionMode) {
|
||||
duplicateBlockSelection(comment);
|
||||
return;
|
||||
}
|
||||
|
||||
QTextCursor cursor = q->textCursor();
|
||||
|
||||
if (cursor.hasSelection()) {
|
||||
|
||||
// Cannot "duplicate and comment" files without multi-line comment
|
||||
if (comment && !m_commentDefinition.hasMultiLineStyle())
|
||||
return;
|
||||
|
||||
QString dupText = cursor.selectedText().replace(QChar::ParagraphSeparator, QLatin1Char('\n'));
|
||||
if (comment)
|
||||
dupText = (m_commentDefinition.multiLineStart + dupText + m_commentDefinition.multiLineEnd);
|
||||
const int selStart = cursor.selectionStart();
|
||||
const int selEnd = cursor.selectionEnd();
|
||||
const bool cursorAtStart = (cursor.position() == selStart);
|
||||
cursor.setPosition(selEnd);
|
||||
cursor.insertText(dupText);
|
||||
cursor.setPosition(cursorAtStart ? selEnd : selStart);
|
||||
cursor.setPosition(cursorAtStart ? selStart : selEnd, QTextCursor::KeepAnchor);
|
||||
} else {
|
||||
const int curPos = cursor.position();
|
||||
const QTextBlock &block = cursor.block();
|
||||
QString dupText = block.text() + QLatin1Char('\n');
|
||||
if (comment && m_commentDefinition.hasSingleLineStyle())
|
||||
dupText.append(m_commentDefinition.singleLine);
|
||||
cursor.setPosition(block.position());
|
||||
cursor.insertText(dupText);
|
||||
cursor.setPosition(curPos);
|
||||
}
|
||||
q->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::duplicateBlockSelection(bool comment)
|
||||
{
|
||||
QTextCursor cursor = q->textCursor();
|
||||
|
||||
const TextBlockSelection curSel = m_blockSelection;
|
||||
|
||||
if (curSel.positionColumn == curSel.anchorColumn) {
|
||||
// No columns selected, duplicating multiple lines
|
||||
|
||||
const bool isUp = curSel.positionBlock > curSel.anchorBlock;
|
||||
const QString commentText =
|
||||
(comment && m_commentDefinition.hasSingleLineStyle()) ?
|
||||
m_commentDefinition.singleLine : QString();
|
||||
|
||||
QTextBlock block = cursor.block();
|
||||
QString dupText = commentText + block.text() + QLatin1Char('\n');
|
||||
|
||||
for (int b = curSel.firstBlockNumber(); b < curSel.lastBlockNumber(); ++b) {
|
||||
if (isUp) {
|
||||
block = block.previous();
|
||||
dupText.prepend(commentText + block.text() + QLatin1Char('\n'));
|
||||
} else {
|
||||
block = block.next();
|
||||
dupText.append(commentText + block.text() + QLatin1Char('\n'));
|
||||
}
|
||||
}
|
||||
|
||||
if (isUp)
|
||||
block = cursor.block();
|
||||
|
||||
cursor.setPosition(block.position() + block.length());
|
||||
cursor.insertText(dupText);
|
||||
|
||||
} else {
|
||||
// Duplicating full block selection with columns
|
||||
|
||||
// Cannot "duplicate and comment" files without multi-line comment
|
||||
if (comment && !m_commentDefinition.hasMultiLineStyle())
|
||||
return;
|
||||
|
||||
const int fc = curSel.firstVisualColumn();
|
||||
const int lc = curSel.lastVisualColumn();
|
||||
const int l = lc - fc;
|
||||
|
||||
cursor.beginEditBlock();
|
||||
for (int b = curSel.firstBlockNumber(); b <= curSel.lastBlockNumber(); ++b) {
|
||||
const QTextBlock &block = m_document->document()->findBlockByNumber(b);
|
||||
QString dupText = block.text();
|
||||
const int dupTextLength = dupText.length();
|
||||
|
||||
if (dupTextLength < lc) {
|
||||
const QString addSpace(lc - dupTextLength, ' ');
|
||||
cursor.setPosition(block.position() + dupTextLength);
|
||||
cursor.insertText(addSpace);
|
||||
dupText.append(addSpace);
|
||||
}
|
||||
|
||||
cursor.setPosition(block.position() + lc);
|
||||
dupText = dupText.mid(fc, l);
|
||||
|
||||
if (comment)
|
||||
dupText = (m_commentDefinition.multiLineStart + dupText + m_commentDefinition.multiLineEnd);
|
||||
cursor.insertText(dupText);
|
||||
}
|
||||
cursor.endEditBlock();
|
||||
}
|
||||
|
||||
enableBlockSelection(curSel.positionBlock, curSel.positionColumn,
|
||||
curSel.anchorBlock, curSel.anchorColumn);
|
||||
|
||||
cursor = m_blockSelection.cursor(m_document.data());
|
||||
q->doSetTextCursor(cursor, m_blockSelection.hasSelection());
|
||||
}
|
||||
|
||||
void TextEditorWidget::duplicateSelection()
|
||||
{
|
||||
d->duplicateSelection(false);
|
||||
}
|
||||
|
||||
void TextEditorWidget::duplicateSelectionAndComment()
|
||||
{
|
||||
d->duplicateSelection(true);
|
||||
}
|
||||
|
||||
void TextEditorWidget::deleteLine()
|
||||
{
|
||||
d->maybeSelectLine();
|
||||
|
||||
Reference in New Issue
Block a user