Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A community-driven Emacs Lisp style guide

NotificationsYou must be signed in to change notification settings

bbatsov/emacs-lisp-style-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 

Repository files navigation

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 experience of using Emacs and creating/maintaining Emacs packages, 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 ofcoding conventions and tips too.

You can generate a PDF or an HTML copy of this guide usingPandoc.

Table of Contents

Source Code Layout & Organization

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)

  • Usespaces for indentation. No hard tabs.

In practical terms this means you should add the following to your Emacs config:

(setq-default indent-tabs-modenil)

An even better idea would be to force the use of spaces using.dir-locals.el in each of your Emacs Lisp projects.

((emacs-lisp-mode  (indent-tabs-modenil)))
  • For regular functions, vertically align function arguments.
;; good(format"%s%d"        something        something-else);; bad(format"%s%d"  something  something-else)
  • If the first argument is on a new line, align it with the function’s name.
;; good(format"%s %d" something something-else);; bad(format"%s %d"  something  something-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.
    ;; good(when something  (something-else));; bad - four spaces on the body(when something    (something-else));; bad - aligned like a regular function(when something (something-else))
  • Note that the “then” clause of anif form is a special argument, indent it by 4 spaces.
    ;; good(if something    then-clause  else-clause);; bad(if something  then-clause  else-clause)
  • Vertically alignlet bindings.
    ;; good(let ((thing1"some stuff")      (thing2"other stuff"))  ...);; bad(let ((thing1"some stuff")  (thing2"other stuff"))  ...)
  • Use Unix-style line endings. (*BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful.)
    • If you’re using Git you might want to add the following configuration setting to protect your project from Windows line endings creeping in:
    bash$ 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.
    ;; good(foo (bar baz) quux);; bad(foo(bar baz)quux)(foo ( bar baz ) quux)
  • Place all trailing parentheses on a single line instead of distinct lines.
    ;; good; single line(when something  (something-else));; bad; distinct lines(when something  (something-else))
  • Use empty lines between top-level forms.
    ;; good(defvarx ...)(defunfoo ...);; bad(defvarx ...)(defunfoo ...)

    An exception to the rule is the grouping of related =def=s together.

    ;; good(defconstmin-rows10)(defconstmax-rows20)(defconstmin-cols15)(defconstmax-cols30)
  • 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= andcond.
  • 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; -*-

Syntax

  • Don’t wrap the else clause of anif in aprogn (it’s wrapped inprogn implicitly).
;; good(if something    if-clause  (something)  (something-else));; bad(if something    if-clause  (progn    (something)    (something-else)))
  • Usewhen instead of(if ... (progn ...).
;; good(when pred  (foo)  (bar));; bad(if pred  (progn    (foo)    (bar)))
  • Useunless instead of(when (not ...) ...).
;; good(unless pred  (foo)  (bar));; bad(when (not pred)  (foo)  (bar))
  • Usenot instead ofnull, unless your checking whether something isnil (empty list). Despite its name (null instead ofnullp), the functionnull is mostly meant to be used as a predicate.
;; good(if (null lst) ...)(if (or (not foo) something) ...);; bad(if (not lst))(if (and (null foo) bar) ...)
  • When doing comparisons, keep in mind that the functions<,>, etc. accept a variable number of arguments as of Emacs 24.4.
;; Preferred(<5 x10);; Old(and (> x5) (< x10))
  • Uset as the catch-all test expression incond.
;; good(cond  ((< n0)"negative")  ((> n0)"positive")  (t"zero"));; bad(cond  ((< n0)"negative")  ((> n0)"positive")  (:else"zero"))
  • Use(1+ x) &(1- x) instead of(+ x 1) and(- x 1).
  • Usewith-eval-after-load instead ofeval-after-load.
;; good(with-eval-after-load"foo"  (bar)  (baz));; bad(eval-after-load"foo"  '(progn     (bar)     (baz)))

Naming

The only real difficulties in programming are cache invalidation and naming things.

– Phil Karlton

  • Uselisp-case for function and variable names.
;; good(defvarsome-var ...)(defunsome-fun ...);; bad(defvarsomeVar ...)(defunsomefun ...)(defvarsome_fun ...)
  • Prefix top-level names with the name of the library they belong to in order to avoid name clashes.
;; good(defunprojectile-project-root ...);; bad(defunproject-root ...)
  • Prefix unused local (lexically scoped) variables with_.
;; good(lambda (x_y) x);; bad(lambda (xy) 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 ap if it’s a single-word name and a-p if it’s a multi-word name (e.g.,evenp andbuffer-live-p).
;; good(defunpalindromep ...)(defunonly-one-p ...);; bad(defunpalindrome? ...); Scheme style(defunis-palindrome ...); Java style
;; good(deffacewidget-inactive ...);; bad(deffacewidget-inactive-face ...)

Macros

  • 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.

Functions

  • 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(mapcar (lambda (x) (or (car x)"")) some-list)(let ((predicate (lambda (x) (and (numberp x) (evenp x)))))  (funcall predicate1000));;; Bad - Define real functions for these.(defcustommy-predicate (lambda (x) (and (numberp x) (evenp x)))  ...)(define-key my-keymap (kbd"C-f")  (lambda () (interactive) (forward-char1)))(add-hook'my-hook (lambda () (save-some-buffers)))
  • Never hard quote a lambda, it impedes byte-compilation.
;;; Good(lambda (x) (car x));;; Ok, but redundant.#'(lambda (x) (car x));;; Bad'(lambda (x) (car x))
  • Don’t wrap functions in anonymous functions when you don’t need to.
;; good(cl-remove-if-not#'evenp numbers);; bad(cl-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 (likecl-labels).
;; good(cl-remove-if-not#'evenp numbers)(global-set-key (kbd"C-l C-l")#'redraw-display)(cl-labels ((butterfly () (message"42")))  (funcall#'butterfly));; bad(cl-remove-if-not'evenp numbers)(global-set-key (kbd"C-l C-l")'redraw-display)(cl-labels ((butterfly () (message"42")))  (funcall'butterfly))

Macro Declarations

  • Always declare thedebug-specification, this tells edebug which arguments are meant for evaluation. If all arguments are evaluated, a simple(declare (debug t)) is enough.
  • Declare theindent specification if the macro arguments should not be aligned like a function (think ofdefun orwith-current-buffer).
(defmacrodefine-widget (name&restforms)"Description"  (declare (debug (sexp body))           (indentdefun))  ...)

Loading and Autoloading

  • Always end each library file with aprovide statement and an appropriate comment (theprovide statement will allow dependent libraries to userequire).
(provide'foo);;; foo.el ends here
  • Always load library dependencies withrequire, rather thanload orload-library (the former is idempotent, while the others can result in multiple evaluations).
  • Includeautoload 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(define-derived-mode foo-mode ...);;;###autoload(define-minor-mode foo-minor-mode ...);;;###autoload(defunfoo-setup () ...);;; bad;;;###autoload(defunfoo--internal () ...);;;###autoload(defvarfoo-option)
  • Do not provideautoload 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(add-to-list'auto-mode-alist '("\\.foo\\'". foo-mode));;; bad;;;###autoload(foo-setup)

Lists

  • Usedolist instead of calling the same s-exps over different variables:
;;; good(dolist (hook '(prog-mode-hook text-mode-hook))  (add-hook hook'turn-on-column-number-mode)  (add-hook hook'turn-off-line-number-mode)  (add-hook hook'linum-mode));;; bad(add-hook'prog-mode-hook'turn-on-column-number-mode)(add-hook'prog-mode-hook'turn-off-line-number-mode)(add-hook'prog-mode-hook'linum-mode)(add-hook'text-mode-hook'turn-on-column-number-mode)(add-hook'text-mode-hook'turn-off-line-number-mode)(add-hook'text-mode-hook'linum-mode)
  • Useseq-do ordolist instead ofmapcar if you don’t intend to concatenate the result.
;;; good(font-lock-add-keywordsnil (mapcar'downcase list-of-crazy-cased-words))(seq-do'load list-of-files-to-load);;; bad(mapcar'load list-of-files-to-load)
  • Usedolist instead of callingseq-do over a lambda. Reserveseq-do for single function calls.
;;; good(dolist (map (list c-mode-map c++-mode-map))  (define-key map"\C-c\C-c"'compile));;; bad(mapc  (lambda (map) (define-key map"\C-c\C-c"'compile))  (list c-mode-map c++-mode-map))

Comments

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;; This is where Frob grovels and where Grovel frobs.;; This section of code has some important implications:;;   1. Foo.;;   2. Bar.;;   3. Baz.(defunfnord (zarquon);; If zob, then veeblefitz.  (quux 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.
;; bad(1+ 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

  • Avoid writing comments to explain bad code. Refactor the code to make it self-explanatory.

Do, or do not. There is no try. – Yoda

Comment Annotations

  • 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.
(defunsome-fun ();; FIXME: This has crashed occasionally since v1.2.3. It may;;        be related to the BarBazUtil upgrade. (xz 13-1-31)  (baz))
  • 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.
(defunbar ()  (sleep100)); OPTIMIZE
  • UseTODO to note missing features or functionality that should be added at a later date.
  • UseFIXME to note broken code that needs to be fixed.
  • UseOPTIMIZE to note slow or inefficient code that may cause performance problems.
  • UseHACK to note “code smells” where questionable coding practices were used and should be refactored away.
  • UseREVIEW 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’sREADME or similar.

Docstrings

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.
;; good(defungoto-line (line&optionalbuffer)"Go to LINE, counting from line 1 at beginning of buffer.If called interactively, a numeric prefix argument specifiesLINE; without a numeric prefix argument, read LINE from theminibuffer..."...);; bad(defungoto-line (line&optionalbuffer)"Go to LINE, counting from line 1 at beginning of buffer.   If called interactively, a numeric prefix argument specifies   LINE; without a numeric prefix argument, read LINE from the   minibuffer..."  ...);; also bad(defungoto-line (line&optionalbuffer)"Go to LINE, counting from line 1 at beginning of buffer.   If called interactively, a numeric prefix argument specifies LINE; without a numeric prefix argument, read LINE from the minibuffer..."  ...)

Tools

  • Usecheckdoc to check for docstring style issues.
    • Many people in the Emacs community usecheckdoc withFlycheck.
  • Usepackage-lint to check packages before submission to repositories such asMELPA.
    • See thepackage-lint README about integration withFlycheck.

Existential

  • Be consistent. In an ideal world, be consistent with these guidelines.
  • Use common sense.

Contributing

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!

License

http://i.creativecommons.org/l/by/3.0/88x31.png This work is licensed under aCreative Commons Attribution 3.0 Unported License

Spread the Word

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

About

A community-driven Emacs Lisp style guide

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors12


[8]ページ先頭

©2009-2025 Movatter.jp