Wyatt Hepler | f9fb90f | 2020-09-30 18:59:33 -0700 | [diff] [blame] | 1 | .. _docs-pw-style: |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 2 | |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 3 | =========== |
| 4 | Style Guide |
| 5 | =========== |
Armando Montanez | f2bbb75 | 2020-03-03 09:50:37 -0800 | [diff] [blame] | 6 | .. tip:: |
| 7 | Pigweed runs ``pw format`` as part of ``pw presubmit`` to perform some code |
| 8 | formatting checks. To speed up the review process, consider adding ``pw |
| 9 | presubmit`` as a git push hook using the following command: |
| 10 | ``pw presubmit --install`` |
| 11 | |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 12 | --------- |
| 13 | C++ style |
| 14 | --------- |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 15 | The Pigweed C++ style guide is closely based on Google's external C++ Style |
| 16 | Guide, which is found on the web at |
| 17 | https://google.github.io/styleguide/cppguide.html. The Google C++ Style Guide |
| 18 | applies to Pigweed except as described in this document. |
| 19 | |
| 20 | The Pigweed style guide only applies to Pigweed itself. It does not apply to |
Alexei Frolov | 44d5473 | 2020-01-10 14:45:43 -0800 | [diff] [blame] | 21 | projects that use Pigweed or to the third-party code included with Pigweed. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 22 | Non-Pigweed code is free to use features restricted by Pigweed, such as dynamic |
| 23 | memory allocation and the entirety of the C++ Standard Library. |
| 24 | |
| 25 | Recommendations in the :doc:`embedded_cpp_guide` are considered part of the |
| 26 | Pigweed style guide, but are separated out since it covers more general |
| 27 | embedded development beyond just C++ style. |
| 28 | |
Wyatt Hepler | 0132da5 | 2021-10-11 16:20:11 -0700 | [diff] [blame] | 29 | C++ standard |
| 30 | ============ |
| 31 | Pigweed primarily uses the C++17 standard. A few modules maintain support for |
| 32 | C++14, however (e.g. :ref:`module-pw_kvs` and its dependencies). |
| 33 | |
| 34 | All Pigweed C++ code must compile with ``-std=C++17`` in Clang and GCC. C++20 |
| 35 | features may be used as long as the code still compiles unmodified with C++17. |
| 36 | See ``pw_polyfill/language_feature_macros.h`` for macros that provide C++20 |
| 37 | features when supported. |
| 38 | |
| 39 | Compiler extensions should not be used unless wrapped in a macro or properly |
| 40 | guarded in the preprocessor. See ``pw_processor/compiler.h`` for macros that |
| 41 | wrap compiler-specific features. |
| 42 | |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 43 | Automatic formatting |
| 44 | ==================== |
| 45 | Pigweed uses `clang-format <https://clang.llvm.org/docs/ClangFormat.html>`_ to |
| 46 | automatically format Pigweed source code. A ``.clang-format`` configuration is |
| 47 | provided with the Pigweed repository. |
| 48 | |
| 49 | Automatic formatting is essential to facilitate large-scale, automated changes |
| 50 | in Pigweed. Therefore, all code in Pigweed is expected to be formatted with |
| 51 | ``clang-format`` prior to submission. Existing code may be reformatted at any |
| 52 | time. |
| 53 | |
| 54 | If ``clang-format`` formats code in an undesirable or incorrect way, it can be |
| 55 | disabled for the affected lines by adding ``// clang-format off``. |
| 56 | ``clang-format`` must then be re-enabled with a ``// clang-format on`` comment. |
| 57 | |
| 58 | .. code-block:: cpp |
| 59 | |
| 60 | // clang-format off |
Alexei Frolov | 44d5473 | 2020-01-10 14:45:43 -0800 | [diff] [blame] | 61 | constexpr int kMyMatrix[] = { |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 62 | 100, 23, 0, |
| 63 | 0, 542, 38, |
| 64 | 1, 2, 201, |
| 65 | }; |
| 66 | // clang-format on |
| 67 | |
| 68 | C Standard Library |
| 69 | ================== |
| 70 | In C++ headers, always use the C++ versions of C Standard Library headers (e.g. |
| 71 | ``<cstdlib>`` instead of ``<stdlib.h>``). If the header is used by both C and |
| 72 | C++ code, only the C header should be used. |
| 73 | |
| 74 | In C++ code, it is preferred to use C functions from the ``std`` namespace. For |
| 75 | example, use ``std::memcpy`` instead of ``memcpy``. The C++ standard does not |
| 76 | require the global namespace versions of the functions to be provided. Using |
| 77 | ``std::`` is more consistent with the C++ Standard Library and makes it easier |
| 78 | to distinguish Pigweed functions from library functions. |
| 79 | |
| 80 | Within core Pigweed, do not use C standard library functions that allocate |
| 81 | memory, such as ``std::malloc``. There are exceptions to this for when dynamic |
| 82 | allocation is enabled for a system; Pigweed modules are allowed to add extra |
| 83 | functionality when a heap is present; but this must be optional. |
| 84 | |
| 85 | C++ Standard Library |
| 86 | ==================== |
| 87 | Much of the C++ Standard Library is not a good fit for embedded software. Many |
| 88 | of the classes and functions were not designed with the RAM, flash, and |
| 89 | performance constraints of a microcontroller in mind. For example, simply |
| 90 | adding the line ``#include <iostream>`` can increase the binary size by 150 KB! |
Alexei Frolov | 44d5473 | 2020-01-10 14:45:43 -0800 | [diff] [blame] | 91 | This is larger than many microcontrollers' entire internal storage. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 92 | |
| 93 | However, with appropriate caution, a limited set of standard C++ libraries can |
| 94 | be used to great effect. Developers can leverage familiar, well-tested |
| 95 | abstractions instead of writing their own. C++ library algorithms and classes |
| 96 | can give equivalent or better performance than hand-written C code. |
| 97 | |
| 98 | A limited subset of the C++ Standard Library is permitted in Pigweed. To keep |
| 99 | Pigweed small, flexible, and portable, functions that allocate dynamic memory |
| 100 | must be avoided. Care must be exercised when using multiple instantiations of a |
| 101 | template function, which can lead to code bloat. |
| 102 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 103 | Permitted Headers |
| 104 | ----------------- |
| 105 | .. admonition:: The following C++ Standard Library headers are always permitted: |
| 106 | :class: checkmark |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 107 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 108 | * ``<array>`` |
| 109 | * ``<complex>`` |
| 110 | * ``<initializer_list>`` |
| 111 | * ``<iterator>`` |
| 112 | * ``<limits>`` |
| 113 | * ``<optional>`` |
| 114 | * ``<random>`` |
| 115 | * ``<ratio>`` |
| 116 | * ``<span>`` |
| 117 | * ``<string_view>`` |
| 118 | * ``<tuple>`` |
| 119 | * ``<type_traits>`` |
| 120 | * ``<utility>`` |
| 121 | * ``<variant>`` |
| 122 | * C Standard Library headers (``<c*>``) |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 123 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 124 | .. admonition:: With caution, parts of the following headers can be used: |
| 125 | :class: warning |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 126 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 127 | * ``<algorithm>`` -- be wary of potential memory allocation |
| 128 | * ``<atomic>`` -- not all MCUs natively support atomic operations |
| 129 | * ``<bitset>`` -- conversions to or from strings are disallowed |
| 130 | * ``<functional>`` -- do **not** use ``std::function`` |
| 131 | * ``<new>`` -- for placement new |
| 132 | * ``<numeric>`` -- be wary of code size with multiple template instantiations |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 133 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 134 | .. admonition:: Never use any of these headers: |
| 135 | :class: error |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 136 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 137 | * Dynamic containers (``<list>``, ``<map>``, ``<set>``, ``<vector>``, etc.) |
| 138 | * Streams (``<iostream>``, ``<ostream>``, ``<fstream>``, etc.) |
| 139 | * ``<exception>`` |
| 140 | * ``<future>``, ``<mutex>``, ``<thread>`` |
| 141 | * ``<memory>`` |
| 142 | * ``<regex>`` |
| 143 | * ``<scoped_allocator>`` |
| 144 | * ``<sstream>`` |
| 145 | * ``<stdexcept>`` |
| 146 | * ``<string>`` |
| 147 | * ``<valarray>`` |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 148 | |
| 149 | Headers not listed here should be carefully evaluated before they are used. |
| 150 | |
| 151 | These restrictions do not apply to third party code or to projects that use |
| 152 | Pigweed. |
| 153 | |
| 154 | Combining C and C++ |
| 155 | =================== |
| 156 | Prefer to write C++ code over C code, using ``extern "C"`` for symbols that must |
| 157 | have C linkage. ``extern "C"`` functions should be defined within C++ |
| 158 | namespaces to simplify referring to other code. |
| 159 | |
| 160 | C++ functions with no parameters do not include ``void`` in the parameter list. |
| 161 | C functions with no parameters must include ``void``. |
| 162 | |
| 163 | .. code-block:: cpp |
| 164 | |
| 165 | namespace pw { |
| 166 | |
| 167 | bool ThisIsACppFunction() { return true; } |
| 168 | |
| 169 | extern "C" int pw_ThisIsACFunction(void) { return -1; } |
| 170 | |
| 171 | extern "C" { |
| 172 | |
| 173 | int pw_ThisIsAlsoACFunction(void) { |
| 174 | return ThisIsACppFunction() ? 100 : 0; |
| 175 | } |
| 176 | |
| 177 | } // extern "C" |
| 178 | |
| 179 | } // namespace pw |
| 180 | |
| 181 | Comments |
| 182 | ======== |
Ali Zhang | f22f1f1 | 2021-04-02 18:59:28 -0700 | [diff] [blame] | 183 | Prefer C++-style (``//``) comments over C-style comments (``/* */``). C-style |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 184 | comments should only be used for inline comments. |
| 185 | |
| 186 | .. code-block:: cpp |
| 187 | |
| 188 | // Use C++-style comments, except where C-style comments are necessary. |
| 189 | // This returns a random number using an algorithm I found on the internet. |
| 190 | #define RANDOM_NUMBER() [] { \ |
| 191 | return 4; /* chosen by fair dice roll */ \ |
| 192 | }() |
| 193 | |
| 194 | Indent code in comments with two additional spaces, making a total of three |
| 195 | spaces after the ``//``. All code blocks must begin and end with an empty |
Alexei Frolov | 44d5473 | 2020-01-10 14:45:43 -0800 | [diff] [blame] | 196 | comment line, even if the blank comment line is the last line in the block. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 197 | |
| 198 | .. code-block:: cpp |
| 199 | |
| 200 | // Here is an example of code in comments. |
| 201 | // |
| 202 | // int indentation_spaces = 2; |
| 203 | // int total_spaces = 3; |
| 204 | // |
| 205 | // engine_1.thrust = RANDOM_NUMBER() * indentation_spaces + total_spaces; |
| 206 | // |
| 207 | bool SomeFunction(); |
| 208 | |
| 209 | Control statements |
| 210 | ================== |
| 211 | All loops and conditional statements must use braces. |
| 212 | |
Ewout van Bekkum | e072fab | 2020-07-17 16:34:00 -0700 | [diff] [blame] | 213 | The syntax ``while (true)`` is preferred over ``for (;;)`` for infinite loops. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 214 | |
| 215 | Include guards |
| 216 | ============== |
| 217 | The first non-comment line of every header file must be ``#pragma once``. Do |
| 218 | not use traditional macro include guards. The ``#pragma once`` should come |
| 219 | directly after the Pigweed copyright block, with no blank line, followed by a |
| 220 | blank, like this: |
| 221 | |
| 222 | .. code-block:: cpp |
| 223 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 224 | // Copyright 2021 The Pigweed Authors |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 225 | // |
| 226 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
Wyatt Hepler | 1a96094 | 2019-11-26 14:13:38 -0800 | [diff] [blame] | 227 | // use this file except in compliance with the License. You may obtain a copy of |
| 228 | // the License at |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 229 | // |
| 230 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 231 | // |
| 232 | // Unless required by applicable law or agreed to in writing, software |
| 233 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 234 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
Wyatt Hepler | 1a96094 | 2019-11-26 14:13:38 -0800 | [diff] [blame] | 235 | // License for the specific language governing permissions and limitations under |
| 236 | // the License. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 237 | #pragma once |
| 238 | |
| 239 | // Header file-level comment goes here... |
| 240 | |
| 241 | Memory allocation |
| 242 | ================= |
| 243 | Dynamic memory allocation can be problematic. Heap allocations and deallocations |
| 244 | occupy valuable CPU cycles. Memory usage becomes nondeterministic, which can |
| 245 | result in a system crashing without a clear culprit. |
| 246 | |
| 247 | To keep Pigweed portable, core Pigweed code is not permitted to dynamically |
| 248 | (heap) allocate memory, such as with ``malloc`` or ``new``. All memory should be |
| 249 | allocated with automatic (stack) or static (global) storage duration. Pigweed |
| 250 | must not use C++ libraries that use dynamic allocation. |
| 251 | |
| 252 | Projects that use Pigweed are free to use dynamic allocation, provided they |
| 253 | have selected a target that enables the heap. |
| 254 | |
| 255 | Naming |
| 256 | ====== |
| 257 | Entities shall be named according to the `Google style guide |
| 258 | <https://google.github.io/styleguide/cppguide.html>`_, with the following |
| 259 | additional requirements. |
| 260 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 261 | C++ code |
| 262 | -------- |
| 263 | * All Pigweed C++ code must be in the ``pw`` namespace. Namespaces for modules |
| 264 | should be nested under ``pw``. For example, ``pw::string::Format()``. |
| 265 | * Whenever possible, private code should be in a source (.cc) file and placed in |
| 266 | anonymous namespace nested under ``pw``. |
| 267 | * If private code must be exposed in a header file, it must be in a namespace |
| 268 | nested under ``pw``. The namespace may be named for its subsystem or use a |
| 269 | name that designates it as private, such as ``internal``. |
| 270 | * Template arguments for non-type names (e.g. ``template <int kFooBar>``) should |
| 271 | follow the constexpr and const variable Google naming convention, which means |
| 272 | k prefixed camel case (e.g. ``kCamelCase``). This matches the Google C++ |
| 273 | style for variable naming, however the wording in the official style guide |
| 274 | isn't explicit for template arguments and could be interpreted to use |
| 275 | ``foo_bar`` style naming. For consistency with other variables whose value is |
| 276 | always fixed for the duration of the program, the naming convention is |
| 277 | ``kCamelCase``, and so that is the style we use in Pigweed. |
Keir Mierle | 003044a | 2020-04-14 10:56:20 -0700 | [diff] [blame] | 278 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 279 | C code |
| 280 | ------ |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 281 | In general, C symbols should be prefixed with the module name. If the symbol is |
| 282 | not associated with a module, use just ``pw`` as the module name. Facade |
| 283 | backends may chose to prefix symbols with the facade's name to help reduce the |
| 284 | length of the prefix. |
| 285 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 286 | * Public names used by C code must be prefixed with the module name (e.g. |
| 287 | ``pw_tokenizer_*``). |
| 288 | * If private code must be exposed in a header, private names used by C code must |
| 289 | be prefixed with an underscore followed by the module name (e.g. |
| 290 | ``_pw_assert_*``). |
| 291 | * Avoid writing C source (.c) files in Pigweed. Prefer to write C++ code with C |
| 292 | linkage using ``extern "C"``. Within C source, private C functions and |
| 293 | variables must be named with the ``_pw_my_module_*`` prefix and should be |
| 294 | declared ``static`` whenever possible; for example, |
| 295 | ``_pw_my_module_MyPrivateFunction``. |
| 296 | * The C prefix rules apply to |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 297 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 298 | * C functions (``int pw_foo_FunctionName(void);``), |
| 299 | * variables used by C code (``int pw_foo_variable_name;``), |
| 300 | * constant variables used by C code (``int pw_foo_kConstantName;``), |
| 301 | * structs used by C code (``typedef struct {} pw_foo_StructName;``), and |
| 302 | * all of the above for ``extern "C"`` names in C++ code. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 303 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 304 | The prefix does not apply to struct members, which use normal Google style. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 305 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 306 | Preprocessor macros |
| 307 | ------------------- |
| 308 | * Public Pigweed macros must be prefixed with the module name (e.g. |
| 309 | ``PW_MY_MODULE_*``). |
| 310 | * Private Pigweed macros must be prefixed with an underscore followed by the |
| 311 | module name (e.g. ``_PW_MY_MODULE_*``). |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 312 | |
| 313 | **Example** |
| 314 | |
| 315 | .. code-block:: cpp |
| 316 | |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 317 | namespace pw::my_module { |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 318 | namespace nested_namespace { |
| 319 | |
| 320 | // C++ names (types, variables, functions) must be in the pw namespace. |
| 321 | // They are named according to the Google style guide. |
| 322 | constexpr int kGlobalConstant = 123; |
| 323 | |
| 324 | // Prefer using functions over extern global variables. |
| 325 | extern int global_variable; |
| 326 | |
| 327 | class Class {}; |
| 328 | |
| 329 | void Function(); |
| 330 | |
| 331 | extern "C" { |
| 332 | |
| 333 | // Public Pigweed code used from C must be prefixed with pw_. |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 334 | extern const int pw_my_module_kGlobalConstant; |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 335 | |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 336 | extern int pw_my_module_global_variable; |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 337 | |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 338 | void pw_my_module_Function(void); |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 339 | |
| 340 | typedef struct { |
| 341 | int member_variable; |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 342 | } pw_my_module_Struct; |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 343 | |
| 344 | // Private Pigweed code used from C must be prefixed with _pw_. |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 345 | extern const int _pw_my_module_kPrivateGlobalConstant; |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 346 | |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 347 | extern int _pw_my_module_private_global_variable; |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 348 | |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 349 | void _pw_my_module_PrivateFunction(void); |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 350 | |
| 351 | typedef struct { |
| 352 | int member_variable; |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 353 | } _pw_my_module_PrivateStruct; |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 354 | |
| 355 | } // extern "C" |
| 356 | |
| 357 | // Public macros must be prefixed with PW_. |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 358 | #define PW_MY_MODULE_PUBLIC_MACRO(arg) arg |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 359 | |
| 360 | // Private macros must be prefixed with _PW_. |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 361 | #define _PW_MY_MODULE_PRIVATE_MACRO(arg) arg |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 362 | |
| 363 | } // namespace nested_namespace |
Armando Montanez | 59aa278 | 2021-01-12 15:16:36 -0800 | [diff] [blame] | 364 | } // namespace pw::my_module |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 365 | |
| 366 | Namespace scope formatting |
| 367 | ========================== |
| 368 | All non-indented blocks (namespaces, ``extern "C"`` blocks, and preprocessor |
| 369 | conditionals) must have a comment on their closing line with the |
| 370 | contents of the starting line. |
| 371 | |
| 372 | All nested namespaces should be declared together with no blank lines between |
| 373 | them. |
| 374 | |
| 375 | .. code-block:: cpp |
| 376 | |
| 377 | #include "some/header.h" |
| 378 | |
| 379 | namespace pw::nested { |
| 380 | namespace { |
| 381 | |
| 382 | constexpr int kAnonConstantGoesHere = 0; |
| 383 | |
| 384 | } // namespace |
| 385 | |
| 386 | namespace other { |
| 387 | |
| 388 | const char* SomeClass::yes = "no"; |
| 389 | |
| 390 | bool ThisIsAFunction() { |
| 391 | #if PW_CONFIG_IS_SET |
| 392 | return true; |
| 393 | #else |
| 394 | return false; |
| 395 | #endif // PW_CONFIG_IS_SET |
| 396 | } |
| 397 | |
| 398 | extern "C" { |
| 399 | |
| 400 | const int pw_kSomeConstant = 10; |
| 401 | int pw_some_global_variable = 600; |
| 402 | |
| 403 | void pw_CFunction() { ... } |
| 404 | |
| 405 | } // extern "C" |
| 406 | |
| 407 | } // namespace |
| 408 | } // namespace pw::nested |
| 409 | |
| 410 | Pointers and references |
| 411 | ======================= |
| 412 | For pointer and reference types, place the asterisk or ampersand next to the |
| 413 | type. |
| 414 | |
| 415 | .. code-block:: cpp |
| 416 | |
| 417 | int* const number = &that_thing; |
| 418 | constexpr const char* kString = "theory!" |
| 419 | |
| 420 | bool FindTheOneRing(const Region& where_to_look) { ... } |
| 421 | |
| 422 | Prefer storing references over storing pointers. Pointers are required when the |
| 423 | pointer can change its target or may be ``nullptr``. Otherwise, a reference or |
Adam MacBeth | fb12658 | 2021-07-20 18:24:38 +0000 | [diff] [blame] | 424 | const reference should be used. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 425 | |
| 426 | Preprocessor macros |
| 427 | =================== |
| 428 | Macros should only be used when they significantly improve upon the C++ code |
| 429 | they replace. Macros should make code more readable, robust, and safe, or |
| 430 | provide features not possible with standard C++, such as stringification, line |
| 431 | number capturing, or conditional compilation. When possible, use C++ constructs |
| 432 | like constexpr variables in place of macros. Never use macros as constants, |
| 433 | except when a string literal is needed or the value must be used by C code. |
| 434 | |
| 435 | When macros are needed, the macros should be accompanied with extensive tests |
| 436 | to ensure the macros are hard to use wrong. |
| 437 | |
| 438 | Stand-alone statement macros |
| 439 | ---------------------------- |
| 440 | Macros that are standalone statements must require the caller to terminate the |
Alexei Frolov | 44d5473 | 2020-01-10 14:45:43 -0800 | [diff] [blame] | 441 | macro invocation with a semicolon. For example, the following does *not* conform |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 442 | to Pigweed's macro style: |
| 443 | |
| 444 | .. code-block:: cpp |
| 445 | |
| 446 | // BAD! Definition has built-in semicolon. |
| 447 | #define PW_LOG_IF_BAD(mj) \ |
| 448 | CallSomeFunction(mj); |
| 449 | |
| 450 | // BAD! Compiles without error; semicolon is missing. |
Alexei Frolov | 44d5473 | 2020-01-10 14:45:43 -0800 | [diff] [blame] | 451 | PW_LOG_IF_BAD("foo") |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 452 | |
| 453 | Here's how to do this instead: |
| 454 | |
| 455 | .. code-block:: cpp |
| 456 | |
| 457 | // GOOD; requires semicolon to compile. |
| 458 | #define PW_LOG_IF_BAD(mj) \ |
| 459 | CallSomeFunction(mj) |
| 460 | |
| 461 | // GOOD; fails to compile due to lacking semicolon. |
Alexei Frolov | 44d5473 | 2020-01-10 14:45:43 -0800 | [diff] [blame] | 462 | PW_LOG_IF_BAD("foo") |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 463 | |
| 464 | For macros in function scope that do not already require a semicolon, the |
| 465 | contents can be placed in a ``do { ... } while (0)`` loop. |
| 466 | |
| 467 | .. code-block:: cpp |
| 468 | |
| 469 | #define PW_LOG_IF_BAD(mj) \ |
| 470 | do { \ |
| 471 | if (mj.Bad()) { \ |
| 472 | Log(#mj " is bad") \ |
| 473 | } \ |
| 474 | } while (0) |
| 475 | |
| 476 | Standalone macros at global scope that do not already require a semicolon can |
| 477 | add a ``static_assert`` or throwaway struct declaration statement as their |
| 478 | last line. |
| 479 | |
| 480 | .. code-block:: cpp |
| 481 | |
| 482 | #define PW_NEAT_THING(thing) \ |
| 483 | bool IsNeat_##thing() { return true; } \ |
| 484 | static_assert(true, "Macros must be terminated with a semicolon") |
| 485 | |
| 486 | Private macros in public headers |
| 487 | -------------------------------- |
| 488 | Private macros in public headers must be prefixed with ``_PW_``, even if they |
| 489 | are undefined after use; this prevents collisions with downstream users. For |
| 490 | example: |
| 491 | |
| 492 | .. code-block:: cpp |
| 493 | |
| 494 | #define _PW_MY_SPECIAL_MACRO(op) ... |
| 495 | ... |
| 496 | // Code that uses _PW_MY_SPECIAL_MACRO() |
| 497 | ... |
| 498 | #undef _PW_MY_SPECIAL_MACRO |
| 499 | |
| 500 | Macros in private implementation files (.cc) |
| 501 | -------------------------------------------- |
| 502 | Macros within .cc files that should only used within one file should be |
| 503 | undefined after their last use; for example: |
| 504 | |
| 505 | .. code-block:: cpp |
| 506 | |
| 507 | #define DEFINE_OPERATOR(op) \ |
| 508 | T operator ## op(T x, T y) { return x op y; } \ |
| 509 | static_assert(true, "Macros must be terminated with a semicolon") \ |
| 510 | |
| 511 | DEFINE_OPERATOR(+); |
| 512 | DEFINE_OPERATOR(-); |
| 513 | DEFINE_OPERATOR(/); |
| 514 | DEFINE_OPERATOR(*); |
| 515 | |
| 516 | #undef DEFINE_OPERATOR |
| 517 | |
| 518 | Preprocessor conditional statements |
| 519 | =================================== |
| 520 | When using macros for conditional compilation, prefer to use ``#if`` over |
| 521 | ``#ifdef``. This checks the value of the macro rather than whether it exists. |
| 522 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 523 | * ``#if`` handles undefined macros equivalently to ``#ifdef``. Undefined |
| 524 | macros expand to 0 in preprocessor conditional statements. |
| 525 | * ``#if`` evaluates false for macros defined as 0, while ``#ifdef`` evaluates |
| 526 | true. |
| 527 | * Macros defined using compiler flags have a default value of 1 in GCC and |
| 528 | Clang, so they work equivalently for ``#if`` and ``#ifdef``. |
| 529 | * Macros defined to an empty statement cause compile-time errors in ``#if`` |
| 530 | statements, which avoids ambiguity about how the macro should be used. |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 531 | |
| 532 | All ``#endif`` statements should be commented with the expression from their |
| 533 | corresponding ``#if``. Do not indent within preprocessor conditional statements. |
| 534 | |
| 535 | .. code-block:: cpp |
| 536 | |
| 537 | #if USE_64_BIT_WORD |
| 538 | using Word = uint64_t; |
| 539 | #else |
| 540 | using Word = uint32_t; |
| 541 | #endif // USE_64_BIT_WORD |
| 542 | |
| 543 | Unsigned integers |
| 544 | ================= |
| 545 | Unsigned integers are permitted in Pigweed. Aim for consistency with existing |
| 546 | code and the C++ Standard Library. Be very careful mixing signed and unsigned |
| 547 | integers. |
| 548 | |
Wyatt Hepler | 070ebff | 2021-12-15 15:53:58 -0800 | [diff] [blame] | 549 | Features not in the C++ standard |
| 550 | ================================ |
| 551 | Avoid features not available in standard C++. This includes compiler extensions |
| 552 | and features from other standards like POSIX. |
| 553 | |
| 554 | For example, use ``ptrdiff_t`` instead of POSIX's ``ssize_t``, unless |
| 555 | interacting with a POSIX API in intentionally non-portable code. Never use |
| 556 | POSIX functions with suitable standard or Pigweed alternatives, such as |
| 557 | ``strnlen`` (use ``pw::string::NullTerminatedLength`` instead). |
| 558 | |
Keir Mierle | 2c1e56b | 2019-11-15 16:32:11 -0800 | [diff] [blame] | 559 | ------------ |
| 560 | Python style |
| 561 | ------------ |
| 562 | Pigweed uses the standard Python style: PEP8, which is available on the web at |
| 563 | https://www.python.org/dev/peps/pep-0008/. All Pigweed Python code should pass |
| 564 | ``yapf`` when configured for PEP8 style. |
| 565 | |
Wyatt Hepler | ab4eb7a | 2020-01-08 18:04:31 -0800 | [diff] [blame] | 566 | Python 3 |
| 567 | ======== |
| 568 | Pigweed uses Python 3. Some modules may offer limited support for Python 2, but |
| 569 | Python 3.6 or newer is required for most Pigweed code. |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 570 | |
| 571 | --------------- |
| 572 | Build files: GN |
| 573 | --------------- |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 574 | Each Pigweed source module requires a GN build file named BUILD.gn. This |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 575 | encapsulates the build targets and specifies their sources and dependencies. |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 576 | GN build files use a format similar to `Bazel's BUILD files |
| 577 | <https://docs.bazel.build/versions/main/build-ref.html>`_ |
| 578 | (see the `Bazel style guide |
| 579 | <https://docs.bazel.build/versions/main/skylark/build-style.html>`_). |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 580 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 581 | C/C++ build targets include a list of fields. The primary fields are: |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 582 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 583 | * ``<public>`` -- public header files |
| 584 | * ``<sources>`` -- source files and private header files |
| 585 | * ``<public_configs>`` -- public build configuration |
| 586 | * ``<configs>`` -- private build configuration |
| 587 | * ``<public_deps>`` -- public dependencies |
| 588 | * ``<deps>`` -- private dependencies |
| 589 | |
| 590 | Assets within each field must be listed in alphabetical order. |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 591 | |
| 592 | .. code-block:: cpp |
| 593 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 594 | # Here is a brief example of a GN build file. |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 595 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 596 | import("$dir_pw_unit_test/test.gni") |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 597 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 598 | config("public_include_path") { |
| 599 | include_dirs = [ "public" ] |
| 600 | visibility = [":*"] |
| 601 | } |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 602 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 603 | pw_source_set("pw_sample_module") { |
| 604 | public = [ "public/pw_sample_module/sample_module.h" ] |
| 605 | sources = [ |
| 606 | "public/pw_sample_module/internal/secret_header.h", |
| 607 | "sample_module.cc", |
| 608 | "used_by_sample_module.cc", |
| 609 | ] |
| 610 | public_configs = [ ":public_include_path" ] |
| 611 | public_deps = [ dir_pw_status ] |
| 612 | deps = [ dir_pw_varint ] |
| 613 | } |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 614 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 615 | pw_test_group("tests") { |
| 616 | tests = [ ":sample_module_test" ] |
| 617 | } |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 618 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 619 | pw_test("sample_module_test") { |
| 620 | sources = [ "sample_module_test.cc" ] |
| 621 | deps = [ ":sample_module" ] |
| 622 | } |
Wayne Jackson | d597e46 | 2020-06-03 15:03:12 -0700 | [diff] [blame] | 623 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 624 | pw_doc_group("docs") { |
| 625 | sources = [ "docs.rst" ] |
| 626 | } |
Akira Baruah | 40a9c3f | 2021-06-16 15:17:54 -0700 | [diff] [blame] | 627 | |
| 628 | ------------------ |
| 629 | Build files: Bazel |
| 630 | ------------------ |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 631 | Build files for the Bazel build system must be named ``BUILD.bazel``. Bazel can |
| 632 | interpret files named just ``BUILD``, but Pigweed uses ``BUILD.bazel`` to avoid |
| 633 | ambiguity with other build systems or tooling. |
Akira Baruah | 40a9c3f | 2021-06-16 15:17:54 -0700 | [diff] [blame] | 634 | |
Wyatt Hepler | 26bc5a8 | 2021-11-12 10:31:42 -0800 | [diff] [blame] | 635 | Pigweed's Bazel files follow the `Bazel style guide |
| 636 | <https://docs.bazel.build/versions/main/skylark/build-style.html>`_. |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 637 | |
| 638 | ------------- |
| 639 | Documentation |
| 640 | ------------- |
| 641 | .. note:: |
| 642 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 643 | Pigweed's documentation style guide came after much of the documentation was |
| 644 | written, so Pigweed's docs don't yet 100% conform to this style guide. When |
| 645 | updating docs, please update them to match the style guide. |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 646 | |
| 647 | Pigweed documentation is written using the `reStructuredText |
| 648 | <https://docutils.sourceforge.io/rst.html>`_ markup language and processed by |
| 649 | `Sphinx`_. We use the `Furo theme <https://github.com/pradyunsg/furo>`_ along |
| 650 | with the `sphinx-design <https://sphinx-design.readthedocs.io/en/furo-theme/>`_ |
| 651 | extension. |
| 652 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 653 | Syntax Reference Links |
| 654 | ====================== |
| 655 | .. admonition:: See also |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 656 | :class: seealso |
| 657 | |
| 658 | - `reStructuredText Primer`_ |
| 659 | |
| 660 | - `reStructuredText Directives <https://docutils.sourceforge.io/docs/ref/rst/directives.html>`_ |
| 661 | |
| 662 | - `Furo Reference <https://pradyunsg.me/furo/reference/>`_ |
| 663 | |
| 664 | - `Sphinx-design Reference <https://sphinx-design.readthedocs.io/en/furo-theme/>`_ |
| 665 | |
| 666 | ReST is flexible, supporting formatting the same logical document in a few ways |
| 667 | (for example headings, blank lines). Pigweed has the following restrictions to |
| 668 | make our documentation consistent. |
| 669 | |
| 670 | Headings |
| 671 | ======== |
| 672 | Use headings according to the following hierarchy, with the shown characters |
| 673 | for the ReST heading syntax. |
| 674 | |
| 675 | .. code:: rst |
| 676 | |
| 677 | ================================== |
| 678 | Document Title: Two Bars of Equals |
| 679 | ================================== |
| 680 | Document titles use equals ("====="), above and below. Capitalize the words |
| 681 | in the title, except for 'of' and 'the'. |
| 682 | |
| 683 | --------------------------- |
| 684 | Major Sections Within a Doc |
| 685 | --------------------------- |
| 686 | Major sections use hypens ("----"), above and below. Capitalize the words in |
| 687 | the title, except for 'of' and 'the'. |
| 688 | |
| 689 | Heading 1 - For Sections Within a Doc |
| 690 | ===================================== |
| 691 | These should be title cased. Use a single equals bar ("===="). |
| 692 | |
| 693 | Heading 2 - for subsections |
| 694 | --------------------------- |
| 695 | Subsections use hypens ("----"). In many cases, these headings may be |
| 696 | sentence-like. In those cases, only the first letter should be capitalized. |
| 697 | For example, FAQ subsections would have a title with "Why does the X do the |
| 698 | Y?"; note the sentence capitalization (but not title capitalization). |
| 699 | |
| 700 | Heading 3 - for subsubsections |
| 701 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 702 | Use the caret symbol ("^^^^") for subsubsections. |
| 703 | |
| 704 | Note: Generally don't go beyond heading 3. |
| 705 | |
| 706 | Heading 4 - for subsubsubsections |
| 707 | ................................. |
| 708 | Don't use this heading level, but if you must, use period characters |
| 709 | ("....") for the heading. |
| 710 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 711 | Do not put blank lines after headings. |
| 712 | -------------------------------------- |
| 713 | .. admonition:: **Yes**: No blank after heading |
| 714 | :class: checkmark |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 715 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 716 | .. code:: rst |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 717 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 718 | Here is a heading |
| 719 | ----------------- |
| 720 | Note that there is no blank line after the heading separator! |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 721 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 722 | .. admonition:: **No**: Unnecessary blank line |
| 723 | :class: error |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 724 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 725 | .. code:: rst |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 726 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 727 | Here is a heading |
| 728 | ----------------- |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 729 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 730 | There is a totally unnecessary blank line above this one. Don't do this. |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 731 | |
| 732 | Do not put multiple blank lines before a heading. |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 733 | ------------------------------------------------- |
| 734 | .. admonition:: **Yes**: Just one blank after section content before the next heading |
| 735 | :class: checkmark |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 736 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 737 | .. code:: rst |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 738 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 739 | There is some text here in the section before the next. It's just here to |
| 740 | illustrate the spacing standard. Note that there is just one blank line |
| 741 | after this paragraph. |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 742 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 743 | Just one blank! |
| 744 | --------------- |
| 745 | There is just one blank line before the heading. |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 746 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 747 | .. admonition:: **No**: Extra blank lines |
| 748 | :class: error |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 749 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 750 | .. code:: rst |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 751 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 752 | There is some text here in the section before the next. It's just here to |
| 753 | illustrate the spacing standard. Note that there are too many blank lines |
| 754 | after this paragraph; there should be just one. |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 755 | |
| 756 | |
| 757 | |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 758 | Too many blanks |
| 759 | --------------- |
| 760 | There are too many blanks before the heading for this section. |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 761 | |
Keir Mierle | 7508836 | 2021-12-15 12:17:28 -0800 | [diff] [blame] | 762 | Directives |
| 763 | ========== |
| 764 | Indent directives 3 spaces; and put a blank line between the directive and the |
| 765 | content. This aligns the directive content with the directive name. |
| 766 | |
| 767 | .. admonition:: **Yes**: Three space indent for directives; and nested |
| 768 | :class: checkmark |
| 769 | |
| 770 | .. code:: none |
| 771 | |
| 772 | Here is a paragraph that has some content. After this content is a |
| 773 | directive. |
| 774 | |
| 775 | .. my_directive:: |
| 776 | |
| 777 | Note that this line's start aligns with the "m" above. The 3-space |
| 778 | alignment accounts for the ".. " prefix for directives, to vertically |
| 779 | align the directive name with the content. |
| 780 | |
| 781 | This indentation must continue for nested directives. |
| 782 | |
| 783 | .. nested_directive:: |
| 784 | |
| 785 | Here is some nested directive content. |
| 786 | |
| 787 | .. admonition:: **No**: One space, two spaces, four spaces, or other indents |
| 788 | for directives |
| 789 | :class: error |
| 790 | |
| 791 | .. code:: none |
| 792 | |
| 793 | Here is a paragraph with some content. |
| 794 | |
| 795 | .. my_directive:: |
| 796 | |
| 797 | The indentation here is incorrect! It's one space short; doesn't align |
| 798 | with the directive name above. |
| 799 | |
| 800 | .. nested_directive:: |
| 801 | |
| 802 | This isn't indented correctly either; it's too much (4 spaces). |
| 803 | |
| 804 | .. admonition:: **No**: Missing blank between directive and content. |
| 805 | :class: error |
| 806 | |
| 807 | .. code:: none |
| 808 | |
| 809 | Here is a paragraph with some content. |
| 810 | |
| 811 | .. my_directive:: |
| 812 | Note the lack of blank line above here. |
| 813 | |
Keir Mierle | 78db8c6 | 2021-11-10 19:28:21 -0800 | [diff] [blame] | 814 | Tables |
| 815 | ====== |
| 816 | Consider using ``.. list-table::`` syntax, which is more maintainable and |
| 817 | easier to edit for complex tables (`details |
| 818 | <https://docutils.sourceforge.io/docs/ref/rst/directives.html#list-table>`_). |
Anthony DiGirolamo | 6a1484b | 2021-12-09 11:42:03 -0800 | [diff] [blame] | 819 | |
| 820 | .. _Sphinx: https://www.sphinx-doc.org/ |
| 821 | |
| 822 | .. inclusive-language: disable |
| 823 | |
| 824 | .. _reStructuredText Primer: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html |
| 825 | |
| 826 | .. inclusive-language: enable |