doc(dev_style.txt): misc updates

This commit is contained in:
Justin M. Keyes 2021-09-23 06:58:39 -07:00
parent 5f49d0efee
commit c05b10748c

View File

@ -4,9 +4,11 @@
NVIM REFERENCE MANUAL NVIM REFERENCE MANUAL
Neovim style guide *dev-style* Nvim style guide *dev-style*
This reference describes the neovim style guide. This is style guide for developers working on Nvim's source code.
License: CC-By 3.0 http://creativecommons.org/licenses/by/3.0/
Type |gO| to see the table of contents. Type |gO| to see the table of contents.
@ -27,22 +29,22 @@ but we nonetheless keep things as they are in order to preserve consistency.
============================================================================== ==============================================================================
Header Files *dev-style-header* Header Files *dev-style-header*
The #define Guard ~ The #define Guard ~
All header files should have `#define` guards to prevent multiple inclusion. All header files should have `#define` guards to prevent multiple inclusion.
The format of the symbol name should be `NEOVIM_<DIRECTORY>_<FILE>_H`. The format of the symbol name should be `NVIM_<DIRECTORY>_<FILE>_H`.
In foo/bar.h: In foo/bar.h:
> >
#ifndef NEOVIM_FOO_BAR_H #ifndef NVIM_FOO_BAR_H
#define NEOVIM_FOO_BAR_H #define NVIM_FOO_BAR_H
... ...
#endif // NEOVIM_FOO_BAR_H #endif // NVIM_FOO_BAR_H
< <
@ -53,9 +55,9 @@ library, other libraries' `.h`, your project's `.h`.
In foo.c order your includes as follows: In foo.c order your includes as follows:
1. C system files. 1. C system files.
2. Other libraries' `.h` files. 2. Other libraries' `.h` files.
3. Your project's `.h` files. 3. Your project's `.h` files.
Exception: sometimes, system-specific code needs conditional includes. Exception: sometimes, system-specific code needs conditional includes.
Such code can put conditional includes after other includes. Of course, Such code can put conditional includes after other includes. Of course,
@ -74,7 +76,7 @@ represents the size of an array.
============================================================================== ==============================================================================
Scoping *dev-style-scope* Scoping *dev-style-scope*
Local Variables ~ Local Variables ~
@ -88,26 +90,31 @@ variable is and what it was initialized to. In particular, initialization
should be used instead of declaration and assignment, e.g. > should be used instead of declaration and assignment, e.g. >
int i; int i;
i = f(); // Bad -- initialization separate from declaration. i = f(); // BAD: initialization separate from declaration.
int j = g(); // Good -- declaration has initialization. int j = g(); // GOOD: declaration has initialization.
============================================================================== ==============================================================================
Neovim-Specific Magic Nvim-Specific Magic
clint ~ clint ~
Use `clint.py` to detect style errors. Use `clint.py` to detect style errors.
`clint.py` is a tool that reads a source file and identifies many style `src/clint.py` is a Python script that reads a source file and identifies
errors. It is not perfect, and has both false positives and false negatives, style errors. It is not perfect, and has both false positives and false
but it is still a valuable tool. False positives can be ignored by putting `// negatives, but it is still a valuable tool. False positives can be ignored by
NOLINT` at the end of the line. putting `// NOLINT` at the end of the line.
uncrustify ~
src/uncrustify.cfg is the authority for expected code formatting, for cases
not covered by clint.py. We remove checks in clint.py if they are covered by
uncrustify rules.
============================================================================== ==============================================================================
Other C Features *dev-style-features* Other C Features *dev-style-features*
Variable-Length Arrays and alloca() ~ Variable-Length Arrays and alloca() ~
@ -204,7 +211,7 @@ Don't use "yoda-conditions". Use at most one assignment per condition. >
if (1 == x) { if (1 == x) {
if (x == 1) { //use this order if (x == 1) { //use this order
if ((x = f()) && (y = g())) { if ((x = f()) && (y = g())) {
@ -318,7 +325,7 @@ format where a variable of an appropriate C type is not convenient. >
============================================================================== ==============================================================================
Naming *dev-style-naming* Naming *dev-style-naming*
The most important consistency rules are those that govern naming. The style The most important consistency rules are those that govern naming. The style
of a name immediately informs us what sort of thing the named entity is: a of a name immediately informs us what sort of thing the named entity is: a
@ -394,20 +401,20 @@ instance: `my_exciting_local_variable`.
For example: > For example: >
string table_name; // OK - uses underscore. string table_name; // OK: uses underscore.
string tablename; // OK - all lowercase. string tablename; // OK: all lowercase.
string tableName; // Bad - mixed case. string tableName; // BAD: mixed case.
< <
Struct Variables ~ Struct Variables ~
Data members in structs should be named like regular variables. > Data members in structs should be named like regular variables. >
struct url_table_properties { struct url_table_properties {
string name; string name;
int num_entries; int num_entries;
} }
< <
Global Variables ~ Global Variables ~
@ -463,18 +470,16 @@ They're like this: `MY_MACRO_THAT_SCARES_CPP_DEVELOPERS`. >
============================================================================== ==============================================================================
Comments *dev-style-comments* Comments *dev-style-comments*
Though a pain to write, comments are absolutely vital to keeping our code Comments are vital to keeping our code readable. The following rules describe
readable. The following rules describe what you should comment and where. But what you should comment and where. But remember: while comments are very
remember: while comments are very important, the best code is important, the best code is self-documenting.
self-documenting. Giving sensible names to types and variables is much better
than using obscure names that you must then explain through comments.
When writing your comments, write for your audience: the next contributor who When writing your comments, write for your audience: the next contributor who
will need to understand your code. Be generous — the next one may be you! will need to understand your code. Be generous — the next one may be you!
Neovim uses Doxygen comments. Nvim uses Doxygen comments.
Comment Style ~ Comment Style ~
@ -492,7 +497,7 @@ Start each file with a description of its contents.
Legal Notice ~ Legal Notice ~
We have no such thing. These things are in COPYING and only there. We have no such thing. These things are in LICENSE and only there.
File Contents ~ File Contents ~
@ -627,9 +632,9 @@ comments are required.
All global variables should have a comment describing what they are and All global variables should have a comment describing what they are and
what they are used for. For example: > what they are used for. For example: >
/// The total number of tests cases that we run /// The total number of tests cases that we run
/// through in this regression test. /// through in this regression test.
const int kNumTestCases = 6; const int kNumTestCases = 6;
Implementation Comments ~ Implementation Comments ~
@ -643,11 +648,11 @@ interesting, or important parts of your code.
line. These end-of-line comments should be separated from the code by 2 line. These end-of-line comments should be separated from the code by 2
spaces. Example: > spaces. Example: >
// If we have enough memory, mmap the data portion too. // If we have enough memory, mmap the data portion too.
mmap_budget = max<int64>(0, mmap_budget - index_->length()); mmap_budget = max<int64>(0, mmap_budget - index_->length());
if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock)) { if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock)) {
return; // Error already logged. return; // Error already logged.
} }
< <
Note that there are both comments that describe what the code is doing, Note that there are both comments that describe what the code is doing,
and comments that mention that an error has already been logged when the and comments that mention that an error has already been logged when the
@ -656,13 +661,13 @@ interesting, or important parts of your code.
If you have several comments on subsequent lines, it can often be more If you have several comments on subsequent lines, it can often be more
readable to line them up: > readable to line them up: >
do_something(); // Comment here so the comments line up. do_something(); // Comment here so the comments line up.
do_something_else_that_is_longer(); // Comment here so there are two spaces between do_something_else_that_is_longer(); // Comment here so there are two spaces between
// the code and the comment. // the code and the comment.
{ // One space before comment when opening a new scope is allowed, { // One space before comment when opening a new scope is allowed,
// thus the comment lines up with the following comments and code. // thus the comment lines up with the following comments and code.
do_something_else(); // Two spaces before line comments normally. do_something_else(); // Two spaces before line comments normally.
} }
< <
NULL, true/false, 1, 2, 3... ~ NULL, true/false, 1, 2, 3... ~
@ -672,29 +677,29 @@ interesting, or important parts of your code.
make your code self-documenting by using constants. For example, compare: make your code self-documenting by using constants. For example, compare:
> >
bool success = calculate_something(interesting_value, bool success = calculate_something(interesting_value,
10, 10,
false, false,
NULL); // What are these arguments?? NULL); // What are these arguments??
< <
versus: > versus: >
bool success = calculate_something(interesting_value, bool success = calculate_something(interesting_value,
10, // Default base value. 10, // Default base value.
false, // Not the first time we're calling this. false, // Not the first time we're calling this.
NULL); // No callback. NULL); // No callback.
< <
Or alternatively, constants or self-describing variables: > Or alternatively, constants or self-describing variables: >
const int kDefaultBaseValue = 10; const int kDefaultBaseValue = 10;
const bool kFirstTimeCalling = false; const bool kFirstTimeCalling = false;
Callback *null_callback = NULL; Callback *null_callback = NULL;
bool success = calculate_something(interesting_value, bool success = calculate_something(interesting_value,
kDefaultBaseValue, kDefaultBaseValue,
kFirstTimeCalling, kFirstTimeCalling,
null_callback); null_callback);
< <
Don'ts ~ Don'ts ~
@ -703,9 +708,9 @@ interesting, or important parts of your code.
person reading the code knows C better than you do, even though he or she person reading the code knows C better than you do, even though he or she
does not know what you are trying to do: > does not know what you are trying to do: >
// Now go through the b array and make sure that if i occurs, // Now go through the b array and make sure that if i occurs,
// the next element is i+1. // the next element is i+1.
... // Geez. What a useless comment. ... // Geez. What a useless comment.
Punctuation, Spelling and Grammar ~ Punctuation, Spelling and Grammar ~
@ -731,7 +736,7 @@ Use `TODO` comments for code that is temporary, a short-term solution, or
good-enough but not perfect. good-enough but not perfect.
`TODO`s should include the string `TODO` in all caps, followed by the name, `TODO`s should include the string `TODO` in all caps, followed by the name,
e-mail address, or other identifier of the person who can best provide context email address, or other identifier of the person who can best provide context
about the problem referenced by the `TODO`. The main purpose is to have a about the problem referenced by the `TODO`. The main purpose is to have a
consistent `TODO` format that can be searched to find the person who can consistent `TODO` format that can be searched to find the person who can
provide more details upon request. A `TODO` is not a commitment that the provide more details upon request. A `TODO` is not a commitment that the
@ -740,8 +745,7 @@ almost always your name that is given. >
// TODO(kl@gmail.com): Use a "*" here for concatenation operator. // TODO(kl@gmail.com): Use a "*" here for concatenation operator.
// TODO(Zeke): change this to use relations. // TODO(Zeke): change this to use relations.
If your `TODO` is of the form "At a future date do something" make sure that If your `TODO` is of the form "At a future date do something" make sure that
you either include a very specific date ("Fix by November 2005") or a very you either include a very specific date ("Fix by November 2005") or a very
specific event ("Remove this code when all clients can handle XML specific event ("Remove this code when all clients can handle XML
@ -750,14 +754,14 @@ responses.").
Deprecation Comments ~ Deprecation Comments ~
Mark deprecated interface points with `DEPRECATED` comments. Mark deprecated interface points with `@deprecated` docstring token.
You can mark an interface as deprecated by writing a comment containing the You can mark an interface as deprecated by writing a comment containing the
word `DEPRECATED` in all caps. The comment goes either before the declaration word `@deprecated` in all caps. The comment goes either before the declaration
of the interface or on the same line as the declaration. of the interface or on the same line as the declaration.
After the word `DEPRECATED`, write your name, e-mail address, or other After `@deprecated`, write your name, email, or other identifier in
identifier in parentheses. parentheses.
A deprecation comment must include simple, clear directions for people to fix A deprecation comment must include simple, clear directions for people to fix
their callsites. In C, you can implement a deprecated function as an inline their callsites. In C, you can implement a deprecated function as an inline
@ -774,7 +778,7 @@ interface point.
============================================================================== ==============================================================================
Formatting *dev-style-format* Formatting *dev-style-format*
Coding style and formatting are pretty arbitrary, but a project is much easier Coding style and formatting are pretty arbitrary, but a project is much easier
to follow if everyone uses the same style. Individuals may not agree with to follow if everyone uses the same style. Individuals may not agree with
@ -831,7 +835,7 @@ Functions look like this: >
If you have too much text to fit on one line: > If you have too much text to fit on one line: >
ReturnType really_long_function_name(Type par_name1, Type par_name2, ReturnType really_long_function_name(Type par_name1, Type par_name2,
Type par_name3) Type par_name3)
{ {
do_something(); do_something();
... ...
@ -840,9 +844,9 @@ If you have too much text to fit on one line: >
or if you cannot fit even the first parameter (but only then): > or if you cannot fit even the first parameter (but only then): >
ReturnType really_really_really_long_function_name( ReturnType really_really_really_long_function_name(
Type par_name1, // 4 space indent Type par_name1, // 4 space indent
Type par_name2, Type par_name2,
Type par_name3) Type par_name3)
{ {
do_something(); // 2 space indent do_something(); // 2 space indent
... ...
@ -877,15 +881,15 @@ multiple lines, with each subsequent line aligned with the first argument. Do
not add spaces after the open paren or before the close paren: > not add spaces after the open paren or before the close paren: >
bool retval = do_something(averyveryveryverylongargument1, bool retval = do_something(averyveryveryverylongargument1,
argument2, argument3); argument2, argument3);
If the function has many arguments, consider having one per line if this makes If the function has many arguments, consider having one per line if this makes
the code more readable: > the code more readable: >
bool retval = do_something(argument1, bool retval = do_something(argument1,
argument2, argument2,
argument3, argument3,
argument4); argument4);
Arguments may optionally all be placed on subsequent lines, with one line per Arguments may optionally all be placed on subsequent lines, with one line per
argument: > argument: >
@ -894,11 +898,11 @@ argument: >
... ...
... ...
if (...) { if (...) {
do_something( do_something(
argument1, // 4 space indent argument1, // 4 space indent
argument2, argument2,
argument3, argument3,
argument4); argument4);
} }
In particular, this should be done if the function signature is so long that In particular, this should be done if the function signature is so long that
@ -915,11 +919,11 @@ the `{}` were the parentheses of a function call with that name. If there is
no name, assume a zero-length name. > no name, assume a zero-length name. >
struct my_struct m = { // Here, you could also break before {. struct my_struct m = { // Here, you could also break before {.
superlongvariablename1, superlongvariablename1,
superlongvariablename2, superlongvariablename2,
{ short, interior, list }, { short, interior, list },
{ interiorwrappinglist, { interiorwrappinglist,
interiorwrappinglist2 } }; interiorwrappinglist2 } };
Conditionals ~ Conditionals ~
@ -938,11 +942,9 @@ You must have a space between the `if` and the open parenthesis. You must also
have a space between the close parenthesis and the curly brace, if you're have a space between the close parenthesis and the curly brace, if you're
using one. > using one. >
if(condition) { // Bad - space missing after IF. if(condition) { // BAD: space missing after IF.
if (condition){ // Bad - space missing before {. if (condition){ // BAD: space missing before {.
if(condition){ // Doubly bad. if (condition) { // GOOD: proper space after IF and before {.
if (condition) { // Good - proper space after IF and before {.
Loops and Switch Statements ~ Loops and Switch Statements ~
@ -957,13 +959,13 @@ execute, simply `assert`: >
switch (var) { switch (var) {
case 0: // 2 space indent case 0: // 2 space indent
... // 4 space indent ... // 4 space indent
break; break;
case 1: case 1:
... ...
break; break;
default: default:
assert(false); assert(false);
} }
Empty loop bodies should use `{}` or `continue`, but not a single semicolon. > Empty loop bodies should use `{}` or `continue`, but not a single semicolon. >
@ -971,10 +973,10 @@ Empty loop bodies should use `{}` or `continue`, but not a single semicolon. >
while (condition) { while (condition) {
// Repeat test until it returns false. // Repeat test until it returns false.
} }
for (int i = 0; i < kSomeNumber; i++) {} // Good - empty body. for (int i = 0; i < kSomeNumber; i++) {} // GOOD: empty body.
while (condition) continue; // Good - continue indicates no logic. while (condition) continue; // GOOD: continue indicates no logic.
while (condition); // Bad - looks like part of do/while loop. while (condition); // BAD: looks like part of do/while loop.
Pointer Expressions ~ Pointer Expressions ~
@ -999,8 +1001,8 @@ the variable name: >
char *c; char *c;
char * c; // Bad - spaces on both sides of * char * c; // BAD: spaces on both sides of *
char* c; // Bad char* c; // BAD
Boolean Expressions ~ Boolean Expressions ~
@ -1009,8 +1011,8 @@ When you have a boolean expression that is longer than the standard line
length, keep operators at the start of the line. > length, keep operators at the start of the line. >
if (this_one_thing > this_other_thing if (this_one_thing > this_other_thing
&& a_third_thing == a_fourth_thing && a_third_thing == a_fourth_thing
&& yet_another && last_one) { && yet_another && last_one) {
... ...
} }
@ -1041,25 +1043,25 @@ Even when preprocessor directives are within the body of indented code, the
directives should start at the beginning of the line. directives should start at the beginning of the line.
Nested directives should add one spaces after the hash mark for each level of Nested directives should add one spaces after the hash mark for each level of
indentation. > indentation.
// Good - directives at beginning of line // GOOD: directives at beginning of line >
if (lopsided_score) { if (lopsided_score) {
#if DISASTER_PENDING // Correct -- Starts at beginning of line #if DISASTER_PENDING // Correct -- Starts at beginning of line
drop_everything(); drop_everything();
# if NOTIFY // One space after # # if NOTIFY // One space after #
notify_client(); notify_client();
# endif # endif
#endif #endif
BackToNormal(); BackToNormal();
} }
// Bad - indented directives < // BAD: indented directives >
if (lopsided_score) { if (lopsided_score) {
#if DISASTER_PENDING // Wrong! The "#if" should be at beginning of line #if DISASTER_PENDING // Wrong! The "#if" should be at beginning of line
drop_everything(); drop_everything();
#endif // Wrong! Do not indent "#endif" #endif // Wrong! Do not indent "#endif"
back_to_normal(); back_to_normal();
} }
@ -1070,64 +1072,64 @@ whitespace at the end of a line.
General ~ General ~
> >
if (x) { // Open braces should always have a space before them. if (x) { // Open braces should always have a space before them.
... ...
} }
int i = 0; // Semicolons usually have no space before them. int i = 0; // Semicolons usually have no space before them.
int x[] = { 0 }; // Spaces inside braces for braced-init-list. int x[] = { 0 }; // Spaces inside braces for braced-init-list.
< <
Variables ~ Variables ~
> >
int long_variable = 0; // Don't align assignments. int long_variable = 0; // Don't align assignments.
int i = 1; int i = 1;
struct my_struct { // Exception: struct arrays. struct my_struct { // Exception: struct arrays.
const char *boy; const char *boy;
const char *girl; const char *girl;
int pos; int pos;
} my_variable[] = { } my_variable[] = {
{ "Mia", "Michael", 8 }, { "Mia", "Michael", 8 },
{ "Elizabeth", "Aiden", 10 }, { "Elizabeth", "Aiden", 10 },
{ "Emma", "Mason", 2 }, { "Emma", "Mason", 2 },
}; };
< <
Macros ~ Macros ~
> >
#define FI(x) \ // Don't align \'s in macro definitions. #define FI(x) \ // Don't align \'s in macro definitions.
foo(); \ foo(); \
bar(); \ bar(); \
... ...
< <
Loops and Conditionals ~ Loops and Conditionals ~
> >
if (b) { // Space after the keyword in condition. if (b) { // Space after the keyword in condition.
} else { // Spaces around else. } else { // Spaces around else.
} }
while (test) {} // There is usually no space inside parentheses. while (test) {} // There is usually no space inside parentheses.
for (; i < 5; i++) { // For loops always have a space after the for (; i < 5; i++) { // For loops always have a space after the
... // semicolon and no a space before the ... // semicolon and no a space before the
... // semicolon. ... // semicolon.
} }
switch (i) { switch (i) {
case 1: // No space before colon in a switch case. case 1: // No space before colon in a switch case.
... ...
case 2: break; // Space after a colon if there's code after it. case 2: break; // Space after a colon if there's code after it.
< <
Operators ~ Operators ~
> >
x = 0; // Assignment operators always have spaces around x = 0; // Assignment operators always have spaces around
// them. // them.
x = -5; // No spaces separating unary operators and their x = -5; // No spaces separating unary operators and their
x++; // arguments. x++; // arguments.
if (x && !y) if (x && !y)
... ...
v = w*x + y/z; // Use spaces to indicate operator precedence. v = w*x + y/z; // Use spaces to indicate operator precedence.
v = w * (x + z); // Parentheses should have no spaces inside them. v = w * (x + z); // Parentheses should have no spaces inside them.
i = (int)d; // No spaces after a cast operator. i = (int)d; // No spaces after a cast operator.
< <
Vertical Whitespace ~ Vertical Whitespace ~
@ -1149,9 +1151,9 @@ use your judgment. But in general, minimize use of vertical whitespace.
============================================================================== ==============================================================================
Parting Words Parting Words
The style guide is supposed to make the code more readable. If you think you The style guide is intended to make the code more readable. If you think you
have to violate its rules for the sake of clarity, do it! But please add a must violate its rules for the sake of clarity, do it! But please add a note
note to your pull request explaining your reasoning. to your pull request explaining your reasoning.
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:et:ft=help:norl: