forked from qt-creator/qt-creator
TextEditor: Fixed indentation in block selection mode
Made indentation work for block selection mode the same way it does in default mode: 1. delete text if any selected 2. indent block if no text selected 3. indent last line if cursor in first column (QTCREATORBUG-12697) Task-number: QTCREATORBUG-12697 Change-Id: I1f6b218b389f3fdc5232ec02857aa76f5ccbaaf0 Reviewed-by: André Hartmann <aha_1980@gmx.de> Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
committed by
David Schulz
parent
c5bca90b0e
commit
aab3b0fc66
@@ -198,12 +198,13 @@ int TabSettings::columnAt(const QString &text, int position) const
|
|||||||
return column;
|
return column;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TabSettings::positionAtColumn(const QString &text, int column, int *offset) const
|
int TabSettings::positionAtColumn(const QString &text, int column, int *offset, bool allowOverstep) const
|
||||||
{
|
{
|
||||||
int col = 0;
|
int col = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (i < text.size() && col < column) {
|
int textSize = text.size();
|
||||||
if (text.at(i) == QLatin1Char('\t'))
|
while ((i < textSize || allowOverstep) && col < column) {
|
||||||
|
if (i < textSize && text.at(i) == QLatin1Char('\t'))
|
||||||
col = col - (col % m_tabSize) + m_tabSize;
|
col = col - (col % m_tabSize) + m_tabSize;
|
||||||
else
|
else
|
||||||
++col;
|
++col;
|
||||||
@@ -228,6 +229,8 @@ int TabSettings::columnCountForText(const QString &text, int startColumn) const
|
|||||||
|
|
||||||
int TabSettings::spacesLeftFromPosition(const QString &text, int position)
|
int TabSettings::spacesLeftFromPosition(const QString &text, int position)
|
||||||
{
|
{
|
||||||
|
if (position >= text.size())
|
||||||
|
return 0;
|
||||||
int i = position;
|
int i = position;
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
if (!text.at(i-1).isSpace())
|
if (!text.at(i-1).isSpace())
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public:
|
|||||||
|
|
||||||
int lineIndentPosition(const QString &text) const;
|
int lineIndentPosition(const QString &text) const;
|
||||||
int columnAt(const QString &text, int position) const;
|
int columnAt(const QString &text, int position) const;
|
||||||
int positionAtColumn(const QString &text, int column, int *offset = 0) const;
|
int positionAtColumn(const QString &text, int column, int *offset = 0, bool allowOverstep = false) const;
|
||||||
int columnCountForText(const QString &text, int startColumn = 0) const;
|
int columnCountForText(const QString &text, int startColumn = 0) const;
|
||||||
int indentedColumn(int column, bool doIndent = true) const;
|
int indentedColumn(int column, bool doIndent = true) const;
|
||||||
QString indentationString(int startColumn, int targetColumn, const QTextBlock ¤tBlock = QTextBlock()) const;
|
QString indentationString(int startColumn, int targetColumn, const QTextBlock ¤tBlock = QTextBlock()) const;
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextCursor indentOrUnindent(const QTextCursor &textCursor, bool doIndent);
|
QTextCursor indentOrUnindent(const QTextCursor &textCursor, bool doIndent,
|
||||||
|
bool blockSelection = false, int column = 0, int *offset = 0);
|
||||||
void resetRevisions();
|
void resetRevisions();
|
||||||
void updateRevisions();
|
void updateRevisions();
|
||||||
|
|
||||||
@@ -111,56 +112,84 @@ public:
|
|||||||
TextMarks m_marksCache; // Marks not owned
|
TextMarks m_marksCache; // Marks not owned
|
||||||
};
|
};
|
||||||
|
|
||||||
QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor, bool doIndent)
|
QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor, bool doIndent,
|
||||||
|
bool blockSelection, int columnIn, int *offset)
|
||||||
{
|
{
|
||||||
QTextCursor cursor = textCursor;
|
QTextCursor cursor = textCursor;
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
|
|
||||||
if (cursor.hasSelection()) {
|
TabSettings &ts = m_tabSettings;
|
||||||
|
|
||||||
// Indent or unindent the selected lines
|
// Indent or unindent the selected lines
|
||||||
int pos = cursor.position();
|
int pos = cursor.position();
|
||||||
|
int column = blockSelection ? columnIn
|
||||||
|
: ts.columnAt(cursor.block().text(), cursor.positionInBlock());
|
||||||
int anchor = cursor.anchor();
|
int anchor = cursor.anchor();
|
||||||
int start = qMin(anchor, pos);
|
int start = qMin(anchor, pos);
|
||||||
int end = qMax(anchor, pos);
|
int end = qMax(anchor, pos);
|
||||||
|
bool modified = true;
|
||||||
|
|
||||||
QTextBlock startBlock = m_document.findBlock(start);
|
QTextBlock startBlock = m_document.findBlock(start);
|
||||||
QTextBlock endBlock = m_document.findBlock(end-1).next();
|
QTextBlock endBlock = m_document.findBlock(end).next();
|
||||||
|
|
||||||
if (startBlock.next() == endBlock
|
const bool oneLinePartial = (startBlock.next() == endBlock)
|
||||||
&& (start > startBlock.position() || end < endBlock.position() - 1)) {
|
&& (start > startBlock.position() || end < endBlock.position() - 1);
|
||||||
// Only one line partially selected.
|
|
||||||
cursor.removeSelectedText();
|
// Make sure one line selection will get processed in "for" loop
|
||||||
} else {
|
if (startBlock == endBlock)
|
||||||
|
endBlock = endBlock.next();
|
||||||
|
|
||||||
|
if (cursor.hasSelection() && !blockSelection && !oneLinePartial) {
|
||||||
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
|
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
|
||||||
QString text = block.text();
|
const QString text = block.text();
|
||||||
int indentPosition = m_tabSettings.lineIndentPosition(text);
|
int indentPosition = ts.lineIndentPosition(text);
|
||||||
if (!doIndent && !indentPosition)
|
if (!doIndent && !indentPosition)
|
||||||
indentPosition = m_tabSettings.firstNonSpace(text);
|
indentPosition = ts.firstNonSpace(text);
|
||||||
int targetColumn = m_tabSettings.indentedColumn(m_tabSettings.columnAt(text, indentPosition), doIndent);
|
int targetColumn = ts.indentedColumn(ts.columnAt(text, indentPosition), doIndent);
|
||||||
cursor.setPosition(block.position() + indentPosition);
|
cursor.setPosition(block.position() + indentPosition);
|
||||||
cursor.insertText(m_tabSettings.indentationString(0, targetColumn, block));
|
cursor.insertText(ts.indentationString(0, targetColumn, block));
|
||||||
cursor.setPosition(block.position());
|
cursor.setPosition(block.position());
|
||||||
cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor);
|
cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor);
|
||||||
cursor.removeSelectedText();
|
cursor.removeSelectedText();
|
||||||
|
modified = false;
|
||||||
}
|
}
|
||||||
cursor.endEditBlock();
|
} else if (cursor.hasSelection() && !blockSelection && oneLinePartial) {
|
||||||
return textCursor;
|
// Only one line partially selected.
|
||||||
}
|
cursor.removeSelectedText();
|
||||||
|
} else {
|
||||||
|
// Indent or unindent at cursor position
|
||||||
|
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
|
||||||
|
QString text = block.text();
|
||||||
|
|
||||||
|
int blockColumn = ts.columnAt(text, text.size());
|
||||||
|
if (blockColumn < column) {
|
||||||
|
cursor.setPosition(block.position() + text.size());
|
||||||
|
cursor.insertText(ts.indentationString(blockColumn, column, block));
|
||||||
|
text = block.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indent or unindent at cursor position
|
int indentPosition = ts.positionAtColumn(text, column, 0, true);
|
||||||
QTextBlock block = cursor.block();
|
int spaces = ts.spacesLeftFromPosition(text, indentPosition);
|
||||||
QString text = block.text();
|
int startColumn = ts.columnAt(text, indentPosition - spaces);
|
||||||
int indentPosition = cursor.positionInBlock();
|
int targetColumn = ts.indentedColumn(ts.columnAt(text, indentPosition), doIndent);
|
||||||
int spaces = m_tabSettings.spacesLeftFromPosition(text, indentPosition);
|
|
||||||
int startColumn = m_tabSettings.columnAt(text, indentPosition - spaces);
|
|
||||||
int targetColumn = m_tabSettings.indentedColumn(m_tabSettings.columnAt(text, indentPosition), doIndent);
|
|
||||||
cursor.setPosition(block.position() + indentPosition);
|
cursor.setPosition(block.position() + indentPosition);
|
||||||
cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor);
|
cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor);
|
||||||
cursor.removeSelectedText();
|
cursor.removeSelectedText();
|
||||||
cursor.insertText(m_tabSettings.indentationString(startColumn, targetColumn, block));
|
cursor.insertText(ts.indentationString(startColumn, targetColumn, block));
|
||||||
|
}
|
||||||
|
// Preserve initial anchor of block selection
|
||||||
|
if (blockSelection) {
|
||||||
|
end = cursor.position();
|
||||||
|
if (offset)
|
||||||
|
*offset = ts.columnAt(cursor.block().text(), cursor.positionInBlock()) - column;
|
||||||
|
cursor.setPosition(start);
|
||||||
|
cursor.setPosition(end, QTextCursor::KeepAnchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
return cursor;
|
|
||||||
|
return modified ? cursor : textCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextDocumentPrivate::resetRevisions()
|
void TextDocumentPrivate::resetRevisions()
|
||||||
@@ -359,14 +388,16 @@ void TextDocument::autoReindent(const QTextCursor &cursor)
|
|||||||
d->m_indenter->reindent(&d->m_document, cursor, d->m_tabSettings);
|
d->m_indenter->reindent(&d->m_document, cursor, d->m_tabSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextCursor TextDocument::indent(const QTextCursor &cursor)
|
QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column,
|
||||||
|
int *offset)
|
||||||
{
|
{
|
||||||
return d->indentOrUnindent(cursor, true);
|
return d->indentOrUnindent(cursor, true, blockSelection, column, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextCursor TextDocument::unindent(const QTextCursor &cursor)
|
QTextCursor TextDocument::unindent(const QTextCursor &cursor, bool blockSelection, int column,
|
||||||
|
int *offset)
|
||||||
{
|
{
|
||||||
return d->indentOrUnindent(cursor, false);
|
return d->indentOrUnindent(cursor, false, blockSelection, column, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const
|
const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const
|
||||||
|
|||||||
@@ -89,8 +89,10 @@ public:
|
|||||||
Indenter *indenter() const;
|
Indenter *indenter() const;
|
||||||
void autoIndent(const QTextCursor &cursor, QChar typedChar = QChar::Null);
|
void autoIndent(const QTextCursor &cursor, QChar typedChar = QChar::Null);
|
||||||
void autoReindent(const QTextCursor &cursor);
|
void autoReindent(const QTextCursor &cursor);
|
||||||
QTextCursor indent(const QTextCursor &cursor);
|
QTextCursor indent(const QTextCursor &cursor, bool blockSelection = false, int column = 0,
|
||||||
QTextCursor unindent(const QTextCursor &cursor);
|
int *offset = 0);
|
||||||
|
QTextCursor unindent(const QTextCursor &cursor, bool blockSelection = false, int column = 0,
|
||||||
|
int *offset = 0);
|
||||||
|
|
||||||
TextMarks marks() const;
|
TextMarks marks() const;
|
||||||
bool addMark(TextMark *mark);
|
bool addMark(TextMark *mark);
|
||||||
|
|||||||
@@ -1495,12 +1495,26 @@ void TextEditorWidget::lowercaseSelection()
|
|||||||
|
|
||||||
void TextEditorWidget::indent()
|
void TextEditorWidget::indent()
|
||||||
{
|
{
|
||||||
setTextCursor(textDocument()->indent(textCursor()));
|
int offset = 0;
|
||||||
|
doSetTextCursor(textDocument()->indent(textCursor(), d->m_inBlockSelectionMode,
|
||||||
|
d->m_blockSelection.positionColumn, &offset),
|
||||||
|
d->m_inBlockSelectionMode);
|
||||||
|
if (d->m_inBlockSelectionMode) {
|
||||||
|
d->m_blockSelection.anchorColumn += offset;
|
||||||
|
d->m_blockSelection.positionColumn += offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditorWidget::unindent()
|
void TextEditorWidget::unindent()
|
||||||
{
|
{
|
||||||
setTextCursor(textDocument()->unindent(textCursor()));
|
int offset = 0;
|
||||||
|
doSetTextCursor(textDocument()->unindent(textCursor(), d->m_inBlockSelectionMode,
|
||||||
|
d->m_blockSelection.positionColumn, &offset),
|
||||||
|
d->m_inBlockSelectionMode);
|
||||||
|
if (d->m_inBlockSelectionMode) {
|
||||||
|
d->m_blockSelection.anchorColumn += offset;
|
||||||
|
d->m_blockSelection.positionColumn += offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditorWidget::undo()
|
void TextEditorWidget::undo()
|
||||||
@@ -2253,12 +2267,17 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
|||||||
setTextCursor(cursor);
|
setTextCursor(cursor);
|
||||||
}
|
}
|
||||||
d->m_document->autoIndent(cursor);
|
d->m_document->autoIndent(cursor);
|
||||||
|
} else {
|
||||||
|
if (d->m_inBlockSelectionMode
|
||||||
|
&& d->m_blockSelection.firstVisualColumn() != d->m_blockSelection.lastVisualColumn()) {
|
||||||
|
d->removeBlockSelection();
|
||||||
} else {
|
} else {
|
||||||
if (e->key() == Qt::Key_Tab)
|
if (e->key() == Qt::Key_Tab)
|
||||||
indent();
|
indent();
|
||||||
else
|
else
|
||||||
unindent();
|
unindent();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
e->accept();
|
e->accept();
|
||||||
return;
|
return;
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
Reference in New Issue
Block a user