Nvim :help
pages, generated
from source
using the tree-sitter-vimdoc parser.
#pragma once
to prevent multiple inclusion.
#pragma once
fileio.h
and fileio_defs.h
. This distinction is done to minimize
recompilation on change. The reason for this is because adding a function or
modifying a function's signature happens more frequently than changing a type
The goal is to achieve the following:
extern
variables (including the EXTERN
macro)
#define
FUNC_ATTR_ALWAYS_INLINE
attribute
int i;
i = f(); // ❌: initialization separate from declaration.
int j = g(); // ✅: declaration has initialization.
int i;
int j; // ✅
int i, j; // ✅: multiple declarations, no initialization.
int i = 0;
int j = 0; // ✅: one initialization per line.
int i = 0, j; // ❌: multiple declarations with initialization.
int i = 0, j = 0; // ❌: multiple declarations with initialization.
clint.py
to detect style errors.
src/clint.py
is a Python script that reads a source file and identifies
style errors. It is not perfect, and has both false positives and false
negatives, but it is still a valuable tool. False positives can be ignored by
putting // NOLINT
at the end of the line.
alloca()
.
i++
) in statements.for (int i = 0; i < 3; i++) { }
int j = ++i; // ✅: ++i is used as an expression.
for (int i = 0; i < 3; ++i) { }
++i; // ❌: ++i is used as a statement.
const
pointers whenever possible. Avoid const
on non-pointer parameter definitions.
int const *foo
to const int *foo
. They
argue that this is more readable because it's more consistent: it keeps
the rule that const
always follows the object it's describing. However,
this consistency argument doesn't apply in codebases with few
deeply-nested pointer expressions since most const
expressions have only
one const
, and it applies to the underlying value. In such cases, there's
no consistency to maintain. Putting the const
first is arguably more
readable, since it follows English in putting the "adjective" (const
)
before the "noun" (int
).
const
first, we do not require it.
But be consistent with the code around you!void foo(const char *p, int i);
}
int foo(const int a, const bool b) {
}
int foo(int *const p) {
}
char
, int
, uint8_t
, int8_t
,
uint16_t
, int16_t
, uint32_t
, int32_t
, uint64_t
, int64_t
,
uintmax_t
, intmax_t
, size_t
, ssize_t
, uintptr_t
, intptr_t
, and
ptrdiff_t
.
int
for error codes and local, trivial variables only.
char
is
implementation defined.
uint8_t
, etc.)
printf
format placeholders for fixed width types.
Cast to uintmax_t
or intmax_t
if you have to format fixed width integers.
char
%hhu
%hhd
int
n/a %d
(u)intmax_t
%ju
%jd
(s)size_t
%zu
%zd
ptrdiff_t
%tu
%td
bool
to represent boolean values.int loaded = 1; // ❌: loaded should have type bool.
if (1 == x) {
if (x == 1) { //use this order
if ((x = f()) && (y = g())) {
static void f(void);
static void f(void)
{
...
}
<HEADER>
<PUBLIC FUNCTION DEFINITIONS>
<STATIC FUNCTION DEFINITIONS>
.c.generated.h
, *.h.generated.h
files
contain only non-static function declarations.// src/nvim/foo.c file
#include <stddef.h>
typedef int FooType;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "foo.c.generated.h"
#endif
…
// src/nvim/foo.h file
#pragma once
…
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "foo.h.generated.h"
#endif
sizeof(void *)
!= sizeof(int)
. Use intptr_t
if you want
a pointer-sized integer.
int64_t
/`uint64_t` member will by default end up being 8-byte aligned on a
64-bit system. If you have such structures being shared on disk between
32-bit and 64-bit code, you will need to ensure that they are packed the
same on both architectures. Most compilers offer a way to alter structure
alignment. For gcc, you can use __attribute__((packed))
. MSVC offers
#pragma pack()
and __declspec(align())
.
LL
or ULL
suffixes as needed to create 64-bit constants. For
example:int64_t my_value = 0x123456789LL;
uint64_t my_mask = 3ULL << 48;
sizeof ~
sizeof(varname)
to sizeof(type)
.
sizeof(varname)
when you take the size of a particular variable.
sizeof(varname)
will update appropriately if someone changes the variable
type either now or later. You may use sizeof(type)
for code unrelated to any
particular variable, such as code that manages an external or internal data
format where a variable of an appropriate C type is not convenient.Struct data;
memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(Struct));
if (raw_size < sizeof(int)) {
fprintf(stderr, "compressed record not big enough for count: %ju", raw_size);
return false;
}
int price_count_reader; // No abbreviation.
int num_errors; // "num" is a widespread convention.
int num_dns_connections; // Most people know what "DNS" stands for.
int n; // Meaningless.
int nerr; // Ambiguous abbreviation.
int n_comp_conns; // Ambiguous abbreviation.
int wgc_connections; // Only your group knows what this stands for.
int pc_reader; // Lots of things can be abbreviated "pc".
int cstmr_id; // Deletes internal letters.
_
).
my_useful_file.c getline_fix.c // ✅: getline refers to the glibc function.C files should end in
.c
and header files should end in .h
.
/usr/include
, such as db.h
.
http_server_logs.h
rather than logs.h
.
MyExcitingStruct
.
struct my_exciting_struct
.struct my_struct {
...
};
typedef struct my_struct MyAwesomeStruct;
my_exciting_local_variable
.
string table_name; // ✅: uses underscore.
string tablename; // ✅: all lowercase.
string tableName; // ❌: mixed case.
struct url_table_properties {
string name;
int num_entries;
}
g_
.
k
followed by mixed case: kDaysInAWeek
.
k
followed by words with uppercase first letters:const int kDaysInAWeek = 7;
my_exceptional_function()
. All functions in the same header file
should have a common prefix.
os_unix.h
:void unix_open(const char *path);
void unix_user_id(void);
If your function crashes upon an error, you should append or_die
to the
function name. This only applies to functions which could be used by
production code and to errors that are reasonably likely to occur during
normal operation.
kEnumName
.enum url_table_errors {
kOK = 0,
kErrorOutOfMemory,
kErrorMalformedInput,
};
MY_MACRO_THAT_SCARES_CPP_DEVELOPERS
.#define ROUND(x) ...
#define PI_ROUNDED 5.0
//
-style syntax only.// This is a comment spanning
// multiple lines
f();
.h
file will describe the variables and functions that are
declared in the file with an overview of what they are for and how they
are used. A .c
file should contain more information about implementation
details or discussions of tricky algorithms. If you feel the
implementation details or a discussion of the algorithms would be useful
for someone reading the .h
, feel free to put it there instead, but
mention in the .c
that the documentation is in the .h
file.
.h
and the .c
. Duplicated
comments diverge./// A brief description of this file.
///
/// A longer description of this file.
/// Be very generous here.
/// Window info stored with a buffer.
///
/// Two types of info are kept for a buffer which are associated with a
/// specific window:
/// 1. Each window can have a different line number associated with a
/// buffer.
/// 2. The window-local options for a buffer work in a similar way.
/// The window-info is kept in a list at g_wininfo. It is kept in
/// most-recently-used order.
struct win_info {
/// Next entry or NULL for last entry.
WinInfo *wi_next;
/// Previous entry or NULL for first entry.
WinInfo *wi_prev;
/// Pointer to window that did the wi_fpos.
Win *wi_win;
...
};
If the field comments are short, you can also put them next to the field. But
be consistent within one struct, and follow the necessary doxygen style.struct wininfo_S {
WinInfo *wi_next; ///< Next entry or NULL for last entry.
WinInfo *wi_prev; ///< Previous entry or NULL for first entry.
Win *wi_win; ///< Pointer to window that did the wi_fpos.
...
};
If you have already described a struct in detail in the comments at the top of
your file feel free to simply state "See comment at top of file for a complete
description", but be sure to have some sort of comment.
/// Brief description of the function.
///
/// Detailed description.
/// May span multiple paragraphs.
///
/// @param arg1 Description of arg1
/// @param arg2 Description of arg2. May span
/// multiple lines.
///
/// @return Description of the return value.
Iterator *get_iterator(void *arg1, void *arg2);
.h
file or wherever. It's okay to recapitulate
briefly what the function does, but the focus of the comments should be on
how it does it.// Note that we don't use Doxygen comments here.
Iterator *get_iterator(void *arg1, void *arg2)
{
...
}
/// The total number of tests cases that we run
/// through in this regression test.
const int kNumTestCases = 6;
// If we have enough memory, mmap the data portion too.
mmap_budget = max<int64>(0, mmap_budget - index_->length());
if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock)) {
return; // Error already logged.
}
do_something(); // Comment here so the comments line up.
do_something_else_that_is_longer(); // Comment here so there are two spaces between
// the code and the comment.
{ // One space before comment when opening a new scope is allowed,
// thus the comment lines up with the following comments and code.
do_something_else(); // Two spaces before line comments normally.
}
bool success = calculate_something(interesting_value,
10,
false,
NULL); // What are these arguments??
bool success = calculate_something(interesting_value,
10, // Default base value.
false, // Not the first time we're calling this.
NULL); // No callback.
const int kDefaultBaseValue = 10;
const bool kFirstTimeCalling = false;
Callback *null_callback = NULL;
bool success = calculate_something(interesting_value,
kDefaultBaseValue,
kFirstTimeCalling,
null_callback);
// Now go through the b array and make sure that if i occurs,
// the next element is i+1.
... // Geez. What a useless comment.
TODO
comments for code that is temporary, a short-term solution, or
good-enough but not perfect.
TODO
s should include the string TODO
in all caps, followed by the name,
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
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
person referenced will fix the problem. Thus when you create a TODO
, it is
almost always your name that is given.// TODO([email protected]): Use a "*" here for concatenation operator.
// TODO(Zeke): change this to use relations.
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
specific event ("Remove this code when all clients can handle XML
responses.").
@deprecated
docstring token.
@deprecated
in all caps. The comment goes either before the declaration
of the interface or on the same line as the declaration.
@deprecated
, write your name, email, or other identifier in
parentheses.
DEPRECATED
will not magically cause any callsites
to change. If you want people to actually stop using the deprecated facility,
you will have to fix the callsites yourself or recruit a crew to help you.
"\uFEFF"
, is the Unicode zero-width no-break space character, which
would be invisible if included in the source as straight UTF-8.
{
and one space before the }
{}
were the parentheses of a function call with that name. If there is
no name, assume a zero-length name.struct my_struct m = { // Here, you could also break before {.
superlongvariablename1,
superlongvariablename2,
{ short, interior, list },
{ interiorwrappinglist,
interiorwrappinglist2 } };
default
case (in the case of an enumerated value, the compiler will
warn you if any values are not handled). If the default case should never
execute, simply use abort()
:switch (var) {
case 0:
...
break;
case 1:
...
break;
default:
abort();
}
Switch statements that are conditional on an enumerated value should not have
a default
case if it is exhaustive. Explicit case labels are preferred over
default
, even if it leads to multiple case labels for the same code. For
example, instead of:case A:
...
case B:
...
case C:
...
default:
...
You should use:case A:
...
case B:
...
case C:
...
case D:
case E:
case F:
...
Certain compilers do not recognize an exhaustive enum switch statement as
exhaustive, which causes compiler warnings when there is a return statement in
every case of a switch statement, but no catch-all return statement. To fix
these spurious errors, you are advised to use UNREACHABLE
after the switch
statement to explicitly tell the compiler that the switch statement always
returns and any code after it is unreachable. For example:enum { A, B, C } var;
...
switch (var) {
case A:
return 1;
case B:
return 2;
case C:
return 3;
}
UNREACHABLE;
return
expression with parentheses.
return expr
; only where you would use them inx =
expr;`.return result;
return (some_long_condition && another_condition);
return (value); // You wouldn't write var = (value);
return(result); // return is not a function!
int long_variable = 0; // Don't align assignments.
int i = 1;
struct my_struct { // Exception: struct arrays.
const char *boy;
const char *girl;
int pos;
} my_variable[] = {
{ "Mia", "Michael", 8 },
{ "Elizabeth", "Aiden", 10 },
{ "Emma", "Mason", 2 },
};