Clang: Use clang-format for indentation

This is the new experimental plugin based on LibFormat.

It replaces the default indenter for CppEditorDocument
and applies clang-format after the CR or the set of 'electric'
characters.

Uses the global .clang-format kept in QtC settings or
the one for current project. Both can be configured.

For indentation some style modifications and code manipulations
are done to prevent line shrinking when it's not expected.

Manual indentation uses unmodified style from .clang-format file.

Change-Id: I6279b805e418e1804b553efa615f5c843f395a58
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-08-29 15:58:13 +02:00
parent b95b675e41
commit ca84a51f86
35 changed files with 1294 additions and 87 deletions

1
.gitignore vendored
View File

@@ -29,7 +29,6 @@
.DS_Store .DS_Store
/.qmake.cache /.qmake.cache
/.qmake.stash /.qmake.stash
/.clang-format
Makefile* Makefile*
Thumbs.db Thumbs.db
core core

View File

@@ -1,6 +1,6 @@
# .clang-format for Qt Creator # .clang-format for Qt Creator
Alongside this file you find an EXPERIMENTAL .clang-format configuration file In you Qt Creator root there is an EXPERIMENTAL .clang-format configuration file
for the Qt Creator code base. for the Qt Creator code base.
The current configuration is useful, but not fully in accordance with the The current configuration is useful, but not fully in accordance with the
@@ -26,26 +26,12 @@ For more information about clang-format, see
## Set up Qt Creator for use with clang-format ## Set up Qt Creator for use with clang-format
### Install the configuration file
For a given source file to format, clang-format it will read the configuration
from .clang-format in the closest parent directory for the file to format.
Hence symlink/copy .clang-format from this directory to e.g. Qt Creator's top
level directory:
For Linux/macOS:
$ cd $QTC_SOURCE
$ ln -s dist/clangformat/.clang-format
For Windows:
$ cd $QTC_SOURCE
$ copy dist\clangformat\.clang-format # Do not forget to keep this updated
### Configure Qt Creator ### Configure Qt Creator
0. Enable experimental ClangFormat plugin to get C++ indentation based on it.
Or use an alternative way:
1. Enable the Beautifier plugin and restart to load it. 1. Enable the Beautifier plugin and restart to load it.
2. Configure the plugin: 2. Configure the plugin:

View File

@@ -0,0 +1,20 @@
{
\"Name\" : \"ClangFormat\",
\"Version\" : \"$$QTCREATOR_VERSION\",
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
\"Experimental\" : true,
\"Vendor\" : \"The Qt Company Ltd\",
\"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
\"License\" : [ \"Commercial Usage\",
\"\",
\"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\",
\"\",
\"GNU General Public License Usage\",
\"\",
\"Alternatively, this plugin 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 plugin. 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.\"
],
\"Category\" : \"C++\",
\"Description\" : \"clang-format indentation plugin.\",
\"Url\" : \"http://www.qt.io\",
$$dependencyList
}

View File

@@ -0,0 +1,28 @@
include(../../qtcreatorplugin.pri)
include(../../shared/clang/clang_installation.pri)
include(../../shared/clang/clang_defines.pri)
requires(!isEmpty(LLVM_VERSION))
win32 {
LLVM_BUILDMODE = $$system($$llvm_config --build-mode, lines)
CONFIG(debug, debug|release):requires(equals(LLVM_BUILDMODE, "Debug"))
}
LIBS += $$CLANGFORMAT_LIBS
INCLUDEPATH += $$LLVM_INCLUDEPATH
SOURCES = \
clangformatconfigwidget.cpp \
clangformatindenter.cpp \
clangformatplugin.cpp
HEADERS = \
clangformatconfigwidget.h \
clangformatindenter.h \
clangformatplugin.h \
clangformatconstants.h
FORMS += \
clangformatconfigwidget.ui

View File

@@ -0,0 +1,36 @@
import qbs
import qbs.FileInfo
QtcPlugin {
name: "ClangFormat"
Depends { name: "Core" }
Depends { name: "TextEditor" }
Depends { name: "CppTools" }
Depends { name: "ExtensionSystem" }
Depends { name: "Utils" }
Depends { name: "libclang"; required: false }
Depends { name: "clang_defines" }
Depends { name: "Qt.widgets" }
condition: libclang.present
&& (!qbs.targetOS.contains("windows") || libclang.llvmBuildModeMatches)
cpp.defines: base.concat("CLANGPCHMANAGER_LIB")
cpp.includePaths: base.concat(libclang.llvmIncludeDir)
cpp.libraryPaths: base.concat(libclang.llvmLibDir)
cpp.dynamicLibraries: base.concat(libclang.llvmLibs)
cpp.rpaths: base.concat(libclang.llvmLibDir)
files: [
"clangformatconfigwidget.cpp",
"clangformatconfigwidget.h",
"clangformatindenter.cpp",
"clangformatindenter.h",
"clangformatplugin.cpp",
"clangformatplugin.h",
"clangformatconstants.h",
]
}

View File

@@ -0,0 +1,7 @@
QTC_PLUGIN_NAME = ClangFormat
QTC_LIB_DEPENDS += \
extensionsystem \
utils
QTC_PLUGIN_DEPENDS += \
cpptools \
texteditor

View File

@@ -0,0 +1,205 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "clangformatconfigwidget.h"
#include "ui_clangformatconfigwidget.h"
#include <clang/Format/Format.h>
#include <coreplugin/icore.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <QFile>
#include <sstream>
using namespace ProjectExplorer;
namespace ClangFormat {
namespace Internal {
static void createGlobalClangFormatFileIfNeeded(const QString &settingsDir)
{
const QString fileName = settingsDir + "/.clang-format";
if (QFile::exists(fileName))
return;
QFile file(fileName);
if (!file.open(QFile::WriteOnly))
return;
const clang::format::FormatStyle defaultStyle = clang::format::getLLVMStyle();
const std::string configuration = clang::format::configurationAsText(defaultStyle);
file.write(configuration.c_str());
file.close();
}
static void readTable(QTableWidget *table, std::istringstream &stream)
{
table->horizontalHeader()->hide();
table->verticalHeader()->hide();
table->setColumnCount(2);
table->setRowCount(0);
std::string line;
while (std::getline(stream, line)) {
if (line == "---" || line == "...")
continue;
const size_t firstLetter = line.find_first_not_of(' ');
if (firstLetter == std::string::npos || line.at(firstLetter) == '#')
continue;
// Increase indent where it already exists.
if (firstLetter > 0 && firstLetter < 5)
line = " " + line;
table->insertRow(table->rowCount());
const size_t colonPos = line.find_first_of(':');
auto *keyItem = new QTableWidgetItem;
auto *valueItem = new QTableWidgetItem;
keyItem->setFlags(keyItem->flags() & ~Qt::ItemFlags(Qt::ItemIsEditable));
table->setItem(table->rowCount() - 1, 0, keyItem);
table->setItem(table->rowCount() - 1, 1, valueItem);
if (colonPos == std::string::npos) {
keyItem->setText(QString::fromStdString(line));
valueItem->setFlags(valueItem->flags() & ~Qt::ItemFlags(Qt::ItemIsEditable));
continue;
}
keyItem->setText(QString::fromStdString(line.substr(0, colonPos)));
const size_t optionValueStart = line.find_first_not_of(' ', colonPos + 1);
if (optionValueStart == std::string::npos)
valueItem->setFlags(valueItem->flags() & ~Qt::ItemFlags(Qt::ItemIsEditable));
else
valueItem->setText(QString::fromStdString(line.substr(optionValueStart)));
}
table->resizeColumnToContents(0);
table->resizeColumnToContents(1);
}
static QByteArray tableToYAML(QTableWidget *table)
{
QByteArray text;
text += "---\n";
for (int i = 0; i < table->rowCount(); ++i) {
auto *keyItem = table->item(i, 0);
auto *valueItem = table->item(i, 1);
QByteArray itemText = keyItem->text().toUtf8();
// Change the indent back to 2 spaces
itemText.replace(" ", " ");
if (!valueItem->text().isEmpty() || !itemText.trimmed().startsWith('-'))
itemText += ": ";
itemText += valueItem->text().toUtf8() + '\n';
text += itemText;
}
text += "...\n";
return text;
}
ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *project,
QWidget *parent)
: QWidget(parent)
, m_ui(new Ui::ClangFormatConfigWidget)
, m_project(project)
{
m_ui->setupUi(this);
std::string testFilePath;
if (m_project && !m_project->projectDirectory().appendPath(".clang-format").exists()) {
m_ui->projectHasClangFormat->setText("No .clang-format file for the project");
m_ui->clangFormatOptionsTable->hide();
m_ui->applyButton->hide();
return;
}
if (m_project) {
testFilePath = m_project->projectDirectory().appendPath("t.cpp").toString().toStdString();
connect(m_ui->applyButton, &QPushButton::clicked, this, &ClangFormatConfigWidget::apply);
} else {
const QString settingsDir = Core::ICore::userResourcePath();
createGlobalClangFormatFileIfNeeded(settingsDir);
testFilePath = settingsDir.toStdString() + "/t.cpp";
m_ui->applyButton->hide();
}
llvm::Expected<clang::format::FormatStyle> formatStyle =
clang::format::getStyle("file", testFilePath, "LLVM", "");
if (!formatStyle)
return;
const std::string configText = clang::format::configurationAsText(*formatStyle);
std::istringstream stream(configText);
readTable(m_ui->clangFormatOptionsTable, stream);
if (m_project) {
m_ui->projectHasClangFormat->hide();
return;
}
const Project *currentProject = SessionManager::startupProject();
if (!currentProject || !currentProject->projectDirectory().appendPath(".clang-format").exists())
m_ui->projectHasClangFormat->hide();
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
this, [this](ProjectExplorer::Project *project) {
if (project && project->projectDirectory().appendPath(".clang-format").exists())
m_ui->projectHasClangFormat->show();
else
m_ui->projectHasClangFormat->hide();
});
}
ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
void ClangFormatConfigWidget::apply()
{
const QByteArray text = tableToYAML(m_ui->clangFormatOptionsTable);
QString filePath;
if (m_project)
filePath = m_project->projectDirectory().appendPath(".clang-format").toString();
else
filePath = Core::ICore::userResourcePath() + "/.clang-format";
QFile file(filePath);
if (!file.open(QFile::WriteOnly))
return;
file.write(text);
file.close();
}
} // namespace Internal
} // namespace ClangFormat

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** Copyright (C) 2018 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 <QWidget>
#include <memory>
namespace ProjectExplorer { class Project; }
namespace ClangFormat {
namespace Internal {
namespace Ui {
class ClangFormatConfigWidget;
}
class ClangFormatConfigWidget : public QWidget
{
Q_OBJECT
public:
explicit ClangFormatConfigWidget(ProjectExplorer::Project *project = nullptr,
QWidget *parent = nullptr);
~ClangFormatConfigWidget();
void apply();
private:
ProjectExplorer::Project *m_project;
std::unique_ptr<Ui::ClangFormatConfigWidget> m_ui;
};
} // namespace Internal
} // namespace ClangFormat

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ClangFormat::Internal::ClangFormatConfigWidget</class>
<widget class="QWidget" name="ClangFormat::Internal::ClangFormatConfigWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>489</width>
<height>305</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>8</number>
</property>
<property name="topMargin">
<number>8</number>
</property>
<property name="rightMargin">
<number>8</number>
</property>
<property name="bottomMargin">
<number>8</number>
</property>
<item>
<widget class="QLabel" name="projectHasClangFormat">
<property name="text">
<string> Current project has its own .clang-format file and can be configured in Projects -&gt; ClangFormat.</string>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="clangFormatOptionsTable"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="applyButton">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,26 @@
/****************************************************************************
**
** Copyright (C) 2018 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

View File

@@ -0,0 +1,498 @@
/****************************************************************************
**
** Copyright (C) 2018 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 "clangformatindenter.h"
#include <clang/Format/Format.h>
#include <clang/Tooling/Core/Replacement.h>
#include <coreplugin/icore.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <utils/hostosinfo.h>
#include <QDir>
#include <QFileInfo>
#include <QTextBlock>
using namespace clang;
using namespace format;
using namespace llvm;
using namespace tooling;
using namespace ProjectExplorer;
using namespace TextEditor;
namespace ClangFormat {
namespace Internal {
namespace {
void adjustFormatStyleForLineBreak(format::FormatStyle &style,
int length,
int prevBlockSize,
bool prevBlockEndsWithPunctuation)
{
if (length > 0)
style.ColumnLimit = prevBlockSize;
style.AlwaysBreakBeforeMultilineStrings = true;
style.AlwaysBreakTemplateDeclarations = true;
style.AllowAllParametersOfDeclarationOnNextLine = true;
style.AllowShortBlocksOnASingleLine = true;
style.AllowShortCaseLabelsOnASingleLine = true;
style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
style.AllowShortIfStatementsOnASingleLine = true;
style.AllowShortLoopsOnASingleLine = true;
if (prevBlockEndsWithPunctuation) {
style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
style.BreakBeforeTernaryOperators = false;
style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;
} else {
style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
style.BreakBeforeTernaryOperators = true;
style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
}
}
Replacements filteredReplacements(const Replacements &replacements,
unsigned int offset,
unsigned int lengthForFilter,
int extraOffsetToAdd,
int prevBlockLength)
{
Replacements filtered;
for (const Replacement &replacement : replacements) {
unsigned int replacementOffset = replacement.getOffset();
if (replacementOffset > offset + lengthForFilter)
break;
if (offset > prevBlockLength && replacementOffset < offset - prevBlockLength)
continue;
if (lengthForFilter == 0 && replacement.getReplacementText().find('\n') == std::string::npos
&& filtered.empty()) {
continue;
}
if (replacementOffset + 1 >= offset)
replacementOffset += extraOffsetToAdd;
Error error = filtered.add(Replacement(replacement.getFilePath(),
replacementOffset,
replacement.getLength(),
replacement.getReplacementText()));
// Throws if error is not checked.
if (error)
break;
}
return filtered;
}
std::string assumedFilePath()
{
const Project *project = SessionManager::startupProject();
if (project && project->projectDirectory().appendPath(".clang-format").exists())
return project->projectDirectory().appendPath("test.cpp").toString().toStdString();
return QString(Core::ICore::userResourcePath() + "/test.cpp").toStdString();
}
FormatStyle formatStyle()
{
Expected<FormatStyle> style = format::getStyle("file", assumedFilePath(), "none", "");
if (style)
return *style;
return FormatStyle();
}
Replacements replacements(const std::string &buffer,
unsigned int offset,
unsigned int length,
bool blockFormatting = false,
const QChar &typedChar = QChar::Null,
int extraOffsetToAdd = 0,
int prevBlockLength = 1,
bool prevBlockEndsWithPunctuation = false)
{
FormatStyle style = formatStyle();
if (blockFormatting && typedChar == QChar::Null)
adjustFormatStyleForLineBreak(style, length, prevBlockLength, prevBlockEndsWithPunctuation);
std::vector<Range> ranges{{offset, length}};
FormattingAttemptStatus status;
Replacements replacements = reformat(style, buffer, ranges, assumedFilePath(), &status);
if (!status.FormatComplete)
Replacements();
unsigned int lengthForFilter = 0;
if (!blockFormatting)
lengthForFilter = length;
return filteredReplacements(replacements,
offset,
lengthForFilter,
extraOffsetToAdd,
prevBlockLength);
}
void applyReplacements(QTextDocument *doc,
const std::string &stdStrBuffer,
const tooling::Replacements &replacements,
int totalShift)
{
if (replacements.empty())
return;
QTextCursor editCursor(doc);
int fullOffsetDiff = 0;
for (const Replacement &replacement : replacements) {
const int utf16Offset
= QString::fromStdString(stdStrBuffer.substr(0, replacement.getOffset())).length()
+ totalShift + fullOffsetDiff;
const int utf16Length = QString::fromStdString(stdStrBuffer.substr(replacement.getOffset(),
replacement.getLength()))
.length();
const QString replacementText = QString::fromStdString(replacement.getReplacementText());
editCursor.beginEditBlock();
editCursor.setPosition(utf16Offset);
editCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, utf16Length);
editCursor.removeSelectedText();
editCursor.insertText(replacementText);
editCursor.endEditBlock();
fullOffsetDiff += replacementText.length() - utf16Length;
}
}
// Returns offset shift.
int modifyToIndentEmptyLines(QString &buffer, int &offset, int &length, const QTextBlock &block)
{
//This extra text works for the most cases.
QString extraText("a;");
const QString blockText = block.text().trimmed();
// Search for previous character
QTextBlock prevBlock = block.previous();
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
prevBlock = prevBlock.previous();
if (prevBlock.text().endsWith(','))
extraText = "int a,";
const bool closingParenBlock = blockText.startsWith(')');
if (closingParenBlock) {
if (prevBlock.text().endsWith(','))
extraText = "int a";
else
extraText = "&& a";
}
if (length == 0 || closingParenBlock) {
length += extraText.length();
buffer.insert(offset, extraText);
}
if (blockText.startsWith('}')) {
buffer.insert(offset - 1, extraText);
offset += extraText.size();
return extraText.size();
}
return 0;
}
// Returns first non-empty block (searches from current block backwards).
QTextBlock clearFirstNonEmptyBlockFromExtraSpaces(const QTextBlock &currentBlock)
{
QTextBlock prevBlock = currentBlock.previous();
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
prevBlock = prevBlock.previous();
if (prevBlock.text().trimmed().isEmpty())
return prevBlock;
const QString initialText = prevBlock.text();
if (!initialText.at(initialText.length() - 1).isSpace())
return prevBlock;
QTextCursor cursor(prevBlock);
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::EndOfBlock);
cursor.movePosition(QTextCursor::Left);
while (cursor.positionInBlock() >= 0 && initialText.at(cursor.positionInBlock()).isSpace())
cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
if (cursor.hasSelection())
cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
cursor.removeSelectedText();
cursor.endEditBlock();
return prevBlock;
}
// Returns the total langth of previous lines with pure whitespace.
int previousEmptyLinesLength(const QTextBlock &currentBlock)
{
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 constexpr const int MinCharactersBeforeCurrentInBuffer = 200;
static constexpr const int MaxCharactersBeforeCurrentInBuffer = 500;
int startOfIndentationBuffer(const QString &buffer, int start)
{
if (start < MaxCharactersBeforeCurrentInBuffer)
return 0;
auto it = buffer.cbegin() + (start - MinCharactersBeforeCurrentInBuffer);
for (; it != buffer.cbegin() + (start - MaxCharactersBeforeCurrentInBuffer); --it) {
if (*it == '{') {
// Find the start of it's line.
for (auto inner = it;
inner != buffer.cbegin() + (start - MaxCharactersBeforeCurrentInBuffer);
--inner) {
if (*inner == '\n')
return inner + 1 - buffer.cbegin();
}
break;
}
}
return it - buffer.cbegin();
}
int nextEndingScopePosition(const QString &buffer, int start)
{
if (start >= buffer.size() - 1)
return buffer.size() - 1;
for (auto it = buffer.cbegin() + (start + 1); it != buffer.cend(); ++it) {
if (*it == '}')
return it - buffer.cbegin();
}
return buffer.size() - 1;
}
} // 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 (typedChar == QChar::Null && (cursor.hasSelection() || !autoTriggered)) {
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
int offset;
int length;
if (cursor.hasSelection()) {
const QTextBlock start = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd());
offset = start.position();
length = std::max(0, end.position() + end.length() - start.position() - 1);
} else {
const QTextBlock block = cursor.block();
offset = block.position();
length = std::max(0, block.length() - 1);
}
QString buffer = editor->toPlainText();
const int totalShift = startOfIndentationBuffer(buffer, offset);
const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
buffer = buffer.mid(totalShift, cutAtPos - totalShift);
offset -= totalShift;
const std::string stdStrBefore = buffer.left(offset).toStdString();
const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
applyReplacements(doc,
stdStrBuffer,
replacements(stdStrBuffer, stdStrBefore.length(), length),
totalShift);
} else {
indentBlock(doc, cursor.block(), typedChar, tabSettings);
}
}
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)
{
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
if (!editor)
return;
const QTextBlock prevBlock = clearFirstNonEmptyBlockFromExtraSpaces(block);
int offset = block.position();
int length = std::max(0, block.length() - 1);
QString buffer = editor->toPlainText();
int emptySpaceLength = previousEmptyLinesLength(block);
offset -= emptySpaceLength;
buffer.remove(offset, emptySpaceLength);
int extraPrevBlockLength{0};
int prevBlockTextLength{1};
bool prevBlockEndsWithPunctuation = false;
if (typedChar == QChar::Null) {
extraPrevBlockLength = modifyToIndentEmptyLines(buffer, offset, length, block);
const QString prevBlockText = prevBlock.text();
prevBlockEndsWithPunctuation = prevBlockText.size() > 0
? prevBlockText.at(prevBlockText.size() - 1).isPunct()
: false;
prevBlockTextLength = prevBlockText.size() + 1;
}
const int totalShift = startOfIndentationBuffer(buffer, offset);
const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
buffer = buffer.mid(totalShift, cutAtPos - totalShift);
offset -= totalShift;
const std::string stdStrBefore = buffer.left(offset).toStdString();
const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
applyReplacements(doc,
stdStrBuffer,
replacements(stdStrBuffer,
stdStrBefore.length(),
length,
true,
typedChar,
emptySpaceLength - extraPrevBlockLength,
prevBlockTextLength + extraPrevBlockLength,
prevBlockEndsWithPunctuation),
totalShift);
}
int ClangFormatIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings &)
{
TextEditorWidget *editor = TextEditorWidget::currentTextEditorWidget();
if (!editor)
return -1;
const QTextBlock prevBlock = clearFirstNonEmptyBlockFromExtraSpaces(block);
int offset = block.position();
int length = std::max(0, block.length() - 1);
QString buffer = editor->toPlainText();
int emptySpaceLength = previousEmptyLinesLength(block);
offset -= emptySpaceLength;
buffer.replace(offset, emptySpaceLength, "");
int extraPrevBlockLength = modifyToIndentEmptyLines(buffer, offset, length, block);
const QString prevBlockText = prevBlock.text();
bool prevBlockEndsWithPunctuation = prevBlockText.size() > 0
? prevBlockText.at(prevBlockText.size() - 1).isPunct()
: false;
const int totalShift = startOfIndentationBuffer(buffer, offset);
const int cutAtPos = nextEndingScopePosition(buffer, offset + length) + 1;
buffer = buffer.mid(totalShift, cutAtPos - totalShift);
offset -= totalShift;
const std::string stdStrBefore = buffer.left(offset).toStdString();
const std::string stdStrBuffer = stdStrBefore + buffer.mid(offset).toStdString();
Replacements toReplace = replacements(stdStrBuffer,
stdStrBefore.length(),
length,
true,
QChar::Null,
emptySpaceLength - extraPrevBlockLength,
prevBlockText.size() + extraPrevBlockLength + 1,
prevBlockEndsWithPunctuation);
if (toReplace.empty())
return -1;
const Replacement replacement = *toReplace.begin();
const StringRef text = replacement.getReplacementText();
size_t afterLineBreak = text.find_last_of('\n');
afterLineBreak = (afterLineBreak == std::string::npos) ? 0 : afterLineBreak + 1;
return static_cast<int>(text.size() - afterLineBreak);
}
TabSettings ClangFormatIndenter::tabSettings() const
{
FormatStyle style = formatStyle();
TabSettings tabSettings;
switch (style.UseTab) {
case FormatStyle::UT_Never:
tabSettings.m_tabPolicy = TabSettings::SpacesOnlyTabPolicy;
case FormatStyle::UT_Always:
tabSettings.m_tabPolicy = TabSettings::TabsOnlyTabPolicy;
default:
tabSettings.m_tabPolicy = TabSettings::MixedTabPolicy;
}
tabSettings.m_tabSize = style.TabWidth;
tabSettings.m_indentSize = style.IndentWidth;
if (style.AlignAfterOpenBracket)
tabSettings.m_continuationAlignBehavior = TabSettings::ContinuationAlignWithSpaces;
else
tabSettings.m_continuationAlignBehavior = TabSettings::ContinuationAlignWithIndent;
return tabSettings;
}
} // namespace Internal
} // namespace ClangFormat

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** Copyright (C) 2018 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>
namespace ClangFormat {
namespace Internal {
class ClangFormatIndenter final : public TextEditor::Indenter
{
public:
void indent(QTextDocument *doc,
const QTextCursor &cursor,
const QChar &typedChar,
const TextEditor::TabSettings &tabSettings,
bool autoTriggered = true) override;
void reindent(QTextDocument *doc,
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;
bool hasTabSettings() const override { return true; }
TextEditor::TabSettings tabSettings() const override;
};
} // namespace Internal
} // namespace ClangFormat

View File

@@ -0,0 +1,120 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "clangformatplugin.h"
#include "clangformatconfigwidget.h"
#include "clangformatindenter.h"
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/ioptionspage.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/target.h>
#include <QAction>
#include <QDebug>
#include <QMainWindow>
#include <QMessageBox>
#include <QMenu>
#include <QtPlugin>
using namespace ProjectExplorer;
namespace ClangFormat {
namespace Internal {
class ClangFormatOptionsPage : public Core::IOptionsPage
{
public:
explicit ClangFormatOptionsPage()
{
setId("Cpp.CodeStyle.ClangFormat");
setDisplayName(QCoreApplication::translate(
"ClangFormat::Internal::ClangFormatOptionsPage",
"Clang Format"));
setCategory(CppTools::Constants::CPP_SETTINGS_CATEGORY);
}
QWidget *widget()
{
if (!m_widget)
m_widget = new ClangFormatConfigWidget;
return m_widget;
}
void apply()
{
m_widget->apply();
}
void finish()
{
delete m_widget;
}
private:
QPointer<ClangFormatConfigWidget> m_widget;
};
ClangFormatPlugin::ClangFormatPlugin() = default;
ClangFormatPlugin::~ClangFormatPlugin() = default;
bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorString)
{
Q_UNUSED(arguments);
Q_UNUSED(errorString);
m_optionsPage = std::make_unique<ClangFormatOptionsPage>();
auto panelFactory = new ProjectPanelFactory();
panelFactory->setPriority(120);
panelFactory->setDisplayName(tr("Clang Format"));
panelFactory->setCreateWidgetFunction([](Project *project) {
return new ClangFormatConfigWidget(project);
});
ProjectPanelFactory::registerFactory(panelFactory);
CppTools::CppModelManager::instance()->setCppIndenterCreator([]() {
return new ClangFormatIndenter();
});
return true;
}
} // namespace Internal
} // namespace ClangFormat

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** 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 <extensionsystem/iplugin.h>
#include <memory>
namespace ClangFormat {
namespace Internal {
class ClangFormatOptionsPage;
class ClangFormatPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangFormat.json")
public:
ClangFormatPlugin();
~ClangFormatPlugin();
private:
bool initialize(const QStringList &arguments, QString *errorString) final;
void extensionsInitialized() final {}
std::unique_ptr<ClangFormatOptionsPage> m_optionsPage;
};
} // namespace Internal
} // namespace ClangTools

View File

@@ -80,10 +80,7 @@ ClangToolsConfigWidget::ClangToolsConfigWidget(
}); });
} }
ClangToolsConfigWidget::~ClangToolsConfigWidget() ClangToolsConfigWidget::~ClangToolsConfigWidget() = default;
{
delete m_ui;
}
} // namespace Internal } // namespace Internal
} // namespace ClangTools } // namespace ClangTools

View File

@@ -29,6 +29,8 @@
#include <QWidget> #include <QWidget>
#include <memory>
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
@@ -41,12 +43,10 @@ class ClangToolsConfigWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit ClangToolsConfigWidget(ClangToolsSettings *settings, ClangToolsConfigWidget(ClangToolsSettings *settings, QWidget *parent = nullptr);
QWidget *parent = 0);
~ClangToolsConfigWidget(); ~ClangToolsConfigWidget();
private: private:
Ui::ClangToolsConfigWidget *m_ui; std::unique_ptr<Ui::ClangToolsConfigWidget> m_ui;
ClangToolsSettings *m_settings; ClangToolsSettings *m_settings;
}; };

View File

@@ -48,6 +48,9 @@
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/ioptionspage.h> #include <coreplugin/dialogs/ioptionspage.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectpanelfactory.h> #include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>

View File

@@ -103,7 +103,7 @@ CppEditorDocument::CppEditorDocument()
{ {
setId(CppEditor::Constants::CPPEDITOR_ID); setId(CppEditor::Constants::CPPEDITOR_ID);
setSyntaxHighlighter(new CppHighlighter); setSyntaxHighlighter(new CppHighlighter);
setIndenter(new CppTools::CppQtStyleIndenter); setIndenter(CppTools::CppModelManager::instance()->createCppIndenter());
connect(this, &TextEditor::TextDocument::tabSettingsChanged, connect(this, &TextEditor::TextDocument::tabSettingsChanged,
this, &CppEditorDocument::invalidateFormatterCache); this, &CppEditorDocument::invalidateFormatterCache);
@@ -433,5 +433,12 @@ CppTools::BaseEditorDocumentProcessor *CppEditorDocument::processor()
return m_processor.data(); return m_processor.data();
} }
TextEditor::TabSettings CppEditorDocument::tabSettings() const
{
return indenter()->hasTabSettings()
? indenter()->tabSettings()
: TextEditor::TextDocument::tabSettings();
}
} // namespace Internal } // namespace Internal
} // namespace CppEditor } // namespace CppEditor

View File

@@ -67,6 +67,7 @@ public:
ParseContextModel &parseContextModel(); ParseContextModel &parseContextModel();
QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams &params); QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams &params);
TextEditor::TabSettings tabSettings() const override;
signals: signals:
void codeWarningsUpdated(unsigned contentsRevision, void codeWarningsUpdated(unsigned contentsRevision,

View File

@@ -39,6 +39,7 @@
#include "cpplocatordata.h" #include "cpplocatordata.h"
#include "cpplocatorfilter.h" #include "cpplocatorfilter.h"
#include "cppmodelmanagersupportinternal.h" #include "cppmodelmanagersupportinternal.h"
#include "cppqtstyleindenter.h"
#include "cpprefactoringchanges.h" #include "cpprefactoringchanges.h"
#include "cpprefactoringengine.h" #include "cpprefactoringengine.h"
#include "cppsourceprocessor.h" #include "cppsourceprocessor.h"
@@ -61,6 +62,7 @@
#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>
@@ -507,7 +509,9 @@ void CppModelManager::initializeBuiltinModelManagerSupport()
} }
CppModelManager::CppModelManager() CppModelManager::CppModelManager()
: CppModelManagerBase(nullptr), d(new CppModelManagerPrivate) : CppModelManagerBase(nullptr)
, createCppIndenter([]() { return new CppQtStyleIndenter; })
, d(new CppModelManagerPrivate)
{ {
d->m_indexingSupporter = 0; d->m_indexingSupporter = 0;
d->m_enableGC = true; d->m_enableGC = true;

View File

@@ -48,6 +48,7 @@ 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
@@ -212,6 +213,13 @@ public:
RefactoringEngineInterface *refactoringEngine); RefactoringEngineInterface *refactoringEngine);
static void removeRefactoringEngine(RefactoringEngineType type); static void removeRefactoringEngine(RefactoringEngineType type);
using CppIndenterCreator = std::function<TextEditor::Indenter *()>;
void setCppIndenterCreator(CppIndenterCreator indenterCreator)
{
createCppIndenter = std::move(indenterCreator);
}
CppIndenterCreator createCppIndenter;
void setLocatorFilter(std::unique_ptr<Core::ILocatorFilter> &&filter); void setLocatorFilter(std::unique_ptr<Core::ILocatorFilter> &&filter);
void setClassesFilter(std::unique_ptr<Core::ILocatorFilter> &&filter); void setClassesFilter(std::unique_ptr<Core::ILocatorFilter> &&filter);
void setIncludesFilter(std::unique_ptr<Core::ILocatorFilter> &&filter); void setIncludesFilter(std::unique_ptr<Core::ILocatorFilter> &&filter);

View File

@@ -129,7 +129,8 @@ void CppQtStyleIndenter::indentBlock(QTextDocument *doc,
void CppQtStyleIndenter::indent(QTextDocument *doc, void CppQtStyleIndenter::indent(QTextDocument *doc,
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 = doc->findBlock(cursor.selectionStart());

View File

@@ -53,7 +53,8 @@ public:
void indent(QTextDocument *doc, void indent(QTextDocument *doc,
const QTextCursor &cursor, const QTextCursor &cursor,
const QChar &typedChar, const QChar &typedChar,
const TextEditor::TabSettings &tabSettings) override; const TextEditor::TabSettings &tabSettings,
bool autoTriggered = true) override;
void setCodeStylePreferences(TextEditor::ICodeStylePreferences *preferences) override; void setCodeStylePreferences(TextEditor::ICodeStylePreferences *preferences) override;
void invalidateCache(QTextDocument *doc) override; void invalidateCache(QTextDocument *doc) override;

View File

@@ -84,7 +84,8 @@ void GlslIndenter::indentBlock(QTextDocument *doc,
void GlslIndenter::indent(QTextDocument *doc, void GlslIndenter::indent(QTextDocument *doc,
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 = doc->findBlock(cursor.selectionStart());

View File

@@ -45,7 +45,8 @@ public:
virtual void indent(QTextDocument *doc, virtual void indent(QTextDocument *doc,
const QTextCursor &cursor, const QTextCursor &cursor,
const QChar &typedChar, const QChar &typedChar,
const TextEditor::TabSettings &tabSettings) override; const TextEditor::TabSettings &tabSettings,
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 QVector<QTextBlock> &blocks,

View File

@@ -4,6 +4,7 @@ TEMPLATE = subdirs
SUBDIRS = \ SUBDIRS = \
autotest \ autotest \
clangformat \
clangtools \ clangtools \
coreplugin \ coreplugin \
texteditor \ texteditor \

View File

@@ -13,6 +13,7 @@ Project {
"bineditor/bineditor.qbs", "bineditor/bineditor.qbs",
"bookmarks/bookmarks.qbs", "bookmarks/bookmarks.qbs",
"clangcodemodel/clangcodemodel.qbs", "clangcodemodel/clangcodemodel.qbs",
"clangformat/clangformat.qbs",
"clangpchmanager/clangpchmanager.qbs", "clangpchmanager/clangpchmanager.qbs",
"clangrefactoring/clangrefactoring.qbs", "clangrefactoring/clangrefactoring.qbs",
"clangtools/clangtools.qbs", "clangtools/clangtools.qbs",

View File

@@ -290,7 +290,7 @@ static void showError(const QString &error)
* Checks the state of @a task and if the formatting was successful calls updateEditorText() with * Checks the state of @a task and if the formatting was successful calls updateEditorText() with
* the respective members of @a task. * the respective members of @a task.
*/ */
void checkAndApplyTask(const FormatTask &task) static void checkAndApplyTask(const FormatTask &task)
{ {
if (!task.error.isEmpty()) { if (!task.error.isEmpty()) {
showError(task.error); showError(task.error);

View File

@@ -59,7 +59,8 @@ void Indenter::indentBlock(QTextDocument *doc,
void Indenter::indent(QTextDocument *doc, void Indenter::indent(QTextDocument *doc,
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 = doc->findBlock(cursor.selectionStart());

View File

@@ -27,6 +27,8 @@
#include "texteditor_global.h" #include "texteditor_global.h"
#include "tabsettings.h"
#include <QMap> #include <QMap>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -62,7 +64,8 @@ public:
virtual void indent(QTextDocument *doc, virtual void indent(QTextDocument *doc,
const QTextCursor &cursor, const QTextCursor &cursor,
const QChar &typedChar, const QChar &typedChar,
const TabSettings &tabSettings); const TabSettings &tabSettings,
bool autoTriggered = true);
// Reindent at cursor. Selection will be adjusted according to the indentation // Reindent at cursor. Selection will be adjusted according to the indentation
// change of the first block. // change of the first block.
@@ -77,6 +80,9 @@ public:
// 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 TextEditor::TabSettings &tabSettings);
virtual bool hasTabSettings() const { return false; }
virtual TabSettings tabSettings() const { return TabSettings(); }
}; };
} // namespace TextEditor } // namespace TextEditor

View File

@@ -83,6 +83,7 @@ public:
} }
QTextCursor indentOrUnindent(const QTextCursor &textCursor, bool doIndent, QTextCursor indentOrUnindent(const QTextCursor &textCursor, bool doIndent,
const TabSettings &tabSettings,
bool blockSelection = false, int column = 0, bool blockSelection = false, int column = 0,
int *offset = nullptr); int *offset = nullptr);
void resetRevisions(); void resetRevisions();
@@ -110,17 +111,16 @@ public:
}; };
QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor, bool doIndent, QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor, bool doIndent,
const TabSettings &tabSettings,
bool blockSelection, int columnIn, int *offset) bool blockSelection, int columnIn, int *offset)
{ {
QTextCursor cursor = textCursor; QTextCursor cursor = textCursor;
cursor.beginEditBlock(); cursor.beginEditBlock();
TabSettings &ts = m_tabSettings;
// Indent or unindent the selected lines // Indent or unindent the selected lines
int pos = cursor.position(); int pos = cursor.position();
int column = blockSelection ? columnIn int column = blockSelection ? columnIn
: ts.columnAt(cursor.block().text(), cursor.positionInBlock()); : tabSettings.columnAt(cursor.block().text(), cursor.positionInBlock());
int anchor = cursor.anchor(); int anchor = cursor.anchor();
int start = qMin(anchor, pos); int start = qMin(anchor, pos);
int end = qMax(anchor, pos); int end = qMax(anchor, pos);
@@ -140,12 +140,13 @@ QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor,
if (cursor.hasSelection() && !blockSelection && !oneLinePartial) { if (cursor.hasSelection() && !blockSelection && !oneLinePartial) {
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) { for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
const QString text = block.text(); const QString text = block.text();
int indentPosition = ts.lineIndentPosition(text); int indentPosition = tabSettings.lineIndentPosition(text);
if (!doIndent && !indentPosition) if (!doIndent && !indentPosition)
indentPosition = ts.firstNonSpace(text); indentPosition = tabSettings.firstNonSpace(text);
int targetColumn = ts.indentedColumn(ts.columnAt(text, indentPosition), doIndent); int targetColumn = tabSettings.indentedColumn(
tabSettings.columnAt(text, indentPosition), doIndent);
cursor.setPosition(block.position() + indentPosition); cursor.setPosition(block.position() + indentPosition);
cursor.insertText(ts.indentationString(0, targetColumn, 0, block)); cursor.insertText(tabSettings.indentationString(0, targetColumn, 0, block));
cursor.setPosition(block.position()); cursor.setPosition(block.position());
cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor); cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor);
cursor.removeSelectedText(); cursor.removeSelectedText();
@@ -170,27 +171,30 @@ QTextCursor TextDocumentPrivate::indentOrUnindent(const QTextCursor &textCursor,
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) { for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
QString text = block.text(); QString text = block.text();
int blockColumn = ts.columnAt(text, text.size()); int blockColumn = tabSettings.columnAt(text, text.size());
if (blockColumn < column) { if (blockColumn < column) {
cursor.setPosition(block.position() + text.size()); cursor.setPosition(block.position() + text.size());
cursor.insertText(ts.indentationString(blockColumn, column, 0, block)); cursor.insertText(tabSettings.indentationString(blockColumn, column, 0, block));
text = block.text(); text = block.text();
} }
int indentPosition = ts.positionAtColumn(text, column, nullptr, true); int indentPosition = tabSettings.positionAtColumn(text, column, nullptr, true);
int spaces = ts.spacesLeftFromPosition(text, indentPosition); int spaces = tabSettings.spacesLeftFromPosition(text, indentPosition);
int startColumn = ts.columnAt(text, indentPosition - spaces); int startColumn = tabSettings.columnAt(text, indentPosition - spaces);
int targetColumn = ts.indentedColumn(ts.columnAt(text, indentPosition), doIndent); int targetColumn = tabSettings.indentedColumn(
tabSettings.columnAt(text, indentPosition), doIndent);
cursor.setPosition(block.position() + indentPosition); cursor.setPosition(block.position() + indentPosition);
cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor); cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor);
cursor.removeSelectedText(); cursor.removeSelectedText();
cursor.insertText(ts.indentationString(startColumn, targetColumn, 0, block)); cursor.insertText(tabSettings.indentationString(startColumn, targetColumn, 0, block));
} }
// Preserve initial anchor of block selection // Preserve initial anchor of block selection
if (blockSelection) { if (blockSelection) {
end = cursor.position(); end = cursor.position();
if (offset) if (offset) {
*offset = ts.columnAt(cursor.block().text(), cursor.positionInBlock()) - column; *offset = tabSettings.columnAt(cursor.block().text(), cursor.positionInBlock())
- column;
}
cursor.setPosition(start); cursor.setPosition(start);
cursor.setPosition(end, QTextCursor::KeepAnchor); cursor.setPosition(end, QTextCursor::KeepAnchor);
} }
@@ -330,19 +334,19 @@ const StorageSettings &TextDocument::storageSettings() const
return d->m_storageSettings; return d->m_storageSettings;
} }
void TextDocument::setTabSettings(const TabSettings &tabSettings) void TextDocument::setTabSettings(const TabSettings &newTabSettings)
{ {
if (tabSettings == d->m_tabSettings) if (newTabSettings == d->m_tabSettings)
return; return;
d->m_tabSettings = tabSettings; d->m_tabSettings = newTabSettings;
if (Highlighter *highlighter = qobject_cast<Highlighter *>(d->m_highlighter)) if (Highlighter *highlighter = qobject_cast<Highlighter *>(d->m_highlighter))
highlighter->setTabSettings(tabSettings); highlighter->setTabSettings(tabSettings());
emit tabSettingsChanged(); emit tabSettingsChanged();
} }
const TabSettings &TextDocument::tabSettings() const TabSettings TextDocument::tabSettings() const
{ {
return d->m_tabSettings; return d->m_tabSettings;
} }
@@ -412,26 +416,26 @@ void TextDocument::setExtraEncodingSettings(const ExtraEncodingSettings &extraEn
d->m_extraEncodingSettings = extraEncodingSettings; d->m_extraEncodingSettings = extraEncodingSettings;
} }
void TextDocument::autoIndent(const QTextCursor &cursor, QChar typedChar) void TextDocument::autoIndent(const QTextCursor &cursor, QChar typedChar, bool autoTriggered)
{ {
d->m_indenter->indent(&d->m_document, cursor, typedChar, d->m_tabSettings); d->m_indenter->indent(&d->m_document, cursor, typedChar, tabSettings(), autoTriggered);
} }
void TextDocument::autoReindent(const QTextCursor &cursor) void TextDocument::autoReindent(const QTextCursor &cursor)
{ {
d->m_indenter->reindent(&d->m_document, cursor, d->m_tabSettings); d->m_indenter->reindent(&d->m_document, cursor, tabSettings());
} }
QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column, QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column,
int *offset) int *offset)
{ {
return d->indentOrUnindent(cursor, true, blockSelection, column, offset); return d->indentOrUnindent(cursor, true, tabSettings(), blockSelection, column, offset);
} }
QTextCursor TextDocument::unindent(const QTextCursor &cursor, bool blockSelection, int column, QTextCursor TextDocument::unindent(const QTextCursor &cursor, bool blockSelection, int column,
int *offset) int *offset)
{ {
return d->indentOrUnindent(cursor, false, blockSelection, column, offset); return d->indentOrUnindent(cursor, false, tabSettings(), blockSelection, column, offset);
} }
const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const
@@ -814,23 +818,24 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool cleanIndentation, b
if (blocks.isEmpty()) if (blocks.isEmpty())
return; return;
const TabSettings currentTabSettings = tabSettings();
const IndentationForBlock &indentations = const IndentationForBlock &indentations =
d->m_indenter->indentationForBlocks(blocks, d->m_tabSettings); d->m_indenter->indentationForBlocks(blocks, currentTabSettings);
foreach (block, blocks) { foreach (block, blocks) {
QString blockText = block.text(); QString blockText = block.text();
d->m_tabSettings.removeTrailingWhitespace(cursor, block); currentTabSettings.removeTrailingWhitespace(cursor, block);
const int indent = indentations[block.blockNumber()]; const int indent = indentations[block.blockNumber()];
if (cleanIndentation && !d->m_tabSettings.isIndentationClean(block, indent)) { if (cleanIndentation && !currentTabSettings.isIndentationClean(block, indent)) {
cursor.setPosition(block.position()); cursor.setPosition(block.position());
int firstNonSpace = d->m_tabSettings.firstNonSpace(blockText); int firstNonSpace = currentTabSettings.firstNonSpace(blockText);
if (firstNonSpace == blockText.length()) { if (firstNonSpace == blockText.length()) {
cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
cursor.removeSelectedText(); cursor.removeSelectedText();
} else { } else {
int column = d->m_tabSettings.columnAt(blockText, firstNonSpace); int column = currentTabSettings.columnAt(blockText, firstNonSpace);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace);
QString indentationString = d->m_tabSettings.indentationString(0, column, column - indent, block); QString indentationString = currentTabSettings.indentationString(0, column, column - indent, block);
cursor.insertText(indentationString); cursor.insertText(indentationString);
} }
} }

View File

@@ -81,13 +81,14 @@ public:
const TypingSettings &typingSettings() const; const TypingSettings &typingSettings() const;
const StorageSettings &storageSettings() const; const StorageSettings &storageSettings() const;
const TabSettings &tabSettings() const; virtual TabSettings tabSettings() const;
const ExtraEncodingSettings &extraEncodingSettings() const; const ExtraEncodingSettings &extraEncodingSettings() const;
const FontSettings &fontSettings() const; const FontSettings &fontSettings() const;
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);
QTextCursor indent(const QTextCursor &cursor, bool blockSelection = false, int column = 0, QTextCursor indent(const QTextCursor &cursor, bool blockSelection = false, int column = 0,
int *offset = nullptr); int *offset = nullptr);

View File

@@ -2451,7 +2451,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
} }
QTextCursor cursor = textCursor(); QTextCursor cursor = textCursor();
const TabSettings &ts = d->m_document->tabSettings(); const TabSettings ts = d->m_document->tabSettings();
const TypingSettings &tps = d->m_document->typingSettings(); const TypingSettings &tps = d->m_document->typingSettings();
cursor.beginEditBlock(); cursor.beginEditBlock();
@@ -2474,6 +2474,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
e->accept(); e->accept();
if (extraBlocks > 0) { if (extraBlocks > 0) {
const int cursorPosition = cursor.position();
QTextCursor ensureVisible = cursor; QTextCursor ensureVisible = cursor;
while (extraBlocks > 0) { while (extraBlocks > 0) {
--extraBlocks; --extraBlocks;
@@ -2491,6 +2492,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
} }
} }
setTextCursor(ensureVisible); setTextCursor(ensureVisible);
cursor.setPosition(cursorPosition);
} }
setTextCursor(cursor); setTextCursor(cursor);
@@ -3738,7 +3740,7 @@ QString TextEditorWidgetPrivate::copyBlockSelection()
if (!m_inBlockSelectionMode) if (!m_inBlockSelectionMode)
return QString(); return QString();
QString selection; QString selection;
const TabSettings &ts = m_document->tabSettings(); const TabSettings ts = m_document->tabSettings();
QTextBlock block = QTextBlock block =
m_document->document()->findBlockByNumber(m_blockSelection.firstBlockNumber()); m_document->document()->findBlockByNumber(m_blockSelection.firstBlockNumber());
const QTextBlock &lastBlock = const QTextBlock &lastBlock =
@@ -3780,7 +3782,7 @@ QString TextEditorWidgetPrivate::copyBlockSelection()
void TextEditorWidgetPrivate::setCursorToColumn(QTextCursor &cursor, int column, QTextCursor::MoveMode moveMode) void TextEditorWidgetPrivate::setCursorToColumn(QTextCursor &cursor, int column, QTextCursor::MoveMode moveMode)
{ {
const TabSettings &ts = m_document->tabSettings(); const TabSettings ts = m_document->tabSettings();
int offset = 0; int offset = 0;
const int cursorPosition = cursor.position(); const int cursorPosition = cursor.position();
const int pos = ts.positionAtColumn(cursor.block().text(), column, &offset); const int pos = ts.positionAtColumn(cursor.block().text(), column, &offset);
@@ -3841,7 +3843,7 @@ void TextEditorWidgetPrivate::insertIntoBlockSelection(const QString &text)
- m_blockSelection.firstBlockNumber(); - m_blockSelection.firstBlockNumber();
const int textNewLineCount = text.count(QLatin1Char('\n')) ; const int textNewLineCount = text.count(QLatin1Char('\n')) ;
QStringList textLines = text.split(QLatin1Char('\n')); QStringList textLines = text.split(QLatin1Char('\n'));
const TabSettings &ts = m_document->tabSettings(); const TabSettings ts = m_document->tabSettings();
int textLength = 0; int textLength = 0;
const QStringList::const_iterator endLine = textLines.constEnd(); const QStringList::const_iterator endLine = textLines.constEnd();
for (QStringList::const_iterator textLine = textLines.constBegin(); textLine != endLine; ++textLine) for (QStringList::const_iterator textLine = textLines.constBegin(); textLine != endLine; ++textLine)
@@ -3903,7 +3905,7 @@ void TextEditorWidgetPrivate::removeBlockSelection()
cursor.clearSelection(); cursor.clearSelection();
cursor.beginEditBlock(); cursor.beginEditBlock();
const TabSettings &ts = m_document->tabSettings(); const TabSettings ts = m_document->tabSettings();
QTextBlock block = m_document->document()->findBlockByNumber(m_blockSelection.firstBlockNumber()); QTextBlock block = m_document->document()->findBlockByNumber(m_blockSelection.firstBlockNumber());
const QTextBlock &lastBlock = m_document->document()->findBlockByNumber(m_blockSelection.lastBlockNumber()); const QTextBlock &lastBlock = m_document->document()->findBlockByNumber(m_blockSelection.lastBlockNumber());
for (;;) { for (;;) {
@@ -3930,7 +3932,7 @@ void TextEditorWidgetPrivate::removeBlockSelection()
void TextEditorWidgetPrivate::enableBlockSelection(const QTextCursor &cursor) void TextEditorWidgetPrivate::enableBlockSelection(const QTextCursor &cursor)
{ {
const TabSettings &ts = m_document->tabSettings(); const TabSettings ts = m_document->tabSettings();
const QTextBlock &positionTextBlock = cursor.block(); const QTextBlock &positionTextBlock = cursor.block();
int positionBlock = positionTextBlock.blockNumber(); int positionBlock = positionTextBlock.blockNumber();
int positionColumn = ts.columnAt(positionTextBlock.text(), int positionColumn = ts.columnAt(positionTextBlock.text(),
@@ -4350,7 +4352,7 @@ void TextEditorWidgetPrivate::paintFindScope(const PaintEventData &data, QPainte
&& block.position() <= m_findScopeEnd.block().position()) { && block.position() <= m_findScopeEnd.block().position()) {
QTextLayout *layout = block.layout(); QTextLayout *layout = block.layout();
QString text = block.text(); QString text = block.text();
const TabSettings &ts = m_document->tabSettings(); const TabSettings ts = m_document->tabSettings();
qreal spacew = QFontMetricsF(q->font()).width(QLatin1Char(' ')); qreal spacew = QFontMetricsF(q->font()).width(QLatin1Char(' '));
int offset = 0; int offset = 0;
@@ -4440,7 +4442,7 @@ void TextEditorWidgetPrivate::paintBlockSelection(const PaintEventData &data, QP
QTextLayout *layout = data.block.layout(); QTextLayout *layout = data.block.layout();
QRectF blockBoundingRect = q->blockBoundingRect(data.block).translated(data.offset); QRectF blockBoundingRect = q->blockBoundingRect(data.block).translated(data.offset);
QString text = data.block.text(); QString text = data.block.text();
const TabSettings &tabSettings = m_document->tabSettings(); const TabSettings tabSettings = m_document->tabSettings();
const qreal spacew = QFontMetricsF(q->font()).width(QLatin1Char(' ')); const qreal spacew = QFontMetricsF(q->font()).width(QLatin1Char(' '));
const int cursorw = q->overwriteMode() ? QFontMetrics(q->font()).width(QLatin1Char(' ')) const int cursorw = q->overwriteMode() ? QFontMetrics(q->font()).width(QLatin1Char(' '))
: q->cursorWidth(); : q->cursorWidth();
@@ -4726,7 +4728,7 @@ void TextEditorWidgetPrivate::setupSelections(const PaintEventData &data,
o.format = range.format; o.format = range.format;
if (i == data.blockSelectionIndex) { if (i == data.blockSelectionIndex) {
QString text = data.block.text(); QString text = data.block.text();
const TabSettings &ts = m_document->tabSettings(); const TabSettings ts = m_document->tabSettings();
o.start = ts.positionAtColumn(text, m_blockSelection.firstVisualColumn()); o.start = ts.positionAtColumn(text, m_blockSelection.firstVisualColumn());
o.length = ts.positionAtColumn(text, m_blockSelection.lastVisualColumn()) - o.start; o.length = ts.positionAtColumn(text, m_blockSelection.lastVisualColumn()) - o.start;
} }
@@ -5511,12 +5513,13 @@ void TextEditorWidget::mouseMoveEvent(QMouseEvent *e)
QPlainTextEdit::mouseMoveEvent(e); QPlainTextEdit::mouseMoveEvent(e);
if (e->modifiers() & Qt::AltModifier) { if (e->modifiers() & Qt::AltModifier) {
const TabSettings tabSettings = d->m_document->tabSettings();
if (!d->m_inBlockSelectionMode) { if (!d->m_inBlockSelectionMode) {
if (textCursor().hasSelection()) { if (textCursor().hasSelection()) {
d->enableBlockSelection(textCursor()); d->enableBlockSelection(textCursor());
} else { } else {
const QTextCursor &cursor = cursorForPosition(e->pos()); const QTextCursor &cursor = cursorForPosition(e->pos());
int column = d->m_document->tabSettings().columnAt( int column = tabSettings.columnAt(
cursor.block().text(), cursor.positionInBlock()); cursor.block().text(), cursor.positionInBlock());
if (cursor.positionInBlock() == cursor.block().length()-1) if (cursor.positionInBlock() == cursor.block().length()-1)
column += (e->pos().x() - cursorRect().center().x()) / QFontMetricsF(font()).width(QLatin1Char(' ')); column += (e->pos().x() - cursorRect().center().x()) / QFontMetricsF(font()).width(QLatin1Char(' '));
@@ -5529,7 +5532,7 @@ void TextEditorWidget::mouseMoveEvent(QMouseEvent *e)
const QTextCursor &cursor = textCursor(); const QTextCursor &cursor = textCursor();
// get visual column // get visual column
int column = d->m_document->tabSettings().columnAt( int column = tabSettings.columnAt(
cursor.block().text(), cursor.positionInBlock()); cursor.block().text(), cursor.positionInBlock());
if (cursor.positionInBlock() == cursor.block().length()-1) if (cursor.positionInBlock() == cursor.block().length()-1)
column += (e->pos().x() - cursorRect().center().x()) / QFontMetricsF(font()).width(QLatin1Char(' ')); column += (e->pos().x() - cursorRect().center().x()) / QFontMetricsF(font()).width(QLatin1Char(' '));
@@ -6056,7 +6059,7 @@ void TextEditorWidgetPrivate::handleBackspaceKey()
cursorWithinSnippet = snippetCheckCursor(snippetCursor); cursorWithinSnippet = snippetCheckCursor(snippetCursor);
} }
const TabSettings &tabSettings = m_document->tabSettings(); const TabSettings tabSettings = m_document->tabSettings();
const TypingSettings &typingSettings = m_document->typingSettings(); const TypingSettings &typingSettings = m_document->typingSettings();
if (typingSettings.m_autoIndent if (typingSettings.m_autoIndent
@@ -7131,7 +7134,7 @@ void TextEditorWidget::format()
{ {
QTextCursor cursor = textCursor(); QTextCursor cursor = textCursor();
cursor.beginEditBlock(); cursor.beginEditBlock();
d->m_document->autoIndent(cursor); d->m_document->autoIndent(cursor, QChar::Null, false);
cursor.endEditBlock(); cursor.endEditBlock();
} }
@@ -8059,7 +8062,7 @@ QTextCursor TextBlockSelection::cursor(const TextDocument *baseTextDocument,
if (!baseTextDocument) if (!baseTextDocument)
return QTextCursor(); return QTextCursor();
QTextDocument *document = baseTextDocument->document(); QTextDocument *document = baseTextDocument->document();
const TabSettings &ts = baseTextDocument->tabSettings(); const TabSettings ts = baseTextDocument->tabSettings();
int selectionAnchorColumn; int selectionAnchorColumn;
int selectionPositionColumn; int selectionPositionColumn;
@@ -8119,7 +8122,7 @@ bool TextEditorWidget::inFindScope(int selectionStart, int selectionEnd)
if (block != document()->findBlock(selectionEnd)) if (block != document()->findBlock(selectionEnd))
return false; return false;
QString text = block.text(); QString text = block.text();
const TabSettings &ts = d->m_document->tabSettings(); const TabSettings ts = d->m_document->tabSettings();
int startPosition = ts.positionAtColumn(text, d->m_findScopeVerticalBlockSelectionFirstColumn); int startPosition = ts.positionAtColumn(text, d->m_findScopeVerticalBlockSelectionFirstColumn);
int endPosition = ts.positionAtColumn(text, d->m_findScopeVerticalBlockSelectionLastColumn); int endPosition = ts.positionAtColumn(text, d->m_findScopeVerticalBlockSelectionLastColumn);
if (selectionStart - block.position() < startPosition) if (selectionStart - block.position() < startPosition)
@@ -8246,7 +8249,7 @@ void TextEditorWidgetPrivate::transformSelection(TransformationMethod method)
void TextEditorWidgetPrivate::transformBlockSelection(TransformationMethod method) void TextEditorWidgetPrivate::transformBlockSelection(TransformationMethod method)
{ {
QTextCursor cursor = q->textCursor(); QTextCursor cursor = q->textCursor();
const TabSettings &ts = m_document->tabSettings(); const TabSettings ts = m_document->tabSettings();
// saved to restore the blockselection // saved to restore the blockselection
const int positionColumn = m_blockSelection.positionColumn; const int positionColumn = m_blockSelection.positionColumn;

View File

@@ -116,6 +116,9 @@ CLANGTOOLING_LIBS=-lclangTooling -lclangIndex -lclangFrontend -lclangParse -lcla
-lclangASTMatchers -lclangToolingCore -lclangAST -lclangLex -lclangBasic -lclangASTMatchers -lclangToolingCore -lclangAST -lclangLex -lclangBasic
win32:CLANGTOOLING_LIBS += -lversion win32:CLANGTOOLING_LIBS += -lversion
CLANGFORMAT_LIBS=-lclangFormat -lclangToolingCore -lclangRewrite -lclangLex -lclangBasic
win32:CLANGFORMAT_LIBS += -lversion
BIN_EXTENSION = BIN_EXTENSION =
win32: BIN_EXTENSION = .exe win32: BIN_EXTENSION = .exe
@@ -199,6 +202,8 @@ isEmpty(LLVM_VERSION) {
warning("Clang LibTooling is disabled. Set QTC_ENABLE_CLANG_LIBTOOLING to enable it.") warning("Clang LibTooling is disabled. Set QTC_ENABLE_CLANG_LIBTOOLING to enable it.")
} }
CLANGFORMAT_LIBS = -L$${LLVM_LIBDIR} $$CLANGFORMAT_LIBS $$LLVM_STATIC_LIBS
contains(QMAKE_DEFAULT_INCDIRS, $$LLVM_INCLUDEPATH): LLVM_INCLUDEPATH = contains(QMAKE_DEFAULT_INCDIRS, $$LLVM_INCLUDEPATH): LLVM_INCLUDEPATH =
# Remove unwanted flags. It is a workaround for linking. # Remove unwanted flags. It is a workaround for linking.