forked from qt-creator/qt-creator
ClangFormat: Return replacements from 'format' call
We want to have the results of the 'format' call in order to have understanding what has changed and if the existing offsets have to be adjusted. One of the possible use cases is the formatting after fix-its. If we apply several fix-its in the same file we need to know after each of them if the further ones are affected and shift them. Change-Id: I17e8f4dbcf6d36224ab7da9e11035cf3be3d3125 Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -46,6 +46,11 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
using ClangReplacement = clang::tooling::Replacement;
|
||||||
|
using ClangReplacements = clang::tooling::Replacements;
|
||||||
|
using QtReplacement = TextEditor::Replacement;
|
||||||
|
using QtReplacements = TextEditor::Replacements;
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace format;
|
using namespace format;
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
@@ -76,13 +81,13 @@ StringRef clearExtraNewline(StringRef text)
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
Replacements filteredReplacements(const Replacements &replacements,
|
ClangReplacements filteredReplacements(const ClangReplacements &replacements,
|
||||||
int offset,
|
int offset,
|
||||||
int extraOffsetToAdd,
|
int extraOffsetToAdd,
|
||||||
bool onlyIndention)
|
bool onlyIndention)
|
||||||
{
|
{
|
||||||
Replacements filtered;
|
ClangReplacements filtered;
|
||||||
for (const Replacement &replacement : replacements) {
|
for (const ClangReplacement &replacement : replacements) {
|
||||||
int replacementOffset = static_cast<int>(replacement.getOffset());
|
int replacementOffset = static_cast<int>(replacement.getOffset());
|
||||||
if (onlyIndention && replacementOffset != offset - 1)
|
if (onlyIndention && replacementOffset != offset - 1)
|
||||||
continue;
|
continue;
|
||||||
@@ -93,10 +98,10 @@ Replacements filteredReplacements(const Replacements &replacements,
|
|||||||
StringRef text = onlyIndention ? clearExtraNewline(replacement.getReplacementText())
|
StringRef text = onlyIndention ? clearExtraNewline(replacement.getReplacementText())
|
||||||
: replacement.getReplacementText();
|
: replacement.getReplacementText();
|
||||||
|
|
||||||
Error error = filtered.add(Replacement(replacement.getFilePath(),
|
Error error = filtered.add(ClangReplacement(replacement.getFilePath(),
|
||||||
static_cast<unsigned int>(replacementOffset),
|
static_cast<unsigned int>(replacementOffset),
|
||||||
replacement.getLength(),
|
replacement.getLength(),
|
||||||
text));
|
text));
|
||||||
// Throws if error is not checked.
|
// Throws if error is not checked.
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
@@ -188,56 +193,6 @@ void modifyToIndentEmptyLines(QByteArray &buffer, int &offset, int &length, cons
|
|||||||
|
|
||||||
static const int kMaxLinesFromCurrentBlock = 200;
|
static const int kMaxLinesFromCurrentBlock = 200;
|
||||||
|
|
||||||
Replacements replacements(const Utils::FileName &fileName,
|
|
||||||
QByteArray buffer,
|
|
||||||
int utf8Offset,
|
|
||||||
int utf8Length,
|
|
||||||
const QTextBlock *block = nullptr,
|
|
||||||
const QChar &typedChar = QChar::Null)
|
|
||||||
{
|
|
||||||
FormatStyle style = styleForFile(fileName);
|
|
||||||
|
|
||||||
int extraOffset = 0;
|
|
||||||
if (block) {
|
|
||||||
if (block->blockNumber() > kMaxLinesFromCurrentBlock) {
|
|
||||||
extraOffset = Utils::Text::utf8NthLineOffset(
|
|
||||||
block->document(), buffer, block->blockNumber() - kMaxLinesFromCurrentBlock);
|
|
||||||
}
|
|
||||||
int endOffset = Utils::Text::utf8NthLineOffset(
|
|
||||||
block->document(), buffer, block->blockNumber() + kMaxLinesFromCurrentBlock);
|
|
||||||
if (endOffset == -1)
|
|
||||||
endOffset = buffer.size();
|
|
||||||
|
|
||||||
buffer = buffer.mid(extraOffset, endOffset - extraOffset);
|
|
||||||
utf8Offset -= extraOffset;
|
|
||||||
|
|
||||||
const int emptySpaceLength = previousEmptyLinesLength(*block);
|
|
||||||
utf8Offset -= emptySpaceLength;
|
|
||||||
buffer.remove(utf8Offset, emptySpaceLength);
|
|
||||||
|
|
||||||
extraOffset += emptySpaceLength;
|
|
||||||
|
|
||||||
adjustFormatStyleForLineBreak(style);
|
|
||||||
if (typedChar == QChar::Null)
|
|
||||||
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, *block);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Range> ranges{{static_cast<unsigned int>(utf8Offset),
|
|
||||||
static_cast<unsigned int>(utf8Length)}};
|
|
||||||
FormattingAttemptStatus status;
|
|
||||||
|
|
||||||
Replacements replacements = reformat(style, buffer.data(), ranges,
|
|
||||||
fileName.toString().toStdString(), &status);
|
|
||||||
|
|
||||||
if (!status.FormatComplete)
|
|
||||||
Replacements();
|
|
||||||
|
|
||||||
return filteredReplacements(replacements,
|
|
||||||
utf8Offset,
|
|
||||||
extraOffset,
|
|
||||||
block);
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::LineColumn utf16LineColumn(const QTextBlock &block,
|
Utils::LineColumn utf16LineColumn(const QTextBlock &block,
|
||||||
int blockOffsetUtf8,
|
int blockOffsetUtf8,
|
||||||
const QByteArray &utf8Buffer,
|
const QByteArray &utf8Buffer,
|
||||||
@@ -262,62 +217,111 @@ Utils::LineColumn utf16LineColumn(const QTextBlock &block,
|
|||||||
return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1);
|
return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
tooling::Replacements utf16Replacements(const QTextBlock &block,
|
QtReplacements utf16Replacements(const QTextBlock &block,
|
||||||
int blockOffsetUtf8,
|
int blockOffsetUtf8,
|
||||||
const QByteArray &utf8Buffer,
|
const QByteArray &utf8Buffer,
|
||||||
const tooling::Replacements &replacements)
|
const ClangReplacements &replacements)
|
||||||
{
|
{
|
||||||
tooling::Replacements convertedReplacements;
|
QtReplacements convertedReplacements;
|
||||||
for (const Replacement &replacement : replacements) {
|
convertedReplacements.reserve(replacements.size());
|
||||||
const Utils::LineColumn lineColUtf16 = utf16LineColumn(
|
for (const ClangReplacement &replacement : replacements) {
|
||||||
block, blockOffsetUtf8, utf8Buffer, static_cast<int>(replacement.getOffset()));
|
const Utils::LineColumn lineColUtf16 = utf16LineColumn(block,
|
||||||
|
blockOffsetUtf8,
|
||||||
|
utf8Buffer,
|
||||||
|
static_cast<int>(
|
||||||
|
replacement.getOffset()));
|
||||||
if (!lineColUtf16.isValid())
|
if (!lineColUtf16.isValid())
|
||||||
continue;
|
continue;
|
||||||
const int utf16Offset = Utils::Text::positionInText(block.document(),
|
const int utf16Offset = Utils::Text::positionInText(block.document(),
|
||||||
lineColUtf16.line,
|
lineColUtf16.line,
|
||||||
lineColUtf16.column);
|
lineColUtf16.column);
|
||||||
const int utf16Length = QString::fromUtf8(
|
const int utf16Length = QString::fromUtf8(
|
||||||
utf8Buffer.mid(static_cast<int>(replacement.getOffset()),
|
utf8Buffer.mid(static_cast<int>(replacement.getOffset()),
|
||||||
static_cast<int>(replacement.getLength()))).size();
|
static_cast<int>(replacement.getLength())))
|
||||||
Error error = convertedReplacements.add(
|
.size();
|
||||||
Replacement(replacement.getFilePath(),
|
convertedReplacements.emplace_back(utf16Offset,
|
||||||
static_cast<unsigned int>(utf16Offset),
|
utf16Length,
|
||||||
static_cast<unsigned int>(utf16Length),
|
QString::fromStdString(replacement.getReplacementText()));
|
||||||
replacement.getReplacementText()));
|
|
||||||
// Throws if error is not checked.
|
|
||||||
if (error)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertedReplacements;
|
return convertedReplacements;
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyReplacements(const QTextBlock &block,
|
QtReplacements replacements(const Utils::FileName &fileName,
|
||||||
int blockOffsetUtf8,
|
QByteArray buffer,
|
||||||
const QByteArray &utf8Buffer,
|
int utf8Offset,
|
||||||
const tooling::Replacements &replacements)
|
int utf8Length,
|
||||||
|
const QTextBlock &block,
|
||||||
|
const QChar &typedChar = QChar::Null,
|
||||||
|
bool onlyIndention = true)
|
||||||
|
{
|
||||||
|
FormatStyle style = styleForFile(fileName);
|
||||||
|
|
||||||
|
int blockOffsetUtf8 = utf8Offset;
|
||||||
|
QByteArray originalBuffer = buffer;
|
||||||
|
|
||||||
|
int extraOffset = 0;
|
||||||
|
if (onlyIndention) {
|
||||||
|
if (block.blockNumber() > kMaxLinesFromCurrentBlock) {
|
||||||
|
extraOffset = Utils::Text::utf8NthLineOffset(
|
||||||
|
block.document(), buffer, block.blockNumber() - kMaxLinesFromCurrentBlock);
|
||||||
|
}
|
||||||
|
int endOffset = Utils::Text::utf8NthLineOffset(
|
||||||
|
block.document(), buffer, block.blockNumber() + kMaxLinesFromCurrentBlock);
|
||||||
|
if (endOffset == -1)
|
||||||
|
endOffset = buffer.size();
|
||||||
|
|
||||||
|
buffer = buffer.mid(extraOffset, endOffset - extraOffset);
|
||||||
|
utf8Offset -= extraOffset;
|
||||||
|
|
||||||
|
const int emptySpaceLength = previousEmptyLinesLength(block);
|
||||||
|
utf8Offset -= emptySpaceLength;
|
||||||
|
buffer.remove(utf8Offset, emptySpaceLength);
|
||||||
|
|
||||||
|
extraOffset += emptySpaceLength;
|
||||||
|
|
||||||
|
adjustFormatStyleForLineBreak(style);
|
||||||
|
if (typedChar == QChar::Null)
|
||||||
|
modifyToIndentEmptyLines(buffer, utf8Offset, utf8Length, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Range> ranges{{static_cast<unsigned int>(utf8Offset),
|
||||||
|
static_cast<unsigned int>(utf8Length)}};
|
||||||
|
FormattingAttemptStatus status;
|
||||||
|
|
||||||
|
ClangReplacements replacements = reformat(style,
|
||||||
|
buffer.data(),
|
||||||
|
ranges,
|
||||||
|
fileName.toString().toStdString(),
|
||||||
|
&status);
|
||||||
|
|
||||||
|
if (!status.FormatComplete)
|
||||||
|
QtReplacements();
|
||||||
|
|
||||||
|
const ClangReplacements filtered = filteredReplacements(replacements,
|
||||||
|
utf8Offset,
|
||||||
|
extraOffset,
|
||||||
|
onlyIndention);
|
||||||
|
return utf16Replacements(block, blockOffsetUtf8, originalBuffer, filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyReplacements(const QTextBlock &block, const QtReplacements &replacements)
|
||||||
{
|
{
|
||||||
if (replacements.empty())
|
if (replacements.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tooling::Replacements convertedReplacements = utf16Replacements(block,
|
|
||||||
blockOffsetUtf8,
|
|
||||||
utf8Buffer,
|
|
||||||
replacements);
|
|
||||||
|
|
||||||
int fullOffsetShift = 0;
|
int fullOffsetShift = 0;
|
||||||
QTextCursor editCursor(block);
|
QTextCursor editCursor(block);
|
||||||
for (const Replacement &replacement : convertedReplacements) {
|
for (const QtReplacement &replacement : replacements) {
|
||||||
const QString replacementString = QString::fromStdString(replacement.getReplacementText());
|
|
||||||
const int replacementLength = static_cast<int>(replacement.getLength());
|
|
||||||
editCursor.beginEditBlock();
|
editCursor.beginEditBlock();
|
||||||
editCursor.setPosition(static_cast<int>(replacement.getOffset()) + fullOffsetShift);
|
editCursor.setPosition(replacement.offset + fullOffsetShift);
|
||||||
editCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor,
|
editCursor.movePosition(QTextCursor::NextCharacter,
|
||||||
replacementLength);
|
QTextCursor::KeepAnchor,
|
||||||
|
replacement.length);
|
||||||
editCursor.removeSelectedText();
|
editCursor.removeSelectedText();
|
||||||
editCursor.insertText(replacementString);
|
editCursor.insertText(replacement.text);
|
||||||
editCursor.endEditBlock();
|
editCursor.endEditBlock();
|
||||||
fullOffsetShift += replacementString.length() - replacementLength;
|
fullOffsetShift += replacement.text.length() - replacement.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,38 +383,38 @@ void ClangFormatIndenter::indent(QTextDocument *doc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatIndenter::format(QTextDocument *doc,
|
QtReplacements ClangFormatIndenter::format(QTextDocument *doc,
|
||||||
const QTextCursor &cursor,
|
const QTextCursor &cursor,
|
||||||
const TextEditor::TabSettings &/*tabSettings*/)
|
const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
{
|
{
|
||||||
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
|
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
|
||||||
if (!editor)
|
if (!editor)
|
||||||
return;
|
return QtReplacements();
|
||||||
|
|
||||||
const Utils::FileName fileName = editor->textDocument()->filePath();
|
const Utils::FileName fileName = editor->textDocument()->filePath();
|
||||||
int utf8Offset;
|
int utf8Offset;
|
||||||
int utf8Length;
|
int utf8Length;
|
||||||
const QByteArray buffer = doc->toPlainText().toUtf8();
|
const QByteArray buffer = doc->toPlainText().toUtf8();
|
||||||
|
QTextBlock block = cursor.block();
|
||||||
if (cursor.hasSelection()) {
|
if (cursor.hasSelection()) {
|
||||||
const QTextBlock start = doc->findBlock(cursor.selectionStart());
|
block = doc->findBlock(cursor.selectionStart());
|
||||||
const QTextBlock end = doc->findBlock(cursor.selectionEnd());
|
const QTextBlock end = doc->findBlock(cursor.selectionEnd());
|
||||||
utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, start.blockNumber() + 1);
|
utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
||||||
QTC_ASSERT(utf8Offset >= 0, return;);
|
QTC_ASSERT(utf8Offset >= 0, return QtReplacements(););
|
||||||
utf8Length = selectedLines(doc, start, end).toUtf8().size();
|
utf8Length = selectedLines(doc, block, end).toUtf8().size();
|
||||||
applyReplacements(start,
|
|
||||||
utf8Offset,
|
|
||||||
buffer,
|
|
||||||
replacements(fileName, buffer, utf8Offset, utf8Length));
|
|
||||||
} else {
|
} else {
|
||||||
const QTextBlock block = cursor.block();
|
const QTextBlock block = cursor.block();
|
||||||
utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
||||||
QTC_ASSERT(utf8Offset >= 0, return;);
|
QTC_ASSERT(utf8Offset >= 0, return QtReplacements(););
|
||||||
utf8Length = block.text().toUtf8().size();
|
utf8Length = block.text().toUtf8().size();
|
||||||
applyReplacements(block,
|
|
||||||
utf8Offset,
|
|
||||||
buffer,
|
|
||||||
replacements(fileName, buffer, utf8Offset, utf8Length));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QtReplacements toReplace
|
||||||
|
= replacements(fileName, buffer, utf8Offset, utf8Length, block, QChar::Null, false);
|
||||||
|
applyReplacements(block, toReplace);
|
||||||
|
|
||||||
|
return toReplace;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatIndenter::reindent(QTextDocument *doc,
|
void ClangFormatIndenter::reindent(QTextDocument *doc,
|
||||||
@@ -439,9 +443,7 @@ void ClangFormatIndenter::indentBlock(QTextDocument *doc,
|
|||||||
QTC_ASSERT(utf8Offset >= 0, return;);
|
QTC_ASSERT(utf8Offset >= 0, return;);
|
||||||
|
|
||||||
applyReplacements(block,
|
applyReplacements(block,
|
||||||
utf8Offset,
|
replacements(fileName, buffer, utf8Offset, 0, block, typedChar));
|
||||||
buffer,
|
|
||||||
replacements(fileName, buffer, utf8Offset, 0, &block, typedChar));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &)
|
int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &)
|
||||||
@@ -458,17 +460,15 @@ int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::Ta
|
|||||||
const int utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
const int utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
||||||
QTC_ASSERT(utf8Offset >= 0, return 0;);
|
QTC_ASSERT(utf8Offset >= 0, return 0;);
|
||||||
|
|
||||||
Replacements toReplace = replacements(fileName, buffer, utf8Offset, 0, &block);
|
const QtReplacements toReplace = replacements(fileName, buffer, utf8Offset, 0, block);
|
||||||
|
|
||||||
if (toReplace.empty())
|
if (toReplace.empty())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
const Replacement replacement = *toReplace.begin();
|
const QtReplacement &replacement = toReplace.front();
|
||||||
|
int afterLineBreak = replacement.text.lastIndexOf('\n');
|
||||||
const StringRef text = replacement.getReplacementText();
|
afterLineBreak = (afterLineBreak < 0) ? 0 : afterLineBreak + 1;
|
||||||
size_t afterLineBreak = text.find_last_of('\n');
|
return static_cast<int>(replacement.text.size() - afterLineBreak);
|
||||||
afterLineBreak = (afterLineBreak == std::string::npos) ? 0 : afterLineBreak + 1;
|
|
||||||
return static_cast<int>(text.size() - afterLineBreak);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TabSettings ClangFormatIndenter::tabSettings() const
|
TabSettings ClangFormatIndenter::tabSettings() const
|
||||||
|
@@ -40,9 +40,9 @@ public:
|
|||||||
void reindent(QTextDocument *doc,
|
void reindent(QTextDocument *doc,
|
||||||
const QTextCursor &cursor,
|
const QTextCursor &cursor,
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
void format(QTextDocument *doc,
|
TextEditor::Replacements format(QTextDocument *doc,
|
||||||
const QTextCursor &cursor,
|
const QTextCursor &cursor,
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
void indentBlock(QTextDocument *doc,
|
void indentBlock(QTextDocument *doc,
|
||||||
const QTextBlock &block,
|
const QTextBlock &block,
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
|
@@ -102,11 +102,12 @@ void Indenter::reindent(QTextDocument *doc, const QTextCursor &cursor, const Tab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Indenter::format(QTextDocument *doc,
|
Replacements Indenter::format(QTextDocument *doc,
|
||||||
const QTextCursor &cursor,
|
const QTextCursor &cursor,
|
||||||
const TabSettings &tabSettings)
|
const TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
indent(doc, cursor, QChar::Null, tabSettings);
|
indent(doc, cursor, QChar::Null, tabSettings);
|
||||||
|
return Replacements();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Indenter::setCodeStylePreferences(ICodeStylePreferences *)
|
void Indenter::setCodeStylePreferences(ICodeStylePreferences *)
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "tabsettings.h"
|
#include "tabsettings.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QTextDocument;
|
class QTextDocument;
|
||||||
@@ -45,6 +46,21 @@ class TabSettings;
|
|||||||
|
|
||||||
using IndentationForBlock = QMap<int, int>;
|
using IndentationForBlock = QMap<int, int>;
|
||||||
|
|
||||||
|
class TEXTEDITOR_EXPORT Replacement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Replacement(int offset, int length, const QString &text)
|
||||||
|
: offset(offset)
|
||||||
|
, length(length)
|
||||||
|
, text(text)
|
||||||
|
{}
|
||||||
|
int offset;
|
||||||
|
int length;
|
||||||
|
QString text;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Replacements = std::vector<Replacement>;
|
||||||
|
|
||||||
class TEXTEDITOR_EXPORT Indenter
|
class TEXTEDITOR_EXPORT Indenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -68,9 +84,9 @@ public:
|
|||||||
bool autoTriggered = true);
|
bool autoTriggered = true);
|
||||||
|
|
||||||
// By default just calls indent with default settings.
|
// By default just calls indent with default settings.
|
||||||
virtual void format(QTextDocument *doc,
|
virtual Replacements format(QTextDocument *doc,
|
||||||
const QTextCursor &cursor,
|
const QTextCursor &cursor,
|
||||||
const TabSettings &tabSettings);
|
const TabSettings &tabSettings);
|
||||||
|
|
||||||
// Reindent at cursor. Selection will be adjusted according to the indentation
|
// Reindent at cursor. Selection will be adjusted according to the indentation
|
||||||
// change of the first block.
|
// change of the first block.
|
||||||
|
Reference in New Issue
Block a user