mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
documentation: coding style.
CodingStyle.md should not be the first file, not the adhere to the styles. Rename CodingStyle.md --> CODINGSTYLE.md to follow the standard of other documents. Signed-off-by: Jan Iversen <jan@casacondor.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
216ef815c1
commit
4ef1e9cb28
1 changed files with 0 additions and 0 deletions
394
CODINGSTYLE.md
Normal file
394
CODINGSTYLE.md
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
# Coding Style
|
||||
|
||||
Here are some of the basics that we are trying to enforce for our coding style
|
||||
and conventions. The existing code (as of the commit that adds these lines) is
|
||||
not yet fully consistent to these rules, but following these rules will make
|
||||
sure that no one yells at you about your patches.
|
||||
|
||||
We have a script that can be used to reformat code to be reasonably close
|
||||
to these rules; it's in scripts/whitespace.pl - this script requires
|
||||
clang-format to be installed (which sadly isn't installed by default on
|
||||
any of our platforms; even on Mac where clang is the default compiler).
|
||||
|
||||
At the end of this file are some ideas for your .emacs file (if that's
|
||||
your editor of choice) as well as for QtCreator. If you have settings for
|
||||
other editors that implement this coding style, please add them here.
|
||||
|
||||
## Basic rules
|
||||
|
||||
* all indentation is tabs (set to 8 char) with the exception of
|
||||
continuation lines that are aligned with tabs and then spaces
|
||||
|
||||
* all keywords followed by a '(' have a space in between
|
||||
```
|
||||
if (condition)
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
```
|
||||
|
||||
* function calls do NOT have a space between their name and argument
|
||||
```
|
||||
i = some_function(argument);
|
||||
```
|
||||
|
||||
* usually there is no space on the inside of parenthesis (see examples
|
||||
above)
|
||||
|
||||
* function / method implementations have their opening curly braces in
|
||||
column 1
|
||||
|
||||
* all other opening curly braces follow at the end of the line, with a
|
||||
space separating them:
|
||||
```
|
||||
if (condition) {
|
||||
dosomething();
|
||||
dosomethingelse();
|
||||
}
|
||||
```
|
||||
|
||||
* both sides of an if / else clause either use or do not use curly braces:
|
||||
```
|
||||
if (condition)
|
||||
i = 4;
|
||||
else
|
||||
j = 6;
|
||||
|
||||
if (condition) {
|
||||
i = 6;
|
||||
} else {
|
||||
i = 4;
|
||||
j = 6;
|
||||
}
|
||||
```
|
||||
|
||||
* use space to make visual separation easier
|
||||
```
|
||||
a = b + 3 + e / 4;
|
||||
```
|
||||
|
||||
* continuation lines have the operator / comma at the end
|
||||
```
|
||||
if (very_long_condition_1 ||
|
||||
condition_2)
|
||||
|
||||
b = a + (c + d +
|
||||
f + z);
|
||||
```
|
||||
|
||||
* in a C++ constructor initialization list, the colon is on the same line and
|
||||
continuation lines are aligned as the rule above:
|
||||
```
|
||||
ClassName::ClassName() : x(1),
|
||||
y(2),
|
||||
z(3)
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
* unfortunate inconsistency
|
||||
- C code usually uses underscores to structure names
|
||||
```
|
||||
variable_in_C
|
||||
```
|
||||
- In contrast, C++ code usually uses camelCase
|
||||
```
|
||||
variableInCPlusPlus
|
||||
```
|
||||
|
||||
where the two meet, use your best judgment and go for best consistency
|
||||
(i.e., where does the variable "originate")
|
||||
|
||||
* there is a strong preference for lower case file names; sometimes conventions
|
||||
or outside requirements make camelCase filenames the better (or only) choice,
|
||||
but absent such an outside reason all file names should be lower case
|
||||
|
||||
* switch statements with blocks are a little bit special (to avoid indenting
|
||||
too far)
|
||||
```
|
||||
switch (foo) {
|
||||
case FIRST:
|
||||
whatever();
|
||||
break;
|
||||
case SECOND: {
|
||||
int i;
|
||||
for (i = 0; i < 5; i++)
|
||||
do_something(i);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Coding conventions
|
||||
|
||||
* variable declarations
|
||||
In C code we really like them to be at the beginning of a code block,
|
||||
not interspersed in the middle.
|
||||
in C++ we are a bit less strict about this - but still, try not to go
|
||||
crazy. Notably, in C++ the lifetime of a variable often coincides with the
|
||||
lifetime of a resource (e.g. file) and therefore the variable is defined
|
||||
at the place where the resource is needed.
|
||||
|
||||
* The `*`, `&` and `&&` declarators are grouped with the name, not the type
|
||||
(classical C-style) as in `char *string` instead of `char* string`. This
|
||||
reflects the precedence rules of the language: `int &i` means that the name
|
||||
`i` stands for a reference [to an object with type `int`], not that
|
||||
`i` stands for an object of the type [reference to `int`].
|
||||
Although this may seem like hairsplitting (both interpretations
|
||||
have the same effect) it is crucial in the
|
||||
definition of multiple variables, such
|
||||
as
|
||||
```
|
||||
struct dive *next, **pprev;
|
||||
```
|
||||
|
||||
* In C++ code, we generally use explicit types in variable declarations for clarity.
|
||||
Use `auto` sparingly and only in cases where code readability improves.
|
||||
Two classical examples are:
|
||||
- Iterators, whose type names often are verbose:
|
||||
```
|
||||
auto it = m_trackers.find(when);
|
||||
```
|
||||
is not only distinctly shorter than
|
||||
```
|
||||
QMap<qint64, gpsTracker>::iterator it = m_trackers.find(when);
|
||||
```
|
||||
it will also continue working if a different data structure is chosen.
|
||||
- If the type is given in the same line anyway. Thus,
|
||||
```
|
||||
auto service = qobject_cast<QLowEnergyService*>(sender());
|
||||
```
|
||||
is easier to read than and conveys the same information as
|
||||
```
|
||||
QLowEnergyService *service = qobject_cast<QLowEnergyService*>(sender());
|
||||
```
|
||||
- If the variable is a container that is only assigned to a local variable to
|
||||
be able to use it in a range-based for loop
|
||||
```
|
||||
const auto l = device.serviceUuids();
|
||||
for (QBluetoothUuid id: serviceUuids) {
|
||||
```
|
||||
The variable has also to be const to avoid that Qt containers will do a
|
||||
deep copy when the range bases for loop will call the begin() method
|
||||
internally.
|
||||
|
||||
* text strings
|
||||
The default language of subsurface is US English so please use US English
|
||||
spelling and terminology.
|
||||
User-visible strings should be passed to the tr() function to enable
|
||||
translation into other languages.
|
||||
- like this
|
||||
```
|
||||
QString msgTitle = tr("Submit user survey.");
|
||||
```
|
||||
- rather than
|
||||
```
|
||||
QString msgTitle = "Submit user survey.";
|
||||
```
|
||||
|
||||
This works by default in classes (indirectly) derived from QObject. Each
|
||||
string to be translated is associated with a context, which corresponds
|
||||
to the class name. Classes that are not derived from QObject can generate
|
||||
the tr() functions by using the `Q_DECLARE_TR_FUNCTIONS` macro:
|
||||
```
|
||||
#include <QCoreApplication>
|
||||
|
||||
class myClass {
|
||||
Q_DECLARE_TR_FUNCTIONS(gettextfromC)
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
As an alternative, which also works outside of class context, the tr()
|
||||
function of a different class can be called. This avoids creating multiple
|
||||
translations for the same string:
|
||||
```
|
||||
gettextFromC::tr("%1km")
|
||||
```
|
||||
|
||||
The gettextFromC class in the above example was created as a catch-all
|
||||
context for translations accessed in C code. But it can also be used
|
||||
from C++ helper functions. To use it from C, include the "core/gettext.h"
|
||||
header and invoke the translate() macro:
|
||||
```
|
||||
#include "core/gettext.h"
|
||||
|
||||
report_error(translate("gettextFromC", "Remote storage and local data diverged"));
|
||||
```
|
||||
It is crucial to pass "gettextFromC" as a first macro argument so that Qt
|
||||
is able to associate the string with the correct context.
|
||||
The translate macro returns a cached C-style string, which is generated at runtime
|
||||
when the particular translation string is encountered for the first time.
|
||||
It remains valid during the whole application's life time.
|
||||
|
||||
Outside of function context, the `QT_TRANSLATE_NOOP` macro can be used as in
|
||||
```
|
||||
struct ws_info_t ws_info[100] = {
|
||||
{ QT_TRANSLATE_NOOP("gettextFromC", "integrated"), 0 },
|
||||
{ QT_TRANSLATE_NOOP("gettextFromC", "belt"), 0 },
|
||||
{ QT_TRANSLATE_NOOP("gettextFromC", "ankle"), 0 },
|
||||
{ QT_TRANSLATE_NOOP("gettextFromC", "backplate"), 0 },
|
||||
{ QT_TRANSLATE_NOOP("gettextFromC", "clip-on"), 0 },
|
||||
};
|
||||
```
|
||||
Note that here, the texts will be scheduled for translation with the "gettextFromC"
|
||||
context, but the array is only initialized with the original text. The actual
|
||||
translation has to be performed later in code. For C-code, the `QT_TRANSLATE_NOOP`
|
||||
macro is defined in the "core/gettext.h" header.
|
||||
|
||||
* UI text style
|
||||
These guidelines are designed to ensure consistency in presentation within
|
||||
Subsurface.
|
||||
Only the first word of multi-word text strings should be capitalized unless
|
||||
a word would normally be capitalized mid-sentence, like Africa. This applies
|
||||
to all UI text including menus, menu items, tool-tips, button text and label
|
||||
text etc. e.g. "Check for updates" rather than "Check for Updates".
|
||||
We also capitalize Subsurface (NOTE: not SubSurface) when referring to the
|
||||
application itself.
|
||||
Abbreviations should end with a period, e.g. "temp." not "temp" for
|
||||
temperature
|
||||
Numerals in chemical formulae should use subscript characters e.g. O₂ not O2
|
||||
Partial pressures in Subsurface are, by convention, abbreviated with a single
|
||||
"p" rather than 2, as in pO₂ not ppO₂
|
||||
Where more than one term exists for something, please choose the one already
|
||||
in use within Subsurface e.g. Cylinder vs. Tank.
|
||||
|
||||
|
||||
* string manipulation
|
||||
* user interface
|
||||
In UI part of the code use of QString methods is preferred, see this pretty
|
||||
good guide in [QString documentation][1]
|
||||
* core components
|
||||
In the core part of the code, C-string should be used.
|
||||
C-string manipulation is not always straightforward specifically when
|
||||
it comes to memory allocation, a set of helper functions has been developed
|
||||
to help with this. Documentation and usage examples can be found in
|
||||
[core/membuffer.h][2]
|
||||
|
||||
## Sample Settings
|
||||
|
||||
### Emacs
|
||||
|
||||
These lines in your .emacs file should get you fairly close when it comes
|
||||
to indentation - many of the other rules you have to follow manually
|
||||
|
||||
```
|
||||
;; indentation
|
||||
(defun c-lineup-arglist-tabs-only (ignored)
|
||||
"Line up argument lists by tabs, not spaces"
|
||||
(let* ((anchor (c-langelem-pos c-syntactic-element))
|
||||
(column (c-langelem-2nd-pos c-syntactic-element))
|
||||
(offset (- (1+ column) anchor))
|
||||
(steps (floor offset c-basic-offset)))
|
||||
(* (max steps 1)
|
||||
c-basic-offset)))
|
||||
|
||||
(add-hook 'c-mode-common-hook
|
||||
(lambda ()
|
||||
;; Add kernel style
|
||||
(c-add-style
|
||||
"linux-tabs-only"
|
||||
'("linux" (c-offsets-alist
|
||||
(arglist-cont-nonempty
|
||||
c-lineup-gcc-asm-reg
|
||||
c-lineup-arglist-tabs-only))))))
|
||||
|
||||
(add-hook 'c-mode-hook
|
||||
(lambda ()
|
||||
(let ((filename (buffer-file-name)))
|
||||
;; Enable kernel mode for the appropriate files
|
||||
(setq indent-tabs-mode t)
|
||||
(c-set-style "linux-tabs-only"))))
|
||||
|
||||
(add-hook 'c++-mode-hook
|
||||
(lambda ()
|
||||
(let ((filename (buffer-file-name)))
|
||||
;; Enable kernel mode for the appropriate files
|
||||
(setq indent-tabs-mode t)
|
||||
(c-set-style "linux-tabs-only"))))
|
||||
```
|
||||
|
||||
### QtCreator
|
||||
|
||||
These settings seem to get indentation right in QtCreator. Making TAB
|
||||
always adjust indent makes it hard to add hard tabs before '\' when
|
||||
creating continuing lines. Copying a tab with your mouse / ctrl-C and
|
||||
inserting it with ctrl-V seems to work around that problem (use Command
|
||||
instead of ctrl on your Mac)
|
||||
Save this XML code below to a file, open Preferences (or Tools->Options)
|
||||
in QtCreator, pick C++ in the left column and then click on Import...
|
||||
to open the file you just created. Now you should have a "Subsurface"
|
||||
style that you can select which should work well for our coding style.
|
||||
|
||||
```
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorCodeStyle>
|
||||
<!-- Written by QtCreator 3.0.0, 2014-02-27T07:52:57. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>CodeStyleData</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="AlignAssignments">false</value>
|
||||
<value type="bool" key="AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="BindStarToIdentifier">true</value>
|
||||
<value type="bool" key="BindStarToLeftSpecifier">false</value>
|
||||
<value type="bool" key="BindStarToRightSpecifier">false</value>
|
||||
<value type="bool" key="BindStarToTypeName">false</value>
|
||||
<value type="bool" key="ExtraPaddingForConditionsIfConfusingAlign">false</value>
|
||||
<value type="bool" key="IndentAccessSpecifiers">false</value>
|
||||
<value type="bool" key="IndentBlockBody">true</value>
|
||||
<value type="bool" key="IndentBlockBraces">false</value>
|
||||
<value type="bool" key="IndentBlocksRelativeToSwitchLabels">false</value>
|
||||
<value type="bool" key="IndentClassBraces">false</value>
|
||||
<value type="bool" key="IndentControlFlowRelativeToSwitchLabels">true</value>
|
||||
<value type="bool" key="IndentDeclarationsRelativeToAccessSpecifiers">true</value>
|
||||
<value type="bool" key="IndentEnumBraces">false</value>
|
||||
<value type="bool" key="IndentFunctionBody">true</value>
|
||||
<value type="bool" key="IndentFunctionBraces">false</value>
|
||||
<value type="bool" key="IndentNamespaceBody">false</value>
|
||||
<value type="bool" key="IndentNamespaceBraces">false</value>
|
||||
<value type="int" key="IndentSize">8</value>
|
||||
<value type="bool" key="IndentStatementsRelativeToSwitchLabels">true</value>
|
||||
<value type="bool" key="IndentSwitchLabels">false</value>
|
||||
<value type="int" key="PaddingMode">2</value>
|
||||
<value type="bool" key="SpacesForTabs">false</value>
|
||||
<value type="int" key="TabSize">8</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>DisplayName</variable>
|
||||
<value type="QString">Subsurface</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
```
|
||||
|
||||
### Vim
|
||||
|
||||
As everybody knows vim is a way better editor than emacs and thus needs to be
|
||||
in this file too. Put this into your .vimrc and this should produce something
|
||||
close to our coding standards.
|
||||
|
||||
```
|
||||
" Subsurface coding style
|
||||
filetype plugin indent on
|
||||
filetype detect
|
||||
set cindent tabstop=8 shiftwidth=8 cinoptions=l1,:0,(0,g0
|
||||
" TODO: extern "C" gets indented
|
||||
|
||||
" And some sane defaults, optional, but quite nice
|
||||
set nocompatible
|
||||
syntax on
|
||||
colorscheme default
|
||||
set hls
|
||||
set is
|
||||
|
||||
" The default blue is just impossible to see on a black terminal
|
||||
highlight Comment ctermfg=Brown
|
||||
|
||||
" clearly point out when someone have trailing spaces
|
||||
highlight ExtraWhitespace ctermbg=red guibg=red
|
||||
|
||||
" Show trailing whitespace and spaces before a tab:
|
||||
match ExtraWhitespace /\s\+$\| \+\ze\t/
|
||||
```
|
||||
|
||||
[1]: http://doc.qt.io/qt-5/qstring.html#manipulating-string-data
|
||||
[2]: https://github.com/Subsurface-divelog/subsurface/blob/master/core/membuffer.h
|
||||
Loading…
Add table
Add a link
Reference in a new issue