diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..6eee8ee8f9 --- /dev/null +++ b/.clang-format @@ -0,0 +1,251 @@ +# This is the clang-format configuration style to be used by QLCplus, +# based on the rules from https://wiki.qt.io/Qt_Coding_Style and +# https://wiki.qt.io/Coding_Conventions + +--- +Language: Cpp +AccessModifierOffset: -4 + +# Horizontally align arguments after an open bracket. +# The coding style does not specify the following, but this is what gives +# results closest to the existing code. +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Right +AlignConsecutiveMacros: AcrossComments +AlignConsecutiveAssignments: AcrossComments +AlignConsecutiveBitFields: AcrossComments +AlignConsecutiveDeclarations: AcrossComments + +# When escaping newlines in a macro attach the '\' as far left as possible, e.g. +##define a \ +# something; \ +# other; \ +# thelastlineislong; +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false + +AlwaysBreakTemplateDeclarations: MultiLine + +AttributeMacros: + - __capability + - __attribute +BinPackArguments: true +BinPackParameters: true + +# Braces are usually on a new line +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: Never + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true + +# We want to break before the operators, but not before a '='. +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true + +# Break constructor initializers before the colon and after the commas. +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +# Column width is limited to 120 characters as used in the QLCplus code +# https://wiki.qt.io/Qt_Coding_Style defines a limit of 100. +ColumnLimit: 100 + +# Disable reflow of some specific comments +# qdoc comments: indentation rules are different. +# Translation comments and SPDX license identifiers are also excluded. +CommentPragmas: "^!|^:|^ SPDX-License-Identifier:|^ IWYU pragma:" +QualifierAlignment: Leave +CompactNamespaces: false + +# Indent initializers by 4 spaces +ConstructorInitializerIndentWidth: 4 +# Indent width for line continuations. +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' + +# Put constructor initializers each on a new line. +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true + +# Add "// namespace " comments on closing brace for a namespace +# Ignored for namespaces that qualify as a short namespace, +# see 'ShortNamespaceLines' +FixNamespaceComments: true + +# macros for which the opening brace stays attached. +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH + - forever + - Q_FOREVER + - QBENCHMARK + - QBENCHMARK_ONCE +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: true +IndentCaseBlocks: false +IndentGotoLabels: false +IndentPPDirectives: BeforeHash +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +# No indentation for namespaces. +NamespaceIndentation: None + +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 4 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 + +# We want a space between the type and the star for pointer types. +PointerAlignment: Right +PPIndentWidth: 2 +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 + +# The QT coding style specifies some include order categories, but also tells to +# separate categories with an empty line. It does not specify the order within +# the categories. Since the SortInclude feature of clang-format does not +# re-order includes separated by empty lines, the feature is not used. +SortIncludes: Never +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false + +# We use template< without space. +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false + +# Avoids the addition of a space between an identifier and the +# initializer list in list-initialization. +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both + +Standard: Latest + +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/.clang-format-js b/.clang-format-js new file mode 100644 index 0000000000..54f70294d8 --- /dev/null +++ b/.clang-format-js @@ -0,0 +1,191 @@ +--- +Language: JavaScript +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Linux +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 0 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: true +IndentGotoLabels: false +IndentPPDirectives: BeforeHash +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: 2 +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: Never +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 2 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6192f27dfd..416394ed70 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,6 +32,7 @@ jobs: libxml2-utils xvfb ccache + clang-format-14 wget PACKAGES_QML_BASE: libpulse-dev @@ -100,6 +101,13 @@ jobs: echo "QT: ${QT}" echo "NPROC: ${NPROC}" + - name: Register clang-format apt repository + uses: myci-actions/add-deb-repo@11 + with: + repo: deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main + repo-name: apt.llvm.org + keys-asc: https://apt.llvm.org/llvm-snapshot.gpg.key + - name: Download, cache and install packages uses: awalsh128/cache-apt-pkgs-action@latest with: diff --git a/indentation.sh b/indentation.sh new file mode 100755 index 0000000000..0c954f3374 --- /dev/null +++ b/indentation.sh @@ -0,0 +1,188 @@ +#!/bin/bash + +THISCMD=`basename "$0"` +THISDIR=`dirname "$0"` +DIFFARG="-q" +CHECK_MODE="yes" +INDENT_MODE="no" +CLANG_FORMAT=clang-format-14 + +TARGET="qmlui" +MODE="default" + +cd "$THISDIR" + +usage() { + echo >&2 "$THISCMD [options] [indentPathOrFile ...]" + echo >&2 "-c|--check Script mode: check (default)" + echo >&2 "-h|--help Print this help message" + echo >&2 "-i|--indent Script mode: indent" + echo >&2 "-t|--target target Build Target (qmlui|ui) default: qmlui" + echo >&2 "-u|--unify Add unified diff output" +} + +if [ -z `which "$CLANG_FORMAT"` ]; then + echo >&2 "$CLANG_FORMAT: Error: Program not found." + exit 1 +fi + +ERRORS=0 +SEARCHPATH=() +while [[ $# -gt 0 ]]; do + case "$1" in + -t|--target) + TARGET="$2" + case "$TARGET" in + ui|qmlui) + ;; + *) + echo "Unknown target option $2" + ERRORS=1 + ;; + esac + shift # past argument + shift # past value + ;; + -i|--indent) + MODE="indent" + INDENT_MODE="yes" + shift # past argument + ;; + -c|--check) + MODE="check" + CHECK_MODE="yes" + shift # past argument + ;; + -u|--unified) + DIFFARG="-u" + shift # past argument + ;; + -h|--help) + usage + exit 0 + ;; + -*|--*) + echo "Unknown option $1" + shift # past argument + ERRORS=1 + ;; + *) + if [ -r "$1" ]; then + SEARCHPATH+=("$1") + else + echo >&2 "File or directory not readable: $1" + ERRORS=1 + fi + shift # past argument + ;; + esac +done + +if [ $ERRORS -ne 0 ]; then + exit $ERRORS +fi + +# Fall back to check mode if no mode is set +if [ $MODE == "default" ]; then + CHECK_MODE="yes" +fi + +if [ ${#SEARCHPATH[@]} -eq 0 ]; then + ### Excluded directories + # plugins \ + # fixtureeditor \ + # hotplugmonitor \ + + # Common directories + SEARCHPATH+=("engine") + SEARCHPATH+=("launcher") + SEARCHPATH+=("resources/rgbscripts") + + if [ "$TARGET" == "ui"]; then + SEARCHPATH+=("ui") + SEARCHPATH+=("webaccess") + else + # fallback to add qmlui directories (default mode) + SEARCHPATH+=("qmlui") + fi +fi + +TMPFILE=`mktemp /tmp/$THISCMD.XXXXXXXX` +if [ ! -f "$TMPFILE" ]; then + echo >&2 "Unable to create temporary file." + exit 1 +fi + +echo >&2 "Processed paths:" +for i in ${SEARCHPATH[@]}; do + echo >&2 " $i" +done + +############################################################################# +# Indentation application +############################################################################# + +if [ "$INDENT_MODE" == "yes" ]; then + # CPP code indentation + find \ + ${SEARCHPATH[@]} \ + -name '*.h' -and -not -name 'moc_*' -and -not -name 'ui_*' -and -not -name 'qlcconfig.h' -or \ + -name '*.cpp' -and -not -name 'moc_*' -and -not -name 'qrc_*' | while read FILE; do + $CLANG_FORMAT -i -style=file:.clang-format "$FILE" + done + + # JS code indentation + find \ + ${SEARCHPATH[@]} \ + -name '*.js' | while read FILE; do + $CLANG_FORMAT -i -style=file:.clang-format-js "$FILE" + done +fi + +############################################################################# +# Indentation check +############################################################################# + +if [ "$CHECK_MODE" == "yes" ]; then + # CPP code indentation check + find \ + ${SEARCHPATH[@]} \ + -name '*.h' -and -not -name 'moc_*' -and -not -name 'ui_*' -and -not -name 'qlcconfig.h' -or \ + -name '*.cpp' -and -not -name 'moc_*' -and -not -name 'qrc_*' | while read FILE; do + $CLANG_FORMAT -style=file:.clang-format "$FILE" | diff $DIFFARG "$FILE" - + RET=$? + if [ $RET -ne 0 ]; then + #echo >&2 "$FILE: Error in formatting." + echo " $FILE" >> "$TMPFILE" + #else + #echo >&2 "$FILE: Formatting OK" + fi + done + + # JS code indentation check + find \ + ${SEARCHPATH[@]} \ + -name '*.js' | while read FILE; do + $CLANG_FORMAT -style=file:.clang-format-js "$FILE" | diff $DIFFARG "$FILE" - + RET=$? + if [ $RET -ne 0 ]; then + #echo >&2 "$FILE: Error in formatting." + echo " $FILE" >> "$TMPFILE" + #else + #echo >&2 "$FILE: Formatting OK" + fi + done +fi + +ERRCODE=0 +if [ -s "$TMPFILE" ]; then + echo >&2 + echo >&2 "Error in formatting. Run:" + echo >&2 " $THISCMD -i " + echo >&2 "on following files:" + cat "$TMPFILE" + ERRCODE=1 +fi +rm "$TMPFILE" +exit $ERRCODE + diff --git a/unittest.sh b/unittest.sh index 55c724e791..7e63c4b68b 100755 --- a/unittest.sh +++ b/unittest.sh @@ -5,9 +5,12 @@ TESTPREFIX="" SLEEPCMD="" RUN_UI_TESTS="0" THISCMD=`basename "$0"` +THISDIR=`dirname "$0"` TARGET=${1:-} +cd "$THISDIR" + if [ "$TARGET" != "ui" ] && [ "$TARGET" != "qmlui" ]; then echo >&2 "Usage: $THISCMD ui|qmlui" exit 1 @@ -45,6 +48,13 @@ else fi fi +############################################################################# +# Indentation check +############################################################################# + +# TODO: Enable (globally or for selected directories) after applied indentation +#./indentation.sh --check --target "$TARGET" || exit $? + ############################################################################# # Fixture definitions check with xmllint #############################################################################