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 <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2019-10-09 10:35:23 +02:00
parent 41f8186d68
commit 1281774c6a

View File

@@ -169,35 +169,82 @@ QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor,
cursor.removeSelectedText(); cursor.removeSelectedText();
} else { } else {
// Indent or unindent at cursor position // 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<BlockIndenter> blocks;
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) { for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
QString text = block.text(); QString text = block.text();
int blockColumn = tabSettings.columnAt(text, text.size()); const int blockColumn = tabSettings.columnAt(text, text.size());
if (blockColumn < column) { if (blockColumn < column) {
cursor.setPosition(block.position() + text.size()); cursor.setPosition(block.position() + text.size());
cursor.insertText(tabSettings.indentationString(blockColumn, column, 0, block)); cursor.insertText(tabSettings.indentationString(blockColumn, column, 0, block));
text = block.text(); text = block.text();
} }
int indentPosition = tabSettings.positionAtColumn(text, column, nullptr, true); blocks.emplace_back(BlockIndenter(block, column, tabSettings));
int spaces = tabSettings.spacesLeftFromPosition(text, indentPosition); maxTargetColumn = std::max(maxTargetColumn, blocks.back().targetColumn(doIndent));
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));
} }
for (const BlockIndenter &blockIndenter : blocks)
blockIndenter.indent(maxTargetColumn);
// Preserve initial anchor of block selection // Preserve initial anchor of block selection
if (blockSelection) { if (blockSelection) {
end = cursor.position(); if (offset)
if (offset) { *offset = maxTargetColumn - column;
*offset = tabSettings.columnAt(cursor.block().text(), cursor.positionInBlock()) startBlock = pos < anchor ? blocks.front().textBlock() : blocks.back().textBlock();
- column; start = startBlock.position()
} + tabSettings.positionAtColumn(startBlock.text(), maxTargetColumn);
cursor.setPosition(start); endBlock = pos > anchor ? blocks.front().textBlock() : blocks.back().textBlock();
cursor.setPosition(end, QTextCursor::KeepAnchor); end = endBlock.position()
+ tabSettings.positionAtColumn(endBlock.text(), maxTargetColumn);
cursor.setPosition(end);
cursor.setPosition(start, QTextCursor::KeepAnchor);
} }
} }