From 1281774c6a03a9cb3b3c904dda1a219ae1f2cca6 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 9 Oct 2019 10:35:23 +0200 Subject: [PATCH] TextEditor: Fix backtab behavior of multi line selection Check available spaces infront of current column on each line before removing the text. Fixes: QTCREATORBUG-16970 Change-Id: Ie6560ce706297f6818a84ca863abc9b106728890 Reviewed-by: Christian Stenger --- src/plugins/texteditor/textdocument.cpp | 81 +++++++++++++++++++------ 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index ae574bc0ba6..4b2e09caf96 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -169,35 +169,82 @@ QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor, cursor.removeSelectedText(); } else { // Indent or unindent at cursor position + int maxTargetColumn = -1; + + class BlockIndenter + { + public: + BlockIndenter(const QTextBlock &_block, + const int column, + const TabSettings &_tabSettings) + : block(_block) + , text(block.text()) + , tabSettings(_tabSettings) + { + indentPosition = tabSettings.positionAtColumn(text, column, nullptr, true); + spaces = tabSettings.spacesLeftFromPosition(text, indentPosition); + } + + void indent(const int targetColumn) const + { + const int startColumn = tabSettings.columnAt(text, indentPosition - spaces); + QTextCursor cursor(block); + cursor.setPosition(block.position() + indentPosition); + cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor); + cursor.removeSelectedText(); + cursor.insertText(tabSettings.indentationString(startColumn, targetColumn, 0, block)); + } + + int targetColumn(bool doIndent) const + { + const int optimumTargetColumn + = tabSettings.indentedColumn(tabSettings.columnAt(block.text(), indentPosition), + doIndent); + const int minimumTargetColumn = tabSettings.columnAt(text, indentPosition - spaces); + return std::max(optimumTargetColumn, minimumTargetColumn); + } + + const QTextBlock &textBlock() { return block; } + + private: + QTextBlock block; + const QString text; + int indentPosition; + int spaces; + const TabSettings &tabSettings; + }; + + std::vector blocks; + for (QTextBlock block = startBlock; block != endBlock; block = block.next()) { QString text = block.text(); - int blockColumn = tabSettings.columnAt(text, text.size()); + const int blockColumn = tabSettings.columnAt(text, text.size()); if (blockColumn < column) { cursor.setPosition(block.position() + text.size()); cursor.insertText(tabSettings.indentationString(blockColumn, column, 0, block)); text = block.text(); } - int indentPosition = tabSettings.positionAtColumn(text, column, nullptr, true); - int spaces = tabSettings.spacesLeftFromPosition(text, indentPosition); - int startColumn = tabSettings.columnAt(text, indentPosition - spaces); - int targetColumn = tabSettings.indentedColumn( - tabSettings.columnAt(text, indentPosition), doIndent); - cursor.setPosition(block.position() + indentPosition); - cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor); - cursor.removeSelectedText(); - cursor.insertText(tabSettings.indentationString(startColumn, targetColumn, 0, block)); + blocks.emplace_back(BlockIndenter(block, column, tabSettings)); + maxTargetColumn = std::max(maxTargetColumn, blocks.back().targetColumn(doIndent)); } + for (const BlockIndenter &blockIndenter : blocks) + blockIndenter.indent(maxTargetColumn); + // Preserve initial anchor of block selection if (blockSelection) { - end = cursor.position(); - if (offset) { - *offset = tabSettings.columnAt(cursor.block().text(), cursor.positionInBlock()) - - column; - } - cursor.setPosition(start); - cursor.setPosition(end, QTextCursor::KeepAnchor); + if (offset) + *offset = maxTargetColumn - column; + startBlock = pos < anchor ? blocks.front().textBlock() : blocks.back().textBlock(); + start = startBlock.position() + + tabSettings.positionAtColumn(startBlock.text(), maxTargetColumn); + endBlock = pos > anchor ? blocks.front().textBlock() : blocks.back().textBlock(); + end = endBlock.position() + + tabSettings.positionAtColumn(endBlock.text(), maxTargetColumn); + + cursor.setPosition(end); + cursor.setPosition(start, QTextCursor::KeepAnchor); } }