Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
46 changes: 46 additions & 0 deletions .agents/skills/code_style/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: code_style
description: Gkeyll's C/C++/CUDA code style is enforced by clang-format. Use when writing or editing any .c/.h/.cpp/.hpp/.cu/.cuh file, to know how to format it and which files must never be reformatted.
user-invocable: true
---

# Instructions

* Operate relative to the repo root (detect via `git rev-parse --show-toplevel`).

# Code style

The style itself (indentation, brace placement, spacing, etc.) is defined entirely
by the root `.clang-format` file. Don't try to memorize or restate those rules --
just run the formatter and let it decide:

```
clang-format -i <file>
```

A `pre-commit` hook runs this automatically on commit, and CI (`.github/workflows/format-check.yml`)
double-checks on push/PR, so a file that hasn't been run through clang-format will
get reformatted or flagged regardless.

## The rules the config file can't express: never format `ker/` or `core/minus/`

Two kinds of files must never be run through clang-format, and never hand-formatted
to "match" the style either -- leave them exactly as they are:

- Any path matching `*/ker/*` (e.g. `core/ker/`, `gyrokinetic/ker/`) contains
auto-generated DG kernel code (see `gkeyll_guide`'s note on `ker/`: generated with
Maxima, never hand-edited).
- Anything under `core/minus/` is a vendored third-party library (e.g. sqlite3,
kann, pcg_basic, STC), not Gkeyll's own code.

The pre-commit hook and CI already exclude both for this reason.

## Trailing commas in initializer lists are stripped automatically

Don't add a trailing comma after the last element of a struct/array
initializer expecting it to force (or preserve) a multi-line layout --
clang-format expands every element onto its own line whenever one is
present, which is rarely what's wanted. `ci/strip-trailing-commas.py` removes
any comma directly before a closing `}` before clang-format runs, via the
same pre-commit hook and CI check as clang-format itself, so there's also no
need to manually remove existing ones -- the tooling already does it.
124 changes: 124 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Gkeyll code style (EXPERIMENTAL): the actual Linux kernel .clang-format
# (as shipped at the root of torvalds/linux), with every place it hard-codes
# the kernel's 8-character-wide indentation changed to 2 (spaces, not tabs).
# The upstream file's ForEachMacros list is dropped -- it enumerates Linux
# kernel internal iteration macros (bpf_*, drm_*, hlist_*, etc.) that don't
# exist in gkeyll, so keeping it would only add clutter with no effect.
#
# Applies to C/C++/CUDA source under core/, moments/, vlasov/, gyrokinetic/,
# pkpm/, gkeyll/ -- EXCLUDING anything under */ker/* (auto-generated DG kernel
# code) or core/minus/* (vendored third-party libraries), which must never be
# hand-formatted (see .agents/skills/code_style/SKILL.md). These exclusions
# are enforced by the tooling (pre-commit, CI, ci/format-all.sh), not by this
# file, since clang-format configs can't express path excludes.
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: BlockIndent
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
InsertBraces : true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true

# Taken from git's rules (as in the upstream kernel .clang-format)
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60

PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 2
UseTab: Never
AttributeMacros:
- GKYL_CU_DH
- GKYL_CU_D
1 change: 1 addition & 0 deletions .claude/skills/code_style
1 change: 1 addition & 0 deletions .codex/skills/code_style
24 changes: 24 additions & 0 deletions .github/workflows/format-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Format Check

on:
push:
branches: [main]
pull_request:
branches: [main]
types: [opened, synchronize, reopened, ready_for_review]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
clang-format:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- uses: pre-commit/action@v3.0.1
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
repos:
- repo: local
hooks:
- id: strip-trailing-commas
name: Strip trailing commas before closing braces
entry: python3 ci/strip-trailing-commas.py
language: system
files: \.(c|h|cpp|hpp|cu|cuh)$
exclude: (^|/)ker/|^core/minus/
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.8
hooks:
- id: clang-format
files: \.(c|h|cpp|hpp|cu|cuh)$
exclude: (^|/)ker/|^core/minus/
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,3 +380,52 @@ srun -N 1 --ntasks=2 --gpus-per-task=1 --gpu-bind=closest compute-sanitizer --to
```

where the command line arguments must at least contain `-g -M -direction 2` with `direction` being the direction along which the domain is decomposed, e.g. `-e 2` for 3x2v gk simulations.

## Code style

C/C++/CUDA source is formatted by [clang-format](https://clang.llvm.org/docs/ClangFormat.html)
using the style defined in the root `.clang-format` (a Linux-kernel-flavored style with
2-space indentation). Two things are excluded and must never be hand-formatted: files
under any `*/ker/*` directory (auto-generated DG kernel code) and anything under
`core/minus/` (third-party libraries).

One-time setup:

```
pip install pre-commit
pre-commit install
```

After that, `git commit` automatically reformats any staged C/C++/CUDA file that
isn't already formatted (excluding `ker/` and `core/minus/`). CI
(`.github/workflows/format-check.yml`) re-checks the same thing on push/PR as a backstop.

clang-format's output differs slightly across versions, so `pre-commit` and CI both
pin `clang-format` `18.1.8` (see the `rev:` in `.pre-commit-config.yaml`). To run
`ci/format-all.sh` or configure your editor's format-on-save, install the same
version so you don't fight the pinned one:

```
pip install clang-format==18.1.8
```

To format everything by hand (e.g. after pulling changes), run `ci/format-all.sh`,
or `ci/format-all.sh --check` to only check without modifying files.

clang-format expands every element of a braced initializer list onto its own
line whenever the list already ends with a trailing comma, regardless of
column limit -- so the same struct/array literal formats differently
depending on whether its last author happened to add one. `ci/strip-trailing-commas.py`
removes any comma directly before a closing `}` before clang-format ever runs,
so don't rely on a trailing comma to keep an initializer list multi-line; that's
clang-format's call once the comma's gone. This runs automatically as part of
the same pre-commit hook and CI check as clang-format (and as part of
`ci/format-all.sh`), so you shouldn't need to run it by hand.

Since the repo's history includes a single large reformatting commit, run:

```
git config blame.ignoreRevsFile .git-blame-ignore-revs
```

so `git blame` attributes lines to their original author instead of that commit.
57 changes: 57 additions & 0 deletions ci/format-all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Run trailing-comma stripping and clang-format over every in-scope C/C++/CUDA
# file in the repo, in that order (a trailing comma before a closing '}'
# makes clang-format expand the whole list onto one line per element, so it
# has to be gone before clang-format sees the file).
#
# In scope: tracked *.c/*.h/*.cpp/*.hpp/*.cu/*.cuh files, excluding anything
# under a */ker/* directory (auto-generated DG kernel code) or under
# core/minus/ (vendored third-party libraries) -- see
# .agents/skills/code_style/SKILL.md.
#
# Usage:
# ci/format-all.sh # reformat all in-scope files in place
# ci/format-all.sh --check # fail (exit 1) if any in-scope file is not formatted
set -euo pipefail

PINNED_VERSION="18.1.8" # keep in sync with the `rev:` in .pre-commit-config.yaml

repo_root=$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)
cd "$repo_root"

mode=${1:-}

version=$(clang-format --version | grep -o '[0-9][0-9.]*' | head -1)
if [[ "$version" != "$PINNED_VERSION" ]]; then
echo "warning: clang-format $version is on PATH, but pre-commit/CI enforce $PINNED_VERSION." >&2
echo " results may not exactly match the CI check. See README.md." >&2
fi

list_files() {
git ls-files -z -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cu' '*.cuh' \
| grep -zv '/ker/' \
| grep -zv '^core/minus/'
}

if [[ "$mode" == "--check" ]]; then
status=0
while IFS= read -r -d '' f; do
if ! python3 ci/strip-trailing-commas.py --check "$f" > /dev/null 2>&1; then
echo "trailing comma(s) found: $f"
status=1
fi
if ! clang-format --dry-run --Werror "$f" > /dev/null 2>&1; then
echo "not formatted: $f"
status=1
fi
done < <(list_files)
exit "$status"
else
count=0
while IFS= read -r -d '' f; do
python3 ci/strip-trailing-commas.py "$f"
clang-format -i "$f"
count=$((count + 1))
done < <(list_files)
echo "Formatted $count files."
fi
Loading