ClangFormat: Introduce check to format code instead of indenting

Ctrl+I with the new check will reformat the selected code or
the current line instead.

Change-Id: Ia5a72c4a09621034d0dfe463f669fe1ca36b0b5f
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2019-01-28 07:54:05 +01:00
parent 9d046826f8
commit 80fb0178fd
17 changed files with 182 additions and 26 deletions

View File

@@ -24,12 +24,14 @@ SOURCES += \
clangformatconfigwidget.cpp \ clangformatconfigwidget.cpp \
clangformatindenter.cpp \ clangformatindenter.cpp \
clangformatplugin.cpp \ clangformatplugin.cpp \
clangformatsettings.cpp \
clangformatutils.cpp clangformatutils.cpp
HEADERS += \ HEADERS += \
clangformatconfigwidget.h \ clangformatconfigwidget.h \
clangformatindenter.h \ clangformatindenter.h \
clangformatplugin.h \ clangformatplugin.h \
clangformatsettings.h \
clangformatutils.h clangformatutils.h
FORMS += \ FORMS += \

View File

@@ -40,6 +40,8 @@ QtcPlugin {
"clangformatindenter.h", "clangformatindenter.h",
"clangformatplugin.cpp", "clangformatplugin.cpp",
"clangformatplugin.h", "clangformatplugin.h",
"clangformatsettings.cpp",
"clangformatsettings.h",
"clangformatutils.h", "clangformatutils.h",
"clangformatutils.cpp", "clangformatutils.cpp",
] ]

View File

@@ -317,8 +317,7 @@ void ClangFormatBaseIndenter::reindent(const QTextCursor &cursor,
indent(cursor, QChar::Null); indent(cursor, QChar::Null);
} }
TextEditor::Replacements ClangFormatBaseIndenter::format( TextEditor::Replacements ClangFormatBaseIndenter::format(const QTextCursor &cursor)
const QTextCursor &cursor, const TextEditor::TabSettings & /*tabSettings*/)
{ {
int utf8Offset; int utf8Offset;
int utf8Length; int utf8Length;
@@ -345,6 +344,12 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
return toReplace; return toReplace;
} }
TextEditor::Replacements ClangFormatBaseIndenter::format(
const QTextCursor &cursor, const TextEditor::TabSettings & /*tabSettings*/)
{
return format(cursor);
}
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, const QChar &typedChar) void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, const QChar &typedChar)
{ {
trimFirstNonEmptyBlock(block); trimFirstNonEmptyBlock(block);
@@ -405,6 +410,16 @@ bool ClangFormatBaseIndenter::isElectricCharacter(const QChar &ch) const
return false; return false;
} }
void ClangFormatBaseIndenter::formatOrIndent(const QTextCursor &cursor,
const TextEditor::TabSettings & /*tabSettings*/,
int /*cursorPositionInEditor*/)
{
if (formatCodeInsteadOfIndent())
format(cursor);
else
indent(cursor, QChar::Null);
}
clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
{ {
llvm::Expected<clang::format::FormatStyle> style llvm::Expected<clang::format::FormatStyle> style

View File

@@ -45,6 +45,9 @@ public:
void reindent(const QTextCursor &cursor, void reindent(const QTextCursor &cursor,
const TextEditor::TabSettings & /*tabSettings*/) override; const TextEditor::TabSettings & /*tabSettings*/) override;
void formatOrIndent(const QTextCursor &cursor,
const TextEditor::TabSettings &tabSettings,
int cursorPositionInEditor = -1) override;
TextEditor::Replacements format(const QTextCursor &cursor, TextEditor::Replacements format(const QTextCursor &cursor,
const TextEditor::TabSettings & /*tabSettings*/) override; const TextEditor::TabSettings & /*tabSettings*/) override;
@@ -58,8 +61,10 @@ public:
protected: protected:
virtual clang::format::FormatStyle styleForFile() const; virtual clang::format::FormatStyle styleForFile() const;
virtual bool formatCodeInsteadOfIndent() const { return false; }
private: private:
TextEditor::Replacements format(const QTextCursor &cursor);
void indent(const QTextCursor &cursor, const QChar &typedChar); void indent(const QTextCursor &cursor, const QChar &typedChar);
void indentBlock(const QTextBlock &block, const QChar &typedChar); void indentBlock(const QTextBlock &block, const QChar &typedChar);
int indentFor(const QTextBlock &block); int indentFor(const QTextBlock &block);

View File

@@ -27,6 +27,7 @@
#include "clangformatconfigwidget.h" #include "clangformatconfigwidget.h"
#include "clangformatconstants.h" #include "clangformatconstants.h"
#include "clangformatsettings.h"
#include "clangformatutils.h" #include "clangformatutils.h"
#include "ui_clangformatconfigwidget.h" #include "ui_clangformatconfigwidget.h"
@@ -131,6 +132,7 @@ void ClangFormatConfigWidget::initialize()
m_ui->projectHasClangFormat->show(); m_ui->projectHasClangFormat->show();
m_ui->clangFormatOptionsTable->show(); m_ui->clangFormatOptionsTable->show();
m_ui->applyButton->show(); m_ui->applyButton->show();
m_ui->formatAlways->hide();
QLayoutItem *lastItem = m_ui->verticalLayout->itemAt(m_ui->verticalLayout->count() - 1); QLayoutItem *lastItem = m_ui->verticalLayout->itemAt(m_ui->verticalLayout->count() - 1);
if (lastItem->spacerItem()) if (lastItem->spacerItem())
@@ -169,6 +171,8 @@ void ClangFormatConfigWidget::initialize()
"and can be configured in Projects > Code Style > C++.")); "and can be configured in Projects > Code Style > C++."));
} }
createStyleFileIfNeeded(true); createStyleFileIfNeeded(true);
m_ui->formatAlways->setChecked(ClangFormatSettings::instance().formatCodeInsteadOfIndent());
m_ui->formatAlways->show();
m_ui->applyButton->hide(); m_ui->applyButton->hide();
} }
@@ -189,6 +193,12 @@ ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
void ClangFormatConfigWidget::apply() void ClangFormatConfigWidget::apply()
{ {
if (!m_project) {
ClangFormatSettings &settings = ClangFormatSettings::instance();
settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked());
settings.write();
}
const QByteArray text = tableToYAML(m_ui->clangFormatOptionsTable); const QByteArray text = tableToYAML(m_ui->clangFormatOptionsTable);
QString filePath; QString filePath;
if (m_project) if (m_project)

View File

@@ -26,6 +26,13 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>8</number> <number>8</number>
</property> </property>
<item>
<widget class="QCheckBox" name="formatAlways">
<property name="text">
<string>Format instead of indenting</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QLabel" name="projectHasClangFormat"> <widget class="QLabel" name="projectHasClangFormat">
<property name="text"> <property name="text">

View File

@@ -30,5 +30,7 @@ namespace Constants {
static const char SETTINGS_FILE_NAME[] = ".clang-format"; static const char SETTINGS_FILE_NAME[] = ".clang-format";
static const char SETTINGS_FILE_ALT_NAME[] = "_clang-format"; static const char SETTINGS_FILE_ALT_NAME[] = "_clang-format";
static const char SAMPLE_FILE_NAME[] = "test.cpp"; static const char SAMPLE_FILE_NAME[] = "test.cpp";
static const char SETTINGS_ID[] = "ClangFormat";
static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent";
} // namespace Constants } // namespace Constants
} // namespace ClangFormat } // namespace ClangFormat

View File

@@ -24,6 +24,7 @@
****************************************************************************/ ****************************************************************************/
#include "clangformatindenter.h" #include "clangformatindenter.h"
#include "clangformatsettings.h"
#include "clangformatutils.h" #include "clangformatutils.h"
#include <texteditor/tabsettings.h> #include <texteditor/tabsettings.h>
@@ -43,6 +44,11 @@ FormatStyle ClangFormatIndenter::styleForFile() const
return ClangFormat::styleForFile(m_fileName); return ClangFormat::styleForFile(m_fileName);
} }
bool ClangFormatIndenter::formatCodeInsteadOfIndent() const
{
return ClangFormatSettings::instance().formatCodeInsteadOfIndent();
}
Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const
{ {
FormatStyle style = currentProjectStyle(); FormatStyle style = currentProjectStyle();

View File

@@ -38,6 +38,7 @@ public:
Utils::optional<TextEditor::TabSettings> tabSettings() const override; Utils::optional<TextEditor::TabSettings> tabSettings() const override;
private: private:
bool formatCodeInsteadOfIndent() const override;
clang::format::FormatStyle styleForFile() const override; clang::format::FormatStyle styleForFile() const override;
}; };

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** 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 "clangformatconstants.h"
#include "clangformatsettings.h"
#include <coreplugin/icore.h>
namespace ClangFormat {
ClangFormatSettings &ClangFormatSettings::instance()
{
static ClangFormatSettings settings;
return settings;
}
ClangFormatSettings::ClangFormatSettings()
{
QSettings *settings = Core::ICore::settings();
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
m_formatCodeInsteadOfIndent
= settings->value(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool();
settings->endGroup();
}
void ClangFormatSettings::write() const
{
QSettings *settings = Core::ICore::settings();
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
settings->setValue(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID),
m_formatCodeInsteadOfIndent);
settings->endGroup();
}
void ClangFormatSettings::setFormatCodeInsteadOfIndent(bool enable)
{
m_formatCodeInsteadOfIndent = enable;
}
bool ClangFormatSettings::formatCodeInsteadOfIndent() const
{
return m_formatCodeInsteadOfIndent;
}
} // namespace ClangFormat

View File

@@ -0,0 +1,44 @@
/****************************************************************************
**
** 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
namespace ClangFormat {
class ClangFormatSettings
{
public:
static ClangFormatSettings &instance();
ClangFormatSettings();
void write() const;
void setFormatCodeInsteadOfIndent(bool enable);
bool formatCodeInsteadOfIndent() const;
private:
bool m_formatCodeInsteadOfIndent = false;
};
} // namespace ClangFormat

View File

@@ -81,6 +81,21 @@ public:
return -1; return -1;
} }
virtual void formatOrIndent(const QTextCursor &cursor,
const TabSettings &tabSettings,
int /*cursorPositionInEditor*/ = -1)
{
indent(cursor, QChar::Null, tabSettings);
}
// By default just calls indent with default settings.
virtual Replacements format(const QTextCursor &cursor,
const TabSettings &tabSettings)
{
indent(cursor, QChar::Null, tabSettings);
return Replacements();
}
// 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 TabSettings & /*tabSettings*/) const TabSettings & /*tabSettings*/)
@@ -99,9 +114,6 @@ public:
const TabSettings &tabSettings) const TabSettings &tabSettings)
= 0; = 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 // Reindent at cursor. Selection will be adjusted according to the indentation
// change of the first block. // change of the first block.
virtual void reindent(const QTextCursor &cursor, const TabSettings &tabSettings) = 0; virtual void reindent(const QTextCursor &cursor, const TabSettings &tabSettings) = 0;

View File

@@ -422,9 +422,9 @@ void TextDocument::autoReindent(const QTextCursor &cursor)
d->m_indenter->reindent(cursor, tabSettings()); d->m_indenter->reindent(cursor, tabSettings());
} }
void TextDocument::autoFormat(const QTextCursor &cursor) void TextDocument::autoFormatOrIndent(const QTextCursor &cursor)
{ {
d->m_indenter->format(cursor, tabSettings()); d->m_indenter->formatOrIndent(cursor, tabSettings());
} }
QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column, QTextCursor TextDocument::indent(const QTextCursor &cursor, bool blockSelection, int column,

View File

@@ -89,7 +89,7 @@ public:
Indenter *indenter() const; Indenter *indenter() const;
void autoIndent(const QTextCursor &cursor, QChar typedChar = QChar::Null); void autoIndent(const QTextCursor &cursor, QChar typedChar = QChar::Null);
void autoReindent(const QTextCursor &cursor); void autoReindent(const QTextCursor &cursor);
void autoFormat(const QTextCursor &cursor); void autoFormatOrIndent(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);
QTextCursor unindent(const QTextCursor &cursor, bool blockSelection = false, int column = 0, QTextCursor unindent(const QTextCursor &cursor, bool blockSelection = false, int column = 0,

View File

@@ -7135,21 +7135,11 @@ void TextEditorWidget::setIfdefedOutBlocks(const QList<BlockRange> &blocks)
documentLayout->requestUpdate(); documentLayout->requestUpdate();
} }
static bool applyFormattingInsteadOfIndentation()
{
constexpr const char option[] = "QTC_FORMAT_INSTEAD_OF_INDENT";
return qEnvironmentVariableIsSet(option);
}
void TextEditorWidget::format() void TextEditorWidget::format()
{ {
static bool formattingInsteadOfIndentation = applyFormattingInsteadOfIndentation();
QTextCursor cursor = textCursor(); QTextCursor cursor = textCursor();
cursor.beginEditBlock(); cursor.beginEditBlock();
if (formattingInsteadOfIndentation) d->m_document->autoFormatOrIndent(cursor);
d->m_document->autoFormat(cursor);
else
d->m_document->autoIndent(cursor);
cursor.endEditBlock(); cursor.endEditBlock();
} }

View File

@@ -102,12 +102,6 @@ void TextIndenter::reindent(const QTextCursor &cursor, const TabSettings &tabSet
} }
} }
Replacements TextIndenter::format(const QTextCursor &cursor, const TabSettings &tabSettings)
{
indent(cursor, QChar::Null, tabSettings);
return Replacements();
}
Utils::optional<TabSettings> TextIndenter::tabSettings() const Utils::optional<TabSettings> TextIndenter::tabSettings() const
{ {
return Utils::optional<TabSettings>(); return Utils::optional<TabSettings>();

View File

@@ -54,7 +54,6 @@ public:
const QChar &typedChar, const QChar &typedChar,
const TabSettings &tabSettings) override; const TabSettings &tabSettings) override;
Replacements format(const QTextCursor &cursor, const TabSettings &tabSettings) override;
void reindent(const QTextCursor &cursor, const TabSettings &tabSettings) override; void reindent(const QTextCursor &cursor, const TabSettings &tabSettings) override;
Utils::optional<TabSettings> tabSettings() const override; Utils::optional<TabSettings> tabSettings() const override;