Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Tap House Rules — the Tap family house style. Copy verbatim into every *Tap repo.
# 4-space indent (incl. namespaces), aligned declaration/assignment columns,
# attached braces (else/catch break), comma-first ctor initializers,
# left-bound pointers, 120-column limit. Layout only — naming and mandatory
# braces are enforced separately by .clang-tidy (clang-format cannot check
# identifier names, and its brace insertion is not semantically aware).
Language: Cpp
BasedOnStyle: LLVM
Standard: c++20

ColumnLimit: 120
IndentWidth: 4
AccessModifierOffset: -2
NamespaceIndentation: All

PointerAlignment: Left
DerivePointerAlignment: false
BreakBeforeBinaryOperators: NonAssignment
SpaceBeforeCpp11BracedList: false
AlwaysBreakTemplateDeclarations: Yes

# Braces attach everywhere (including functions); only else/catch break.
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: false
AfterClass: false
AfterStruct: false
AfterNamespace: false
AfterControlStatement: Never
BeforeElse: true
BeforeCatch: true
BreakConstructorInitializers: BeforeComma
PackConstructorInitializers: Never

AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignTrailingComments: true

# Short accessor functions and lambdas may stay inline, but control-flow
# statements never do: every if/for/while is braced AND expanded (see
# .clang-tidy readability-braces-around-statements).
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never

BreakStringLiterals: false
KeepEmptyLinesAtTheStartOfBlocks: false
InsertNewlineAtEOF: true

# Include ordering: main header (auto, priority 0) -> C++ standard ->
# third-party -> this project. Regroup enforces it; blank lines between groups.
SortIncludes: CaseSensitive
IncludeBlocks: Regroup
IncludeCategories:
# C++ standard library: <angle> with no '/' and no '.' (e.g. <vector>)
- Regex: '^<[[:alnum:]_]+>$'
Priority: 2
# Other angle-bracket headers (third-party, e.g. <gtest/gtest.h>)
- Regex: '^<.*>$'
Priority: 3
# This project: quoted includes
- Regex: '^".*"$'
Priority: 4

# Min-DevKit declarative DSL (Max/Min externals: TapTools, AmbiTap-Max, ...).
# MIN_FUNCTION / MIN_ARGUMENT_FUNCTION expand to a lambda; teach clang-format
# their shape so attribute/message/argument setter bodies format as lambda
# blocks instead of being shredded. Completely inert for repos that don't use
# these macros (the pure-C++ libraries). Requires clang-format >= 15.
Macros:
- 'MIN_FUNCTION=[](const atoms& args, int inlet) -> atoms'
- 'MIN_ARGUMENT_FUNCTION=[](const atom& arg, int index) -> void'
132 changes: 132 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Tap House Rules — naming + mandatory-braces enforcement. Copy verbatim into
# every *Tap repo. This is what actually checks m_ members, k_ constants, snake_case
# types/functions, PascalCase template parameters, and braces around every
# control-flow body — clang-format cannot (and its InsertBraces is not
# semantically aware). Scope is intentionally limited to these for now;
# correctness/modernize checks can be layered on later.
#
# NOTE: WarningsAsErrors is intentionally NOT set here so local runs only warn.
# CI passes --warnings-as-errors=readability-* to make the gate blocking.
Checks: >
-*,
readability-identifier-naming,
readability-braces-around-statements
# Analyze this project's own headers only (under include/); vendored third_party
# and fetched deps live outside include/ and are excluded. Generated tables
# (room_data.h, hrtf_data.h, tdesigns.h) live under include/ but carry
# // NOLINTBEGIN(readability-identifier-naming) markers from their generators.
# NOTE: clang-tidy uses llvm::Regex, which has NO negative lookahead — a
# '^(?!...)' pattern silently matches nothing and disables the check.
HeaderFilterRegex: '.*/(include|tests)/.*'

# --- Linear-algebra notation carve-out --------------------------------------
# The DSP math deliberately uses capitalized matrix/vector symbols (Y = SH
# matrix, D = decoder, R = rotation, ...). Permit a leading-capital symbol with
# an optional short subscript and _snake suffixes (Y, Yd, R9, Y_virtual). This
# Also matrix products (DtD, YtD). Still rejects camelCase (frameCount).
# Applied below per category via <Category>IgnoredRegexp.
CheckOptions:
# --- Types: snake_case ---
- key: readability-identifier-naming.ClassCase
value: lower_case
- key: readability-identifier-naming.StructCase
value: lower_case
- key: readability-identifier-naming.UnionCase
value: lower_case
- key: readability-identifier-naming.EnumCase
value: lower_case
- key: readability-identifier-naming.EnumConstantCase
value: lower_case
- key: readability-identifier-naming.ScopedEnumConstantCase
value: lower_case
- key: readability-identifier-naming.TypeAliasCase
value: lower_case
- key: readability-identifier-naming.TypedefCase
value: lower_case
- key: readability-identifier-naming.NamespaceCase
value: lower_case

# --- Concepts: snake_case (like the types they constrain, per P1754) ---
- key: readability-identifier-naming.ConceptCase
value: lower_case

# --- Functions / methods: snake_case ---
- key: readability-identifier-naming.FunctionCase
value: lower_case
- key: readability-identifier-naming.MethodCase
value: lower_case

# --- Variables / parameters / locals: snake_case, no prefix ---
- key: readability-identifier-naming.VariableCase
value: lower_case
- key: readability-identifier-naming.ParameterCase
value: lower_case
- key: readability-identifier-naming.LocalVariableCase
value: lower_case
- key: readability-identifier-naming.LocalConstantCase
value: lower_case
# Math-notation carve-out (see header): capitalized matrix/vector symbols.
- key: readability-identifier-naming.ParameterIgnoredRegexp
value: '^[A-Z][A-Za-z0-9]*(_[A-Za-z0-9]+)*$'
- key: readability-identifier-naming.LocalVariableIgnoredRegexp
value: '^[A-Z][A-Za-z0-9]*(_[A-Za-z0-9]+)*$'
- key: readability-identifier-naming.LocalConstantIgnoredRegexp
value: '^[A-Z][A-Za-z0-9]*(_[A-Za-z0-9]+)*$'
- key: readability-identifier-naming.VariableIgnoredRegexp
value: '^[A-Z][A-Za-z0-9]*(_[A-Za-z0-9]+)*$'

# --- Data members: private/protected get m_; public struct fields bare ---
- key: readability-identifier-naming.PrivateMemberCase
value: lower_case
- key: readability-identifier-naming.PrivateMemberPrefix
value: 'm_'
- key: readability-identifier-naming.ProtectedMemberCase
value: lower_case
- key: readability-identifier-naming.ProtectedMemberPrefix
value: 'm_'
- key: readability-identifier-naming.PublicMemberCase
value: lower_case
# const (non-static) data members are still members -> keep the m_ marker
- key: readability-identifier-naming.ConstantMemberCase
value: lower_case
- key: readability-identifier-naming.ConstantMemberPrefix
value: 'm_'
# Math-notation carve-out for capitalized matrix/vector member symbols.
- key: readability-identifier-naming.PublicMemberIgnoredRegexp
value: '^[A-Z][A-Za-z0-9]*(_[A-Za-z0-9]+)*$'
- key: readability-identifier-naming.PrivateMemberIgnoredRegexp
value: '^[A-Z][A-Za-z0-9]*(_[A-Za-z0-9]+)*$'
- key: readability-identifier-naming.ProtectedMemberIgnoredRegexp
value: '^[A-Z][A-Za-z0-9]*(_[A-Za-z0-9]+)*$'

# --- Constants at namespace/class/static scope: k_ + snake_case ---
# (constexpr/const LOCALS stay bare via LocalConstantCase above)
- key: readability-identifier-naming.GlobalConstantCase
value: lower_case
- key: readability-identifier-naming.GlobalConstantPrefix
value: 'k_'
- key: readability-identifier-naming.ClassConstantCase
value: lower_case
- key: readability-identifier-naming.ClassConstantPrefix
value: 'k_'
- key: readability-identifier-naming.StaticConstantCase
value: lower_case
- key: readability-identifier-naming.StaticConstantPrefix
value: 'k_'

# --- Template parameters: PascalCase (the ONLY leading-capital names) ---
# Applies to type AND non-type params: template <int Order>, not <int order>.
- key: readability-identifier-naming.TemplateParameterCase
value: CamelCase
- key: readability-identifier-naming.TypeTemplateParameterCase
value: CamelCase
- key: readability-identifier-naming.ValueTemplateParameterCase
value: CamelCase

# --- Macros: ALL_CAPS ---
- key: readability-identifier-naming.MacroDefinitionCase
value: UPPER_CASE

# --- Mandatory braces: brace every control-flow body, even one-liners ---
- key: readability-braces-around-statements.ShortStatementLines
value: '0'
56 changes: 56 additions & 0 deletions .github/workflows/style.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Tap House Style

# Enforces the shared Tap House Rules: (1) a drift check against the canonical
# TapHouse configs, (2) a clang-format layout check, and (3) clang-tidy naming +
# mandatory-braces over the external's own translation units.
#
# All three run on Linux with the same clang-tidy-18 as the rest of the family.
# tap.python~ only *configures* (via CMake) with the bundled Python runtime,
# which installs on macOS/Windows only — but linting just needs headers, so the
# clang-tidy step compiles the TUs directly against min-api and the system
# Python headers instead of a compile database. (Running the lint on macOS
# instead means fighting the SDK's libc++ against a standalone clang-tidy.)
on: [push, pull_request]

jobs:
drift:
uses: tap/taphouse/.github/workflows/drift-check.yml@v4
with:
ref: v4

clang-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install clang-format
run: sudo apt-get update -q && sudo apt-get install -y -q clang-format-18
- name: clang-format check (own sources)
run: clang-format-18 --dry-run --Werror $(git ls-files 'source/projects/*.cpp' 'source/projects/*.h')

clang-tidy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install tools
run: sudo apt-get update -q && sudo apt-get install -y -q clang-tidy-18 python3-dev
- name: clang-tidy (this object's own TUs; min-api, CPython, deps excluded)
run: |
d=source/projects/tap.python_tilde
msdk=source/min-api/max-sdk-base/c74support
pyinc=$(python3 -c "import sysconfig; print(sysconfig.get_path('include'))")
inc="-Isource/min-api/include -I$msdk -I$msdk/max-includes -I$msdk/msp-includes -I$msdk/jit-includes -I$pyinc -I$d"
# Scope diagnostics to this object's own headers: a path filter over
# source/projects would also match the bundled CPython headers, which
# are reached via …/tap.python_tilde/../../../support/… .
hf='.*/tap\.python_tilde/tap\.python_tilde.*'
fail=0
check() { # <file> <extra compile args…>
local f="$1"; shift
out=$(clang-tidy-18 -header-filter="$hf" --warnings-as-errors='readability-*' "$f" -- -std=c++17 $inc "$@" 2>/dev/null || true)
if echo "$out" | grep -qE "warning:|error:"; then echo "$out"; fail=1; fi
}
check "$d/tap.python_tilde.cpp" -DC74_MIN_API
check "$d/tap.python_tilde_test.cpp" -DC74_MIN_API -DMIN_TEST -Isource/min-api/test -DCATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS
[ "$fail" -eq 0 ] && echo "clang-tidy clean." || { echo "::error::clang-tidy found violations"; exit 1; }
23 changes: 23 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Canonical Tap House pre-commit config — the single source of truth for the
# Tap family's local formatting hook. Distributed to every Tap repo by
# scripts/sync.sh (alongside .clang-format / .clang-tidy / STYLE.md) and kept
# honest by the drift-check workflow, so every repo runs the SAME hook at the
# SAME pinned clang-format version.
#
# Why the pin matters: an ad-hoc hook using each machine's own clang-format
# would format differently than CI and be worse than none. The `rev` below is
# the Tap-wide clang-format version — bump it HERE, re-sync, and every repo
# (and its CI, which runs `pre-commit run --all-files`) moves together.
#
# Adopt in a consumer repo:
# 1. taphouse/scripts/sync.sh /path/to/your-repo # copies this file in
# 2. cd your-repo && pre-commit install # once per clone
# Thereafter `git commit` formats staged C/C++ before it can be pushed, so the
# clang-format CI gate can never fail on a local commit again.
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.3 # Tap-wide clang-format version (matches CI)
hooks:
- id: clang-format
types_or: [c, c++]
exclude: '^third_party/' # vendored sources are formatted upstream, never by us
Loading
Loading