Name: emacs-lisp-style-guide
Owner: emacs-china
Description: :blue_book: Emacs Lisp Style Guide in Chinese
Created: 2015-04-24 10:43:11.0
Updated: 2016-12-10 11:01:58.0
Pushed: 2018-01-17 19:44:58.0
Homepage: https://github.com/emacs-china/emacs-lisp-style-guide/blob/master/README-zhCN.md
Size: 61
Language: null
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
Role models are important.
– Officer Alex J. Murphy / RoboCop
This Emacs Lisp style guide recommends best practices so that real-world Emacs Lisp programmers can write code that can be maintained by other real-world Emacs Lisp programmers. A style guide that reflects real-world usage gets used, and a style guide that holds to an ideal that has been rejected by the people it is supposed to help risks not getting used at all — no matter how good it is.
The guide is separated into several sections of related rules. I've tried to add the rationale behind the rules (if it's omitted, I've assumed that it's pretty obvious).
I didn't come up with all the rules out of nowhere; they are mostly based on my extensive career as a professional software engineer, feedback and suggestions from members of the Emacs Lisp community, and various highly regarded Emacs Lisp programming resources, such as “GNU Emacs Lisp Reference Manual”.
The guide is still a work in progress; some sections are missing, others are incomplete, some rules are lacking examples, some rules don't have examples that illustrate them clearly enough. In due time these issues will be addressed — just keep them in mind for now.
Please note, that the Emacs developers maintain a list of coding conventions and tips too.
You can generate a PDF or an HTML copy of this guide using Transmuter.
Nearly everybody is convinced that every style but their own is ugly and unreadable. Leave out the “but their own” and they're probably right…
– Jerry Coffin (on indentation)
The indentation guidelines specified here can be taken for granted if
you're writing in Emacs. It will always do the right thing when you
hit <tab>
.
Use spaces for indentation. No hard tabs.
For regular functions, vertically align function arguments.
ood
mat "%s %d"
something
something-else)
ad
mat "%s %d"
mething
mething-else)
If the first argument is on a new line, align it with the function's name.
ood
mat
%d"
ething
ething-else)
ad
mat
s %d"
mething
mething-else)
Some forms are special, they take 1 or more “special” arguments
followed by a “body” (an arbitrary number of arguments where only
the final return value matters), e.g. if
, let
,
with-current-buffer
, etc. The special arguments should either be
on the same line as the form's name or be indented by 4 spaces. The
body arguments should be indented by 2 spaces.
ood
n something
omething-else))
ad - four spaces on the body
n something
(something-else))
ad - aligned like a regular function
n
ething
mething-else))
Note the “if” clause of an if
form is a special argument, indent it
by 4 spaces.
ood
something
if-clause
se-clause)
ad
something
-clause
se-clause)
Vertically align let
bindings.
ood
((thing1 "some stuff")
(thing2 "other stuff")
.)
ad
((thing1 "some stuff")
hing2 "other stuff"))
.)
Use Unix-style line endings. (*BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful.)
$ git config --global core.autocrlf true
If any text precedes an opening bracket((
, {
and
[
) or follows a closing bracket()
, }
and ]
), separate that
text from that bracket with a space. Conversely, leave no space after
an opening bracket and before following text, or after preceding text
and before a closing bracket.
ood
(bar baz) quux)
ad
(bar baz)quux)
( bar baz ) quux)
Place all trailing parentheses on a single line instead of distinct lines.
ood; single line
n something
omething-else))
ad; distinct lines
n something
omething-else)
Use empty lines between top-level forms.
ood
var x ...)
un foo ...)
ad
var x ...)
un foo ...)
An exception to the rule is the grouping of related def
s together.
ood
const min-rows 10)
const max-rows 20)
const min-cols 15)
const max-cols 30)
Do not place blank lines in the middle of a function or
macro definition. An exception can be made to indicate grouping of
pairwise constructs as found in e.g. let
and cond
.
Where feasible, avoid making lines longer than 80 characters.
Avoid trailing whitespace.
Avoid parameter lists with more than three or four positional parameters.
Always enable lexical scoping. This must be done on the first line as a file local variable.
-*- lexical-binding: t; -*-
Don't wrap the else clause of an if
in a progn
(it's wrapped in progn
implicitly).
ood
something
if-clause
omething)
omething-else))
ad
something
if-clause
rogn
(something)
(something-else)))
Use when
instead of (if ... (progn ...)
.
ood
n pred
oo)
ar))
ad
pred
rogn
(foo)
(bar)))
Use unless
instead of (when (not ...) ...)
.
ood
ess pred
oo)
ar))
ad
n (not pred)
oo)
ar))
When doing comparisons, keep in mind that the functions <
,
>
, etc. accept a variable number of arguments as of Emacs 24.4.
referred
x 10)
ld
(> x 5) (< x 10))
Use t
as the catch-all test expression in cond
.
ood
d
< n 0) "negative")
> n 0) "positive")
"zero"))
ad
d
< n 0) "negative")
> n 0) "positive")
else "zero"))
Use (1+ x)
& (1- x)
instead of (+ x 1)
and (- x 1)
.
The only real difficulties in programming are cache invalidation and naming things.
– Phil Karlton
Use lisp-case
for function and variable names.
ood
var some-var ...)
un some-fun ...)
ad
var someVar ...)
un somefun ...)
var some_fun ...)
Prefix top-level names with the name of the library they belong to in order to avoid name clashes.
ood
un projectile-project-root ...)
ad
un project-root ...)
Prefix unused local (lexically scoped) variables with _
.
ood
bda (x _y) x)
ad
bda (x y) x)
Use --
to denote private top-level definitions (e.g. projectile--private-fun
).
The names of predicate methods (methods that return a boolean value)
should end in a p
if it's a single-word name and a -p
if it's a
multi-word name (e.g., evenp
and buffer-live-p
).
ood
un palindromep ...)
un only-one-p ...)
ad
un palindrome? ...) ; Scheme style
un is-palindrome ...) ; Java style
Face names should not end in -face
.
ood
face widget-inactive ...)
ad
face widget-inactive-face ...)
Don't write a macro if a function will do.
Create an example of a macro usage first and the macro afterwards.
Break complicated macros into smaller functions whenever possible.
A macro should usually just provide syntactic sugar and the core of the macro should be a plain function. Doing so will improve composability.
Prefer syntax-quoted forms over building lists manually.
Use lambda
s for local bindings and function calls, not for
hooks or global variables. Define named functions for the latter,
they aid readability and customizability.
Good
car (lambda (x) (or (car x) "")) some-list)
((predicate (lambda (x) (and (numberp x) (evenp x)))))
uncall predicate 1000))
Bad - Define real functions for these.
custom my-predicate (lambda (x) (and (numberp x) (evenp x)))
.)
ine-key my-keymap (kbd "C-f")
ambda () (interactive) (forward-char 1)))
-hook 'my-hook (lambda () (save-some-buffers)))
Never hard quote a lambda, it impedes byte-compilation.
Good
bda (x) (car x))
Ok, but redundant.
ambda (x) (car x))
Bad
mbda (x) (car x))
Don't wrap functions in anonymous functions when you don't need to.
ood
remove-if-not #'evenp numbers)
ad
remove-if-not (lambda (x) (evenp x)) numbers)
Use a sharp quote (#'
) when quoting function names. It's a good
hint for the byte-compiler, which will warn you if the function is
undefined. Some macros can also behave differently otherwise (like
cl-labels
).
ood
remove-if-not #'evenp numbers)
bal-set-key (kbd "C-l C-l") #'redraw-display)
labels ((butterfly () (message "42")))
uncall #'butterfly))
ad
remove-if-not 'evenp numbers)
bal-set-key (kbd "C-l C-l") 'redraw-display)
labels ((butterfly () (message "42")))
uncall 'butterfly))
Always declare the debug-specification,
this tells edebug which arguments are meant for evaluation. If all
arguments are evaluated, a simple (declare (debug t))
is enough.
Declare the indent specification
if the macro arguments should not be aligned like a function (think
of defun
or with-current-buffer
).
macro define-widget (name &rest forms)
escription"
eclare (debug (sexp body))
(indent defun))
.)
Always end each library file with a provide
statement and an
appropriate comment (the provide
statement will allow dependent
libraries to use require
).
vide 'foo)
foo.el ends here
Always load library dependencies with require
, rather than load
or load-library
(the former is idempotent, while the others can
result in multiple evaluations).
Include autoload
cookies for mode definitions and commonly-used
user-facing functions and commands (i.e. setup functions and
commands that could be bound to a key). Conversely, do not
provide autoload cookies for global variables or internal functions.
good
##autoload
ine-derived-mode foo-mode ...)
##autoload
ine-minor-mode foo-minor-mode ...)
##autoload
un foo-setup () ...)
bad
##autoload
un foo--internal () ...)
##autoload
var foo-option)
Do not provide autoload
cookies for non-definition top-level
forms (autoloading a library should never alter the behavior of a
user's configuration). The single exception: auto-mode-alist
can
be altered for new major modes.
good
##autoload
-to-list 'auto-mode-alist '("\\.foo\\'" . foo-mode))
bad
##autoload
-setup)
Good code is its own best documentation. As you're about to add a comment, ask yourself, “How can I improve the code so that this comment isn't needed?” Improve the code and then document it to make it even clearer.
– Steve McConnell
Endeavor to make your code as self-documenting as possible.
Write heading comments with at least three semicolons.
Write top-level comments with three semicolons if it represents a heading, otherwise use two semicolons.
Write comments on a particular fragment of code before that fragment and aligned with it, using two semicolons.
Write margin comments with one semicolon.
Always have at least one space between the semicolon and the text that follows it.
Frob Grovel
his is where Frob grovels and where Grovel frobs.
his section of code has some important implications:
1. Foo.
2. Bar.
3. Baz.
un fnord (zarquon)
If zob, then veeblefitz.
uux zot
mumble ; Zibblefrotz.
frotz))
Comments longer than a word begin with a capital letter and use punctuation. Separate sentences with two spaces.
Avoid superfluous comments.
ad
counter) ; increments counter by one
Keep existing comments up-to-date. An outdated comment is worse than no comment at all.
Good code is like a good joke - it needs no explanation.
– Russ Olsen
Annotations should usually be written on the line immediately above the relevant code.
The annotation keyword is followed by a colon and a space, then a note describing the problem.
If multiple lines are required to describe the problem, subsequent lines should be indented as much as the first one.
Tag the annotation with your initials and a date so its relevance can be easily verified.
un some-fun ()
FIXME: This has crashed occasionally since v1.2.3. It may
be related to the BarBazUtil upgrade. (xz 13-1-31)
az))
In cases where the problem is so obvious that any documentation would be redundant, annotations may be left at the end of the offending line with no note. This usage should be the exception and not the rule.
un bar ()
leep 100)) ; OPTIMIZE
Use TODO
to note missing features or functionality that should be
added at a later date.
Use FIXME
to note broken code that needs to be fixed.
Use OPTIMIZE
to note slow or inefficient code that may cause
performance problems.
Use HACK
to note “code smells” where questionable coding practices
were used and should be refactored away.
Use REVIEW
to note anything that should be looked at to confirm it
is working as intended. For example: REVIEW: Are we sure this is how the
client does X currently?
Use other custom annotation keywords if it feels appropriate, but be
sure to document them in your project's README
or similar.
Emacs is famous for the breadth, depth, and ubiquity of its documentation. By taking the time to write docstrings in your package, you are helping to continue that tradition!
Begin with a terse, complete sentence. Use imperative language. For example, prefer “Verify” over “Verifies”, and “Check” over “Checks”.
When a function takes arguments, mention what the arguments do, whether they are required, and so on. Describe the arguments in UPCASE, and order them as they are used.
Always capitalize “Emacs”.
Do not indent subsequent lines of a documentation string. This looks nice in the source code, but looks bizarre when users view the documentation.
ood
un goto-line (line &optional buffer)
to LINE, counting from line 1 at beginning of buffer.
alled interactively, a numeric prefix argument specifies
; without a numeric prefix argument, read LINE from the
buffer..."
ad
un goto-line (line &optional buffer)
to LINE, counting from line 1 at beginning of buffer.
called interactively, a numeric prefix argument specifies
E; without a numeric prefix argument, read LINE from the
ibuffer..."
lso bad
un goto-line (line &optional buffer)
to LINE, counting from line 1 at beginning of buffer.
called interactively, a numeric prefix argument specifies
; without a numeric prefix argument, read LINE from the
buffer..."
checkdoc
to check for style issuescheckdoc
with Flycheck.package-lint
to check
packages before submission to repositories such
as MELPA.package-lint
README about integration with flycheck
.Nothing written in this guide is set in stone. It's my desire to work together with everyone interested in Emacs Lisp coding style, so that we could ultimately create a resource that will be beneficial to the entire Emacs community.
Feel free to open tickets or send pull requests with improvements. Thanks in advance for your help!
You can also support the style guide with financial contributions via gittip.
This work is licensed under a Creative Commons Attribution 3.0 Unported License
A community-driven style guide is of little use to a community that doesn't know about its existence. Tweet about the guide, share it with your friends and colleagues. Every comment, suggestion or opinion we get makes the guide just a little bit better. And we want to have the best possible guide, don't we?
Cheers,
Bozhidar