forked from qt-creator/qt-creator
ClangFormat: Refactor indenter to allow ClangFormat unit-tests
We do not build texteditor files in unit-tests so some tricks were required to make ClangFormatIndenter available. First simple unit-test proofs it builds and runs. Change-Id: I81d5ea099bd27fd1c1ed8b5b7877299dcc62a67f Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
@@ -49,7 +49,7 @@ static TextEditor::TextDocument *createJavaDocument()
|
|||||||
auto doc = new TextEditor::TextDocument;
|
auto doc = new TextEditor::TextDocument;
|
||||||
doc->setId(Constants::JAVA_EDITOR_ID);
|
doc->setId(Constants::JAVA_EDITOR_ID);
|
||||||
doc->setMimeType(QLatin1String(Constants::JAVA_MIMETYPE));
|
doc->setMimeType(QLatin1String(Constants::JAVA_MIMETYPE));
|
||||||
doc->setIndenter(new JavaIndenter);
|
doc->setIndenter(new JavaIndenter(doc->document()));
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,7 +31,9 @@
|
|||||||
using namespace Android;
|
using namespace Android;
|
||||||
using namespace Android::Internal;
|
using namespace Android::Internal;
|
||||||
|
|
||||||
JavaIndenter::JavaIndenter() = default;
|
JavaIndenter::JavaIndenter(QTextDocument *doc)
|
||||||
|
: TextEditor::TextIndenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
JavaIndenter::~JavaIndenter() = default;
|
JavaIndenter::~JavaIndenter() = default;
|
||||||
|
|
||||||
@@ -44,20 +46,17 @@ bool JavaIndenter::isElectricCharacter(const QChar &ch) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaIndenter::indentBlock(QTextDocument *doc,
|
void JavaIndenter::indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings)
|
const TextEditor::TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
Q_UNUSED(doc);
|
|
||||||
int indent = indentFor(block, tabSettings);
|
int indent = indentFor(block, tabSettings);
|
||||||
if (typedChar == QLatin1Char('}'))
|
if (typedChar == QLatin1Char('}'))
|
||||||
indent -= tabSettings.m_indentSize;
|
indent -= tabSettings.m_indentSize;
|
||||||
tabSettings.indentLine(block, qMax(0, indent));
|
tabSettings.indentLine(block, qMax(0, indent));
|
||||||
}
|
}
|
||||||
|
|
||||||
int JavaIndenter::indentFor(const QTextBlock &block,
|
int JavaIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings)
|
||||||
const TextEditor::TabSettings &tabSettings)
|
|
||||||
{
|
{
|
||||||
QTextBlock previous = block.previous();
|
QTextBlock previous = block.previous();
|
||||||
if (!previous.isValid())
|
if (!previous.isValid())
|
||||||
|
@@ -25,20 +25,19 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/textindenter.h>
|
||||||
|
|
||||||
namespace Android {
|
namespace Android {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class JavaIndenter : public TextEditor::Indenter
|
class JavaIndenter : public TextEditor::TextIndenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
JavaIndenter();
|
explicit JavaIndenter(QTextDocument *doc);
|
||||||
~JavaIndenter() override;
|
~JavaIndenter() override;
|
||||||
|
|
||||||
bool isElectricCharacter(const QChar &ch) const override;
|
bool isElectricCharacter(const QChar &ch) const override;
|
||||||
|
|
||||||
void indentBlock(QTextDocument *doc,
|
void indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
|
|
||||||
|
8
src/plugins/clangformat/clangformat-source.pri
Normal file
8
src/plugins/clangformat/clangformat-source.pri
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$PWD/clangformatconstants.h \
|
||||||
|
$$PWD/clangformatbaseindenter.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$PWD/clangformatbaseindenter.cpp
|
@@ -1,4 +1,5 @@
|
|||||||
include(../../qtcreatorplugin.pri)
|
include(../../qtcreatorplugin.pri)
|
||||||
|
include(clangformat-source.pri)
|
||||||
include(../../shared/clang/clang_installation.pri)
|
include(../../shared/clang/clang_installation.pri)
|
||||||
|
|
||||||
include(../../shared/clang/clang_defines.pri)
|
include(../../shared/clang/clang_defines.pri)
|
||||||
@@ -19,17 +20,16 @@ QMAKE_CXXFLAGS *= $$LLVM_CXXFLAGS
|
|||||||
gcc:QMAKE_CXXFLAGS *= -Wno-comment
|
gcc:QMAKE_CXXFLAGS *= -Wno-comment
|
||||||
unix:!macos:QMAKE_LFLAGS += -Wl,--exclude-libs,ALL
|
unix:!macos:QMAKE_LFLAGS += -Wl,--exclude-libs,ALL
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES += \
|
||||||
clangformatconfigwidget.cpp \
|
clangformatconfigwidget.cpp \
|
||||||
clangformatindenter.cpp \
|
clangformatindenter.cpp \
|
||||||
clangformatplugin.cpp \
|
clangformatplugin.cpp \
|
||||||
clangformatutils.cpp
|
clangformatutils.cpp
|
||||||
|
|
||||||
HEADERS = \
|
HEADERS += \
|
||||||
clangformatconfigwidget.h \
|
clangformatconfigwidget.h \
|
||||||
clangformatindenter.h \
|
clangformatindenter.h \
|
||||||
clangformatplugin.h \
|
clangformatplugin.h \
|
||||||
clangformatconstants.h \
|
|
||||||
clangformatutils.h
|
clangformatutils.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
|
@@ -30,6 +30,8 @@ QtcPlugin {
|
|||||||
cpp.rpaths: base.concat(libclang.llvmLibDir)
|
cpp.rpaths: base.concat(libclang.llvmLibDir)
|
||||||
|
|
||||||
files: [
|
files: [
|
||||||
|
"clangformatbaseindenter.h",
|
||||||
|
"clangformatbaseindenter.cpp",
|
||||||
"clangformatconfigwidget.cpp",
|
"clangformatconfigwidget.cpp",
|
||||||
"clangformatconfigwidget.h",
|
"clangformatconfigwidget.h",
|
||||||
"clangformatconfigwidget.ui",
|
"clangformatconfigwidget.ui",
|
||||||
|
500
src/plugins/clangformat/clangformatbaseindenter.cpp
Normal file
500
src/plugins/clangformat/clangformatbaseindenter.cpp
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "clangformatbaseindenter.h"
|
||||||
|
|
||||||
|
#include <clang/Tooling/Core/Replacement.h>
|
||||||
|
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/textutils.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
namespace ClangFormat {
|
||||||
|
|
||||||
|
static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style)
|
||||||
|
{
|
||||||
|
style.DisableFormat = false;
|
||||||
|
style.ColumnLimit = 0;
|
||||||
|
#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
|
||||||
|
style.KeepLineBreaksForNonEmptyLines = true;
|
||||||
|
#endif
|
||||||
|
style.MaxEmptyLinesToKeep = 2;
|
||||||
|
style.SortIncludes = false;
|
||||||
|
style.SortUsingDeclarations = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static llvm::StringRef clearExtraNewline(llvm::StringRef text)
|
||||||
|
{
|
||||||
|
while (text.startswith("\n\n"))
|
||||||
|
text = text.drop_front();
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
static clang::tooling::Replacements filteredReplacements(
|
||||||
|
const clang::tooling::Replacements &replacements,
|
||||||
|
int offset,
|
||||||
|
int extraOffsetToAdd,
|
||||||
|
bool onlyIndention)
|
||||||
|
{
|
||||||
|
clang::tooling::Replacements filtered;
|
||||||
|
for (const clang::tooling::Replacement &replacement : replacements) {
|
||||||
|
int replacementOffset = static_cast<int>(replacement.getOffset());
|
||||||
|
if (onlyIndention && replacementOffset != offset - 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (replacementOffset + 1 >= offset)
|
||||||
|
replacementOffset += extraOffsetToAdd;
|
||||||
|
|
||||||
|
llvm::StringRef text = onlyIndention ? clearExtraNewline(replacement.getReplacementText())
|
||||||
|
: replacement.getReplacementText();
|
||||||
|
|
||||||
|
llvm::Error error = filtered.add(
|
||||||
|
clang::tooling::Replacement(replacement.getFilePath(),
|
||||||
|
static_cast<unsigned int>(replacementOffset),
|
||||||
|
replacement.getLength(),
|
||||||
|
text));
|
||||||
|
// Throws if error is not checked.
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock)
|
||||||
|
{
|
||||||
|
QTextBlock prevBlock = currentBlock.previous();
|
||||||
|
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
|
||||||
|
prevBlock = prevBlock.previous();
|
||||||
|
|
||||||
|
if (prevBlock.text().trimmed().isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString initialText = prevBlock.text();
|
||||||
|
if (!initialText.at(initialText.size() - 1).isSpace())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto lastNonSpace = std::find_if_not(initialText.rbegin(),
|
||||||
|
initialText.rend(),
|
||||||
|
[](const QChar &letter) { return letter.isSpace(); });
|
||||||
|
const int extraSpaceCount = static_cast<int>(std::distance(initialText.rbegin(), lastNonSpace));
|
||||||
|
|
||||||
|
QTextCursor cursor(prevBlock);
|
||||||
|
cursor.beginEditBlock();
|
||||||
|
cursor.movePosition(QTextCursor::Right,
|
||||||
|
QTextCursor::MoveAnchor,
|
||||||
|
initialText.size() - extraSpaceCount);
|
||||||
|
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, extraSpaceCount);
|
||||||
|
cursor.removeSelectedText();
|
||||||
|
cursor.endEditBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trimCurrentBlock(const QTextBlock ¤tBlock)
|
||||||
|
{
|
||||||
|
if (currentBlock.text().trimmed().isEmpty()) {
|
||||||
|
// Clear the block containing only spaces
|
||||||
|
QTextCursor cursor(currentBlock);
|
||||||
|
cursor.beginEditBlock();
|
||||||
|
cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
|
||||||
|
cursor.removeSelectedText();
|
||||||
|
cursor.endEditBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the total langth of previous lines with pure whitespace.
|
||||||
|
static int previousEmptyLinesLength(const QTextBlock ¤tBlock)
|
||||||
|
{
|
||||||
|
int length{0};
|
||||||
|
QTextBlock prevBlock = currentBlock.previous();
|
||||||
|
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty()) {
|
||||||
|
length += prevBlock.text().length() + 1;
|
||||||
|
prevBlock = prevBlock.previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void modifyToIndentEmptyLines(
|
||||||
|
QByteArray &buffer, int offset, int &length, const QTextBlock &block, bool secondTry)
|
||||||
|
{
|
||||||
|
const QString blockText = block.text().trimmed();
|
||||||
|
const bool closingParenBlock = blockText.startsWith(')');
|
||||||
|
if (blockText.isEmpty() || closingParenBlock) {
|
||||||
|
//This extra text works for the most cases.
|
||||||
|
QByteArray dummyText("a;");
|
||||||
|
|
||||||
|
// Search for previous character
|
||||||
|
QTextBlock prevBlock = block.previous();
|
||||||
|
bool prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
|
||||||
|
while (prevBlockIsEmpty) {
|
||||||
|
prevBlock = prevBlock.previous();
|
||||||
|
prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
|
||||||
|
}
|
||||||
|
if (prevBlock.text().endsWith(','))
|
||||||
|
dummyText = "int a";
|
||||||
|
|
||||||
|
if (closingParenBlock) {
|
||||||
|
if (prevBlock.text().endsWith(','))
|
||||||
|
dummyText = "int a";
|
||||||
|
else
|
||||||
|
dummyText = "&& a";
|
||||||
|
}
|
||||||
|
|
||||||
|
length += dummyText.length();
|
||||||
|
buffer.insert(offset, dummyText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secondTry) {
|
||||||
|
int nextLinePos = buffer.indexOf('\n', offset);
|
||||||
|
if (nextLinePos > 0) {
|
||||||
|
// If first try was not successful try to put ')' in the end of the line to close possibly
|
||||||
|
// unclosed parentheses.
|
||||||
|
// TODO: Does it help to add different endings depending on the context?
|
||||||
|
buffer.insert(nextLinePos, ')');
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kMaxLinesFromCurrentBlock = 200;
|
||||||
|
|
||||||
|
static Utils::LineColumn utf16LineColumn(const QTextBlock &block,
|
||||||
|
int blockOffsetUtf8,
|
||||||
|
const QByteArray &utf8Buffer,
|
||||||
|
int utf8Offset)
|
||||||
|
{
|
||||||
|
// If lastIndexOf('\n') returns -1 then we are fine to add 1 and get 0 offset.
|
||||||
|
const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1;
|
||||||
|
int line = block.blockNumber() + 1; // Init with the line corresponding the block.
|
||||||
|
|
||||||
|
if (utf8Offset < blockOffsetUtf8) {
|
||||||
|
line -= static_cast<int>(std::count(utf8Buffer.begin() + lineStartUtf8Offset,
|
||||||
|
utf8Buffer.begin() + blockOffsetUtf8,
|
||||||
|
'\n'));
|
||||||
|
} else {
|
||||||
|
line += static_cast<int>(std::count(utf8Buffer.begin() + blockOffsetUtf8,
|
||||||
|
utf8Buffer.begin() + lineStartUtf8Offset,
|
||||||
|
'\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray lineText = utf8Buffer.mid(lineStartUtf8Offset,
|
||||||
|
utf8Offset - lineStartUtf8Offset);
|
||||||
|
return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TextEditor::Replacements utf16Replacements(const QTextBlock &block,
|
||||||
|
int blockOffsetUtf8,
|
||||||
|
const QByteArray &utf8Buffer,
|
||||||
|
const clang::tooling::Replacements &replacements)
|
||||||
|
{
|
||||||
|
TextEditor::Replacements convertedReplacements;
|
||||||
|
convertedReplacements.reserve(replacements.size());
|
||||||
|
for (const clang::tooling::Replacement &replacement : replacements) {
|
||||||
|
const Utils::LineColumn lineColUtf16 = utf16LineColumn(block,
|
||||||
|
blockOffsetUtf8,
|
||||||
|
utf8Buffer,
|
||||||
|
static_cast<int>(
|
||||||
|
replacement.getOffset()));
|
||||||
|
if (!lineColUtf16.isValid())
|
||||||
|
continue;
|
||||||
|
const int utf16Offset = Utils::Text::positionInText(block.document(),
|
||||||
|
lineColUtf16.line,
|
||||||
|
lineColUtf16.column);
|
||||||
|
const int utf16Length = QString::fromUtf8(
|
||||||
|
utf8Buffer.mid(static_cast<int>(replacement.getOffset()),
|
||||||
|
static_cast<int>(replacement.getLength())))
|
||||||
|
.size();
|
||||||
|
convertedReplacements.emplace_back(utf16Offset,
|
||||||
|
utf16Length,
|
||||||
|
QString::fromStdString(replacement.getReplacementText()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertedReplacements;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void applyReplacements(const QTextBlock &block, const TextEditor::Replacements &replacements)
|
||||||
|
{
|
||||||
|
if (replacements.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int fullOffsetShift = 0;
|
||||||
|
QTextCursor editCursor(block);
|
||||||
|
for (const TextEditor::Replacement &replacement : replacements) {
|
||||||
|
editCursor.beginEditBlock();
|
||||||
|
editCursor.setPosition(replacement.offset + fullOffsetShift);
|
||||||
|
editCursor.movePosition(QTextCursor::NextCharacter,
|
||||||
|
QTextCursor::KeepAnchor,
|
||||||
|
replacement.length);
|
||||||
|
editCursor.removeSelectedText();
|
||||||
|
editCursor.insertText(replacement.text);
|
||||||
|
editCursor.endEditBlock();
|
||||||
|
fullOffsetShift += replacement.text.length() - replacement.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString selectedLines(QTextDocument *doc,
|
||||||
|
const QTextBlock &startBlock,
|
||||||
|
const QTextBlock &endBlock)
|
||||||
|
{
|
||||||
|
QString text = Utils::Text::textAt(QTextCursor(doc),
|
||||||
|
startBlock.position(),
|
||||||
|
std::max(0,
|
||||||
|
endBlock.position() + endBlock.length()
|
||||||
|
- startBlock.position() - 1));
|
||||||
|
while (!text.isEmpty() && text.rbegin()->isSpace())
|
||||||
|
text.chop(1);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangFormatBaseIndenter::ClangFormatBaseIndenter(QTextDocument *doc)
|
||||||
|
: TextEditor::Indenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks(
|
||||||
|
const QVector<QTextBlock> &blocks, const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
|
{
|
||||||
|
TextEditor::IndentationForBlock ret;
|
||||||
|
for (QTextBlock block : blocks)
|
||||||
|
ret.insert(block.blockNumber(), indentFor(block));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangFormatBaseIndenter::indent(const QTextCursor &cursor, const QChar &typedChar)
|
||||||
|
{
|
||||||
|
if (cursor.hasSelection()) {
|
||||||
|
// Calling currentBlock.next() might be unsafe because we change the document.
|
||||||
|
// Let's operate with block numbers instead.
|
||||||
|
const int startNumber = m_doc->findBlock(cursor.selectionStart()).blockNumber();
|
||||||
|
const int endNumber = m_doc->findBlock(cursor.selectionEnd()).blockNumber();
|
||||||
|
for (int currentBlockNumber = startNumber; currentBlockNumber <= endNumber;
|
||||||
|
++currentBlockNumber) {
|
||||||
|
const QTextBlock currentBlock = m_doc->findBlockByNumber(currentBlockNumber);
|
||||||
|
if (currentBlock.isValid()) {
|
||||||
|
const int blocksAmount = m_doc->blockCount();
|
||||||
|
indentBlock(currentBlock, typedChar);
|
||||||
|
QTC_CHECK(blocksAmount == m_doc->blockCount()
|
||||||
|
&& "ClangFormat plugin indentation changed the amount of blocks.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
indentBlock(cursor.block(), typedChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
|
||||||
|
const QChar &typedChar,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
|
{
|
||||||
|
indent(cursor, typedChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangFormatBaseIndenter::reindent(const QTextCursor &cursor,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
|
{
|
||||||
|
indent(cursor, QChar::Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditor::Replacements ClangFormatBaseIndenter::format(
|
||||||
|
const QTextCursor &cursor, const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
|
{
|
||||||
|
int utf8Offset;
|
||||||
|
int utf8Length;
|
||||||
|
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||||
|
QTextBlock block = cursor.block();
|
||||||
|
if (cursor.hasSelection()) {
|
||||||
|
block = m_doc->findBlock(cursor.selectionStart());
|
||||||
|
const QTextBlock end = m_doc->findBlock(cursor.selectionEnd());
|
||||||
|
utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
|
||||||
|
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
|
||||||
|
utf8Length = selectedLines(m_doc, block, end).toUtf8().size();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const QTextBlock block = cursor.block();
|
||||||
|
utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
|
||||||
|
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
|
||||||
|
utf8Length = block.text().toUtf8().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TextEditor::Replacements toReplace
|
||||||
|
= replacements(buffer, utf8Offset, utf8Length, block, QChar::Null, false);
|
||||||
|
applyReplacements(block, toReplace);
|
||||||
|
|
||||||
|
return toReplace;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, const QChar &typedChar)
|
||||||
|
{
|
||||||
|
trimFirstNonEmptyBlock(block);
|
||||||
|
trimCurrentBlock(block);
|
||||||
|
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||||
|
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
|
||||||
|
QTC_ASSERT(utf8Offset >= 0, return;);
|
||||||
|
|
||||||
|
applyReplacements(block, replacements(buffer, utf8Offset, 0, block, typedChar));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
||||||
|
const QChar &typedChar,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
|
{
|
||||||
|
indentBlock(block, typedChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block)
|
||||||
|
{
|
||||||
|
trimFirstNonEmptyBlock(block);
|
||||||
|
trimCurrentBlock(block);
|
||||||
|
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||||
|
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
|
||||||
|
QTC_ASSERT(utf8Offset >= 0, return 0;);
|
||||||
|
|
||||||
|
const TextEditor::Replacements toReplace = replacements(buffer, utf8Offset, 0, block);
|
||||||
|
|
||||||
|
if (toReplace.empty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const TextEditor::Replacement &replacement = toReplace.front();
|
||||||
|
int afterLineBreak = replacement.text.lastIndexOf('\n');
|
||||||
|
afterLineBreak = (afterLineBreak < 0) ? 0 : afterLineBreak + 1;
|
||||||
|
return static_cast<int>(replacement.text.size() - afterLineBreak);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/)
|
||||||
|
{
|
||||||
|
return indentFor(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangFormatBaseIndenter::isElectricCharacter(const QChar &ch) const
|
||||||
|
{
|
||||||
|
switch (ch.toLatin1()) {
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case ':':
|
||||||
|
case '#':
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
case ';':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case ',':
|
||||||
|
case '.':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
|
||||||
|
{
|
||||||
|
llvm::Expected<clang::format::FormatStyle> style
|
||||||
|
= clang::format::getStyle("file", m_fileName.toString().toStdString(), "none");
|
||||||
|
if (style)
|
||||||
|
return *style;
|
||||||
|
|
||||||
|
handleAllErrors(style.takeError(), [](const llvm::ErrorInfoBase &) {
|
||||||
|
// do nothing
|
||||||
|
});
|
||||||
|
|
||||||
|
return clang::format::getLLVMStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer,
|
||||||
|
int utf8Offset,
|
||||||
|
int utf8Length,
|
||||||
|
const QTextBlock &block,
|
||||||
|
const QChar &typedChar,
|
||||||
|
bool onlyIndention,
|
||||||
|
bool secondTry) const
|
||||||
|
{
|
||||||
|
clang::format::FormatStyle style = styleForFile();
|
||||||
|
|
||||||
|
int originalOffsetUtf8 = utf8Offset;
|
||||||
|
int originalLengthUtf8 = utf8Length;
|
||||||
|
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, secondTry);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<clang::tooling::Range> ranges{
|
||||||
|
{static_cast<unsigned int>(utf8Offset), static_cast<unsigned int>(utf8Length)}};
|
||||||
|
clang::format::FormattingAttemptStatus status;
|
||||||
|
|
||||||
|
clang::tooling::Replacements clangReplacements = reformat(style,
|
||||||
|
buffer.data(),
|
||||||
|
ranges,
|
||||||
|
m_fileName.toString().toStdString(),
|
||||||
|
&status);
|
||||||
|
|
||||||
|
if (!status.FormatComplete)
|
||||||
|
return TextEditor::Replacements();
|
||||||
|
|
||||||
|
const clang::tooling::Replacements filtered = filteredReplacements(clangReplacements,
|
||||||
|
utf8Offset,
|
||||||
|
extraOffset,
|
||||||
|
onlyIndention);
|
||||||
|
const bool canTryAgain = onlyIndention && typedChar == QChar::Null && !secondTry;
|
||||||
|
if (canTryAgain && filtered.empty()) {
|
||||||
|
return replacements(originalBuffer,
|
||||||
|
originalOffsetUtf8,
|
||||||
|
originalLengthUtf8,
|
||||||
|
block,
|
||||||
|
typedChar,
|
||||||
|
onlyIndention,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return utf16Replacements(block, originalOffsetUtf8, originalBuffer, filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ClangFormat
|
75
src/plugins/clangformat/clangformatbaseindenter.h
Normal file
75
src/plugins/clangformat/clangformatbaseindenter.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <texteditor/indenter.h>
|
||||||
|
|
||||||
|
#include <clang/Format/Format.h>
|
||||||
|
|
||||||
|
namespace ClangFormat {
|
||||||
|
|
||||||
|
class ClangFormatBaseIndenter : public TextEditor::Indenter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClangFormatBaseIndenter(QTextDocument *doc);
|
||||||
|
|
||||||
|
TextEditor::IndentationForBlock indentationForBlocks(
|
||||||
|
const QVector<QTextBlock> &blocks, const TextEditor::TabSettings & /*tabSettings*/) override;
|
||||||
|
void indent(const QTextCursor &cursor,
|
||||||
|
const QChar &typedChar,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/) override;
|
||||||
|
|
||||||
|
void reindent(const QTextCursor &cursor,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/) override;
|
||||||
|
|
||||||
|
TextEditor::Replacements format(const QTextCursor &cursor,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/) override;
|
||||||
|
|
||||||
|
void indentBlock(const QTextBlock &block,
|
||||||
|
const QChar &typedChar,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/) override;
|
||||||
|
|
||||||
|
int indentFor(const QTextBlock &block, const TextEditor::TabSettings & /*tabSettings*/) override;
|
||||||
|
|
||||||
|
bool isElectricCharacter(const QChar &ch) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual clang::format::FormatStyle styleForFile() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void indent(const QTextCursor &cursor, const QChar &typedChar);
|
||||||
|
void indentBlock(const QTextBlock &block, const QChar &typedChar);
|
||||||
|
int indentFor(const QTextBlock &block);
|
||||||
|
TextEditor::Replacements replacements(QByteArray buffer,
|
||||||
|
int utf8Offset,
|
||||||
|
int utf8Length,
|
||||||
|
const QTextBlock &block,
|
||||||
|
const QChar &typedChar = QChar::Null,
|
||||||
|
bool onlyIndention = true,
|
||||||
|
bool secondTry = false) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ClangFormat
|
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2018 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of Qt Creator.
|
** This file is part of Qt Creator.
|
||||||
@@ -24,479 +24,26 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "clangformatindenter.h"
|
#include "clangformatindenter.h"
|
||||||
|
|
||||||
#include "clangformatutils.h"
|
#include "clangformatutils.h"
|
||||||
|
|
||||||
#include <clang/Format/Format.h>
|
#include <texteditor/tabsettings.h>
|
||||||
#include <clang/Tooling/Core/Replacement.h>
|
|
||||||
|
|
||||||
#include <cpptools/cppmodelmanager.h>
|
|
||||||
#include <texteditor/textdocument.h>
|
|
||||||
#include <texteditor/texteditor.h>
|
|
||||||
|
|
||||||
#include <utils/hostosinfo.h>
|
|
||||||
#include <utils/textutils.h>
|
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
|
|
||||||
#include <llvm/Config/llvm-config.h>
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QTextBlock>
|
|
||||||
|
|
||||||
#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 tooling;
|
|
||||||
using namespace ProjectExplorer;
|
|
||||||
using namespace TextEditor;
|
using namespace TextEditor;
|
||||||
|
|
||||||
namespace ClangFormat {
|
namespace ClangFormat {
|
||||||
|
|
||||||
namespace {
|
ClangFormatIndenter::ClangFormatIndenter(QTextDocument *doc)
|
||||||
|
: ClangFormatBaseIndenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
void adjustFormatStyleForLineBreak(format::FormatStyle &style)
|
FormatStyle ClangFormatIndenter::styleForFile() const
|
||||||
{
|
{
|
||||||
style.DisableFormat = false;
|
return ClangFormat::styleForFile(m_fileName);
|
||||||
style.ColumnLimit = 0;
|
|
||||||
#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
|
|
||||||
style.KeepLineBreaksForNonEmptyLines = true;
|
|
||||||
#endif
|
|
||||||
style.MaxEmptyLinesToKeep = 2;
|
|
||||||
style.SortIncludes = false;
|
|
||||||
style.SortUsingDeclarations = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef clearExtraNewline(StringRef text)
|
Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const
|
||||||
{
|
|
||||||
while (text.startswith("\n\n"))
|
|
||||||
text = text.drop_front();
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClangReplacements filteredReplacements(const ClangReplacements &replacements,
|
|
||||||
int offset,
|
|
||||||
int extraOffsetToAdd,
|
|
||||||
bool onlyIndention)
|
|
||||||
{
|
|
||||||
ClangReplacements filtered;
|
|
||||||
for (const ClangReplacement &replacement : replacements) {
|
|
||||||
int replacementOffset = static_cast<int>(replacement.getOffset());
|
|
||||||
if (onlyIndention && replacementOffset != offset - 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (replacementOffset + 1 >= offset)
|
|
||||||
replacementOffset += extraOffsetToAdd;
|
|
||||||
|
|
||||||
StringRef text = onlyIndention ? clearExtraNewline(replacement.getReplacementText())
|
|
||||||
: replacement.getReplacementText();
|
|
||||||
|
|
||||||
Error error = filtered.add(ClangReplacement(replacement.getFilePath(),
|
|
||||||
static_cast<unsigned int>(replacementOffset),
|
|
||||||
replacement.getLength(),
|
|
||||||
text));
|
|
||||||
// Throws if error is not checked.
|
|
||||||
if (error)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return filtered;
|
|
||||||
}
|
|
||||||
|
|
||||||
void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock)
|
|
||||||
{
|
|
||||||
QTextBlock prevBlock = currentBlock.previous();
|
|
||||||
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
|
|
||||||
prevBlock = prevBlock.previous();
|
|
||||||
|
|
||||||
if (prevBlock.text().trimmed().isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const QString initialText = prevBlock.text();
|
|
||||||
if (!initialText.at(initialText.size() - 1).isSpace())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto lastNonSpace = std::find_if_not(initialText.rbegin(),
|
|
||||||
initialText.rend(),
|
|
||||||
[](const QChar &letter) {
|
|
||||||
return letter.isSpace();
|
|
||||||
});
|
|
||||||
const int extraSpaceCount = static_cast<int>(std::distance(initialText.rbegin(), lastNonSpace));
|
|
||||||
|
|
||||||
QTextCursor cursor(prevBlock);
|
|
||||||
cursor.beginEditBlock();
|
|
||||||
cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor,
|
|
||||||
initialText.size() - extraSpaceCount);
|
|
||||||
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, extraSpaceCount);
|
|
||||||
cursor.removeSelectedText();
|
|
||||||
cursor.endEditBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void trimCurrentBlock(const QTextBlock ¤tBlock)
|
|
||||||
{
|
|
||||||
if (currentBlock.text().trimmed().isEmpty()) {
|
|
||||||
// Clear the block containing only spaces
|
|
||||||
QTextCursor cursor(currentBlock);
|
|
||||||
cursor.beginEditBlock();
|
|
||||||
cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
|
|
||||||
cursor.removeSelectedText();
|
|
||||||
cursor.endEditBlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the total langth of previous lines with pure whitespace.
|
|
||||||
int previousEmptyLinesLength(const QTextBlock ¤tBlock)
|
|
||||||
{
|
|
||||||
int length{0};
|
|
||||||
QTextBlock prevBlock = currentBlock.previous();
|
|
||||||
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty()) {
|
|
||||||
length += prevBlock.text().length() + 1;
|
|
||||||
prevBlock = prevBlock.previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void modifyToIndentEmptyLines(
|
|
||||||
QByteArray &buffer, int offset, int &length, const QTextBlock &block, bool secondTry)
|
|
||||||
{
|
|
||||||
const QString blockText = block.text().trimmed();
|
|
||||||
const bool closingParenBlock = blockText.startsWith(')');
|
|
||||||
if (blockText.isEmpty() || closingParenBlock) {
|
|
||||||
//This extra text works for the most cases.
|
|
||||||
QByteArray dummyText("a;");
|
|
||||||
|
|
||||||
// Search for previous character
|
|
||||||
QTextBlock prevBlock = block.previous();
|
|
||||||
bool prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
|
|
||||||
while (prevBlockIsEmpty) {
|
|
||||||
prevBlock = prevBlock.previous();
|
|
||||||
prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty();
|
|
||||||
}
|
|
||||||
if (prevBlock.text().endsWith(','))
|
|
||||||
dummyText = "int a";
|
|
||||||
|
|
||||||
if (closingParenBlock) {
|
|
||||||
if (prevBlock.text().endsWith(','))
|
|
||||||
dummyText = "int a";
|
|
||||||
else
|
|
||||||
dummyText = "&& a";
|
|
||||||
}
|
|
||||||
|
|
||||||
length += dummyText.length();
|
|
||||||
buffer.insert(offset, dummyText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (secondTry) {
|
|
||||||
int nextLinePos = buffer.indexOf('\n', offset);
|
|
||||||
if (nextLinePos > 0) {
|
|
||||||
// If first try was not successful try to put ')' in the end of the line to close possibly
|
|
||||||
// unclosed parentheses.
|
|
||||||
// TODO: Does it help to add different endings depending on the context?
|
|
||||||
buffer.insert(nextLinePos, ')');
|
|
||||||
length += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const int kMaxLinesFromCurrentBlock = 200;
|
|
||||||
|
|
||||||
Utils::LineColumn utf16LineColumn(const QTextBlock &block,
|
|
||||||
int blockOffsetUtf8,
|
|
||||||
const QByteArray &utf8Buffer,
|
|
||||||
int utf8Offset)
|
|
||||||
{
|
|
||||||
// If lastIndexOf('\n') returns -1 then we are fine to add 1 and get 0 offset.
|
|
||||||
const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1;
|
|
||||||
int line = block.blockNumber() + 1; // Init with the line corresponding the block.
|
|
||||||
|
|
||||||
if (utf8Offset < blockOffsetUtf8) {
|
|
||||||
line -= static_cast<int>(std::count(utf8Buffer.begin() + lineStartUtf8Offset,
|
|
||||||
utf8Buffer.begin() + blockOffsetUtf8,
|
|
||||||
'\n'));
|
|
||||||
} else {
|
|
||||||
line += static_cast<int>(std::count(utf8Buffer.begin() + blockOffsetUtf8,
|
|
||||||
utf8Buffer.begin() + lineStartUtf8Offset,
|
|
||||||
'\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray lineText = utf8Buffer.mid(lineStartUtf8Offset,
|
|
||||||
utf8Offset - lineStartUtf8Offset);
|
|
||||||
return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
QtReplacements utf16Replacements(const QTextBlock &block,
|
|
||||||
int blockOffsetUtf8,
|
|
||||||
const QByteArray &utf8Buffer,
|
|
||||||
const ClangReplacements &replacements)
|
|
||||||
{
|
|
||||||
QtReplacements convertedReplacements;
|
|
||||||
convertedReplacements.reserve(replacements.size());
|
|
||||||
for (const ClangReplacement &replacement : replacements) {
|
|
||||||
const Utils::LineColumn lineColUtf16 = utf16LineColumn(block,
|
|
||||||
blockOffsetUtf8,
|
|
||||||
utf8Buffer,
|
|
||||||
static_cast<int>(
|
|
||||||
replacement.getOffset()));
|
|
||||||
if (!lineColUtf16.isValid())
|
|
||||||
continue;
|
|
||||||
const int utf16Offset = Utils::Text::positionInText(block.document(),
|
|
||||||
lineColUtf16.line,
|
|
||||||
lineColUtf16.column);
|
|
||||||
const int utf16Length = QString::fromUtf8(
|
|
||||||
utf8Buffer.mid(static_cast<int>(replacement.getOffset()),
|
|
||||||
static_cast<int>(replacement.getLength())))
|
|
||||||
.size();
|
|
||||||
convertedReplacements.emplace_back(utf16Offset,
|
|
||||||
utf16Length,
|
|
||||||
QString::fromStdString(replacement.getReplacementText()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return convertedReplacements;
|
|
||||||
}
|
|
||||||
|
|
||||||
QtReplacements replacements(const Utils::FileName &fileName,
|
|
||||||
QByteArray buffer,
|
|
||||||
int utf8Offset,
|
|
||||||
int utf8Length,
|
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar = QChar::Null,
|
|
||||||
bool onlyIndention = true,
|
|
||||||
bool secondTry = false)
|
|
||||||
{
|
|
||||||
FormatStyle style = styleForFile(fileName);
|
|
||||||
|
|
||||||
int originalOffsetUtf8 = utf8Offset;
|
|
||||||
int originalLengthUtf8 = utf8Length;
|
|
||||||
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, secondTry);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Range> ranges{{static_cast<unsigned int>(utf8Offset),
|
|
||||||
static_cast<unsigned int>(utf8Length)}};
|
|
||||||
FormattingAttemptStatus status;
|
|
||||||
|
|
||||||
ClangReplacements clangReplacements = reformat(style,
|
|
||||||
buffer.data(),
|
|
||||||
ranges,
|
|
||||||
fileName.toString().toStdString(),
|
|
||||||
&status);
|
|
||||||
|
|
||||||
if (!status.FormatComplete)
|
|
||||||
QtReplacements();
|
|
||||||
|
|
||||||
const ClangReplacements filtered = filteredReplacements(clangReplacements,
|
|
||||||
utf8Offset,
|
|
||||||
extraOffset,
|
|
||||||
onlyIndention);
|
|
||||||
|
|
||||||
const bool canTryAgain = onlyIndention && typedChar == QChar::Null && !secondTry;
|
|
||||||
if (canTryAgain && filtered.empty()) {
|
|
||||||
return replacements(fileName,
|
|
||||||
originalBuffer,
|
|
||||||
originalOffsetUtf8,
|
|
||||||
originalLengthUtf8,
|
|
||||||
block,
|
|
||||||
typedChar,
|
|
||||||
onlyIndention,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return utf16Replacements(block, originalOffsetUtf8, originalBuffer, filtered);
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyReplacements(const QTextBlock &block, const QtReplacements &replacements)
|
|
||||||
{
|
|
||||||
if (replacements.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
int fullOffsetShift = 0;
|
|
||||||
QTextCursor editCursor(block);
|
|
||||||
for (const QtReplacement &replacement : replacements) {
|
|
||||||
editCursor.beginEditBlock();
|
|
||||||
editCursor.setPosition(replacement.offset + fullOffsetShift);
|
|
||||||
editCursor.movePosition(QTextCursor::NextCharacter,
|
|
||||||
QTextCursor::KeepAnchor,
|
|
||||||
replacement.length);
|
|
||||||
editCursor.removeSelectedText();
|
|
||||||
editCursor.insertText(replacement.text);
|
|
||||||
editCursor.endEditBlock();
|
|
||||||
fullOffsetShift += replacement.text.length() - replacement.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString selectedLines(QTextDocument *doc, const QTextBlock &startBlock, const QTextBlock &endBlock)
|
|
||||||
{
|
|
||||||
QString text = Utils::Text::textAt(
|
|
||||||
QTextCursor(doc),
|
|
||||||
startBlock.position(),
|
|
||||||
std::max(0, endBlock.position() + endBlock.length() - startBlock.position() - 1));
|
|
||||||
while (!text.isEmpty() && text.rbegin()->isSpace())
|
|
||||||
text.chop(1);
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
bool ClangFormatIndenter::isElectricCharacter(const QChar &ch) const
|
|
||||||
{
|
|
||||||
switch (ch.toLatin1()) {
|
|
||||||
case '{':
|
|
||||||
case '}':
|
|
||||||
case ':':
|
|
||||||
case '#':
|
|
||||||
case '<':
|
|
||||||
case '>':
|
|
||||||
case ';':
|
|
||||||
case '(':
|
|
||||||
case ')':
|
|
||||||
case ',':
|
|
||||||
case '.':
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangFormatIndenter::indent(QTextDocument *doc,
|
|
||||||
const QTextCursor &cursor,
|
|
||||||
const QChar &typedChar,
|
|
||||||
const TabSettings &tabSettings,
|
|
||||||
bool /*autoTriggered*/)
|
|
||||||
{
|
|
||||||
if (cursor.hasSelection()) {
|
|
||||||
// Calling currentBlock.next() might be unsafe because we change the document.
|
|
||||||
// Let's operate with block numbers instead.
|
|
||||||
const int startNumber = doc->findBlock(cursor.selectionStart()).blockNumber();
|
|
||||||
const int endNumber = doc->findBlock(cursor.selectionEnd()).blockNumber();
|
|
||||||
for (int currentBlockNumber = startNumber; currentBlockNumber <= endNumber;
|
|
||||||
++currentBlockNumber) {
|
|
||||||
const QTextBlock currentBlock = doc->findBlockByNumber(currentBlockNumber);
|
|
||||||
if (currentBlock.isValid()) {
|
|
||||||
const int blocksAmount = doc->blockCount();
|
|
||||||
indentBlock(doc, currentBlock, typedChar, tabSettings);
|
|
||||||
QTC_CHECK(blocksAmount == doc->blockCount()
|
|
||||||
&& "ClangFormat plugin indentation changed the amount of blocks.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
indentBlock(doc, cursor.block(), typedChar, tabSettings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QtReplacements ClangFormatIndenter::format(QTextDocument *doc,
|
|
||||||
const Utils::FileName &fileName,
|
|
||||||
const QTextCursor &cursor,
|
|
||||||
const TextEditor::TabSettings & /*tabSettings*/)
|
|
||||||
{
|
|
||||||
int utf8Offset;
|
|
||||||
int utf8Length;
|
|
||||||
const QByteArray buffer = doc->toPlainText().toUtf8();
|
|
||||||
QTextBlock block = cursor.block();
|
|
||||||
if (cursor.hasSelection()) {
|
|
||||||
block = doc->findBlock(cursor.selectionStart());
|
|
||||||
const QTextBlock end = doc->findBlock(cursor.selectionEnd());
|
|
||||||
utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
|
||||||
QTC_ASSERT(utf8Offset >= 0, return QtReplacements(););
|
|
||||||
utf8Length = selectedLines(doc, block, end).toUtf8().size();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const QTextBlock block = cursor.block();
|
|
||||||
utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
|
||||||
QTC_ASSERT(utf8Offset >= 0, return QtReplacements(););
|
|
||||||
utf8Length = block.text().toUtf8().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QtReplacements toReplace
|
|
||||||
= replacements(fileName, buffer, utf8Offset, utf8Length, block, QChar::Null, false);
|
|
||||||
applyReplacements(block, toReplace);
|
|
||||||
|
|
||||||
return toReplace;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangFormatIndenter::reindent(QTextDocument *doc,
|
|
||||||
const QTextCursor &cursor,
|
|
||||||
const TabSettings &tabSettings)
|
|
||||||
{
|
|
||||||
indent(doc, cursor, QChar::Null, tabSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangFormatIndenter::indentBlock(QTextDocument *doc,
|
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
|
||||||
const TabSettings &tabSettings)
|
|
||||||
{
|
|
||||||
Q_UNUSED(tabSettings);
|
|
||||||
|
|
||||||
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
|
|
||||||
if (!editor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const Utils::FileName fileName = editor->textDocument()->filePath();
|
|
||||||
trimFirstNonEmptyBlock(block);
|
|
||||||
trimCurrentBlock(block);
|
|
||||||
const QByteArray buffer = doc->toPlainText().toUtf8();
|
|
||||||
const int utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
|
||||||
QTC_ASSERT(utf8Offset >= 0, return;);
|
|
||||||
|
|
||||||
applyReplacements(block,
|
|
||||||
replacements(fileName, buffer, utf8Offset, 0, block, typedChar));
|
|
||||||
}
|
|
||||||
|
|
||||||
int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &)
|
|
||||||
{
|
|
||||||
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
|
|
||||||
if (!editor)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
const Utils::FileName fileName = editor->textDocument()->filePath();
|
|
||||||
trimFirstNonEmptyBlock(block);
|
|
||||||
trimCurrentBlock(block);
|
|
||||||
const QTextDocument *doc = block.document();
|
|
||||||
const QByteArray buffer = doc->toPlainText().toUtf8();
|
|
||||||
const int utf8Offset = Utils::Text::utf8NthLineOffset(doc, buffer, block.blockNumber() + 1);
|
|
||||||
QTC_ASSERT(utf8Offset >= 0, return 0;);
|
|
||||||
|
|
||||||
const QtReplacements toReplace = replacements(fileName, buffer, utf8Offset, 0, block);
|
|
||||||
|
|
||||||
if (toReplace.empty())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
const QtReplacement &replacement = toReplace.front();
|
|
||||||
int afterLineBreak = replacement.text.lastIndexOf('\n');
|
|
||||||
afterLineBreak = (afterLineBreak < 0) ? 0 : afterLineBreak + 1;
|
|
||||||
return static_cast<int>(replacement.text.size() - afterLineBreak);
|
|
||||||
}
|
|
||||||
|
|
||||||
TabSettings ClangFormatIndenter::tabSettings() const
|
|
||||||
{
|
{
|
||||||
FormatStyle style = currentProjectStyle();
|
FormatStyle style = currentProjectStyle();
|
||||||
TabSettings tabSettings;
|
TabSettings tabSettings;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2018 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of Qt Creator.
|
** This file is part of Qt Creator.
|
||||||
@@ -25,35 +25,20 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include "clangformatbaseindenter.h"
|
||||||
|
|
||||||
|
#include <texteditor/tabsettings.h>
|
||||||
|
|
||||||
namespace ClangFormat {
|
namespace ClangFormat {
|
||||||
|
|
||||||
class ClangFormatIndenter final : public TextEditor::Indenter
|
class ClangFormatIndenter final : public ClangFormatBaseIndenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void indent(QTextDocument *doc,
|
ClangFormatIndenter(QTextDocument *doc);
|
||||||
const QTextCursor &cursor,
|
Utils::optional<TextEditor::TabSettings> tabSettings() const override;
|
||||||
const QChar &typedChar,
|
|
||||||
const TextEditor::TabSettings &tabSettings,
|
|
||||||
bool autoTriggered = true) override;
|
|
||||||
void reindent(QTextDocument *doc,
|
|
||||||
const QTextCursor &cursor,
|
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
|
||||||
TextEditor::Replacements format(QTextDocument *doc,
|
|
||||||
const Utils::FileName &fileName,
|
|
||||||
const QTextCursor &cursor,
|
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
|
||||||
void indentBlock(QTextDocument *doc,
|
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
|
||||||
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
|
||||||
|
|
||||||
bool isElectricCharacter(const QChar &ch) const override;
|
private:
|
||||||
|
clang::format::FormatStyle styleForFile() const override;
|
||||||
bool hasTabSettings() const override { return true; }
|
|
||||||
TextEditor::TabSettings tabSettings() const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ClangFormat
|
} // namespace ClangFormat
|
||||||
|
@@ -84,9 +84,9 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::Indenter *createIndenter() const override
|
TextEditor::Indenter *createIndenter(QTextDocument *doc) const override
|
||||||
{
|
{
|
||||||
return new ClangFormatIndenter();
|
return new ClangFormatIndenter(doc);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <texteditor/icodestylepreferencesfactory.h>
|
#include <texteditor/icodestylepreferencesfactory.h>
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/indenter.h>
|
||||||
|
#include <texteditor/tabsettings.h>
|
||||||
#include <texteditor/texteditorsettings.h>
|
#include <texteditor/texteditorsettings.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -83,7 +84,6 @@ bool FixitsRefactoringFile::apply()
|
|||||||
|
|
||||||
ICodeStylePreferencesFactory *factory = TextEditorSettings::codeStyleFactory(
|
ICodeStylePreferencesFactory *factory = TextEditorSettings::codeStyleFactory(
|
||||||
CppTools::Constants::CPP_SETTINGS_ID);
|
CppTools::Constants::CPP_SETTINGS_ID);
|
||||||
std::unique_ptr<TextEditor::Indenter> indenter(factory->createIndenter());
|
|
||||||
|
|
||||||
const TextEditor::TabSettings tabSettings
|
const TextEditor::TabSettings tabSettings
|
||||||
= CppTools::CppCodeStyleSettings::currentProjectTabSettings();
|
= CppTools::CppCodeStyleSettings::currentProjectTabSettings();
|
||||||
@@ -103,6 +103,9 @@ bool FixitsRefactoringFile::apply()
|
|||||||
|
|
||||||
// Apply
|
// Apply
|
||||||
QTextDocument *doc = document(op.fileName);
|
QTextDocument *doc = document(op.fileName);
|
||||||
|
std::unique_ptr<TextEditor::Indenter> indenter(factory->createIndenter(doc));
|
||||||
|
indenter->setFileName(Utils::FileName::fromString(op.fileName));
|
||||||
|
|
||||||
QTextCursor cursor(doc);
|
QTextCursor cursor(doc);
|
||||||
cursor.setPosition(op.pos);
|
cursor.setPosition(op.pos);
|
||||||
cursor.setPosition(op.pos + op.length, QTextCursor::KeepAnchor);
|
cursor.setPosition(op.pos + op.length, QTextCursor::KeepAnchor);
|
||||||
@@ -139,10 +142,7 @@ void FixitsRefactoringFile::tryToFormat(TextEditor::Indenter &indenter,
|
|||||||
cursor.movePosition(QTextCursor::Right,
|
cursor.movePosition(QTextCursor::Right,
|
||||||
QTextCursor::KeepAnchor,
|
QTextCursor::KeepAnchor,
|
||||||
op.text.length());
|
op.text.length());
|
||||||
const Replacements replacements = indenter.format(doc,
|
const Replacements replacements = indenter.format(cursor, tabSettings);
|
||||||
Utils::FileName::fromString(op.fileName),
|
|
||||||
cursor,
|
|
||||||
tabSettings);
|
|
||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
|
|
||||||
if (replacements.empty())
|
if (replacements.empty())
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <texteditor/indenter.h>
|
||||||
|
|
||||||
#include <utils/changeset.h>
|
#include <utils/changeset.h>
|
||||||
#include <utils/textfileformat.h>
|
#include <utils/textfileformat.h>
|
||||||
|
|
||||||
@@ -32,13 +34,6 @@
|
|||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
namespace TextEditor {
|
|
||||||
class Indenter;
|
|
||||||
class Replacement;
|
|
||||||
using Replacements = std::vector<Replacement>;
|
|
||||||
class TabSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ClangTools {
|
namespace ClangTools {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
@@ -229,7 +229,7 @@ CMakeEditorFactory::CMakeEditorFactory()
|
|||||||
setEditorCreator([]() { return new CMakeEditor; });
|
setEditorCreator([]() { return new CMakeEditor; });
|
||||||
setEditorWidgetCreator([]() { return new CMakeEditorWidget; });
|
setEditorWidgetCreator([]() { return new CMakeEditorWidget; });
|
||||||
setDocumentCreator(createCMakeDocument);
|
setDocumentCreator(createCMakeDocument);
|
||||||
setIndenterCreator([]() { return new CMakeIndenter; });
|
setIndenterCreator([](QTextDocument *doc) { return new CMakeIndenter(doc); });
|
||||||
setUseGenericHighlighter(true);
|
setUseGenericHighlighter(true);
|
||||||
setCommentDefinition(Utils::CommentDefinition::HashStyle);
|
setCommentDefinition(Utils::CommentDefinition::HashStyle);
|
||||||
setCodeFoldingSupported(true);
|
setCodeFoldingSupported(true);
|
||||||
|
@@ -34,6 +34,10 @@
|
|||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
CMakeIndenter::CMakeIndenter(QTextDocument *doc)
|
||||||
|
: TextEditor::TextIndenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
bool CMakeIndenter::isElectricCharacter(const QChar &ch) const
|
bool CMakeIndenter::isElectricCharacter(const QChar &ch) const
|
||||||
{
|
{
|
||||||
return ch == QLatin1Char('(') || ch == QLatin1Char(')');
|
return ch == QLatin1Char('(') || ch == QLatin1Char(')');
|
||||||
@@ -98,7 +102,8 @@ static int paranthesesLevel(const QString &line)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CMakeIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings)
|
int CMakeIndenter::indentFor(const QTextBlock &block,
|
||||||
|
const TextEditor::TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
QTextBlock previousBlock = block.previous();
|
QTextBlock previousBlock = block.previous();
|
||||||
// find the next previous block that is non-empty (contains non-whitespace characters)
|
// find the next previous block that is non-empty (contains non-whitespace characters)
|
||||||
|
@@ -27,17 +27,19 @@
|
|||||||
|
|
||||||
#include "cmake_global.h"
|
#include "cmake_global.h"
|
||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/textindenter.h>
|
||||||
|
|
||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class CMAKE_EXPORT CMakeIndenter : public TextEditor::Indenter
|
class CMAKE_EXPORT CMakeIndenter : public TextEditor::TextIndenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit CMakeIndenter(QTextDocument *doc);
|
||||||
bool isElectricCharacter(const QChar &ch) const override;
|
bool isElectricCharacter(const QChar &ch) const override;
|
||||||
|
|
||||||
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
int indentFor(const QTextBlock &block,
|
||||||
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -42,7 +42,8 @@ CppEditor::CppEditor()
|
|||||||
void CppEditor::decorateEditor(TextEditor::TextEditorWidget *editor)
|
void CppEditor::decorateEditor(TextEditor::TextEditorWidget *editor)
|
||||||
{
|
{
|
||||||
editor->textDocument()->setSyntaxHighlighter(new CppHighlighter);
|
editor->textDocument()->setSyntaxHighlighter(new CppHighlighter);
|
||||||
editor->textDocument()->setIndenter(new CppTools::CppQtStyleIndenter);
|
editor->textDocument()->setIndenter(
|
||||||
|
new CppTools::CppQtStyleIndenter(editor->textDocument()->document()));
|
||||||
editor->setAutoCompleter(new CppAutoCompleter);
|
editor->setAutoCompleter(new CppAutoCompleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -111,7 +111,7 @@ CppEditorDocument::CppEditorDocument()
|
|||||||
|
|
||||||
ICodeStylePreferencesFactory *factory
|
ICodeStylePreferencesFactory *factory
|
||||||
= TextEditorSettings::codeStyleFactory(CppTools::Constants::CPP_SETTINGS_ID);
|
= TextEditorSettings::codeStyleFactory(CppTools::Constants::CPP_SETTINGS_ID);
|
||||||
setIndenter(factory->createIndenter());
|
setIndenter(factory->createIndenter(document()));
|
||||||
|
|
||||||
connect(this, &TextEditor::TextDocument::tabSettingsChanged,
|
connect(this, &TextEditor::TextDocument::tabSettingsChanged,
|
||||||
this, &CppEditorDocument::invalidateFormatterCache);
|
this, &CppEditorDocument::invalidateFormatterCache);
|
||||||
@@ -243,6 +243,7 @@ void CppEditorDocument::onFilePathChanged(const Utils::FileName &oldPath,
|
|||||||
Q_UNUSED(oldPath);
|
Q_UNUSED(oldPath);
|
||||||
|
|
||||||
if (!newPath.isEmpty()) {
|
if (!newPath.isEmpty()) {
|
||||||
|
indenter()->setFileName(newPath);
|
||||||
setMimeType(Utils::mimeTypeForFile(newPath.toFileInfo()).name());
|
setMimeType(Utils::mimeTypeForFile(newPath.toFileInfo()).name());
|
||||||
|
|
||||||
connect(this, &Core::IDocument::contentsChanged,
|
connect(this, &Core::IDocument::contentsChanged,
|
||||||
@@ -443,9 +444,7 @@ CppTools::BaseEditorDocumentProcessor *CppEditorDocument::processor()
|
|||||||
|
|
||||||
TextEditor::TabSettings CppEditorDocument::tabSettings() const
|
TextEditor::TabSettings CppEditorDocument::tabSettings() const
|
||||||
{
|
{
|
||||||
return indenter()->hasTabSettings()
|
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
|
||||||
? indenter()->tabSettings()
|
|
||||||
: TextEditor::TextDocument::tabSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -111,9 +111,9 @@ QWidget *CppCodeStylePreferencesFactory::createEditor(TextEditor::ICodeStylePref
|
|||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::Indenter *CppCodeStylePreferencesFactory::createIndenter() const
|
TextEditor::Indenter *CppCodeStylePreferencesFactory::createIndenter(QTextDocument *doc) const
|
||||||
{
|
{
|
||||||
return new CppQtStyleIndenter();
|
return new CppQtStyleIndenter(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CppCodeStylePreferencesFactory::snippetProviderGroupId() const
|
QString CppCodeStylePreferencesFactory::snippetProviderGroupId() const
|
||||||
|
@@ -41,7 +41,7 @@ public:
|
|||||||
TextEditor::ICodeStylePreferences *createCodeStyle() const override;
|
TextEditor::ICodeStylePreferences *createCodeStyle() const override;
|
||||||
QWidget *createEditor(TextEditor::ICodeStylePreferences *settings,
|
QWidget *createEditor(TextEditor::ICodeStylePreferences *settings,
|
||||||
QWidget *parent) const override;
|
QWidget *parent) const override;
|
||||||
TextEditor::Indenter *createIndenter() const override;
|
TextEditor::Indenter *createIndenter(QTextDocument *doc) const override;
|
||||||
QString snippetProviderGroupId() const override;
|
QString snippetProviderGroupId() const override;
|
||||||
QString previewText() const override;
|
QString previewText() const override;
|
||||||
};
|
};
|
||||||
|
@@ -481,7 +481,7 @@ void CppCodeStylePreferencesWidget::updatePreview()
|
|||||||
QTextCursor tc = preview->textCursor();
|
QTextCursor tc = preview->textCursor();
|
||||||
tc.beginEditBlock();
|
tc.beginEditBlock();
|
||||||
while (block.isValid()) {
|
while (block.isValid()) {
|
||||||
preview->textDocument()->indenter()->indentBlock(doc, block, QChar::Null, ts);
|
preview->textDocument()->indenter()->indentBlock(block, QChar::Null, ts);
|
||||||
|
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
|
@@ -61,7 +61,6 @@
|
|||||||
#include <projectexplorer/projectexplorer.h>
|
#include <projectexplorer/projectexplorer.h>
|
||||||
#include <projectexplorer/projectmacro.h>
|
#include <projectexplorer/projectmacro.h>
|
||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
#include <texteditor/indenter.h>
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
@@ -49,7 +49,6 @@ namespace CPlusPlus { class LookupContext; }
|
|||||||
namespace ProjectExplorer { class Project; }
|
namespace ProjectExplorer { class Project; }
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
class BaseHoverHandler;
|
class BaseHoverHandler;
|
||||||
class Indenter;
|
|
||||||
class TextDocument;
|
class TextDocument;
|
||||||
} // namespace TextEditor
|
} // namespace TextEditor
|
||||||
|
|
||||||
|
@@ -36,7 +36,8 @@
|
|||||||
|
|
||||||
using namespace CppTools;
|
using namespace CppTools;
|
||||||
|
|
||||||
CppQtStyleIndenter::CppQtStyleIndenter()
|
CppQtStyleIndenter::CppQtStyleIndenter(QTextDocument *doc)
|
||||||
|
: TextEditor::TextIndenter(doc)
|
||||||
{
|
{
|
||||||
// Just for safety. setCodeStylePreferences should be called when the editor the
|
// Just for safety. setCodeStylePreferences should be called when the editor the
|
||||||
// indenter belongs to gets initialized.
|
// indenter belongs to gets initialized.
|
||||||
@@ -67,12 +68,9 @@ static bool isElectricInLine(const QChar ch, const QString &text)
|
|||||||
return text.contains(QLatin1String("break"));
|
return text.contains(QLatin1String("break"));
|
||||||
case ':':
|
case ':':
|
||||||
// switch cases and access declarations should be reindented
|
// switch cases and access declarations should be reindented
|
||||||
if (text.contains(QLatin1String("case"))
|
if (text.contains(QLatin1String("case")) || text.contains(QLatin1String("default"))
|
||||||
|| text.contains(QLatin1String("default"))
|
|| text.contains(QLatin1String("public")) || text.contains(QLatin1String("private"))
|
||||||
|| text.contains(QLatin1String("public"))
|
|| text.contains(QLatin1String("protected")) || text.contains(QLatin1String("signals"))
|
||||||
|| text.contains(QLatin1String("private"))
|
|
||||||
|| text.contains(QLatin1String("protected"))
|
|
||||||
|| text.contains(QLatin1String("signals"))
|
|
||||||
|| text.contains(QLatin1String("Q_SIGNALS"))) {
|
|| text.contains(QLatin1String("Q_SIGNALS"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -93,13 +91,10 @@ static bool isElectricInLine(const QChar ch, const QString &text)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppQtStyleIndenter::indentBlock(QTextDocument *doc,
|
void CppQtStyleIndenter::indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings)
|
const TextEditor::TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
Q_UNUSED(doc)
|
|
||||||
|
|
||||||
QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
|
QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
|
||||||
|
|
||||||
codeFormatter.updateStateUntil(block);
|
codeFormatter.updateStateUntil(block);
|
||||||
@@ -124,15 +119,13 @@ void CppQtStyleIndenter::indentBlock(QTextDocument *doc,
|
|||||||
tabSettings.indentLine(block, indent + padding, padding);
|
tabSettings.indentLine(block, indent + padding, padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppQtStyleIndenter::indent(QTextDocument *doc,
|
void CppQtStyleIndenter::indent(const QTextCursor &cursor,
|
||||||
const QTextCursor &cursor,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings,
|
const TextEditor::TabSettings &tabSettings)
|
||||||
bool /*autoTriggered*/)
|
|
||||||
{
|
{
|
||||||
if (cursor.hasSelection()) {
|
if (cursor.hasSelection()) {
|
||||||
QTextBlock block = doc->findBlock(cursor.selectionStart());
|
QTextBlock block = m_doc->findBlock(cursor.selectionStart());
|
||||||
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
|
const QTextBlock end = m_doc->findBlock(cursor.selectionEnd()).next();
|
||||||
|
|
||||||
QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
|
QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
|
||||||
codeFormatter.updateStateUntil(block);
|
codeFormatter.updateStateUntil(block);
|
||||||
@@ -149,7 +142,7 @@ void CppQtStyleIndenter::indent(QTextDocument *doc,
|
|||||||
} while (block.isValid() && block != end);
|
} while (block.isValid() && block != end);
|
||||||
tc.endEditBlock();
|
tc.endEditBlock();
|
||||||
} else {
|
} else {
|
||||||
indentBlock(doc, cursor.block(), typedChar, tabSettings);
|
indentBlock(cursor.block(), typedChar, tabSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,13 +153,14 @@ void CppQtStyleIndenter::setCodeStylePreferences(TextEditor::ICodeStylePreferenc
|
|||||||
m_cppCodeStylePreferences = cppCodeStylePreferences;
|
m_cppCodeStylePreferences = cppCodeStylePreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppQtStyleIndenter::invalidateCache(QTextDocument *doc)
|
void CppQtStyleIndenter::invalidateCache()
|
||||||
{
|
{
|
||||||
QtStyleCodeFormatter formatter;
|
QtStyleCodeFormatter formatter;
|
||||||
formatter.invalidateCache(doc);
|
formatter.invalidateCache(m_doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CppQtStyleIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings)
|
int CppQtStyleIndenter::indentFor(const QTextBlock &block,
|
||||||
|
const TextEditor::TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
|
QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
|
||||||
|
|
||||||
@@ -185,9 +179,8 @@ CppCodeStyleSettings CppQtStyleIndenter::codeStyleSettings() const
|
|||||||
return CppCodeStyleSettings();
|
return CppCodeStyleSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::IndentationForBlock
|
TextEditor::IndentationForBlock CppQtStyleIndenter::indentationForBlocks(
|
||||||
CppQtStyleIndenter::indentationForBlocks(const QVector<QTextBlock> &blocks,
|
const QVector<QTextBlock> &blocks, const TextEditor::TabSettings &tabSettings)
|
||||||
const TextEditor::TabSettings &tabSettings)
|
|
||||||
{
|
{
|
||||||
QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
|
QtStyleCodeFormatter codeFormatter(tabSettings, codeStyleSettings());
|
||||||
|
|
||||||
|
@@ -27,10 +27,9 @@
|
|||||||
|
|
||||||
#include "cpptools_global.h"
|
#include "cpptools_global.h"
|
||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/textindenter.h>
|
||||||
|
|
||||||
namespace TextEditor
|
namespace TextEditor {
|
||||||
{
|
|
||||||
class ICodeStylePreferences;
|
class ICodeStylePreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,32 +37,30 @@ namespace CppTools {
|
|||||||
class CppCodeStyleSettings;
|
class CppCodeStyleSettings;
|
||||||
class CppCodeStylePreferences;
|
class CppCodeStylePreferences;
|
||||||
|
|
||||||
class CPPTOOLS_EXPORT CppQtStyleIndenter : public TextEditor::Indenter
|
class CPPTOOLS_EXPORT CppQtStyleIndenter : public TextEditor::TextIndenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CppQtStyleIndenter();
|
explicit CppQtStyleIndenter(QTextDocument *doc);
|
||||||
~CppQtStyleIndenter() override;
|
~CppQtStyleIndenter() override;
|
||||||
|
|
||||||
bool isElectricCharacter(const QChar &ch) const override;
|
bool isElectricCharacter(const QChar &ch) const override;
|
||||||
void indentBlock(QTextDocument *doc,
|
void indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
|
|
||||||
void indent(QTextDocument *doc,
|
void indent(const QTextCursor &cursor,
|
||||||
const QTextCursor &cursor,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings,
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
bool autoTriggered = true) override;
|
|
||||||
|
|
||||||
void setCodeStylePreferences(TextEditor::ICodeStylePreferences *preferences) override;
|
void setCodeStylePreferences(TextEditor::ICodeStylePreferences *preferences) override;
|
||||||
void invalidateCache(QTextDocument *doc) override;
|
void invalidateCache() override;
|
||||||
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
||||||
TextEditor::IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
TextEditor::IndentationForBlock indentationForBlocks(
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const QVector<QTextBlock> &blocks, const TextEditor::TabSettings &tabSettings) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CppCodeStyleSettings codeStyleSettings() const;
|
CppCodeStyleSettings codeStyleSettings() const;
|
||||||
CppCodeStylePreferences *m_cppCodeStylePreferences = nullptr;
|
CppCodeStylePreferences *m_cppCodeStylePreferences = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // CppTools
|
} // namespace CppTools
|
||||||
|
@@ -56,8 +56,8 @@ public:
|
|||||||
const TextEditor::TabSettings &tabSettings =
|
const TextEditor::TabSettings &tabSettings =
|
||||||
ProjectExplorer::actualTabSettings(fileName, textDocument);
|
ProjectExplorer::actualTabSettings(fileName, textDocument);
|
||||||
|
|
||||||
CppQtStyleIndenter indenter;
|
CppQtStyleIndenter indenter(selection.document());
|
||||||
indenter.indent(selection.document(), selection, QChar::Null, tabSettings);
|
indenter.indent(selection, QChar::Null, tabSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reindentSelection(const QTextCursor &selection,
|
void reindentSelection(const QTextCursor &selection,
|
||||||
@@ -67,8 +67,9 @@ public:
|
|||||||
const TextEditor::TabSettings &tabSettings =
|
const TextEditor::TabSettings &tabSettings =
|
||||||
ProjectExplorer::actualTabSettings(fileName, textDocument);
|
ProjectExplorer::actualTabSettings(fileName, textDocument);
|
||||||
|
|
||||||
CppQtStyleIndenter indenter;
|
CppQtStyleIndenter indenter(selection.document());
|
||||||
indenter.reindent(selection.document(), selection, tabSettings);
|
indenter.reindent(selection,
|
||||||
|
tabSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileChanged(const QString &fileName) override
|
void fileChanged(const QString &fileName) override
|
||||||
|
@@ -1633,7 +1633,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
|
|||||||
while (!cursor.atBlockEnd())
|
while (!cursor.atBlockEnd())
|
||||||
cursor.deleteChar();
|
cursor.deleteChar();
|
||||||
} else {
|
} else {
|
||||||
tew->textDocument()->indenter()->indentBlock(doc, block, typedChar, tabSettings);
|
tew->textDocument()->indenter()->indentBlock(block, typedChar, tabSettings);
|
||||||
}
|
}
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
|
@@ -319,7 +319,7 @@ GlslEditorFactory::GlslEditorFactory()
|
|||||||
|
|
||||||
setDocumentCreator([]() { return new TextDocument(Constants::C_GLSLEDITOR_ID); });
|
setDocumentCreator([]() { return new TextDocument(Constants::C_GLSLEDITOR_ID); });
|
||||||
setEditorWidgetCreator([]() { return new GlslEditorWidget; });
|
setEditorWidgetCreator([]() { return new GlslEditorWidget; });
|
||||||
setIndenterCreator([]() { return new GlslIndenter; });
|
setIndenterCreator([](QTextDocument *doc) { return new GlslIndenter(doc); });
|
||||||
setSyntaxHighlighterCreator([]() { return new GlslHighlighter; });
|
setSyntaxHighlighterCreator([]() { return new GlslHighlighter; });
|
||||||
setCommentDefinition(Utils::CommentDefinition::CppStyle);
|
setCommentDefinition(Utils::CommentDefinition::CppStyle);
|
||||||
setCompletionAssistProvider(new GlslCompletionAssistProvider);
|
setCompletionAssistProvider(new GlslCompletionAssistProvider);
|
||||||
|
@@ -38,25 +38,24 @@
|
|||||||
namespace GlslEditor {
|
namespace GlslEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
GlslIndenter::GlslIndenter(QTextDocument *doc)
|
||||||
|
: TextEditor::TextIndenter(doc)
|
||||||
|
{}
|
||||||
GlslIndenter::~GlslIndenter() = default;
|
GlslIndenter::~GlslIndenter() = default;
|
||||||
|
|
||||||
bool GlslIndenter::isElectricCharacter(const QChar &ch) const
|
bool GlslIndenter::isElectricCharacter(const QChar &ch) const
|
||||||
{
|
{
|
||||||
return ch == QLatin1Char('{')
|
return ch == QLatin1Char('{') || ch == QLatin1Char('}') || ch == QLatin1Char(':')
|
||||||
|| ch == QLatin1Char('}')
|
|
||||||
|| ch == QLatin1Char(':')
|
|
||||||
|| ch == QLatin1Char('#');
|
|| ch == QLatin1Char('#');
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlslIndenter::indentBlock(QTextDocument *doc,
|
void GlslIndenter::indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings)
|
const TextEditor::TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
Q_UNUSED(doc)
|
|
||||||
|
|
||||||
// TODO: do something with it
|
// TODO: do something with it
|
||||||
CppTools::QtStyleCodeFormatter codeFormatter(tabSettings,
|
CppTools::QtStyleCodeFormatter
|
||||||
|
codeFormatter(tabSettings,
|
||||||
CppTools::CppToolsSettings::instance()->cppCodeStyle()->codeStyleSettings());
|
CppTools::CppToolsSettings::instance()->cppCodeStyle()->codeStyleSettings());
|
||||||
|
|
||||||
codeFormatter.updateStateUntil(block);
|
codeFormatter.updateStateUntil(block);
|
||||||
@@ -77,19 +76,19 @@ void GlslIndenter::indentBlock(QTextDocument *doc,
|
|||||||
tabSettings.indentLine(block, indent + padding, padding);
|
tabSettings.indentLine(block, indent + padding, padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlslIndenter::indent(QTextDocument *doc,
|
void GlslIndenter::indent(const QTextCursor &cursor,
|
||||||
const QTextCursor &cursor,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings,
|
const TextEditor::TabSettings &tabSettings)
|
||||||
bool /*autoTriggered*/)
|
|
||||||
{
|
{
|
||||||
if (cursor.hasSelection()) {
|
if (cursor.hasSelection()) {
|
||||||
QTextBlock block = doc->findBlock(cursor.selectionStart());
|
QTextBlock block = m_doc->findBlock(cursor.selectionStart());
|
||||||
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
|
const QTextBlock end = m_doc->findBlock(cursor.selectionEnd()).next();
|
||||||
|
|
||||||
// TODO: do something with it
|
// TODO: do something with it
|
||||||
CppTools::QtStyleCodeFormatter codeFormatter(tabSettings,
|
CppTools::QtStyleCodeFormatter codeFormatter(tabSettings,
|
||||||
CppTools::CppToolsSettings::instance()->cppCodeStyle()->codeStyleSettings());
|
CppTools::CppToolsSettings::instance()
|
||||||
|
->cppCodeStyle()
|
||||||
|
->codeStyleSettings());
|
||||||
codeFormatter.updateStateUntil(block);
|
codeFormatter.updateStateUntil(block);
|
||||||
|
|
||||||
QTextCursor tc = cursor;
|
QTextCursor tc = cursor;
|
||||||
@@ -104,13 +103,14 @@ void GlslIndenter::indent(QTextDocument *doc,
|
|||||||
} while (block.isValid() && block != end);
|
} while (block.isValid() && block != end);
|
||||||
tc.endEditBlock();
|
tc.endEditBlock();
|
||||||
} else {
|
} else {
|
||||||
indentBlock(doc, cursor.block(), typedChar, tabSettings);
|
indentBlock(cursor.block(), typedChar, tabSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GlslIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings)
|
int GlslIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
CppTools::QtStyleCodeFormatter codeFormatter(tabSettings,
|
CppTools::QtStyleCodeFormatter
|
||||||
|
codeFormatter(tabSettings,
|
||||||
CppTools::CppToolsSettings::instance()->cppCodeStyle()->codeStyleSettings());
|
CppTools::CppToolsSettings::instance()->cppCodeStyle()->codeStyleSettings());
|
||||||
|
|
||||||
codeFormatter.updateStateUntil(block);
|
codeFormatter.updateStateUntil(block);
|
||||||
@@ -121,11 +121,11 @@ int GlslIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettin
|
|||||||
return indent;
|
return indent;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::IndentationForBlock
|
TextEditor::IndentationForBlock GlslIndenter::indentationForBlocks(
|
||||||
GlslIndenter::indentationForBlocks(const QVector<QTextBlock> &blocks,
|
const QVector<QTextBlock> &blocks, const TextEditor::TabSettings &tabSettings)
|
||||||
const TextEditor::TabSettings &tabSettings)
|
|
||||||
{
|
{
|
||||||
CppTools::QtStyleCodeFormatter codeFormatter(tabSettings,
|
CppTools::QtStyleCodeFormatter
|
||||||
|
codeFormatter(tabSettings,
|
||||||
CppTools::CppToolsSettings::instance()->cppCodeStyle()->codeStyleSettings());
|
CppTools::CppToolsSettings::instance()->cppCodeStyle()->codeStyleSettings());
|
||||||
|
|
||||||
codeFormatter.updateStateUntil(blocks.last());
|
codeFormatter.updateStateUntil(blocks.last());
|
||||||
|
@@ -25,31 +25,29 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/textindenter.h>
|
||||||
|
|
||||||
namespace GlslEditor {
|
namespace GlslEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class GlslIndenter : public TextEditor::Indenter
|
class GlslIndenter : public TextEditor::TextIndenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit GlslIndenter(QTextDocument *doc);
|
||||||
~GlslIndenter() override;
|
~GlslIndenter() override;
|
||||||
|
|
||||||
bool isElectricCharacter(const QChar &ch) const override;
|
bool isElectricCharacter(const QChar &ch) const override;
|
||||||
void indentBlock(QTextDocument *doc,
|
void indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
|
|
||||||
void indent(QTextDocument *doc,
|
void indent(const QTextCursor &cursor,
|
||||||
const QTextCursor &cursor,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings,
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
bool autoTriggered = true) override;
|
|
||||||
|
|
||||||
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
||||||
TextEditor::IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
TextEditor::IndentationForBlock indentationForBlocks(
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const QVector<QTextBlock> &blocks, const TextEditor::TabSettings &tabSettings) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -60,8 +60,8 @@ NimEditorFactory::NimEditorFactory()
|
|||||||
setDocumentCreator([]() {
|
setDocumentCreator([]() {
|
||||||
return new TextDocument(Constants::C_NIMEDITOR_ID);
|
return new TextDocument(Constants::C_NIMEDITOR_ID);
|
||||||
});
|
});
|
||||||
setIndenterCreator([]() {
|
setIndenterCreator([](QTextDocument *doc) {
|
||||||
return new NimIndenter;
|
return new NimIndenter(doc);
|
||||||
});
|
});
|
||||||
setSyntaxHighlighterCreator([]() {
|
setSyntaxHighlighterCreator([]() {
|
||||||
return new NimHighlighter;
|
return new NimHighlighter;
|
||||||
@@ -80,7 +80,7 @@ Core::IEditor *NimEditorFactory::createEditor()
|
|||||||
void NimEditorFactory::decorateEditor(TextEditorWidget *editor)
|
void NimEditorFactory::decorateEditor(TextEditorWidget *editor)
|
||||||
{
|
{
|
||||||
editor->textDocument()->setSyntaxHighlighter(new NimHighlighter());
|
editor->textDocument()->setSyntaxHighlighter(new NimHighlighter());
|
||||||
editor->textDocument()->setIndenter(new NimIndenter());
|
editor->textDocument()->setIndenter(new NimIndenter(editor->textDocument()->document()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,8 @@
|
|||||||
|
|
||||||
namespace Nim {
|
namespace Nim {
|
||||||
|
|
||||||
NimIndenter::NimIndenter()
|
NimIndenter::NimIndenter(QTextDocument *doc)
|
||||||
|
: TextEditor::TextIndenter(doc)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool NimIndenter::isElectricCharacter(const QChar &ch) const
|
bool NimIndenter::isElectricCharacter(const QChar &ch) const
|
||||||
@@ -45,12 +46,10 @@ bool NimIndenter::isElectricCharacter(const QChar &ch) const
|
|||||||
return NimIndenter::electricCharacters().contains(ch);
|
return NimIndenter::electricCharacters().contains(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NimIndenter::indentBlock(QTextDocument *document,
|
void NimIndenter::indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &settings)
|
const TextEditor::TabSettings &settings)
|
||||||
{
|
{
|
||||||
Q_UNUSED(document);
|
|
||||||
Q_UNUSED(typedChar);
|
Q_UNUSED(typedChar);
|
||||||
|
|
||||||
const QString currentLine = block.text();
|
const QString currentLine = block.text();
|
||||||
|
@@ -25,23 +25,24 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/textindenter.h>
|
||||||
|
|
||||||
namespace TextEditor { class SimpleCodeStylePreferences; }
|
namespace TextEditor {
|
||||||
|
class SimpleCodeStylePreferences;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Nim {
|
namespace Nim {
|
||||||
|
|
||||||
class NimLexer;
|
class NimLexer;
|
||||||
|
|
||||||
class NimIndenter : public TextEditor::Indenter
|
class NimIndenter : public TextEditor::TextIndenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NimIndenter();
|
explicit NimIndenter(QTextDocument *doc);
|
||||||
|
|
||||||
bool isElectricCharacter(const QChar &ch) const override;
|
bool isElectricCharacter(const QChar &ch) const override;
|
||||||
|
|
||||||
void indentBlock(QTextDocument *document,
|
void indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &settings) override;
|
const TextEditor::TabSettings &settings) override;
|
||||||
|
|
||||||
@@ -51,9 +52,11 @@ private:
|
|||||||
bool startsBlock(const QString &line, int state) const;
|
bool startsBlock(const QString &line, int state) const;
|
||||||
bool endsBlock(const QString &line, int state) const;
|
bool endsBlock(const QString &line, int state) const;
|
||||||
|
|
||||||
int calculateIndentationDiff(const QString &previousLine, int previousState, int indentSize) const;
|
int calculateIndentationDiff(const QString &previousLine,
|
||||||
|
int previousState,
|
||||||
|
int indentSize) const;
|
||||||
|
|
||||||
static QString rightTrimmed(const QString &other);
|
static QString rightTrimmed(const QString &other);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace Nim
|
||||||
|
@@ -67,9 +67,9 @@ QWidget *NimCodeStylePreferencesFactory::createEditor(TextEditor::ICodeStylePref
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::Indenter *NimCodeStylePreferencesFactory::createIndenter() const
|
TextEditor::Indenter *NimCodeStylePreferencesFactory::createIndenter(QTextDocument *doc) const
|
||||||
{
|
{
|
||||||
return new NimIndenter();
|
return new NimIndenter(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString NimCodeStylePreferencesFactory::snippetProviderGroupId() const
|
QString NimCodeStylePreferencesFactory::snippetProviderGroupId() const
|
||||||
|
@@ -41,7 +41,7 @@ public:
|
|||||||
TextEditor::ICodeStylePreferences *createCodeStyle() const override;
|
TextEditor::ICodeStylePreferences *createCodeStyle() const override;
|
||||||
QWidget *createEditor(TextEditor::ICodeStylePreferences *settings,
|
QWidget *createEditor(TextEditor::ICodeStylePreferences *settings,
|
||||||
QWidget *parent) const override;
|
QWidget *parent) const override;
|
||||||
TextEditor::Indenter *createIndenter() const override;
|
TextEditor::Indenter *createIndenter(QTextDocument *doc) const override;
|
||||||
QString snippetProviderGroupId() const override;
|
QString snippetProviderGroupId() const override;
|
||||||
QString previewText() const override;
|
QString previewText() const override;
|
||||||
};
|
};
|
||||||
|
@@ -96,8 +96,7 @@ void NimCodeStylePreferencesWidget::updatePreview()
|
|||||||
QTextCursor tc = m_ui->previewTextEdit->textCursor();
|
QTextCursor tc = m_ui->previewTextEdit->textCursor();
|
||||||
tc.beginEditBlock();
|
tc.beginEditBlock();
|
||||||
while (block.isValid()) {
|
while (block.isValid()) {
|
||||||
m_ui->previewTextEdit->textDocument()->indenter()
|
m_ui->previewTextEdit->textDocument()->indenter()->indentBlock(block, QChar::Null, ts);
|
||||||
->indentBlock(doc, block, QChar::Null, ts);
|
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
tc.endEditBlock();
|
tc.endEditBlock();
|
||||||
|
@@ -36,7 +36,6 @@
|
|||||||
#include <coreplugin/dialogs/promptoverwritedialog.h>
|
#include <coreplugin/dialogs/promptoverwritedialog.h>
|
||||||
#include <texteditor/icodestylepreferences.h>
|
#include <texteditor/icodestylepreferences.h>
|
||||||
#include <texteditor/icodestylepreferencesfactory.h>
|
#include <texteditor/icodestylepreferencesfactory.h>
|
||||||
#include <texteditor/indenter.h>
|
|
||||||
#include <texteditor/normalindenter.h>
|
#include <texteditor/normalindenter.h>
|
||||||
#include <texteditor/storagesettings.h>
|
#include <texteditor/storagesettings.h>
|
||||||
#include <texteditor/tabsettings.h>
|
#include <texteditor/tabsettings.h>
|
||||||
@@ -94,18 +93,22 @@ bool JsonWizardGenerator::formatFile(const JsonWizard *wizard, GeneratedFile *fi
|
|||||||
auto baseProject = qobject_cast<Project *>(wizard->property("SelectedProject").value<QObject *>());
|
auto baseProject = qobject_cast<Project *>(wizard->property("SelectedProject").value<QObject *>());
|
||||||
ICodeStylePreferencesFactory *factory = TextEditorSettings::codeStyleFactory(languageId);
|
ICodeStylePreferencesFactory *factory = TextEditorSettings::codeStyleFactory(languageId);
|
||||||
|
|
||||||
Indenter *indenter = nullptr;
|
|
||||||
if (factory)
|
|
||||||
indenter = factory->createIndenter();
|
|
||||||
if (!indenter)
|
|
||||||
indenter = new NormalIndenter();
|
|
||||||
|
|
||||||
ICodeStylePreferences *codeStylePrefs = codeStylePreferences(baseProject, languageId);
|
|
||||||
indenter->setCodeStylePreferences(codeStylePrefs);
|
|
||||||
QTextDocument doc(file->contents());
|
QTextDocument doc(file->contents());
|
||||||
QTextCursor cursor(&doc);
|
QTextCursor cursor(&doc);
|
||||||
|
Indenter *indenter = nullptr;
|
||||||
|
if (factory) {
|
||||||
|
indenter = factory->createIndenter(&doc);
|
||||||
|
indenter->setFileName(Utils::FileName::fromString(file->path()));
|
||||||
|
}
|
||||||
|
if (!indenter)
|
||||||
|
indenter = new NormalIndenter(&doc);
|
||||||
|
ICodeStylePreferences *codeStylePrefs = codeStylePreferences(baseProject, languageId);
|
||||||
|
indenter->setCodeStylePreferences(codeStylePrefs);
|
||||||
|
|
||||||
cursor.select(QTextCursor::Document);
|
cursor.select(QTextCursor::Document);
|
||||||
indenter->indent(&doc, cursor, QChar::Null, codeStylePrefs->currentTabSettings());
|
indenter->indent(cursor,
|
||||||
|
QChar::Null,
|
||||||
|
codeStylePrefs->currentTabSettings());
|
||||||
delete indenter;
|
delete indenter;
|
||||||
if (TextEditorSettings::storageSettings().m_cleanWhitespace) {
|
if (TextEditorSettings::storageSettings().m_cleanWhitespace) {
|
||||||
QTextBlock block = doc.firstBlock();
|
QTextBlock block = doc.firstBlock();
|
||||||
|
@@ -252,18 +252,23 @@ void ProjectFileWizardExtension::applyCodeStyle(GeneratedFile *file) const
|
|||||||
|
|
||||||
ICodeStylePreferencesFactory *factory = TextEditorSettings::codeStyleFactory(languageId);
|
ICodeStylePreferencesFactory *factory = TextEditorSettings::codeStyleFactory(languageId);
|
||||||
|
|
||||||
|
QTextDocument doc(file->contents());
|
||||||
Indenter *indenter = nullptr;
|
Indenter *indenter = nullptr;
|
||||||
if (factory)
|
if (factory) {
|
||||||
indenter = factory->createIndenter();
|
indenter = factory->createIndenter(&doc);
|
||||||
|
indenter->setFileName(Utils::FileName::fromString(file->path()));
|
||||||
|
}
|
||||||
if (!indenter)
|
if (!indenter)
|
||||||
indenter = new NormalIndenter();
|
indenter = new NormalIndenter(&doc);
|
||||||
|
|
||||||
ICodeStylePreferences *codeStylePrefs = codeStylePreferences(baseProject, languageId);
|
ICodeStylePreferences *codeStylePrefs = codeStylePreferences(baseProject, languageId);
|
||||||
indenter->setCodeStylePreferences(codeStylePrefs);
|
indenter->setCodeStylePreferences(codeStylePrefs);
|
||||||
QTextDocument doc(file->contents());
|
|
||||||
QTextCursor cursor(&doc);
|
QTextCursor cursor(&doc);
|
||||||
cursor.select(QTextCursor::Document);
|
cursor.select(QTextCursor::Document);
|
||||||
indenter->indent(&doc, cursor, QChar::Null, codeStylePrefs->currentTabSettings());
|
indenter->indent(cursor,
|
||||||
|
QChar::Null,
|
||||||
|
codeStylePrefs->currentTabSettings());
|
||||||
delete indenter;
|
delete indenter;
|
||||||
if (TextEditorSettings::storageSettings().m_cleanWhitespace) {
|
if (TextEditorSettings::storageSettings().m_cleanWhitespace) {
|
||||||
QTextBlock block = doc.firstBlock();
|
QTextBlock block = doc.firstBlock();
|
||||||
|
@@ -54,7 +54,7 @@ PythonEditorFactory::PythonEditorFactory()
|
|||||||
| TextEditorActionHandler::FollowSymbolUnderCursor);
|
| TextEditorActionHandler::FollowSymbolUnderCursor);
|
||||||
|
|
||||||
setDocumentCreator([] { return new TextDocument(Constants::C_PYTHONEDITOR_ID); });
|
setDocumentCreator([] { return new TextDocument(Constants::C_PYTHONEDITOR_ID); });
|
||||||
setIndenterCreator([] { return new PythonIndenter; });
|
setIndenterCreator([](QTextDocument *doc) { return new PythonIndenter(doc); });
|
||||||
setSyntaxHighlighterCreator([] { return new PythonHighlighter; });
|
setSyntaxHighlighterCreator([] { return new PythonHighlighter; });
|
||||||
setCommentDefinition(Utils::CommentDefinition::HashStyle);
|
setCommentDefinition(Utils::CommentDefinition::HashStyle);
|
||||||
setParenthesesMatchingEnabled(true);
|
setParenthesesMatchingEnabled(true);
|
||||||
|
@@ -50,6 +50,10 @@ static QTextBlock previousNonEmptyBlock(const QTextBlock &block)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PythonIndenter::PythonIndenter(QTextDocument *doc)
|
||||||
|
: TextEditor::TextIndenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Does given character change indentation level?
|
* @brief Does given character change indentation level?
|
||||||
* @param ch Any value
|
* @param ch Any value
|
||||||
|
@@ -25,12 +25,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/textindenter.h>
|
||||||
|
|
||||||
namespace PythonEditor {
|
namespace PythonEditor {
|
||||||
|
|
||||||
class PythonIndenter : public TextEditor::Indenter
|
class PythonIndenter : public TextEditor::TextIndenter
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
explicit PythonIndenter(QTextDocument *doc);
|
||||||
private:
|
private:
|
||||||
bool isElectricCharacter(const QChar &ch) const override;
|
bool isElectricCharacter(const QChar &ch) const override;
|
||||||
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
||||||
|
@@ -61,8 +61,8 @@ void BaseTextEditModifier::indentLines(int startLine, int endLine)
|
|||||||
QTextBlock start = textDocument->findBlockByNumber(i);
|
QTextBlock start = textDocument->findBlockByNumber(i);
|
||||||
|
|
||||||
if (start.isValid()) {
|
if (start.isValid()) {
|
||||||
QmlJSEditor::Internal::Indenter indenter;
|
QmlJSEditor::Internal::Indenter indenter(textDocument);
|
||||||
indenter.indentBlock(textDocument, start, QChar::Null, tabSettings);
|
indenter.indentBlock(start, QChar::Null, tabSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tc.endEditBlock();
|
tc.endEditBlock();
|
||||||
|
@@ -1071,7 +1071,7 @@ QmlJSEditorFactory::QmlJSEditorFactory()
|
|||||||
void QmlJSEditorFactory::decorateEditor(TextEditorWidget *editor)
|
void QmlJSEditorFactory::decorateEditor(TextEditorWidget *editor)
|
||||||
{
|
{
|
||||||
editor->textDocument()->setSyntaxHighlighter(new QmlJSHighlighter);
|
editor->textDocument()->setSyntaxHighlighter(new QmlJSHighlighter);
|
||||||
editor->textDocument()->setIndenter(new Indenter);
|
editor->textDocument()->setIndenter(new Indenter(editor->textDocument()->document()));
|
||||||
editor->setAutoCompleter(new AutoCompleter);
|
editor->setAutoCompleter(new AutoCompleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -653,7 +653,7 @@ QmlJSEditorDocument::QmlJSEditorDocument()
|
|||||||
connect(this, &TextEditor::TextDocument::tabSettingsChanged,
|
connect(this, &TextEditor::TextDocument::tabSettingsChanged,
|
||||||
d, &Internal::QmlJSEditorDocumentPrivate::invalidateFormatterCache);
|
d, &Internal::QmlJSEditorDocumentPrivate::invalidateFormatterCache);
|
||||||
setSyntaxHighlighter(new QmlJSHighlighter(document()));
|
setSyntaxHighlighter(new QmlJSHighlighter(document()));
|
||||||
setIndenter(new Internal::Indenter);
|
setIndenter(new Internal::Indenter(document()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlJSEditorDocument::~QmlJSEditorDocument()
|
QmlJSEditorDocument::~QmlJSEditorDocument()
|
||||||
|
@@ -421,8 +421,8 @@ void QuickToolBar::indentLines(int startLine, int endLine)
|
|||||||
QTextBlock start = m_editorWidget->document()->findBlockByNumber(i);
|
QTextBlock start = m_editorWidget->document()->findBlockByNumber(i);
|
||||||
|
|
||||||
if (start.isValid()) {
|
if (start.isValid()) {
|
||||||
QmlJSEditor::Internal::Indenter indenterMy;
|
QmlJSEditor::Internal::Indenter indenterMy(m_editorWidget->document());
|
||||||
indenterMy.indentBlock(m_editorWidget->document(), start, QChar::Null, tabSettings);
|
indenterMy.indentBlock(start, QChar::Null, tabSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,9 +80,9 @@ QWidget *QmlJSCodeStylePreferencesFactory::createEditor(TextEditor::ICodeStylePr
|
|||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::Indenter *QmlJSCodeStylePreferencesFactory::createIndenter() const
|
TextEditor::Indenter *QmlJSCodeStylePreferencesFactory::createIndenter(QTextDocument *doc) const
|
||||||
{
|
{
|
||||||
return new QmlJSEditor::Internal::Indenter();
|
return new QmlJSEditor::Internal::Indenter(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QmlJSCodeStylePreferencesFactory::snippetProviderGroupId() const
|
QString QmlJSCodeStylePreferencesFactory::snippetProviderGroupId() const
|
||||||
|
@@ -39,7 +39,7 @@ public:
|
|||||||
TextEditor::ICodeStylePreferences *createCodeStyle() const override;
|
TextEditor::ICodeStylePreferences *createCodeStyle() const override;
|
||||||
QWidget *createEditor(TextEditor::ICodeStylePreferences *settings,
|
QWidget *createEditor(TextEditor::ICodeStylePreferences *settings,
|
||||||
QWidget *parent) const override;
|
QWidget *parent) const override;
|
||||||
TextEditor::Indenter *createIndenter() const override;
|
TextEditor::Indenter *createIndenter(QTextDocument *doc) const override;
|
||||||
QString snippetProviderGroupId() const override;
|
QString snippetProviderGroupId() const override;
|
||||||
QString previewText() const override;
|
QString previewText() const override;
|
||||||
};
|
};
|
||||||
|
@@ -113,8 +113,7 @@ void QmlJSCodeStylePreferencesWidget::updatePreview()
|
|||||||
QTextCursor tc = m_ui->previewTextEdit->textCursor();
|
QTextCursor tc = m_ui->previewTextEdit->textCursor();
|
||||||
tc.beginEditBlock();
|
tc.beginEditBlock();
|
||||||
while (block.isValid()) {
|
while (block.isValid()) {
|
||||||
m_ui->previewTextEdit->textDocument()->indenter()
|
m_ui->previewTextEdit->textDocument()->indenter()->indentBlock(block, QChar::Null, ts);
|
||||||
->indentBlock(doc, block, QChar::Null, ts);
|
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
tc.endEditBlock();
|
tc.endEditBlock();
|
||||||
|
@@ -35,7 +35,9 @@
|
|||||||
using namespace QmlJSEditor;
|
using namespace QmlJSEditor;
|
||||||
using namespace Internal;
|
using namespace Internal;
|
||||||
|
|
||||||
Indenter::Indenter() = default;
|
Indenter::Indenter(QTextDocument *doc)
|
||||||
|
: TextEditor::TextIndenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
Indenter::~Indenter() = default;
|
Indenter::~Indenter() = default;
|
||||||
|
|
||||||
@@ -49,13 +51,10 @@ bool Indenter::isElectricCharacter(const QChar &ch) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Indenter::indentBlock(QTextDocument *doc,
|
void Indenter::indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings)
|
const TextEditor::TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
Q_UNUSED(doc)
|
|
||||||
|
|
||||||
const int depth = indentFor(block, tabSettings);
|
const int depth = indentFor(block, tabSettings);
|
||||||
if (depth == -1)
|
if (depth == -1)
|
||||||
return;
|
return;
|
||||||
@@ -74,29 +73,24 @@ void Indenter::indentBlock(QTextDocument *doc,
|
|||||||
tabSettings.indentLine(block, depth);
|
tabSettings.indentLine(block, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Indenter::invalidateCache(QTextDocument *doc)
|
void Indenter::invalidateCache()
|
||||||
{
|
{
|
||||||
QmlJSTools::CreatorCodeFormatter codeFormatter;
|
QmlJSTools::CreatorCodeFormatter codeFormatter;
|
||||||
codeFormatter.invalidateCache(doc);
|
codeFormatter.invalidateCache(m_doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Indenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings)
|
||||||
int Indenter::indentFor(const QTextBlock &block,
|
|
||||||
const TextEditor::TabSettings &tabSettings)
|
|
||||||
{
|
{
|
||||||
QmlJSTools::CreatorCodeFormatter codeFormatter(tabSettings);
|
QmlJSTools::CreatorCodeFormatter codeFormatter(tabSettings);
|
||||||
codeFormatter.updateStateUntil(block);
|
codeFormatter.updateStateUntil(block);
|
||||||
return codeFormatter.indentFor(block);
|
return codeFormatter.indentFor(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextEditor::IndentationForBlock Indenter::indentationForBlocks(
|
||||||
TextEditor::IndentationForBlock
|
const QVector<QTextBlock> &blocks, const TextEditor::TabSettings &tabSettings)
|
||||||
Indenter::indentationForBlocks(const QVector<QTextBlock> &blocks,
|
|
||||||
const TextEditor::TabSettings &tabSettings)
|
|
||||||
{
|
{
|
||||||
QmlJSTools::CreatorCodeFormatter codeFormatter(tabSettings);
|
QmlJSTools::CreatorCodeFormatter codeFormatter(tabSettings);
|
||||||
|
|
||||||
|
|
||||||
codeFormatter.updateStateUntil(blocks.last());
|
codeFormatter.updateStateUntil(blocks.last());
|
||||||
|
|
||||||
TextEditor::IndentationForBlock ret;
|
TextEditor::IndentationForBlock ret;
|
||||||
|
@@ -27,27 +27,26 @@
|
|||||||
|
|
||||||
#include "qmljstools_global.h"
|
#include "qmljstools_global.h"
|
||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/textindenter.h>
|
||||||
|
|
||||||
namespace QmlJSEditor {
|
namespace QmlJSEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class QMLJSTOOLS_EXPORT Indenter : public TextEditor::Indenter
|
class QMLJSTOOLS_EXPORT Indenter : public TextEditor::TextIndenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Indenter();
|
explicit Indenter(QTextDocument *doc);
|
||||||
~Indenter() override;
|
~Indenter() override;
|
||||||
|
|
||||||
bool isElectricCharacter(const QChar &ch) const override;
|
bool isElectricCharacter(const QChar &ch) const override;
|
||||||
void indentBlock(QTextDocument *doc,
|
void indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const TextEditor::TabSettings &tabSettings) override;
|
||||||
void invalidateCache(QTextDocument *doc) override;
|
void invalidateCache() override;
|
||||||
|
|
||||||
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings) override;
|
||||||
TextEditor::IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
TextEditor::IndentationForBlock indentationForBlocks(
|
||||||
const TextEditor::TabSettings &tabSettings) override;
|
const QVector<QTextBlock> &blocks, const TextEditor::TabSettings &tabSettings) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Internal
|
} // Internal
|
||||||
|
@@ -77,8 +77,8 @@ public:
|
|||||||
const TextEditor::TabSettings &tabSettings =
|
const TextEditor::TabSettings &tabSettings =
|
||||||
ProjectExplorer::actualTabSettings(fileName, textDocument);
|
ProjectExplorer::actualTabSettings(fileName, textDocument);
|
||||||
|
|
||||||
QmlJSEditor::Internal::Indenter indenter;
|
QmlJSEditor::Internal::Indenter indenter(selection.document());
|
||||||
indenter.reindent(selection.document(), selection, tabSettings);
|
indenter.reindent(selection, tabSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileChanged(const QString &fileName) override
|
void fileChanged(const QString &fileName) override
|
||||||
|
@@ -83,14 +83,15 @@ void CodeStyleEditor::updatePreview()
|
|||||||
{
|
{
|
||||||
QTextDocument *doc = m_preview->document();
|
QTextDocument *doc = m_preview->document();
|
||||||
|
|
||||||
m_preview->textDocument()->indenter()->invalidateCache(doc);
|
m_preview->textDocument()->indenter()->invalidateCache();
|
||||||
|
|
||||||
QTextBlock block = doc->firstBlock();
|
QTextBlock block = doc->firstBlock();
|
||||||
QTextCursor tc = m_preview->textCursor();
|
QTextCursor tc = m_preview->textCursor();
|
||||||
tc.beginEditBlock();
|
tc.beginEditBlock();
|
||||||
while (block.isValid()) {
|
while (block.isValid()) {
|
||||||
m_preview->textDocument()->indenter()
|
m_preview->textDocument()->indenter()->indentBlock(block,
|
||||||
->indentBlock(doc, block, QChar::Null, m_codeStyle->currentTabSettings());
|
QChar::Null,
|
||||||
|
m_codeStyle->currentTabSettings());
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
tc.endEditBlock();
|
tc.endEditBlock();
|
||||||
|
@@ -27,13 +27,14 @@
|
|||||||
|
|
||||||
#include "texteditor_global.h"
|
#include "texteditor_global.h"
|
||||||
|
|
||||||
|
#include "indenter.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
namespace Core { class Id; }
|
namespace Core { class Id; }
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
|
|
||||||
class ICodeStylePreferences;
|
class ICodeStylePreferences;
|
||||||
class Indenter;
|
|
||||||
class SnippetProvider;
|
class SnippetProvider;
|
||||||
|
|
||||||
class TEXTEDITOR_EXPORT ICodeStylePreferencesFactory : public QObject
|
class TEXTEDITOR_EXPORT ICodeStylePreferencesFactory : public QObject
|
||||||
@@ -48,7 +49,7 @@ public:
|
|||||||
virtual QString displayName() = 0;
|
virtual QString displayName() = 0;
|
||||||
virtual ICodeStylePreferences *createCodeStyle() const = 0;
|
virtual ICodeStylePreferences *createCodeStyle() const = 0;
|
||||||
virtual QWidget *createEditor(ICodeStylePreferences *preferences, QWidget *parent) const = 0;
|
virtual QWidget *createEditor(ICodeStylePreferences *preferences, QWidget *parent) const = 0;
|
||||||
virtual TextEditor::Indenter *createIndenter() const = 0;
|
virtual TextEditor::Indenter *createIndenter(QTextDocument *doc) const = 0;
|
||||||
virtual QString snippetProviderGroupId() const = 0;
|
virtual QString snippetProviderGroupId() const = 0;
|
||||||
virtual QString previewText() const = 0;
|
virtual QString previewText() const = 0;
|
||||||
};
|
};
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of Qt Creator.
|
** This file is part of Qt Creator.
|
||||||
@@ -25,21 +25,16 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "texteditor_global.h"
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/optional.h>
|
||||||
#include "tabsettings.h"
|
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QTextBlock>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
namespace Utils {
|
||||||
class QTextDocument;
|
class FileName;
|
||||||
class QTextCursor;
|
}
|
||||||
class QTextBlock;
|
|
||||||
class QChar;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace Utils { class FileName; }
|
|
||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
|
|
||||||
@@ -48,7 +43,7 @@ class TabSettings;
|
|||||||
|
|
||||||
using IndentationForBlock = QMap<int, int>;
|
using IndentationForBlock = QMap<int, int>;
|
||||||
|
|
||||||
class TEXTEDITOR_EXPORT Replacement
|
class Replacement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Replacement(int offset, int length, const QString &text)
|
Replacement(int offset, int length, const QString &text)
|
||||||
@@ -63,50 +58,57 @@ public:
|
|||||||
|
|
||||||
using Replacements = std::vector<Replacement>;
|
using Replacements = std::vector<Replacement>;
|
||||||
|
|
||||||
class TEXTEDITOR_EXPORT Indenter
|
class Indenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Indenter();
|
explicit Indenter(QTextDocument *doc)
|
||||||
virtual ~Indenter();
|
: m_doc(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void setFileName(const Utils::FileName &fileName) { m_fileName = fileName; }
|
||||||
|
|
||||||
|
virtual ~Indenter() = default;
|
||||||
|
|
||||||
// Returns true if key triggers an indent.
|
// Returns true if key triggers an indent.
|
||||||
virtual bool isElectricCharacter(const QChar &ch) const;
|
virtual bool isElectricCharacter(const QChar & /*ch*/) const { return false; }
|
||||||
|
|
||||||
// Indent a text block based on previous line. Default does nothing
|
virtual void setCodeStylePreferences(ICodeStylePreferences * /*preferences*/) {}
|
||||||
virtual void indentBlock(QTextDocument *doc,
|
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
|
||||||
const TabSettings &tabSettings);
|
|
||||||
|
|
||||||
// Indent at cursor. Calls indentBlock for selection or current line.
|
virtual void invalidateCache() {}
|
||||||
virtual void indent(QTextDocument *doc,
|
|
||||||
const QTextCursor &cursor,
|
|
||||||
const QChar &typedChar,
|
|
||||||
const TabSettings &tabSettings,
|
|
||||||
bool autoTriggered = true);
|
|
||||||
|
|
||||||
// By default just calls indent with default settings.
|
virtual int indentFor(const QTextBlock & /*block*/, const TabSettings & /*tabSettings*/)
|
||||||
virtual Replacements format(QTextDocument *doc,
|
{
|
||||||
const Utils::FileName &fileName,
|
return -1;
|
||||||
const QTextCursor &cursor,
|
}
|
||||||
const TabSettings &tabSettings);
|
|
||||||
|
|
||||||
// Reindent at cursor. Selection will be adjusted according to the indentation
|
|
||||||
// change of the first block.
|
|
||||||
virtual void reindent(QTextDocument *doc, const QTextCursor &cursor, const TabSettings &tabSettings);
|
|
||||||
|
|
||||||
virtual void setCodeStylePreferences(ICodeStylePreferences *preferences);
|
|
||||||
|
|
||||||
virtual void invalidateCache(QTextDocument *doc);
|
|
||||||
|
|
||||||
virtual int indentFor(const QTextBlock &block, const TextEditor::TabSettings &tabSettings);
|
|
||||||
|
|
||||||
// Expects a list of blocks in order of occurrence in the document.
|
// Expects a list of blocks in order of occurrence in the document.
|
||||||
virtual IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
virtual IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
||||||
const TextEditor::TabSettings &tabSettings);
|
const TabSettings & /*tabSettings*/)
|
||||||
|
= 0;
|
||||||
|
virtual Utils::optional<TabSettings> tabSettings() const = 0;
|
||||||
|
|
||||||
virtual bool hasTabSettings() const { return false; }
|
// Indent a text block based on previous line. Default does nothing
|
||||||
virtual TabSettings tabSettings() const { return TabSettings(); }
|
virtual void indentBlock(const QTextBlock &block,
|
||||||
|
const QChar &typedChar,
|
||||||
|
const TabSettings &tabSettings)
|
||||||
|
= 0;
|
||||||
|
|
||||||
|
// Indent at cursor. Calls indentBlock for selection or current line.
|
||||||
|
virtual void indent(const QTextCursor &cursor,
|
||||||
|
const QChar &typedChar,
|
||||||
|
const TabSettings &tabSettings)
|
||||||
|
= 0;
|
||||||
|
|
||||||
|
// By default just calls indent with default settings.
|
||||||
|
virtual Replacements format(const QTextCursor &cursor, const TabSettings &tabSettings) = 0;
|
||||||
|
|
||||||
|
// Reindent at cursor. Selection will be adjusted according to the indentation
|
||||||
|
// change of the first block.
|
||||||
|
virtual void reindent(const QTextCursor &cursor, const TabSettings &tabSettings) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QTextDocument *m_doc;
|
||||||
|
Utils::FileName m_fileName;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace TextEditor
|
} // namespace TextEditor
|
||||||
|
@@ -50,6 +50,10 @@
|
|||||||
|
|
||||||
using namespace TextEditor;
|
using namespace TextEditor;
|
||||||
|
|
||||||
|
NormalIndenter::NormalIndenter(QTextDocument *doc)
|
||||||
|
: TextIndenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
int NormalIndenter::indentFor(const QTextBlock &block, const TabSettings &tabSettings)
|
int NormalIndenter::indentFor(const QTextBlock &block, const TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
Q_UNUSED(tabSettings);
|
Q_UNUSED(tabSettings);
|
||||||
|
@@ -25,14 +25,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "indenter.h"
|
#include "textindenter.h"
|
||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
|
|
||||||
class TEXTEDITOR_EXPORT NormalIndenter : public Indenter
|
class TEXTEDITOR_EXPORT NormalIndenter : public TextIndenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NormalIndenter() = default;
|
explicit NormalIndenter(QTextDocument *doc);
|
||||||
~NormalIndenter() override = default;
|
~NormalIndenter() override = default;
|
||||||
|
|
||||||
int indentFor(const QTextBlock &block, const TabSettings &tabSettings) override;
|
int indentFor(const QTextBlock &block, const TabSettings &tabSettings) override;
|
||||||
|
@@ -65,7 +65,7 @@ PlainTextEditorFactory::PlainTextEditorFactory()
|
|||||||
|
|
||||||
setDocumentCreator([]() { return new TextDocument(Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); });
|
setDocumentCreator([]() { return new TextDocument(Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); });
|
||||||
setEditorWidgetCreator([]() { return new PlainTextEditorWidget; });
|
setEditorWidgetCreator([]() { return new PlainTextEditorWidget; });
|
||||||
setIndenterCreator([]() { return new NormalIndenter; });
|
setIndenterCreator([](QTextDocument *doc) { return new NormalIndenter(doc); });
|
||||||
setUseGenericHighlighter(true);
|
setUseGenericHighlighter(true);
|
||||||
|
|
||||||
setEditorActionHandlers(TextEditorActionHandler::Format |
|
setEditorActionHandlers(TextEditorActionHandler::Format |
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#include "extraencodingsettings.h"
|
#include "extraencodingsettings.h"
|
||||||
#include "fontsettings.h"
|
#include "fontsettings.h"
|
||||||
#include "indenter.h"
|
#include "textindenter.h"
|
||||||
#include "storagesettings.h"
|
#include "storagesettings.h"
|
||||||
#include "syntaxhighlighter.h"
|
#include "syntaxhighlighter.h"
|
||||||
#include "tabsettings.h"
|
#include "tabsettings.h"
|
||||||
@@ -78,7 +78,7 @@ class TextDocumentPrivate
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TextDocumentPrivate()
|
TextDocumentPrivate()
|
||||||
: m_indenter(new Indenter)
|
: m_indenter(new TextIndenter(&m_document))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,19 +416,19 @@ void TextDocument::setExtraEncodingSettings(const ExtraEncodingSettings &extraEn
|
|||||||
d->m_extraEncodingSettings = extraEncodingSettings;
|
d->m_extraEncodingSettings = extraEncodingSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextDocument::autoIndent(const QTextCursor &cursor, QChar typedChar, bool autoTriggered)
|
void TextDocument::autoIndent(const QTextCursor &cursor, QChar typedChar)
|
||||||
{
|
{
|
||||||
d->m_indenter->indent(&d->m_document, cursor, typedChar, tabSettings(), autoTriggered);
|
d->m_indenter->indent(cursor, typedChar, tabSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextDocument::autoReindent(const QTextCursor &cursor)
|
void TextDocument::autoReindent(const QTextCursor &cursor)
|
||||||
{
|
{
|
||||||
d->m_indenter->reindent(&d->m_document, cursor, tabSettings());
|
d->m_indenter->reindent(cursor, tabSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextDocument::autoFormat(const QTextCursor &cursor)
|
void TextDocument::autoFormat(const QTextCursor &cursor)
|
||||||
{
|
{
|
||||||
d->m_indenter->format(&d->m_document, filePath(), cursor, tabSettings());
|
d->m_indenter->format(cursor, tabSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column,
|
QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column,
|
||||||
@@ -824,8 +824,8 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, b
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const TabSettings currentTabSettings = tabSettings();
|
const TabSettings currentTabSettings = tabSettings();
|
||||||
const IndentationForBlock &indentations =
|
const IndentationForBlock &indentations
|
||||||
d->m_indenter->indentationForBlocks(blocks, currentTabSettings);
|
= d->m_indenter->indentationForBlocks(blocks, currentTabSettings);
|
||||||
|
|
||||||
foreach (block, blocks) {
|
foreach (block, blocks) {
|
||||||
QString blockText = block.text();
|
QString blockText = block.text();
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "texteditor_global.h"
|
#include "texteditor_global.h"
|
||||||
|
#include "indenter.h"
|
||||||
|
|
||||||
#include <coreplugin/id.h>
|
#include <coreplugin/id.h>
|
||||||
#include <coreplugin/textdocument.h>
|
#include <coreplugin/textdocument.h>
|
||||||
@@ -48,7 +49,6 @@ namespace TextEditor {
|
|||||||
class CompletionAssistProvider;
|
class CompletionAssistProvider;
|
||||||
class ExtraEncodingSettings;
|
class ExtraEncodingSettings;
|
||||||
class FontSettings;
|
class FontSettings;
|
||||||
class Indenter;
|
|
||||||
class IAssistProvider;
|
class IAssistProvider;
|
||||||
class StorageSettings;
|
class StorageSettings;
|
||||||
class SyntaxHighlighter;
|
class SyntaxHighlighter;
|
||||||
@@ -87,8 +87,7 @@ public:
|
|||||||
|
|
||||||
void setIndenter(Indenter *indenter);
|
void setIndenter(Indenter *indenter);
|
||||||
Indenter *indenter() const;
|
Indenter *indenter() const;
|
||||||
void autoIndent(const QTextCursor &cursor, QChar typedChar = QChar::Null,
|
void autoIndent(const QTextCursor &cursor, QChar typedChar = QChar::Null);
|
||||||
bool autoTriggered = true);
|
|
||||||
void autoReindent(const QTextCursor &cursor);
|
void autoReindent(const QTextCursor &cursor);
|
||||||
void autoFormat(const QTextCursor &cursor);
|
void autoFormat(const QTextCursor &cursor);
|
||||||
QTextCursor indent(const QTextCursor &cursor, bool blockSelection = false, int column = 0,
|
QTextCursor indent(const QTextCursor &cursor, bool blockSelection = false, int column = 0,
|
||||||
|
@@ -8738,7 +8738,7 @@ IEditor *TextEditorFactory::createEditor()
|
|||||||
TextDocumentPtr doc(d->m_documentCreator());
|
TextDocumentPtr doc(d->m_documentCreator());
|
||||||
|
|
||||||
if (d->m_indenterCreator)
|
if (d->m_indenterCreator)
|
||||||
doc->setIndenter(d->m_indenterCreator());
|
doc->setIndenter(d->m_indenterCreator(doc->document()));
|
||||||
|
|
||||||
if (d->m_syntaxHighlighterCreator)
|
if (d->m_syntaxHighlighterCreator)
|
||||||
doc->setSyntaxHighlighter(d->m_syntaxHighlighterCreator());
|
doc->setSyntaxHighlighter(d->m_syntaxHighlighterCreator());
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "texteditor_global.h"
|
#include "texteditor_global.h"
|
||||||
#include "blockrange.h"
|
#include "blockrange.h"
|
||||||
|
#include "indenter.h"
|
||||||
#include "codeassist/assistenums.h"
|
#include "codeassist/assistenums.h"
|
||||||
|
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
@@ -85,7 +86,6 @@ class CompletionSettings;
|
|||||||
class DisplaySettings;
|
class DisplaySettings;
|
||||||
class ExtraEncodingSettings;
|
class ExtraEncodingSettings;
|
||||||
class FontSettings;
|
class FontSettings;
|
||||||
class Indenter;
|
|
||||||
class MarginSettings;
|
class MarginSettings;
|
||||||
class StorageSettings;
|
class StorageSettings;
|
||||||
class TypingSettings;
|
class TypingSettings;
|
||||||
@@ -635,7 +635,7 @@ public:
|
|||||||
using DocumentCreator = std::function<TextDocument *()>;
|
using DocumentCreator = std::function<TextDocument *()>;
|
||||||
using EditorWidgetCreator = std::function<TextEditorWidget *()>;
|
using EditorWidgetCreator = std::function<TextEditorWidget *()>;
|
||||||
using SyntaxHighLighterCreator = std::function<SyntaxHighlighter *()>;
|
using SyntaxHighLighterCreator = std::function<SyntaxHighlighter *()>;
|
||||||
using IndenterCreator = std::function<Indenter *()>;
|
using IndenterCreator = std::function<Indenter *(QTextDocument *)>;
|
||||||
using AutoCompleterCreator = std::function<AutoCompleter *()>;
|
using AutoCompleterCreator = std::function<AutoCompleter *()>;
|
||||||
|
|
||||||
void setDocumentCreator(const DocumentCreator &creator);
|
void setDocumentCreator(const DocumentCreator &creator);
|
||||||
|
@@ -31,7 +31,7 @@ SOURCES += texteditorplugin.cpp \
|
|||||||
textdocumentlayout.cpp \
|
textdocumentlayout.cpp \
|
||||||
completionsettings.cpp \
|
completionsettings.cpp \
|
||||||
normalindenter.cpp \
|
normalindenter.cpp \
|
||||||
indenter.cpp \
|
textindenter.cpp \
|
||||||
quickfix.cpp \
|
quickfix.cpp \
|
||||||
syntaxhighlighter.cpp \
|
syntaxhighlighter.cpp \
|
||||||
highlighterutils.cpp \
|
highlighterutils.cpp \
|
||||||
@@ -135,7 +135,7 @@ HEADERS += texteditorplugin.h \
|
|||||||
textdocumentlayout.h \
|
textdocumentlayout.h \
|
||||||
completionsettings.h \
|
completionsettings.h \
|
||||||
normalindenter.h \
|
normalindenter.h \
|
||||||
indenter.h \
|
textindenter.h \
|
||||||
quickfix.h \
|
quickfix.h \
|
||||||
syntaxhighlighter.h \
|
syntaxhighlighter.h \
|
||||||
highlighterutils.h \
|
highlighterutils.h \
|
||||||
@@ -218,7 +218,8 @@ HEADERS += texteditorplugin.h \
|
|||||||
commentssettings.h \
|
commentssettings.h \
|
||||||
textstyles.h \
|
textstyles.h \
|
||||||
formattexteditor.h \
|
formattexteditor.h \
|
||||||
command.h
|
command.h \
|
||||||
|
indenter.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
displaysettingspage.ui \
|
displaysettingspage.ui \
|
||||||
|
@@ -88,7 +88,6 @@ Project {
|
|||||||
"icodestylepreferences.h",
|
"icodestylepreferences.h",
|
||||||
"icodestylepreferencesfactory.cpp",
|
"icodestylepreferencesfactory.cpp",
|
||||||
"icodestylepreferencesfactory.h",
|
"icodestylepreferencesfactory.h",
|
||||||
"indenter.cpp",
|
|
||||||
"indenter.h",
|
"indenter.h",
|
||||||
"ioutlinewidget.h",
|
"ioutlinewidget.h",
|
||||||
"linenumberfilter.cpp",
|
"linenumberfilter.cpp",
|
||||||
@@ -143,6 +142,8 @@ Project {
|
|||||||
"texteditorplugin.h",
|
"texteditorplugin.h",
|
||||||
"texteditorsettings.cpp",
|
"texteditorsettings.cpp",
|
||||||
"texteditorsettings.h",
|
"texteditorsettings.h",
|
||||||
|
"textindenter.cpp",
|
||||||
|
"textindenter.h",
|
||||||
"textmark.cpp",
|
"textmark.cpp",
|
||||||
"textmark.h",
|
"textmark.h",
|
||||||
"textstyles.h",
|
"textstyles.h",
|
||||||
|
@@ -23,30 +23,32 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "indenter.h"
|
#include "textindenter.h"
|
||||||
#include "tabsettings.h"
|
|
||||||
#include "textdocumentlayout.h"
|
|
||||||
|
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
|
|
||||||
using namespace TextEditor;
|
using namespace TextEditor;
|
||||||
|
|
||||||
Indenter::Indenter() = default;
|
TextIndenter::TextIndenter(QTextDocument *doc)
|
||||||
|
: Indenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
Indenter::~Indenter() = default;
|
TextIndenter::~TextIndenter() = default;
|
||||||
|
|
||||||
bool Indenter::isElectricCharacter(const QChar &) const
|
IndentationForBlock TextIndenter::indentationForBlocks(const QVector<QTextBlock> &blocks,
|
||||||
|
const TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
return false;
|
IndentationForBlock ret;
|
||||||
|
for (QTextBlock block : blocks)
|
||||||
|
ret.insert(block.blockNumber(), indentFor(block, tabSettings));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Indenter::indentBlock(QTextDocument *doc,
|
void TextIndenter::indentBlock(const QTextBlock &block,
|
||||||
const QTextBlock &block,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TabSettings &tabSettings)
|
const TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
Q_UNUSED(doc);
|
|
||||||
Q_UNUSED(typedChar);
|
Q_UNUSED(typedChar);
|
||||||
const int indent = indentFor(block, tabSettings);
|
const int indent = indentFor(block, tabSettings);
|
||||||
if (indent < 0)
|
if (indent < 0)
|
||||||
@@ -54,41 +56,39 @@ void Indenter::indentBlock(QTextDocument *doc,
|
|||||||
tabSettings.indentLine(block, indent);
|
tabSettings.indentLine(block, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Indenter::indent(QTextDocument *doc,
|
void TextIndenter::indent(const QTextCursor &cursor,
|
||||||
const QTextCursor &cursor,
|
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TabSettings &tabSettings,
|
const TabSettings &tabSettings)
|
||||||
bool /*autoTriggered*/)
|
|
||||||
{
|
{
|
||||||
if (cursor.hasSelection()) {
|
if (cursor.hasSelection()) {
|
||||||
QTextBlock block = doc->findBlock(cursor.selectionStart());
|
QTextBlock block = m_doc->findBlock(cursor.selectionStart());
|
||||||
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
|
const QTextBlock end = m_doc->findBlock(cursor.selectionEnd()).next();
|
||||||
do {
|
do {
|
||||||
indentBlock(doc, block, typedChar, tabSettings);
|
indentBlock(block, typedChar, tabSettings);
|
||||||
block = block.next();
|
block = block.next();
|
||||||
} while (block.isValid() && block != end);
|
} while (block.isValid() && block != end);
|
||||||
} else {
|
} else {
|
||||||
indentBlock(doc, cursor.block(), typedChar, tabSettings);
|
indentBlock(cursor.block(), typedChar, tabSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Indenter::reindent(QTextDocument *doc, const QTextCursor &cursor, const TabSettings &tabSettings)
|
void TextIndenter::reindent(const QTextCursor &cursor, const TabSettings &tabSettings)
|
||||||
{
|
{
|
||||||
if (cursor.hasSelection()) {
|
if (cursor.hasSelection()) {
|
||||||
QTextBlock block = doc->findBlock(cursor.selectionStart());
|
QTextBlock block = m_doc->findBlock(cursor.selectionStart());
|
||||||
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
|
const QTextBlock end = m_doc->findBlock(cursor.selectionEnd()).next();
|
||||||
|
|
||||||
// skip empty blocks
|
// skip empty blocks
|
||||||
while (block.isValid() && block != end) {
|
while (block.isValid() && block != end) {
|
||||||
QString bt = block.text();
|
QString bt = block.text();
|
||||||
if (tabSettings.firstNonSpace(bt) < bt.size())
|
if (tabSettings.firstNonSpace(bt) < bt.size())
|
||||||
break;
|
break;
|
||||||
indentBlock(doc, block, QChar::Null, tabSettings);
|
indentBlock(block, QChar::Null, tabSettings);
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
int previousIndentation = tabSettings.indentationColumn(block.text());
|
int previousIndentation = tabSettings.indentationColumn(block.text());
|
||||||
indentBlock(doc, block, QChar::Null, tabSettings);
|
indentBlock(block, QChar::Null, tabSettings);
|
||||||
int currentIndentation = tabSettings.indentationColumn(block.text());
|
int currentIndentation = tabSettings.indentationColumn(block.text());
|
||||||
int delta = currentIndentation - previousIndentation;
|
int delta = currentIndentation - previousIndentation;
|
||||||
|
|
||||||
@@ -98,40 +98,17 @@ void Indenter::reindent(QTextDocument *doc, const QTextCursor &cursor, const Tab
|
|||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
indentBlock(doc, cursor.block(), QChar::Null, tabSettings);
|
indentBlock(cursor.block(), QChar::Null, tabSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Replacements Indenter::format(QTextDocument *doc,
|
Replacements TextIndenter::format(const QTextCursor &cursor, const TabSettings &tabSettings)
|
||||||
const Utils::FileName & /*fileName*/,
|
|
||||||
const QTextCursor &cursor,
|
|
||||||
const TabSettings &tabSettings)
|
|
||||||
{
|
{
|
||||||
indent(doc, cursor, QChar::Null, tabSettings);
|
indent(cursor, QChar::Null, tabSettings);
|
||||||
return Replacements();
|
return Replacements();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Indenter::setCodeStylePreferences(ICodeStylePreferences *)
|
Utils::optional<TabSettings> TextIndenter::tabSettings() const
|
||||||
{
|
{
|
||||||
|
return Utils::optional<TabSettings>();
|
||||||
}
|
|
||||||
|
|
||||||
void Indenter::invalidateCache(QTextDocument *)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int Indenter::indentFor(const QTextBlock &block, const TabSettings &tabSettings)
|
|
||||||
{
|
|
||||||
Q_UNUSED(block)
|
|
||||||
Q_UNUSED(tabSettings)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
IndentationForBlock Indenter::indentationForBlocks(const QVector<QTextBlock> &blocks,
|
|
||||||
const TabSettings &tabSettings)
|
|
||||||
{
|
|
||||||
IndentationForBlock ret;
|
|
||||||
foreach (QTextBlock block, blocks)
|
|
||||||
ret.insert(block.blockNumber(), indentFor(block, tabSettings));
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
63
src/plugins/texteditor/textindenter.h
Normal file
63
src/plugins/texteditor/textindenter.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "texteditor_global.h"
|
||||||
|
|
||||||
|
#include "indenter.h"
|
||||||
|
#include "tabsettings.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QTextDocument;
|
||||||
|
class QTextCursor;
|
||||||
|
class QChar;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace TextEditor {
|
||||||
|
|
||||||
|
class TEXTEDITOR_EXPORT TextIndenter : public Indenter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit TextIndenter(QTextDocument *doc);
|
||||||
|
~TextIndenter() override;
|
||||||
|
|
||||||
|
IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
||||||
|
const TabSettings &tabSettings) override;
|
||||||
|
void indentBlock(const QTextBlock &block,
|
||||||
|
const QChar &typedChar,
|
||||||
|
const TabSettings &tabSettings) override;
|
||||||
|
|
||||||
|
void indent(const QTextCursor &cursor,
|
||||||
|
const QChar &typedChar,
|
||||||
|
const TabSettings &tabSettings) override;
|
||||||
|
|
||||||
|
Replacements format(const QTextCursor &cursor, const TabSettings &tabSettings) override;
|
||||||
|
|
||||||
|
void reindent(const QTextCursor &cursor, const TabSettings &tabSettings) override;
|
||||||
|
Utils::optional<TabSettings> tabSettings() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace TextEditor
|
@@ -153,11 +153,20 @@ LLVM_VERSION = $$extractVersion($$output)
|
|||||||
!isEmpty(LLVM_VERSION) {
|
!isEmpty(LLVM_VERSION) {
|
||||||
versionIsAtLeast($$LLVM_VERSION, 7, 0, 0): {
|
versionIsAtLeast($$LLVM_VERSION, 7, 0, 0): {
|
||||||
CLANGFORMAT_LIBS=-lclangFormat -lclangToolingInclusions -lclangToolingCore -lclangRewrite -lclangLex -lclangBasic
|
CLANGFORMAT_LIBS=-lclangFormat -lclangToolingInclusions -lclangToolingCore -lclangRewrite -lclangLex -lclangBasic
|
||||||
win32:CLANGFORMAT_LIBS += -lversion
|
ALL_CLANG_LIBS=-lclangFormat -lclangToolingInclusions -lclangTooling -lclangToolingCore \
|
||||||
|
-lclangRewrite -lclangIndex -lclangFrontend -lclangParse -lclangSerialization \
|
||||||
|
-lclangSema -lclangEdit -lclangAnalysis -lclangDriver -lclangDynamicASTMatchers \
|
||||||
|
-lclangASTMatchers -lclangAST -lclangLex -lclangBasic
|
||||||
} else:versionIsAtLeast($$LLVM_VERSION, 6, 0, 0): {
|
} else:versionIsAtLeast($$LLVM_VERSION, 6, 0, 0): {
|
||||||
CLANGFORMAT_LIBS=-lclangFormat -lclangToolingCore -lclangRewrite -lclangLex -lclangBasic
|
CLANGFORMAT_LIBS=-lclangFormat -lclangToolingCore -lclangRewrite -lclangLex -lclangBasic
|
||||||
win32:CLANGFORMAT_LIBS += -lversion
|
ALL_CLANG_LIBS=-lclangFormat -lclangTooling -lclangToolingCore \
|
||||||
|
-lclangRewrite -lclangIndex -lclangFrontend -lclangParse -lclangSerialization \
|
||||||
|
-lclangSema -lclangEdit -lclangAnalysis -lclangDriver -lclangDynamicASTMatchers \
|
||||||
|
-lclangASTMatchers -lclangAST -lclangLex -lclangBasic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
win32:CLANGFORMAT_LIBS += -lversion
|
||||||
|
win32:ALL_CLANG_LIBS += -lversion
|
||||||
}
|
}
|
||||||
|
|
||||||
isEmpty(LLVM_VERSION) {
|
isEmpty(LLVM_VERSION) {
|
||||||
@@ -223,6 +232,7 @@ isEmpty(LLVM_VERSION) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CLANGFORMAT_LIBS = -L$${LLVM_LIBDIR} $$CLANGFORMAT_LIBS $$LLVM_STATIC_LIBS
|
CLANGFORMAT_LIBS = -L$${LLVM_LIBDIR} $$CLANGFORMAT_LIBS $$LLVM_STATIC_LIBS
|
||||||
|
ALL_CLANG_LIBS = -L$${LLVM_LIBDIR} $$ALL_CLANG_LIBS $$CLANG_LIB $$LLVM_STATIC_LIBS
|
||||||
|
|
||||||
contains(QMAKE_DEFAULT_INCDIRS, $$LLVM_INCLUDEPATH): LLVM_INCLUDEPATH =
|
contains(QMAKE_DEFAULT_INCDIRS, $$LLVM_INCLUDEPATH): LLVM_INCLUDEPATH =
|
||||||
|
|
||||||
|
@@ -9,8 +9,6 @@ include(../../../src/shared/clang/clang_defines.pri)
|
|||||||
DEFINES += CLANG_UNIT_TESTS
|
DEFINES += CLANG_UNIT_TESTS
|
||||||
INCLUDEPATH += $$LLVM_INCLUDEPATH
|
INCLUDEPATH += $$LLVM_INCLUDEPATH
|
||||||
win32 {
|
win32 {
|
||||||
LIBS += -lVersion
|
|
||||||
|
|
||||||
# set run path for clang.dll dependency
|
# set run path for clang.dll dependency
|
||||||
bin_path = $$LLVM_BINDIR
|
bin_path = $$LLVM_BINDIR
|
||||||
bin_path ~= s,/,\\,g
|
bin_path ~= s,/,\\,g
|
||||||
@@ -18,7 +16,8 @@ include(../../../src/shared/clang/clang_defines.pri)
|
|||||||
check.commands = cd . & set PATH=$$bin_path;%PATH%& cmd /c
|
check.commands = cd . & set PATH=$$bin_path;%PATH%& cmd /c
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBS += $$LIBTOOLING_LIBS $$LIBCLANG_LIBS
|
LIBS += $$ALL_CLANG_LIBS
|
||||||
|
|
||||||
!contains(QMAKE_DEFAULT_LIBDIRS, $$LLVM_LIBDIR): QMAKE_RPATHDIR += $$LLVM_LIBDIR
|
!contains(QMAKE_DEFAULT_LIBDIRS, $$LLVM_LIBDIR): QMAKE_RPATHDIR += $$LLVM_LIBDIR
|
||||||
|
|
||||||
LLVM_CXXFLAGS ~= s,-g\d?,
|
LLVM_CXXFLAGS ~= s,-g\d?,
|
||||||
|
106
tests/unit/unittest/clangformat-test.cpp
Normal file
106
tests/unit/unittest/clangformat-test.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "googletest.h"
|
||||||
|
|
||||||
|
#include <clangformat/clangformatbaseindenter.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
namespace TextEditor {
|
||||||
|
class TabSettings
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ClangFormatIndenter : public ClangFormat::ClangFormatBaseIndenter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClangFormatIndenter(QTextDocument *doc)
|
||||||
|
: ClangFormat::ClangFormatBaseIndenter(doc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Utils::optional<TextEditor::TabSettings> tabSettings() const override
|
||||||
|
{
|
||||||
|
return Utils::optional<TextEditor::TabSettings>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClangFormat : public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void SetUp() final
|
||||||
|
{
|
||||||
|
indenter.setFileName(Utils::FileName::fromString(TESTDATA_DIR"/test.cpp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertLines(const std::vector<QString> &lines)
|
||||||
|
{
|
||||||
|
cursor.setPosition(0);
|
||||||
|
for (size_t lineNumber = 1; lineNumber <= lines.size(); ++lineNumber) {
|
||||||
|
if (lineNumber > 1)
|
||||||
|
cursor.insertBlock();
|
||||||
|
|
||||||
|
cursor.insertText(lines[lineNumber - 1]);
|
||||||
|
}
|
||||||
|
cursor.setPosition(0);
|
||||||
|
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<QString> documentLines()
|
||||||
|
{
|
||||||
|
std::vector<QString> result;
|
||||||
|
const int lines = doc.blockCount();
|
||||||
|
result.reserve(static_cast<size_t>(lines));
|
||||||
|
for (int line = 0; line < lines; ++line)
|
||||||
|
result.push_back(doc.findBlockByNumber(line).text());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextDocument doc;
|
||||||
|
ClangFormatIndenter indenter{&doc};
|
||||||
|
QTextCursor cursor{&doc};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(ClangFormat, SimpleIndent)
|
||||||
|
{
|
||||||
|
insertLines({"int main()",
|
||||||
|
"{",
|
||||||
|
"int a;",
|
||||||
|
"}"});
|
||||||
|
|
||||||
|
indenter.indent(cursor, QChar::Null, TextEditor::TabSettings());
|
||||||
|
|
||||||
|
ASSERT_THAT(documentLines(), ElementsAre("int main()",
|
||||||
|
"{",
|
||||||
|
" int a;",
|
||||||
|
"}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -19,6 +19,7 @@ include(cplusplus.pri)
|
|||||||
include($$PWD/../../../src/shared/clang/clang_defines.pri)
|
include($$PWD/../../../src/shared/clang/clang_defines.pri)
|
||||||
include($$PWD/../../../src/tools/clangbackend/source/clangbackendclangipc-source.pri)
|
include($$PWD/../../../src/tools/clangbackend/source/clangbackendclangipc-source.pri)
|
||||||
include($$PWD/../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri)
|
include($$PWD/../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri)
|
||||||
|
include($$PWD/../../../src/plugins/clangformat/clangformat-source.pri)
|
||||||
} else {
|
} else {
|
||||||
DEFINES += CLANG_VERSION=\\\"6.0.0\\\"
|
DEFINES += CLANG_VERSION=\\\"6.0.0\\\"
|
||||||
DEFINES += "\"CLANG_RESOURCE_DIR=\\\"/usr/include\\\"\""
|
DEFINES += "\"CLANG_RESOURCE_DIR=\\\"/usr/include\\\"\""
|
||||||
|
102
tests/unit/unittest/data/.clang-format
Normal file
102
tests/unit/unittest/data/.clang-format
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: DontAlign
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: true
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
SplitEmptyNamespace: false
|
||||||
|
BreakBeforeBinaryOperators: All
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 100
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- forever # avoids { wrapped to next line
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^<Q.*'
|
||||||
|
Priority: 200
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
# Do not add QT_BEGIN_NAMESPACE/QT_END_NAMESPACE as this will indent lines in between.
|
||||||
|
MacroBlockBegin: ""
|
||||||
|
MacroBlockEnd: ""
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 150
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 300
|
||||||
|
PenaltyBreakComment: 500
|
||||||
|
PenaltyBreakFirstLessLess: 400
|
||||||
|
PenaltyBreakString: 600
|
||||||
|
PenaltyExcessCharacter: 50
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 300
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: true
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
@@ -194,6 +194,10 @@ SOURCES += \
|
|||||||
builddependencycollector-test.cpp
|
builddependencycollector-test.cpp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
!isEmpty(CLANGFORMAT_LIBS) {
|
||||||
|
SOURCES += clangformat-test.cpp
|
||||||
|
}
|
||||||
|
|
||||||
exists($$GOOGLEBENCHMARK_DIR) {
|
exists($$GOOGLEBENCHMARK_DIR) {
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
smallstring-benchmark.cpp
|
smallstring-benchmark.cpp
|
||||||
|
Reference in New Issue
Block a user