diff --git a/scripts/generateClangFormatChecksUI.py b/scripts/generateClangFormatChecksUI.py new file mode 100644 index 00000000000..0775dd96f69 --- /dev/null +++ b/scripts/generateClangFormatChecksUI.py @@ -0,0 +1,286 @@ +#!/usr/bin/env python +############################################################################ +# +# 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. +# +############################################################################ + +import argparse +import json +import os +import docutils.nodes +import docutils.parsers.rst +import docutils.utils + +def full_ui_content(checks): + return ''' + + ClangFormat::ClangFormatChecksWidget + + + + 450 + 16777215 + + + +''' + checks + ''' + + + + +''' + +def parse_arguments(): + parser = argparse.ArgumentParser(description='Clazy checks header file generator') + parser.add_argument('--clang-format-options-rst', help='path to ClangFormatStyleOptions.rst', + default=None, dest='options_rst') + return parser.parse_args() + +def parse_rst(text): + parser = docutils.parsers.rst.Parser() + components = (docutils.parsers.rst.Parser,) + settings = docutils.frontend.OptionParser(components=components).get_default_values() + document = docutils.utils.new_document('', settings=settings) + parser.parse(text, document) + return document + +def createItem(key, value, index): + label = ''' + + + ''' + key + ''' + + + +''' + value_item = '' + if value[0] == 'bool': + value_item = ''' + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + +''' + elif value[0].startswith('std::string') or value[0] == 'unsigned' or value[0] == 'int': + value_item = ''' + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + +''' + elif value[0].startswith('std::vector'): + value_item = ''' + + + + + + + + + 16777215 + 50 + + + + + + + + + 40 + 16777215 + + + + Set + + + + + +''' + else: + if ' ' in value[1]: + value_item = '' + for i, val in enumerate(value): + if i == 0: + continue + index += 1 + space_index = val.find(' ') + val = val[space_index + 1:] + value_item += ''' + + + ''' + val + ''' + + + +''' + value_item += ''' + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + +''' + else: + value_item = ''' + + + Qt::StrongFocus + +''' + if index > 0: + value_item += ''' + + Default + + +''' + for i, val in enumerate(value): + if i == 0: + continue + underline_index = val.find('_') + val = val[underline_index + 1:] + value_item += ''' + + ''' + val + ''' + + +''' + value_item += ''' + +''' + + return label + value_item, index + +class MyVisitor(docutils.nodes.NodeVisitor): + in_bullet_list = False + in_bullet_list_paragraph = False + tree = {} + last_key = '' + def visit_term(self, node): + node_values = node.traverse(condition=docutils.nodes.Text) + name = node_values[0].astext() + self.last_key = name + self.tree[name] = [node_values[2].astext()] + def visit_bullet_list(self, node): + self.in_bullet_list = True + def depart_bullet_list(self, node): + self.in_bullet_list = False + def visit_paragraph(self, node): + if self.in_bullet_list: + self.in_bullet_list_paragraph = True + def depart_paragraph(self, node): + self.in_bullet_list_paragraph = False + def visit_literal(self, node): + if self.in_bullet_list_paragraph: + value = node.traverse(condition=docutils.nodes.Text)[0].astext() + self.tree[self.last_key].append(value) + self.in_bullet_list_paragraph = False + def unknown_visit(self, node): + """Called for all other node types.""" + #print(node) + pass + def unknown_departure(self, node): + pass + +def main(): + arguments = parse_arguments() + + content = file(arguments.options_rst).read() + document = parse_rst(content) + visitor = MyVisitor(document) + document.walkabout(visitor) + keys = visitor.tree.keys() + basedOnStyleKey = 'BasedOnStyle' + keys.remove(basedOnStyleKey) + keys.sort() + + text = '' + line, index = createItem(basedOnStyleKey, visitor.tree[basedOnStyleKey], 0) + text += line + index = 1 + for key in keys: + line, index = createItem(key, visitor.tree[key], index) + text += line + index += 1 + + current_path = os.path.dirname(os.path.abspath(__file__)) + ui_path = os.path.abspath(os.path.join(current_path, '..', 'src', + 'plugins', 'clangformat', 'clangformatchecks.ui')) + with open(ui_path, 'w') as f: + f.write(full_ui_content(text)) + +if __name__ == "__main__": + main() diff --git a/src/plugins/clangformat/clangformat.pro b/src/plugins/clangformat/clangformat.pro index 665083e995a..e1ccdb98dc1 100644 --- a/src/plugins/clangformat/clangformat.pro +++ b/src/plugins/clangformat/clangformat.pro @@ -33,4 +33,5 @@ HEADERS += \ clangformatutils.h FORMS += \ + clangformatchecks.ui \ clangformatconfigwidget.ui diff --git a/src/plugins/clangformat/clangformatchecks.ui b/src/plugins/clangformat/clangformatchecks.ui new file mode 100644 index 00000000000..e12e69f240f --- /dev/null +++ b/src/plugins/clangformat/clangformatchecks.ui @@ -0,0 +1,3296 @@ + + + ClangFormat::ClangFormatChecksWidget + + + + 450 + 16777215 + + + + + + + BasedOnStyle + + + + + + + Qt::StrongFocus + + + + LLVM + + + + + Google + + + + + Chromium + + + + + Mozilla + + + + + WebKit + + + + + + + + AccessModifierOffset + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + AlignAfterOpenBracket + + + + + + + Qt::StrongFocus + + + + Default + + + + + Align + + + + + DontAlign + + + + + AlwaysBreak + + + + + + + + AlignConsecutiveAssignments + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AlignConsecutiveDeclarations + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AlignEscapedNewlines + + + + + + + Qt::StrongFocus + + + + Default + + + + + DontAlign + + + + + Left + + + + + Right + + + + + + + + AlignOperands + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AlignTrailingComments + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AllowAllParametersOfDeclarationOnNextLine + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AllowShortBlocksOnASingleLine + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AllowShortCaseLabelsOnASingleLine + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AllowShortFunctionsOnASingleLine + + + + + + + Qt::StrongFocus + + + + Default + + + + + None + + + + + InlineOnly + + + + + Empty + + + + + Inline + + + + + All + + + + + + + + AllowShortIfStatementsOnASingleLine + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AllowShortLoopsOnASingleLine + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AlwaysBreakAfterDefinitionReturnType + + + + + + + Qt::StrongFocus + + + + Default + + + + + None + + + + + All + + + + + TopLevel + + + + + + + + AlwaysBreakAfterReturnType + + + + + + + Qt::StrongFocus + + + + Default + + + + + None + + + + + All + + + + + TopLevel + + + + + AllDefinitions + + + + + TopLevelDefinitions + + + + + + + + AlwaysBreakBeforeMultilineStrings + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AlwaysBreakTemplateDeclarations + + + + + + + Qt::StrongFocus + + + + Default + + + + + No + + + + + MultiLine + + + + + Yes + + + + + + + + BinPackArguments + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + BinPackParameters + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + BraceWrapping + + + + + + + AfterClass + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AfterControlStatement + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AfterEnum + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AfterFunction + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AfterNamespace + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AfterObjCDeclaration + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AfterStruct + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AfterUnion + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + AfterExternBlock + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + BeforeCatch + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + BeforeElse + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + IndentBraces + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SplitEmptyFunction + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SplitEmptyRecord + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SplitEmptyNamespace + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + BreakAfterJavaFieldAnnotations + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + BreakBeforeBinaryOperators + + + + + + + Qt::StrongFocus + + + + Default + + + + + None + + + + + NonAssignment + + + + + All + + + + + + + + BreakBeforeBraces + + + + + + + Qt::StrongFocus + + + + Default + + + + + Attach + + + + + Linux + + + + + Mozilla + + + + + Stroustrup + + + + + Allman + + + + + GNU + + + + + WebKit + + + + + Custom + + + + + + + + BreakBeforeTernaryOperators + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + BreakConstructorInitializers + + + + + + + Qt::StrongFocus + + + + Default + + + + + BeforeColon + + + + + BeforeComma + + + + + AfterColon + + + + + + + + BreakInheritanceList + + + + + + + Qt::StrongFocus + + + + Default + + + + + BeforeColon + + + + + BeforeComma + + + + + AfterColon + + + + + + + + BreakStringLiterals + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + ColumnLimit + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + CommentPragmas + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + CompactNamespaces + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + ConstructorInitializerAllOnOneLineOrOnePerLine + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + ConstructorInitializerIndentWidth + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + ContinuationIndentWidth + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + Cpp11BracedListStyle + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + DerivePointerAlignment + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + DisableFormat + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + ExperimentalAutoDetectBinPacking + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + FixNamespaceComments + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + ForEachMacros + + + + + + + + + + + + + 16777215 + 50 + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + IncludeBlocks + + + + + + + Qt::StrongFocus + + + + Default + + + + + Preserve + + + + + Merge + + + + + Regroup + + + + + + + + IncludeCategories + + + + + + + + + + + + + 16777215 + 50 + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + IncludeIsMainRegex + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + IndentCaseLabels + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + IndentPPDirectives + + + + + + + Qt::StrongFocus + + + + Default + + + + + None + + + + + AfterHash + + + + + + + + IndentWidth + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + IndentWrappedFunctionNames + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + JavaImportGroups + + + + + + + + + + + + + 16777215 + 50 + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + JavaScriptQuotes + + + + + + + Qt::StrongFocus + + + + Default + + + + + Leave + + + + + Single + + + + + Double + + + + + + + + JavaScriptWrapImports + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + KeepEmptyLinesAtTheStartOfBlocks + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + Language + + + + + + + Qt::StrongFocus + + + + Default + + + + + None + + + + + Cpp + + + + + Java + + + + + JavaScript + + + + + ObjC + + + + + Proto + + + + + TableGen + + + + + TextProto + + + + + + + + MacroBlockBegin + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + MacroBlockEnd + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + MaxEmptyLinesToKeep + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + NamespaceIndentation + + + + + + + Qt::StrongFocus + + + + Default + + + + + None + + + + + Inner + + + + + All + + + + + + + + ObjCBinPackProtocolList + + + + + + + Qt::StrongFocus + + + + Default + + + + + Auto + + + + + Always + + + + + Never + + + + + + + + ObjCBlockIndentWidth + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + ObjCSpaceAfterProperty + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + ObjCSpaceBeforeProtocolList + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + PenaltyBreakAssignment + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + PenaltyBreakBeforeFirstCallParameter + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + PenaltyBreakComment + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + PenaltyBreakFirstLessLess + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + PenaltyBreakString + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + PenaltyBreakTemplateDeclaration + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + PenaltyExcessCharacter + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + PenaltyReturnTypeOnItsOwnLine + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + PointerAlignment + + + + + + + Qt::StrongFocus + + + + Default + + + + + Left + + + + + Right + + + + + Middle + + + + + + + + RawStringFormats + + + + + + + + + + + + + 16777215 + 50 + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + ReflowComments + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SortIncludes + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SortUsingDeclarations + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpaceAfterCStyleCast + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpaceAfterTemplateKeyword + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpaceBeforeAssignmentOperators + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpaceBeforeCpp11BracedList + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpaceBeforeCtorInitializerColon + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpaceBeforeInheritanceColon + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpaceBeforeParens + + + + + + + Qt::StrongFocus + + + + Default + + + + + Never + + + + + ControlStatements + + + + + Always + + + + + + + + SpaceBeforeRangeBasedForLoopColon + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpaceInEmptyParentheses + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpacesBeforeTrailingComments + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + SpacesInAngles + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpacesInCStyleCastParentheses + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpacesInContainerLiterals + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpacesInParentheses + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + SpacesInSquareBrackets + + + + + + + Qt::StrongFocus + + + + Default + + + + + true + + + + + false + + + + + + + + Standard + + + + + + + Qt::StrongFocus + + + + Default + + + + + Cpp03 + + + + + Cpp11 + + + + + Auto + + + + + + + + StatementMacros + + + + + + + + + + + + + 16777215 + 50 + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + TabWidth + + + + + + + + + + + + + + 40 + 16777215 + + + + Set + + + + + + + + + UseTab + + + + + + + Qt::StrongFocus + + + + Default + + + + + Never + + + + + ForIndentation + + + + + ForContinuationAndIndentation + + + + + Always + + + + + + + + + diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index 739b8ea06e1..2e903c63006 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -29,6 +29,7 @@ #include "clangformatindenter.h" #include "clangformatsettings.h" #include "clangformatutils.h" +#include "ui_clangformatchecks.h" #include "ui_clangformatconfigwidget.h" #include @@ -42,9 +43,11 @@ #include #include #include +#include #include #include +#include #include @@ -52,13 +55,47 @@ using namespace ProjectExplorer; namespace ClangFormat { +bool ClangFormatConfigWidget::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::Wheel && qobject_cast(object)) { + event->ignore(); + return true; + } + return QWidget::eventFilter(object, event); +} + ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *project, QWidget *parent) : CodeStyleEditorWidget(parent) , m_project(project) + , m_checks(std::make_unique()) , m_ui(std::make_unique()) { m_ui->setupUi(this); + QScrollArea *scrollArea = new QScrollArea(); + m_checksWidget = new QWidget(); + m_checks->setupUi(m_checksWidget); + scrollArea->setWidget(m_checksWidget); + scrollArea->setMaximumWidth(470); + + m_ui->horizontalLayout_2->addWidget(scrollArea); + + for (QObject *child : m_checksWidget->children()) { + auto comboBox = qobject_cast(child); + if (comboBox != nullptr) { + connect(comboBox, + QOverload::of(&QComboBox::currentIndexChanged), + this, + &ClangFormatConfigWidget::onTableChanged); + comboBox->installEventFilter(this); + continue; + } + + auto button = qobject_cast(child); + if (button != nullptr) + connect(button, &QPushButton::clicked, this, &ClangFormatConfigWidget::onTableChanged); + } + m_preview = new TextEditor::SnippetEditorWidget(this); m_ui->horizontalLayout_2->addWidget(m_preview); if (m_project) { @@ -83,6 +120,19 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje initialize(); } +void ClangFormatConfigWidget::onTableChanged() +{ + const std::string newConfig = tableToString(sender()); + if (newConfig.empty()) + return; + clang::format::FormatStyle style = m_project ? currentProjectStyle() : currentGlobalStyle(); + const std::string oldConfig = clang::format::configurationAsText(style); + saveConfig(newConfig); + fillTable(); + updatePreview(); + saveConfig(oldConfig); +} + void ClangFormatConfigWidget::hideGlobalCheckboxes() { m_ui->formatAlways->hide(); @@ -130,13 +180,13 @@ void ClangFormatConfigWidget::initialize() if (!m_ui->overrideDefault->isChecked() && m_project) { // Show the fallback configuration only globally. - m_ui->clangFormatOptionsTable->hide(); + m_checksWidget->hide(); m_preview->hide(); m_ui->verticalLayout->addStretch(1); return; } - m_ui->clangFormatOptionsTable->show(); + m_checksWidget->show(); m_preview->show(); Utils::FileName fileName; @@ -171,12 +221,152 @@ void ClangFormatConfigWidget::updatePreview() m_preview->textDocument()->autoFormatOrIndent(cursor); } +static inline void ltrim(std::string &s) +{ + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); +} + +static inline void rtrim(std::string &s) +{ + s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), + s.end()); +} + +static inline void trim(std::string &s) +{ + ltrim(s); + rtrim(s); +} + void ClangFormatConfigWidget::fillTable() { clang::format::FormatStyle style = m_project ? currentProjectStyle() : currentGlobalStyle(); - const std::string configText = clang::format::configurationAsText(style); - m_ui->clangFormatOptionsTable->setPlainText(QString::fromStdString(configText)); + using namespace std; + const string configText = clang::format::configurationAsText(style); + + for (QObject *child : m_checksWidget->children()) { + if (!qobject_cast(child) && !qobject_cast(child) + && !qobject_cast(child)) { + continue; + } + + const size_t index = configText.find(child->objectName().toStdString()); + + auto *plainText = qobject_cast(child); + if (plainText) { + if (index == string::npos) { + plainText->setPlainText(""); + continue; + } + size_t valueStart = configText.find('\n', index); + size_t valueEnd; + string value; + QTC_ASSERT(valueStart != string::npos, continue;); + do { + valueEnd = configText.find('\n', valueStart + 1); + if (valueEnd == string::npos) + break; + // Skip also 2 spaces - start with valueStart + 1 + 2. + string line = configText.substr(valueStart + 3, valueEnd - valueStart - 3); + rtrim(line); + value += value.empty() ? line : '\n' + line; + valueStart = valueEnd; + } while (valueEnd < configText.size() - 1 && configText.at(valueEnd + 1) == ' '); + plainText->setPlainText(QString::fromStdString(value)); + } else { + auto *comboBox = qobject_cast(child); + auto *lineEdit = qobject_cast(child); + if (index == string::npos) { + if (comboBox) + comboBox->setCurrentIndex(0); + else + lineEdit->setText(""); + continue; + } + + const size_t valueStart = configText.find(':', index); + QTC_ASSERT(valueStart != string::npos, continue;); + const size_t valueEnd = configText.find('\n', valueStart + 1); + QTC_ASSERT(valueEnd != string::npos, continue;); + string value = configText.substr(valueStart + 1, valueEnd - valueStart - 1); + trim(value); + + if (comboBox) + comboBox->setCurrentText(QString::fromStdString(value)); + else + lineEdit->setText(QString::fromStdString(value)); + } + } +} + +std::string ClangFormatConfigWidget::tableToString(QObject *sender) +{ + std::stringstream content; + content << "---"; + + if (sender->objectName() == "BasedOnStyle") { + auto *basedOnStyle = m_checksWidget->findChild("BasedOnStyle"); + content << "\nBasedOnStyle: " << basedOnStyle->currentText().toStdString() << '\n'; + } else { + for (QObject *child : m_checksWidget->children()) { + auto *label = qobject_cast(child); + if (!label) + continue; + + QWidget *valueWidget = m_checksWidget->findChild(label->text().trimmed()); + if (!valueWidget) { + // Currently BraceWrapping only. + content << '\n' << label->text().toStdString() << ":"; + continue; + } + + if (!qobject_cast(valueWidget) && !qobject_cast(valueWidget) + && !qobject_cast(valueWidget)) { + continue; + } + + auto *plainText = qobject_cast(valueWidget); + if (plainText) { + if (plainText->toPlainText().trimmed().isEmpty()) + continue; + + content << '\n' << label->text().toStdString() << ":"; + QStringList list = plainText->toPlainText().split('\n'); + for (const QString &line : list) + content << "\n " << line.toStdString(); + } else { + auto *comboBox = qobject_cast(valueWidget); + std::string text; + if (comboBox) { + text = comboBox->currentText().toStdString(); + } else { + auto *lineEdit = qobject_cast(valueWidget); + QTC_ASSERT(lineEdit, continue;); + text = lineEdit->text().toStdString(); + } + + if (!text.empty() && text != "Default") + content << '\n' << label->text().toStdString() << ": " << text; + } + } + content << '\n'; + } + + std::string text = content.str(); + clang::format::FormatStyle style; + style.Language = clang::format::FormatStyle::LK_Cpp; + const std::error_code error = clang::format::parseConfiguration(text, &style); + if (error.value() != static_cast(clang::format::ParseError::Success)) { + QMessageBox::warning(this, + tr("Error in ClangFormat configuration"), + QString::fromStdString(error.message())); + fillTable(); + updatePreview(); + return std::string(); + } + + return text; } ClangFormatConfigWidget::~ClangFormatConfigWidget() = default; @@ -194,24 +384,20 @@ void ClangFormatConfigWidget::apply() } settings.write(); - if (!m_ui->clangFormatOptionsTable->isVisible()) + if (!m_checksWidget->isVisible()) return; - const QString text = m_ui->clangFormatOptionsTable->toPlainText(); - clang::format::FormatStyle style; - style.Language = clang::format::FormatStyle::LK_Cpp; - const std::error_code error = clang::format::parseConfiguration(text.toStdString(), &style); - if (error.value() != static_cast(clang::format::ParseError::Success)) { - QMessageBox::warning(this, - tr("Error in ClangFormat configuration"), - QString::fromStdString(error.message())); - if (m_ui->overrideDefault->isChecked()) { - fillTable(); - updatePreview(); - } + const std::string config = tableToString(this); + if (config.empty()) return; - } + saveConfig(config); + fillTable(); + updatePreview(); +} + +void ClangFormatConfigWidget::saveConfig(const std::string &text) const +{ QString filePath = Core::ICore::userResourcePath(); if (m_project) filePath += "/clang-format/" + currentProjectUniqueId(); @@ -221,11 +407,8 @@ void ClangFormatConfigWidget::apply() if (!file.open(QFile::WriteOnly)) return; - file.write(text.toUtf8()); + file.write(text.c_str()); file.close(); - - if (m_ui->overrideDefault->isChecked()) - updatePreview(); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatconfigwidget.h b/src/plugins/clangformat/clangformatconfigwidget.h index 58570d9bf68..01812debcc0 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.h +++ b/src/plugins/clangformat/clangformatconfigwidget.h @@ -40,6 +40,7 @@ namespace ClangFormat { namespace Ui { class ClangFormatConfigWidget; +class ClangFormatChecksWidget; } class ClangFormatConfigWidget : public TextEditor::CodeStyleEditorWidget @@ -53,16 +54,24 @@ public: void apply() override; private: + void onTableChanged(); + + bool eventFilter(QObject *object, QEvent *event) override; + void initialize(); void fillTable(); + std::string tableToString(QObject *sender); void hideGlobalCheckboxes(); void showGlobalCheckboxes(); + void saveConfig(const std::string &text) const; void updatePreview(); ProjectExplorer::Project *m_project; + QWidget *m_checksWidget; TextEditor::SnippetEditorWidget *m_preview; + std::unique_ptr m_checks; std::unique_ptr m_ui; }; diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui index cc7dbd45c9b..d9126a4c269 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.ui +++ b/src/plugins/clangformat/clangformatconfigwidget.ui @@ -70,9 +70,6 @@ - - -