Repository navigation
Code style
The C++ sources and the .txt configurations of SMS++ have a layout of their
own, which the pipeline of every merge request checks: the job style fails,
and the merge request cannot be merged, until what it changes is in that
layout (a merge request that has to keep a layout of its own says so with
[skip style] in its title, and the job does not run). This page says what
the layout is, how to put a file in it, and how to have the IDE do it.
The formatters of the code are those of the repository
code-style, which the umbrella holds
as the submodule scripts/code-style at a tag, so that the layout changes
only when the umbrella moves it. The layout of the C++ code is the one of its
.clang-format, i.e., an indentation of one space, a space inside
parentheses, brackets and angles (if( x ), v[ i ], std::vector< int >),
T * p and T & r, ! x, 79 columns at most, with what its format.py
adds to it and clang-format has no option for: the expression of a return and of a
throw in parentheses (return( x );, throw( e );), a space before every
comma and before the semicolons of a for (f( a , b )), the closing brace
of a block on the indentation of the block (the one of a namespace excepted),
the opening brace of a function defined out of a class on a line of its own,
and the #define of an include guard one space in. The comments, the order
of the includes, the string literals and the indentation of the preprocessor
directives are left as the author wrote them, and so is a file that says in
its first lines that a program writes it (DO NOT EDIT), such as the
*_maps.h of MILPSolver.
The layout of a configuration is the one of scripts/cfgformat.py of the
umbrella, to which the .code-format at its root hands the .txt files, and
which
reads it with the grammar of the load() methods of the core
(ComputeConfig, BlockConfig, BlockSolverConfig,
SimpleConfiguration< T >, the overrides *file +) and writes it again with
the box of the head and of the end 77 columns wide and with the name of the
file in it, every element on a line of its own and an empty line between two
elements, the values and their comments in columns (the ones of the author,
when most of the rows of a table share them), and the structural comments of
a ComputeConfig (# number of integer parameters, # now all the integer parameters, # [none]) written as everywhere. Every other comment is kept,
and nothing that SMS++ reads changes: the script checks that the tokens out of
the comments are the same before and after, and a file that it cannot read
with the grammar of the core is reported and left as it is.
From the umbrella,
scripts/smspp-format --since origin/develop <files>formats a C++ source only in the lines changed since origin/develop, so that
the code around them stays as it was written (the layout of the existing code
is in part made by hand, e.g., where a long line breaks and how its
continuation aligns, and no formatter reproduces it), and a configuration
whole; --git does the same with the lines changed since HEAD, --check
writes nothing and lists the files that are not in the layout, which is what
the job style runs. smspp-format runs code-format of
scripts/code-style, which a recursive clone of the umbrella brings along
(otherwise git submodule update --init scripts/code-style). The scripts
need Python 3 and clang-format 22, e.g.,
pip install clang-format==22.1.5since the layout clang-format produces changes slightly from one version to
the next. The tests of the formatters are in scripts/code-style/tests/ and
in scripts/test_cfgformat.py.
When the job style fails, it runs the formatters on its own copy of the
files and keeps what they change as the artifact style.patch of the job
(style patch among the artifacts of the merge request), which
git apply style.patchapplies in the module. If the variable STYLE_TOKEN of the pipeline (set
once for the whole group) holds an access token (of the role Reporter and
with the scope api, masked), the job also posts the changes on the merge request: a change of
the lines that the merge request adds is a suggestion on them, which its
author applies with one click, and the others (e.g., of a configuration,
which is formatted whole) go together in one note; the notes of a pipeline
replace the ones of the last.
scripts/code-style/hooks/install-hooks .installs, in the umbrella and in every submodule, a pre-commit hook of git
that checks the files of a commit as the job style does, and stops the
commit if one is not in the style, printing the command that puts it there
(git commit --no-verify commits all the same). The hook is a link to
scripts/code-style/hooks/pre-commit, so that it follows the submodule, and
it runs the scripts/smspp-format of the umbrella; in a worktree out of the
umbrella it finds it through the variable CODE_FORMAT, which names it.
Any IDE that can run an external command on the file it shows can bind
smspp-format to the key of its own formatter. In CLion:
-
Settings | Tools | External Tools, add a tool named
smspp-formatwith program$ProjectFileDir$/scripts/smspp-format, arguments--git $FilePath$and working directory$ProjectFileDir$, and uncheck Open console for tool output; -
Settings | Keymap, duplicate the keymap in use, remove
Ctrl+Alt+Lfrom Code | Reformat Code and give it to External Tools | smspp-format.
The file is reformatted on disk and CLion reloads it; with --git only the
lines changed since the last commit are touched, as the job style asks.