aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/_summary.md4
-rw-r--r--docs/cli.md31
-rw-r--r--docs/coding_conventions_c.md58
-rw-r--r--docs/coding_conventions_python.md314
-rw-r--r--docs/contributing.md58
-rw-r--r--docs/python_development.md45
6 files changed, 455 insertions, 55 deletions
diff --git a/docs/_summary.md b/docs/_summary.md
index 8a40ccd7f..611c283ac 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -8,6 +8,7 @@
8 8
9* [QMK Basics](README.md) 9* [QMK Basics](README.md)
10 * [QMK Introduction](getting_started_introduction.md) 10 * [QMK Introduction](getting_started_introduction.md)
11 * [QMK CLI](cli.md)
11 * [Contributing to QMK](contributing.md) 12 * [Contributing to QMK](contributing.md)
12 * [How to Use Github](getting_started_github.md) 13 * [How to Use Github](getting_started_github.md)
13 * [Getting Help](getting_started_getting_help.md) 14 * [Getting Help](getting_started_getting_help.md)
@@ -34,6 +35,8 @@
34 * [Keyboard Guidelines](hardware_keyboard_guidelines.md) 35 * [Keyboard Guidelines](hardware_keyboard_guidelines.md)
35 * [Config Options](config_options.md) 36 * [Config Options](config_options.md)
36 * [Keycodes](keycodes.md) 37 * [Keycodes](keycodes.md)
38 * [Coding Conventions - C](coding_conventions_c.md)
39 * [Coding Conventions - Python](coding_conventions_python.md)
37 * [Documentation Best Practices](documentation_best_practices.md) 40 * [Documentation Best Practices](documentation_best_practices.md)
38 * [Documentation Templates](documentation_templates.md) 41 * [Documentation Templates](documentation_templates.md)
39 * [Glossary](reference_glossary.md) 42 * [Glossary](reference_glossary.md)
@@ -41,6 +44,7 @@
41 * [Useful Functions](ref_functions.md) 44 * [Useful Functions](ref_functions.md)
42 * [Configurator Support](reference_configurator_support.md) 45 * [Configurator Support](reference_configurator_support.md)
43 * [info.json Format](reference_info_json.md) 46 * [info.json Format](reference_info_json.md)
47 * [Python Development](python_development.md)
44 48
45* [Features](features.md) 49* [Features](features.md)
46 * [Basic Keycodes](keycodes_basic.md) 50 * [Basic Keycodes](keycodes_basic.md)
diff --git a/docs/cli.md b/docs/cli.md
new file mode 100644
index 000000000..0365f2c9c
--- /dev/null
+++ b/docs/cli.md
@@ -0,0 +1,31 @@
1# QMK CLI
2
3This page describes how to setup and use the QMK CLI.
4
5# Overview
6
7The QMK CLI makes building and working with QMK keyboards easier. We have provided a number of commands to help you work with QMK:
8
9* `qmk compile-json`
10
11# Setup
12
13Simply add the `qmk_firmware/bin` directory to your `PATH`. You can run the `qmk` commands from any directory.
14
15```
16export PATH=$PATH:$HOME/qmk_firmware/bin
17```
18
19You may want to add this to your `.profile`, `.bash_profile`, `.zsh_profile`, or other shell startup scripts.
20
21# Commands
22
23## `qmk compile-json`
24
25This command allows you to compile JSON files you have downloaded from <https://config.qmk.fm>.
26
27**Usage**:
28
29```
30qmk compile-json mine.json
31```
diff --git a/docs/coding_conventions_c.md b/docs/coding_conventions_c.md
new file mode 100644
index 000000000..cbddedf8b
--- /dev/null
+++ b/docs/coding_conventions_c.md
@@ -0,0 +1,58 @@
1# Coding Conventions (C)
2
3Most of our style is pretty easy to pick up on, but right now it's not entirely consistent. You should match the style of the code surrounding your change, but if that code is inconsistent or unclear use the following guidelines:
4
5* We indent using four (4) spaces (soft tabs)
6* We use a modified One True Brace Style
7 * Opening Brace: At the end of the same line as the statement that opens the block
8 * Closing Brace: Lined up with the first character of the statement that opens the block
9 * Else If: Place the closing brace at the beginning of the line and the next opening brace at the end of the same line.
10 * Optional Braces: Always include optional braces.
11 * Good: if (condition) { return false; }
12 * Bad: if (condition) return false;
13* We encourage use of C style comments: `/* */`
14 * Think of them as a story describing the feature
15 * Use them liberally to explain why particular decisions were made.
16 * Do not write obvious comments
17 * If you not sure if a comment is obvious, go ahead and include it.
18* In general we don't wrap lines, they can be as long as needed. If you do choose to wrap lines please do not wrap any wider than 76 columns.
19* We use `#pragma once` at the start of header files rather than old-style include guards (`#ifndef THIS_FILE_H`, `#define THIS_FILE_H`, ..., `#endif`)
20* We accept both forms of preprocessor if's: `#ifdef DEFINED` and `#if defined(DEFINED)`
21 * If you are not sure which to prefer use the `#if defined(DEFINED)` form.
22 * Do not change existing code from one style to the other, except when moving to a multiple condition `#if`.
23 * Do not put whitespace between `#` and `if`.
24 * When deciding how (or if) to indent directives keep these points in mind:
25 * Readability is more important than consistency.
26 * Follow the file's existing style. If the file is mixed follow the style that makes sense for the section you are modifying.
27 * When choosing to indent you can follow the indention level of the surrounding C code, or preprocessor directives can have their own indent level. Choose the style that best communicates the intent of your code.
28
29Here is an example for easy reference:
30
31```c
32/* Enums for foo */
33enum foo_state {
34 FOO_BAR,
35 FOO_BAZ,
36};
37
38/* Returns a value */
39int foo(void) {
40 if (some_condition) {
41 return FOO_BAR;
42 } else {
43 return -1;
44 }
45}
46```
47
48# Auto-formatting with clang-format
49
50[Clang-format](https://clang.llvm.org/docs/ClangFormat.html) is part of LLVM and can automatically format your code for you, because ain't nobody got time to do it manually. We supply a configuration file for it that applies most of the coding conventions listed above. It will only change whitespace and newlines, so you will still have to remember to include optional braces yourself.
51
52Use the [full LLVM installer](http://llvm.org/builds/) to get clang-format on Windows, or use `sudo apt install clang-format` on Ubuntu.
53
54If you run it from the command-line, pass `-style=file` as an option and it will automatically find the .clang-format configuration file in the QMK root directory.
55
56If you use VSCode, the standard C/C++ plugin supports clang-format, alternatively there is a [separate extension](https://marketplace.visualstudio.com/items?itemName=LLVMExtensions.ClangFormat) for it.
57
58Some things (like LAYOUT macros) are destroyed by clang-format, so either don't run it on those files, or wrap the sensitive code in `// clang-format off` and `// clang-format on`.
diff --git a/docs/coding_conventions_python.md b/docs/coding_conventions_python.md
new file mode 100644
index 000000000..c7743050e
--- /dev/null
+++ b/docs/coding_conventions_python.md
@@ -0,0 +1,314 @@
1# Coding Conventions (Python)
2
3Most of our style follows PEP8 with some local modifications to make things less nit-picky.
4
5* We target Python 3.5 for compatability with all supported platforms.
6* We indent using four (4) spaces (soft tabs)
7* We encourage liberal use of comments
8 * Think of them as a story describing the feature
9 * Use them liberally to explain why particular decisions were made.
10 * Do not write obvious comments
11 * If you not sure if a comment is obvious, go ahead and include it.
12* We require useful docstrings for all functions.
13* In general we don't wrap lines, they can be as long as needed. If you do choose to wrap lines please do not wrap any wider than 76 columns.
14* Some of our practices conflict with the wider python community to make our codebase more approachable to non-pythonistas.
15
16# YAPF
17
18You can use [yapf](https://github.com/google/yapf) to style your code. We provide a config in [setup.cfg](setup.cfg).
19
20# Imports
21
22We don't have a hard and fast rule for when to use `import ...` vs `from ... import ...`. Understandability and maintainability is our ultimate goal.
23
24Generally we prefer to import specific function and class names from a module to keep code shorter and easier to understand. Sometimes this results in a name that is ambiguous, and in such cases we prefer to import the module instead. You should avoid using the "as" keyword when importing, unless you are importing a compatability module.
25
26Imports should be one line per module. We group import statements together using the standard python rules- system, 3rd party, local.
27
28Do not use `from foo import *`. Supply a list of objects you want to import instead, or import the whole module.
29
30## Import Examples
31
32Good:
33
34```
35from qmk import effects
36
37effects.echo()
38```
39
40Bad:
41
42```
43from qmk.effects import echo
44
45echo() # It's unclear where echo comes from
46```
47
48Good:
49
50```
51from qmk.keymap import compile_firmware
52
53compile_firmware()
54```
55
56OK, but the above is better:
57
58```
59import qmk.keymap
60
61qmk.keymap.compile_firmware()
62```
63
64# Statements
65
66One statement per line.
67
68Even when allowed (EG `if foo: bar`) we do not combine 2 statements onto a single line.
69
70# Naming
71
72`module_name`, `package_name`, `ClassName`, `method_name`, `ExceptionName`, `function_name`, `GLOBAL_CONSTANT_NAME`, `global_var_name`, `instance_var_name`, `function_parameter_name`, `local_var_name`.
73
74Function names, variable names, and filenames should be descriptive; eschew abbreviation. In particular, do not use abbreviations that are ambiguous or unfamiliar to readers outside your project, and do not abbreviate by deleting letters within a word.
75
76Always use a .py filename extension. Never use dashes.
77
78## Names to Avoid
79
80* single character names except for counters or iterators. You may use "e" as an exception identifier in try/except statements.
81* dashes (-) in any package/module name
82* __double_leading_and_trailing_underscore__ names (reserved by Python)
83
84# Docstrings
85
86To maintain consistency with our docstrings we've set out the following guidelines.
87
88* Use markdown formatting
89* Always use triple-dquote docstrings with at least one linebreak: `"""\n"""`
90* First line is a short (< 70 char) description of what the function does
91* If you need more in your docstring leave a blank line between the description and the rest.
92* Start indented lines at the same indent level as the opening triple-dquote
93* Document all function arguments using the format described below
94* If present, Args:, Returns:, and Raises: should be the last three things in the docstring, separated by a blank line each.
95
96## Simple docstring example
97
98```
99def my_awesome_function():
100 """Return the number of seconds since 1970 Jan 1 00:00 UTC.
101 """
102 return int(time.time())
103```
104
105## Complex docstring example
106
107```
108def my_awesome_function():
109 """Return the number of seconds since 1970 Jan 1 00:00 UTC.
110
111 This function always returns an integer number of seconds.
112 """
113 return int(time.time())
114```
115
116## Function arguments docstring example
117
118```
119def my_awesome_function(start=None, offset=0):
120 """Return the number of seconds since 1970 Jan 1 00:00 UTC.
121
122 This function always returns an integer number of seconds.
123
124
125 Args:
126 start
127 The time to start at instead of 1970 Jan 1 00:00 UTC
128
129 offset
130 Return an answer that has this number of seconds subtracted first
131
132 Returns:
133 An integer describing a number of seconds.
134
135 Raises:
136 ValueError
137 When `start` or `offset` are not positive numbers
138 """
139 if start < 0 or offset < 0:
140 raise ValueError('start and offset must be positive numbers.')
141
142 if not start:
143 start = time.time()
144
145 return int(start - offset)
146```
147
148# Exceptions
149
150Exceptions are used to handle exceptional situations. They should not be used for flow control. This is a break from the python norm of "ask for forgiveness." If you are catching an exception it should be to handle a situation that is unusual.
151
152If you use a catch-all exception for any reason you must log the exception and stacktrace using cli.log.
153
154Make your try/except blocks as short as possible. If you need a lot of try statements you may need to restructure your code.
155
156# Tuples
157
158When defining one-item tuples always include a trailing comma so that it is obvious you are using a tuple. Do not rely on implicit one-item tuple unpacking. Better still use a list which is unambiguous.
159
160This is particularly important when using the printf-style format strings that are commonly used.
161
162# Lists and Dictionaries
163
164We have configured YAPF to differentiate between sequence styles with a trailing comma. When a trailing comma is omitted YAPF will format the sequence as a single line. When a trailing comma is included YAPF will format the sequence with one item per line.
165
166You should generally prefer to keep short definition on a single line. Break out to multiple lines sooner rather than later to aid readability and maintainability.
167
168# Parentheses
169
170Avoid excessive parentheses, but do use parentheses to make code easier to understand. Do not use them in return statements unless you are explicitly returning a tuple, or it is part of a math expression.
171
172# Format Strings
173
174We generally prefer printf-style format strings. Example:
175
176```
177name = 'World'
178print('Hello, %s!' % (name,))
179```
180
181This style is used by the logging module, which we make use of extensively, and we have adopted it in other places for consistency. It is also more familiar to C programmers, who are a big part of our casual audience.
182
183Our included CLI module has support for using these without using the percent (%) operator. Look at `cli.echo()` and the various `cli.log` functions (EG, `cli.log.info()`) for more details.
184
185# Comprehensions & Generator Expressions
186
187We encourage the liberal use of comprehensions and generators, but do not let them get too complex. If you need complexity fall back to a for loop that is easier to understand.
188
189# Lambdas
190
191OK to use but probably should be avoided. With comprehensions and generators the need for lambdas is not as strong as it once was.
192
193# Conditional Expressions
194
195OK in variable assignment, but otherwise should be avoided.
196
197Conditional expressions are if statements that are in line with code. For example:
198
199```
200x = 1 if cond else 2
201```
202
203It's generally not a good idea to use these as function arguments, sequence items, etc. It's too easy to overlook.
204
205# Default Argument Values
206
207Encouraged, but values must be immutable objects.
208
209When specifying default values in argument lists always be careful to specify objects that can't be modified in place. If you use a mutable object the changes you make will persist between calls, which is usually not what you want. Even if that is what you intend to do it is confusing for others and will hinder understanding.
210
211Bad:
212
213```
214def my_func(foo={}):
215 pass
216```
217
218Good:
219
220```
221def my_func(foo=None):
222 if not foo:
223 foo = {}
224```
225
226# Properties
227
228Always use properties instead of getter and setter functions.
229
230```
231class Foo(object):
232 def __init__(self):
233 self._bar = None
234
235 @property
236 def bar(self):
237 return self._bar
238
239 @bar.setter
240 def bar(self, bar):
241 self._bar = bar
242```
243
244# True/False Evaluations
245
246You should generally prefer the implicit True/False evaluation in if statements, rather than checking equivalency.
247
248Bad:
249
250```
251if foo == True:
252 pass
253
254if bar == False:
255 pass
256```
257
258Good:
259
260```
261if foo:
262 pass
263
264if not bar:
265 pass
266```
267
268# Decorators
269
270Use when appropriate. Try to avoid too much magic unless it helps with understanding.
271
272# Threading and Multiprocessing
273
274Should be avoided. If you need this you will have to make a strong case before we merge your code.
275
276# Power Features
277
278Python is an extremely flexible language and gives you many fancy features such as custom metaclasses, access to bytecode, on-the-fly compilation, dynamic inheritance, object reparenting, import hacks, reflection, modification of system internals, etc.
279
280Don't use these.
281
282Performance is not a critical concern for us, and code understandability is. We want our codebase to be approachable by someone who only has a day or two to play with it. These features generally come with a cost to easy understanding, and we would prefer to have code that can be readily understood over faster or more compact code.
283
284Note that some standard library modules use these techniques and it is ok to make use of those modules. But please keep readability and understandability in mind when using them.
285
286# Type Annotated Code
287
288For now we are not using any type annotation system, and would prefer that code remain unannotated. We may revisit this in the future.
289
290# Function length
291
292Prefer small and focused functions.
293
294We recognize that long functions are sometimes appropriate, so no hard limit is placed on function length. If a function exceeds about 40 lines, think about whether it can be broken up without harming the structure of the program.
295
296Even if your long function works perfectly now, someone modifying it in a few months may add new behavior. This could result in bugs that are hard to find. Keeping your functions short and simple makes it easier for other people to read and modify your code.
297
298You could find long and complicated functions when working with some code. Do not be intimidated by modifying existing code: if working with such a function proves to be difficult, you find that errors are hard to debug, or you want to use a piece of it in several different contexts, consider breaking up the function into smaller and more manageable pieces.
299
300# FIXMEs
301
302It is OK to leave FIXMEs in code. Why? Encouraging people to at least document parts of code that need to be thought out more (or that are confusing) is better than leaving this code undocumented.
303
304All FIXMEs should be formatted like:
305
306```
307FIXME(username): Revisit this code when the frob feature is done.
308```
309
310...where username is your GitHub username.
311
312# Unit Tests
313
314These are good. We should have some one day.
diff --git a/docs/contributing.md b/docs/contributing.md
index 7d1a9691c..761bc9959 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -54,62 +54,10 @@ Never made an open source contribution before? Wondering how contributions work
54 54
55# Coding Conventions 55# Coding Conventions
56 56
57Most of our style is pretty easy to pick up on, but right now it's not entirely consistent. You should match the style of the code surrounding your change, but if that code is inconsistent or unclear use the following guidelines: 57Most of our style is pretty easy to pick up on. If you are familiar with either C or Python you should not have too much trouble with our local styles.
58
59* We indent using four (4) spaces (soft tabs)
60* We use a modified One True Brace Style
61 * Opening Brace: At the end of the same line as the statement that opens the block
62 * Closing Brace: Lined up with the first character of the statement that opens the block
63 * Else If: Place the closing brace at the beginning of the line and the next opening brace at the end of the same line.
64 * Optional Braces: Always include optional braces.
65 * Good: if (condition) { return false; }
66 * Bad: if (condition) return false;
67* We encourage use of C style comments: `/* */`
68 * Think of them as a story describing the feature
69 * Use them liberally to explain why particular decisions were made.
70 * Do not write obvious comments
71 * If you not sure if a comment is obvious, go ahead and include it.
72* In general we don't wrap lines, they can be as long as needed. If you do choose to wrap lines please do not wrap any wider than 76 columns.
73* We use `#pragma once` at the start of header files rather than old-style include guards (`#ifndef THIS_FILE_H`, `#define THIS_FILE_H`, ..., `#endif`)
74* We accept both forms of preprocessor if's: `#ifdef DEFINED` and `#if defined(DEFINED)`
75 * If you are not sure which to prefer use the `#if defined(DEFINED)` form.
76 * Do not change existing code from one style to the other, except when moving to a multiple condition `#if`.
77 * Do not put whitespace between `#` and `if`.
78 * When deciding how (or if) to indent directives keep these points in mind:
79 * Readability is more important than consistency.
80 * Follow the file's existing style. If the file is mixed follow the style that makes sense for the section you are modifying.
81 * When choosing to indent you can follow the indention level of the surrounding C code, or preprocessor directives can have their own indent level. Choose the style that best communicates the intent of your code.
82
83Here is an example for easy reference:
84 58
85```c 59* [Coding Conventions - C](coding_conventions_c.md)
86/* Enums for foo */ 60* [Coding Conventions - Python](coding_conventions_python.md)
87enum foo_state {
88 FOO_BAR,
89 FOO_BAZ,
90};
91
92/* Returns a value */
93int foo(void) {
94 if (some_condition) {
95 return FOO_BAR;
96 } else {
97 return -1;
98 }
99}
100```
101
102# Auto-formatting with clang-format
103
104[Clang-format](https://clang.llvm.org/docs/ClangFormat.html) is part of LLVM and can automatically format your code for you, because ain't nobody got time to do it manually. We supply a configuration file for it that applies most of the coding conventions listed above. It will only change whitespace and newlines, so you will still have to remember to include optional braces yourself.
105
106Use the [full LLVM installer](http://llvm.org/builds/) to get clang-format on Windows, or use `sudo apt install clang-format` on Ubuntu.
107
108If you run it from the command-line, pass `-style=file` as an option and it will automatically find the .clang-format configuration file in the QMK root directory.
109
110If you use VSCode, the standard C/C++ plugin supports clang-format, alternatively there is a [separate extension](https://marketplace.visualstudio.com/items?itemName=LLVMExtensions.ClangFormat) for it.
111
112Some things (like LAYOUT macros) are destroyed by clang-format, so either don't run it on those files, or wrap the sensitive code in `// clang-format off` and `// clang-format on`.
113 61
114# General Guidelines 62# General Guidelines
115 63
diff --git a/docs/python_development.md b/docs/python_development.md
new file mode 100644
index 000000000..b976a7c0e
--- /dev/null
+++ b/docs/python_development.md
@@ -0,0 +1,45 @@
1# Python Development in QMK
2
3This document gives an overview of how QMK has structured its python code. You should read this before working on any of the python code.
4
5## Script directories
6
7There are two places scripts live in QMK: `qmk_firmware/bin` and `qmk_firmware/util`. You should use `bin` for any python scripts that utilize the `qmk` wrapper. Scripts that are standalone and not run very often live in `util`.
8
9We discourage putting anything into `bin` that does not utilize the `qmk` wrapper. If you think you have a good reason for doing so please talk to us about your use case.
10
11## Python Modules
12
13Most of the QMK python modules can be found in `qmk_firmware/lib/python`. This is the path that we append to `sys.path`.
14
15We have a module hierarchy under that path:
16
17* `qmk_firmware/lib/python`
18 * `milc.py` - The CLI library we use. Will be pulled out into its own module in the future.
19 * `qmk` - Code associated with QMK
20 * `cli` - Modules that will be imported for CLI commands.
21 * `errors.py` - Errors that can be raised within QMK apps
22 * `keymap.py` - Functions for working with keymaps
23
24## CLI Scripts
25
26We have a CLI wrapper that you should utilize for any user facing scripts. We think it's pretty easy to use and it gives you a lot of nice things for free.
27
28To use the wrapper simply place a module into `qmk_firmware/lib/python/qmk/cli`, and create a symlink to `bin/qmk` named after your module. Dashes in command names will be converted into dots so you can use hierarchy to manage commands.
29
30When `qmk` is run it checks to see how it was invoked. If it was invoked as `qmk` the module name is take from `sys.argv[1]`. If it was invoked as `qmk-<module-name>` then everything after the first dash is taken as the module name. Dashes and underscores are converted to dots, and then `qmk.cli` is prepended before the module is imported.
31
32The module uses `@cli.entrypoint()` and `@cli.argument()` decorators to define an entrypoint, which is where execution starts.
33
34## Example CLI Script
35
36We have provided a QMK Hello World script you can use as an example. To run it simply run `qmk hello` or `qmk-hello`. The source code is listed below.
37
38```
39from milc import cli
40
41@cli.argument('-n', '--name', default='World', help='Name to greet.')
42@cli.entrypoint('QMK Python Hello World.')
43def main(cli):
44 cli.echo('Hello, %s!', cli.config.general.name)
45```