aboutsummaryrefslogtreecommitdiff
path: root/contributing.md
diff options
context:
space:
mode:
Diffstat (limited to 'contributing.md')
-rw-r--r--contributing.md447
1 files changed, 397 insertions, 50 deletions
diff --git a/contributing.md b/contributing.md
index 775119a..2fe46f7 100644
--- a/contributing.md
+++ b/contributing.md
@@ -1,94 +1,441 @@
-# Contributing new code
+This document contains
+<details><summary>
+examples
+</summary>
+that you can click on to open them.
+</details>
+
+# Git
- Please do the following *before* sending a pull request:
- Merge upstream code (if any) back into your own branch
- Run formatters/linters
-
-# Git
-
- Push as often as possible
- Development is done on separate branches, these follow a pattern of
`name/feature` (i.e. `loek/dll-so-poc` or `jaro/class2`)
- The master branch is considered stable, and should always contain a
working/compiling version of the project
-
- TODO: tagging / versions
-
# Code style
-- ASCII only
-- Class names are always singular
-- Explanatory comments are placed above the line(s) they are explaining
-- Source files should only contain comments that plainly state what the code is
- supposed to do
-- Explanatory comments in headers may be used to clarify implementation design
- decisions
- Formatting nitty-gritty is handled by clang-format/clang-tidy (run `make
format` in the root folder of this repository to format all sources files)
+- <details><summary>
+ ASCII only
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ // crepe startup message
+ std::string message = "Hello, world!";
+ ```
+ </td><td>
+
+ ```cpp
+ // crêpe startup message
+ std::string message = "こんにちは世界";
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ Class names are always singular
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ class Foo {};
+ ```
+ </td><td>
+
+ ```cpp
+ class Cars {};
+ ```
+ </td></tr></table></details>
+- Source files contain the following types of comments:
+ - What is the code supposed to do (optional)
+ - Implementation details (if applicable)
+- Header files contain the following types of comments:
+ - Usage documentation (required)
+ - Implementation details (if they affect the header)
+ - Design/data structure decisions (if applicable)
+- <details><summary>
+ Comments are placed *above* the line(s) they are explaining
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ int add(int a, int b) {
+ // add numbers
+ int out = a + b;
+ return out;
+ }
+ ```
+ </td><td>
+
+ ```cpp
+ int add(int a, int b) {
+ int out = a + b; // add numbers
+ return out;
+ }
+ ```
+ </td></tr></table></details>
- Header includes are split into paragraphs separated by a blank line. The
order is:
1. system headers (using `<`brackets`>`)
2. relative headers NOT in the same folder as the current file
3. relative headers in the same folder as the current file
-- When using libraries of which the header include order is important, make
- sure to separate the include statements using a blank line (clang-format may
- sort include statements, but does not sort across empty lines).
-- All engine-related code is implemented under the `crepe` namespace,
- user-facing APIs under `crepe::api` (the folder structure should also reflect
- this).
-- `using namespace` may not be used in header files, only in source files.
-- Do not (indirectly) include private *dependency* headers in API header files,
- as these are no longer accessible when the engine is installed
-- Getter and setter functions are appropriately prefixed with `get_` and
- `set_`.
-- Doxygen commands are used with a backslash instead of an at-sign (i.e.
- `\brief` instead of `@brief`)
-- A singleton's instance is always accessed using a getter function that
- instantiates its own class as a static variable within the getter function
- scope, instead of storing the instance as a member variable directly:
+
+ > [!NOTE]
+ > When using libraries of which the header include order is important, make
+ > sure to separate the include statements using a blank line (clang-format
+ > may sort include statements, but does not sort across empty lines).
+
+ <details><summary>Example</summary>
+ <table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ #include <SDL2/SDL.h>
+ #include <iostream>
+
+ #include "api/Sprite.h"
+ #include "util/log.h"
+
+ #include "SDLContext.h"
+ ```
+ </td><td>
```cpp
- class Bad {
- static Bad instance;
- Bad & get_instance() { return instance; }
+ #include <SDL2/SDL.h>
+ #include "SDLContext.h"
+ #include "util/log.h"
+ #include <iostream>
+ #include "api/Sprite.h"
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ <code>using namespace</code> may not be used in header files, only in source files.
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ example.h:
+ ```cpp
+ namespace crepe {
+ void foo();
+ }
+ ```
+
+ example.cpp:
+ ```cpp
+ #include "example.h"
+ using namespace crepe;
+ void foo() {}
+ ```
+ </td><td>
+
+ example.h:
+ ```cpp
+ namespace crepe {
+ template <typename T>
+ T foo();
+ }
+ ```
+
+ example.hpp:
+ ```cpp
+ #include "example.h"
+ using namespace crepe;
+ template <typename T>
+ T foo();
+ ```
+ </td></tr></table></details>
+
+- <details><summary>
+ Getter and setter functions are appropriately prefixed with <code>get_</code>
+ and <code>set_</code>.
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ class Foo {
+ public:
+ int get_speed() const;
+ void set_speed(int speed);
+ private:
+ int speed;
};
+
+ ```
+ </td><td>
- class Good {
- Good & get_instance() {
- static Good instance;
+ ```cpp
+ class Foo {
+ public:
+ int speed() const;
+ void set_speed(int speed);
+ private:
+ int speed;
+ };
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ A singleton's instance is always accessed using a getter function that
+ instantiates its own class as a static variable within the getter function
+ scope, instead of storing the instance as a member variable directly.
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ class Foo {
+ Foo & get_instance() {
+ static Foo instance;
return instance;
}
};
```
-- Member variable default values should be directly defined in the class
+ </td><td>
+
+ ```cpp
+ Foo Foo::instance {};
+
+ class Foo {
+ static Foo instance;
+ Foo & get_instance() { return Foo::instance; }
+ };
+
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ Member variable default values should be directly defined in the class/struct
declaration instead of using the constructor.
-- Header files declare either a single class or symbols within a single
- namespace.
-- Use of the `auto` type is not allowed, with the following exceptions:
- - When naming the item type in a range-based for loop
- - When calling template factory methods that explicitly name the return type
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ class Foo {
+ int speed = 0;
+ };
+
+ ```
+ </td><td>
+
+ ```cpp
+ class Foo {
+ Foo() : speed(0) {}
+ int speed;
+ };
+ ```
+ </td></tr></table></details>
+- Use of the `auto` type is *not* allowed, with the following exceptions:
+ - <details><summary>
+ When naming the item type in a range-based for loop
+ </summary>
+
+ ```cpp
+ for (auto & item : foo()) {
+ // ...
+ }
+ ```
+ </details>
+ - <details><summary>
+ When calling template factory methods that explicitly name the return type
in the function call signature
- - When fetching a singleton instance
-- Only use member initializer lists for non-trivial types.
-- C++-style structs should define default values for all non-trivial fields.
-- Declare incomplete classes instead of including the relevant header where
- possible (i.e. if you only need a reference or pointer type).
-- Template functions are only declared in a `.h` header, and defined in a
- matching `.hpp` header.
-- Where possible, end (initializer) lists with a trailing comma (e.g. with
+ </summary>
+
+ ```cpp
+ auto ptr = make_unique<Foo>();
+ ```
+ </details>
+ - <details><summary>
+ When fetching a singleton instance
+ </summary>
+
+ ```cpp
+ auto & mgr = crepe::api::Config::get_instance();
+ ```
+ </details>
+
+- <details><summary>
+ Only use member initializer lists for non-trivial types.
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ class Foo {
+ public:
+ Foo() : bar("baz") {}
+ private:
+ std::string bar;
+ };
+
+ ```
+ </td><td>
+
+ ```cpp
+ class Foo {
+ public:
+ Foo() : bar(0) {}
+ private:
+ int bar;
+ };
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ C++-style structs should define default values for all non-trivial fields.
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ struct Foo {
+ int bar;
+ std::string baz;
+ };
+ ```
+ </td><td>
+
+ ```cpp
+ struct Foo {
+ int bar = 0;
+ std::string baz;
+ };
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ Declare incomplete classes instead of including the relevant header where
+ possible (i.e. if you only need a reference or raw pointer).
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ class Bar;
+ class Foo {
+ Bar & bar;
+ };
+
+ ```
+ </td><td>
+
+ ```cpp
+ #include "Bar.h"
+ class Foo {
+ Bar & bar;
+ };
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ Template functions are only <i>declared</i> in a <code>.h</code> header, and
+ <i>defined</i> in a matching <code>.hpp</code> header.
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ add.h:
+ ```cpp
+ template <typename T>
+ T add(T a, T b);
+
+ #include "add.hpp"
+ ```
+
+ add.hpp:
+ ```cpp
+ #include "add.h"
+
+ template <typename T>
+ T add(T a, T b) {
+ return a + b;
+ }
+ ```
+ </td><td>
+
+ add.h:
+ ```cpp
+ template <typename T>
+ T add(T a, T b) {
+ return a + b;
+ }
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ Where possible, end (initializer) lists with a trailing comma (e.g. with
structs, enums)
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ enum Color {
+ Red,
+ Green,
+ Blue,
+ };
+
+ ```
+ </td><td>
-## CMakeLists specific
+ ```cpp
+ enum Color {
+ Red,
+ Green,
+ Blue
+ };
+ ```
+ </td></tr></table></details>
+- <details><summary>
+ <code>#pragma</code> should be used instead of include guards
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ #pragma once
+
+ // ...
+ ```
+ </td><td>
+
+ ```cpp
+ #ifndef __INCLUDED_H
+ #define __INCLUDED_H
+
+ // ...
+
+ #endif
+ ```
+ </td></tr></table></details>
+
+## CMakeLists-specific
- Make sure list arguments (e.g. sources, libraries) given to commands (e.g.
`target_sources`, `target_link_libraries`) are on separate lines. This makes
resolving merge conflicts when multiple sources were added by different
people to the same CMakeLists.txt easier.
+# Structure
+
+- Files are placed in the appropriate directory:
+ |Path|Purpose|
+ |-|-|
+ |`crepe/`|Auxiliary, managers|
+ |`crepe/api/`|User-facing APIs|
+ |`crepe/util/`|Standalone utilities and helper functions|
+ |`crepe/system/`|(ECS) system classes|
+ |`crepe/facade/`|Library façades|
+- Do not (indirectly) include private *dependency* headers in API header files,
+ as these are no longer accessible when the engine is installed
+- All code is implemented under the `crepe` namespace.
+- Header files declare either a single class or symbols within a single
+ namespace.
+
# Documentation
- All documentation is written in U.S. English
+- <details><summary>
+ Doxygen commands are used with a backslash instead of an at-sign.
+ </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>
+
+ ```cpp
+ /**
+ * \brief do something
+ *
+ * \param bar Magic number
+ */
+ void foo(int bar);
+ ```
+ </td><td>
+
+ ```cpp
+ /**
+ * @brief do something
+ *
+ * @param bar Magic number
+ */
+ void foo();
+ ```
+ </td></tr></table></details>
# Libraries