{"id":13837725,"url":"https://github.com/alphapapa/emacs-package-dev-handbook","last_synced_at":"2025-05-16T07:05:53.358Z","repository":{"id":37821507,"uuid":"99223466","full_name":"alphapapa/emacs-package-dev-handbook","owner":"alphapapa","description":"An Emacs package development handbook. Built with Emacs, by Emacs package developers, for Emacs package developers.","archived":false,"fork":false,"pushed_at":"2024-04-22T16:14:16.000Z","size":3046,"stargazers_count":1170,"open_issues_count":10,"forks_count":46,"subscribers_count":33,"default_branch":"master","last_synced_at":"2025-04-12T04:46:48.979Z","etag":null,"topics":["emacs","emacs-lisp"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alphapapa.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-03T11:00:45.000Z","updated_at":"2025-04-11T14:09:19.000Z","dependencies_parsed_at":"2023-01-29T19:31:04.893Z","dependency_job_id":"3267caef-62b7-4739-89cb-4730738c0901","html_url":"https://github.com/alphapapa/emacs-package-dev-handbook","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alphapapa%2Femacs-package-dev-handbook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alphapapa%2Femacs-package-dev-handbook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alphapapa%2Femacs-package-dev-handbook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alphapapa%2Femacs-package-dev-handbook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alphapapa","download_url":"https://codeload.github.com/alphapapa/emacs-package-dev-handbook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254485062,"owners_count":22078767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["emacs","emacs-lisp"],"created_at":"2024-08-04T15:01:22.568Z","updated_at":"2025-05-16T07:05:48.344Z","avatar_url":"https://github.com/alphapapa.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"#+TITLE: The Emacs Package Developer's Handbook\n\n#+OPTIONS: broken-links:t num:nil H:8 d:nil\n#+TAGS: Emacs\n#+SETUPFILE: export/setup/theme-darksun-local.setup\n\nAfter developing some little Emacs packages for a year or so, I began to notice how I'd forget little things that I learned, and then I'd have to go hunting for that information again.  I also noticed how there are some issues for which there doesn't seem to be a \"best practice\" or \"Standard Operating Procedure\" to refer to.\n\nSo this is intended to be a place to collect and organize information related to Emacs package development.  Built with Emacs, by Emacs package developers, for Emacs package developers.\n\nYou can read this Org file directly on the [[https://github.com/alphapapa/emacs-package-dev-handbook][repository]] rendered by GitHub (which lacks support for some minor features of the document), or you can read the [[https://alphapapa.github.io/emacs-package-dev-handbook/][HTML version]].\n\n*Note:* The primary sections are listed at the top of the page in the horizontal bar.\n\n* Contents                                                         :noexport:\n:PROPERTIES:\n:TOC:      :include siblings :ignore this :depth 1 :force depth\n:END:\n:CONTENTS:\n- [[#emacs-lisp][Emacs Lisp]]\n- [[#blogs][Blogs]]\n- [[#people][People]]\n- [[#contributions][Contributions]]\n- [[#tasks][Tasks]]\n:END:\n\n* Emacs Lisp                                                          :elisp:\n:PROPERTIES:\n:TOC:      :include descendants :depth 1 :force depth\n:ID:       50ce456f-4988-4984-9fa3-858089429580\n:CUSTOM_ID: emacs-lisp\n:END:\n:CONTENTS:\n- [[#animations--screencasts][Animations / Screencasts]]\n- [[#asynchronicity][Asynchronicity]]\n- [[#auditing--reviewing][Auditing / Reviewing]]\n- [[#binding][Binding]]\n- [[#buffers][Buffers]]\n- [[#checkers--linters][Checkers / linters]]\n- [[#collections-lists-vectors-hash-tables-etc][Collections (lists, vectors, hash-tables, etc.)]]\n- [[#color][Color]]\n- [[#data-structure][Data structure]]\n- [[#date--time][Date / Time]]\n- [[#debugging][Debugging]]\n- [[#destructuring][Destructuring]]\n- [[#documentation][Documentation]]\n- [[#editing][Editing]]\n- [[#general][General]]\n- [[#highlighting--font-locking][Highlighting / font-locking]]\n- [[#multiprocessing-generators-threads][Multiprocessing (generators, threads)]]\n- [[#networking][Networking]]\n- [[#packaging][Packaging]]\n- [[#pattern-matching][Pattern matching]]\n- [[#processes-incl-ipc-rpc][Processes (incl. IPC, RPC)]]\n- [[#optimization][Optimization]]\n- [[#refactoring][Refactoring]]\n- [[#regular-expressions][Regular expressions]]\n- [[#strings][Strings]]\n- [[#testing][Testing]]\n- [[#user-interface][User interface]]\n- [[#version-control][Version control]]\n- [[#xml--html][XML / HTML]]\n:END:\n\n*Note:* Usable Emacs Lisp code snippets (not examples) are tangled to the file =epdh.el=, which may be found in the [[https://github.com/alphapapa/emacs-package-dev-handbook/blob/master/epdh.el][repository]].  You could even install the file as a package with [[https://framagit.org/steckerhalter/quelpa-use-package][quelpa-use-package]], like this:\n\n#+BEGIN_SRC elisp :exports code\n  (use-package epdh\n    :quelpa (epdh :fetcher github :repo \"alphapapa/emacs-package-dev-handbook\"))\n#+END_SRC\n\n# Elisp header\n\n#+BEGIN_SRC elisp :exports none :tangle epdh.el\n  ;;; epdh.el --- Code useful for developing Emacs packages -*- lexical-binding: t; -*-\n\n  ;; Copyright (C) 2018  Adam Porter\n\n  ;; Author: Adam Porter \u003cadam@alphapapa.net\u003e\n  ;; Keywords: convenience, development\n  ;; URL: https://github.com/alphapapa/emacs-package-dev-handbook\n  ;; Package-Requires: ((emacs \"25.1\") (map \"2.1\") (dash \"2.13\") (s \"1.10.0\"))\n\n  ;;; License:\n\n  ;; This program is free software; you can redistribute it and/or modify\n  ;; it under the terms of the GNU General Public License as published by\n  ;; the Free Software Foundation, either version 3 of the License, or\n  ;; (at your option) any later version.\n\n  ;; This program is distributed in the hope that it will be useful,\n  ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n  ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n  ;; GNU General Public License for more details.\n\n  ;; You should have received a copy of the GNU General Public License\n  ;; along with this program.  If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n\n  ;;; Commentary:\n\n  ;; Code useful for developing Emacs packages.  Contributions welcome.\n\n  ;;; Code:\n\n  ;;;; Requirements\n\n  (require 'cl-lib)\n\n  (require 'dash)\n  (require 's)\n\n#+END_SRC\n\n** Animations / Screencasts                    :animations:screencasts:video:\n:PROPERTIES:\n:TOC:      :include descendants :depth 2\n:CUSTOM_ID: animations--screencasts\n:END:\n:CONTENTS:\n- [[#tools][Tools]]\n  - [[#demonstration][Demonstration]]\n  - [[#recording][Recording]]\n:END:\n\n*** Tools                                                           :tools:\n:PROPERTIES:\n:CUSTOM_ID: tools\n:END:\n\n**** Demonstration                                         :demonstration:\n:PROPERTIES:\n:CUSTOM_ID: demonstration\n:END:\n\nTools to aid demonstrating use of Emacs.\n\n***** [[https://github.com/tarsius/keycast][keycast: Show current command and its key in the mode line]]\n\n***** [[https://github.com/lewang/command-log-mode][command-log-mode: log commands to buffer]]\n\n**** Recording                                                 :recording:\n:PROPERTIES:\n:CUSTOM_ID: recording\n:END:\n\nTools to record screencasts of Emacs.\n\n***** [[https://gitlab.com/ambrevar/emacs-gif-screencast][emacs-gif-screencast]]                                         :GIFs:\n\n#+BEGIN_QUOTE\nMost Emacs screencasts are done by first recording a video, then converting it to a GIF.  It seems like a waste of resources considering the little animation Emacs features.\n\nMost of the time, one user action equals one visual change.  By exploiting this fact, this package tailors GIF-screencasting for Emacs and captures one frame per user action.  It’s much more efficient than capturing frames even at a frequency as low as 10 per second.  You could roughly expect 3 to 10 times smaller files compared to videos of the same quality.  (Benchmarks are welcome.)\n\nAnother neat perk of action-based captures is that it produces editable GIF files: programs such as Gifsicle or The GIMP can be used to edit the delays or rearrange frames.  This is particularly useful to fix mistakes in “post-processing”, without having to record the demo all over again.\n#+END_QUOTE\n\nThe author of this document can vouch for the fact that this package is the easiest, most powerful way to make screencast animations in Emacs!\n\n***** [[https://github.com/alphapapa/bashcaster][Bashcaster]]\n\nWhile =emacs-gif-screencast= should usually be your first choice, the way it works, recording one frame per Emacs command, isn't suitable for every case.  For general use, your editor can recommend Bashcaster, which is an easy-to-use script that can record the whole screen or individual windows, to videos or GIFs.\n\n** Asynchronicity                                                    :async:\n:PROPERTIES:\n:CUSTOM_ID: asynchronicity\n:END:\n\nSee [[id:94092c16-061c-45c9-9c66-77c5fdeceee8][Multiprocessing (generators, threads)]].\n\n** Auditing / Reviewing                                 :auditing:reviewing:\n:PROPERTIES:\n:CUSTOM_ID: auditing--reviewing\n:END:\n\nAuditing, reviewing, and analyzing source code.\n\n*** Tools                                                           :tools:\n\n**** [[https://github.com/cyrus-and/comb][comb: Interactive grep annotation tool for manual static analysis]]\n\n#+BEGIN_QUOTE\nComb is a native Emacs Lisp solution to search, browse and annotate occurrences of regular expressions in files. The interactive interface allows to perform an exhaustive classification of all the results to rule out false positives and asses proper matches during manual static analysis.\n#+END_QUOTE\n\n** Binding                                             :scope:binding:\n:PROPERTIES:\n:ID:       50f0cde2-34ca-4131-a688-b434ecde6819\n:TOC:      :include descendants :depth 2\n:CUSTOM_ID: binding\n:END:\n:CONTENTS:\n- [[#articles][Articles]]\n- [[#libraries][Libraries]]\n  - [[#dashel][dash.el]]\n  - [[#thunk][thunk]]\n- [[#tools-0][Tools]]\n  - [[#lexical-binding][Lexical binding]]\n:END:\n\nInformation related to variable scope and binding in elisp code (e.g. lexical vs. dynamic scope).\n\n*** Articles                                                     :articles:\n:PROPERTIES:\n:TOC:      :depth 0\n:CUSTOM_ID: articles\n:END:\n\n**** [[https://nullprogram.com/blog/2017/10/27/][Make Flet Great Again « null program]]      :macros:flet:letf:\n:PROPERTIES:\n:archive.today: http://archive.today/T8dHM\n:END:\n\nChris Wellons explains how the old ~cl~ macro ~flet~ changes in its new ~cl-lib~ version, ~cl-flet~, and how to use ~cl-letf~ to achieve the old functionality.  It's a way to override functions in both lexical and dynamic scope, which is especially useful for unit testing.\n\n*** Libraries                                                   :libraries:\n:PROPERTIES:\n:CUSTOM_ID: libraries\n:END:\n\n**** [[id:e85e4252-ea03-4473-b52f-9393e7527fad][dash.el]]\n:PROPERTIES:\n:CUSTOM_ID: dashel\n:END:\n\n**** [[https://github.com/emacs-mirror/emacs/blob/master/lisp/emacs-lisp/thunk.el][thunk]]                                                      :built_in:\n:PROPERTIES:\n:ID:       2f389382-af81-4f18-b6bc-ef33e39df1eb\n:CUSTOM_ID: thunk\n:END:\n\n#+BEGIN_QUOTE\nThunk provides functions and macros to delay the evaluation of forms.\n\nUse =thunk-delay= to delay the evaluation of a form (requires lexical-binding), and =thunk-force= to evaluate it. The result of\nthe evaluation is cached, and only happens once.\n\nHere is an example of a form which evaluation is delayed:\n\n    =(setq delayed (thunk-delay (message \"this message is delayed\")))=\n\n=delayed= is not evaluated until =thunk-force= is called, like the following:\n\n   =(thunk-force delayed)=\n\nThis file also defines macros =thunk-let= and =thunk-let*= that are analogous to =let= and =let*= but provide lazy evaluation of bindings by using thunks implicitly (i.e. in the expansion).\n#+END_QUOTE\n\n*** Tools                                                           :tools:\n:PROPERTIES:\n:CUSTOM_ID: tools-0\n:END:\n\n**** [[id:7247be4d-4f66-43ff-bb70-1b4a7458611b][Lexical binding]]                            :built_in:lexical_binding:\n:PROPERTIES:\n:CUSTOM_ID: lexical-binding\n:END:\n\n** Buffers                                                         :buffers:\n:PROPERTIES:\n:TOC: :include descendants\n:CUSTOM_ID: buffers\n:END:\n:CONTENTS:\n- [[#articles-0][Articles]]\n  - [[#buffer-passing-style][Buffer-Passing Style]]\n- [[#best-practices][Best practices]]\n  - [[#accessing-buffer-local-variables][Accessing buffer-local variables]]\n  - [[#inserting-strings][Inserting strings]]\n- [[#libraries-0][Libraries]]\n:END:\n\n*** Articles\n:PROPERTIES:\n:CUSTOM_ID: articles-0\n:END:\n\n**** [[*%5B%5Bhttps://nullprogram.com/blog/2014/05/27/%5D%5BEmacs%20Lisp%20Buffer%20Passing%20Style%5D%5D][Buffer-Passing Style]]                             :strings:\n:PROPERTIES:\n:CUSTOM_ID: buffer-passing-style\n:END:\n\n*** Best practices                                         :best_practices:\n:PROPERTIES:\n:TOC: :depth 1\n:CUSTOM_ID: best-practices\n:END:\n\n**** Accessing buffer-local variables\n:PROPERTIES:\n:CUSTOM_ID: accessing-buffer-local-variables\n:END:\n\nIt's much faster to use ~buffer-local-value~ than ~with-current-buffer~ to access the value of a variable in a buffer.\n\n#+BEGIN_SRC elisp :exports both :eval no-export\n  (bench-multi :times 1000 :ensure-equal t\n    :forms ((\"buffer-local-value\" (--filter (equal 'magit-status-mode (buffer-local-value 'major-mode it))\n                                            (buffer-list)))\n            (\"with-current-buffer\" (--filter (equal 'magit-status-mode (with-current-buffer it\n                                                                         major-mode))\n                                             (buffer-list)))))\n#+END_SRC\n\n#+RESULTS:\n| Form                | x faster than next | Total runtime | # of GCs | Total GC runtime |\n|---------------------+--------------------+---------------+----------+------------------|\n| buffer-local-value  | 50.34              |   0.047657734 |        0 |              0.0 |\n| with-current-buffer | slowest            |   2.399323452 |        0 |              0.0 |\n\n**** Inserting strings                                           :strings:\n:PROPERTIES:\n:CUSTOM_ID: inserting-strings\n:END:\n\nInserting strings into buffers with ~insert~ is generally fast, but it can slow down in buffers with lots of markers or overlays.  In general, it can be faster to insert one large string (which may include newlines).  For example:\n\n#+BEGIN_SRC elisp :exports both :cache yes\n  (let ((strings (cl-loop for i from 1 to 1000\n                          collect (number-to-string i))))\n    (garbage-collect)\n    (--sort (\u003c (caddr it) (caddr other))\n            (cl-loop for times in '(1 10 100)\n                     append (a-list \"(loop do (insert ...\"\n                                    (cons times\n                                          (benchmark-run-compiled times\n                                            (with-temp-buffer\n                                              (cl-loop for string in strings\n                                                       do (insert string)))))\n                                    \"(apply #'insert ...\"\n                                    (cons times\n                                          (benchmark-run-compiled times\n                                            (with-temp-buffer\n                                              (apply #'insert strings))))\n                                    \"(insert (apply #'concat ...\"\n                                    (cons times\n                                          (benchmark-run-compiled times\n                                            (with-temp-buffer\n                                              (insert (apply #'concat strings)))))))))\n#+END_SRC\n\n#+RESULTS[aa866ca87dbf71476c735ed51fca7373934bbf4f]:\n| (insert (apply #'concat ... | 100 | 0.000142085 | 0 | 0.0 |\n| (insert (apply #'concat ... |  10 | 0.000161172 | 0 | 0.0 |\n| (insert (apply #'concat ... |   1 |  0.00018764 | 0 | 0.0 |\n| (apply #'insert ...         |  10 | 0.000665472 | 0 | 0.0 |\n| (apply #'insert ...         | 100 | 0.000678471 | 0 | 0.0 |\n| (apply #'insert ...         |   1 | 0.000755329 | 0 | 0.0 |\n| (loop do (insert ...        |  10 | 0.000817031 | 0 | 0.0 |\n| (loop do (insert ...        | 100 | 0.000869779 | 0 | 0.0 |\n| (loop do (insert ...        |   1 | 0.001490397 | 0 | 0.0 |\n\nThe fastest method here is to call ~insert~ once with the result of calling ~concat~ once, using ~apply~ to pass all of the strings.  With 100 iterations, it's about 6x faster than the next-fastest method, and even with 1 iteration, it's over 2x faster.\n\n*** Libraries                                                   :libraries:\n:PROPERTIES:\n:ID:       523aa766-36a3-4827-a114-6babf72edc6b\n:TOC:      :depth 0\n:CUSTOM_ID: libraries-0\n:END:\n\n**** [[https://github.com/phillord/m-buffer-el][m-buffer-el: List Oriented Buffer Operations]]\n:PROPERTIES:\n:ID:       6858c112-9756-43b4-a2e3-fa00a71e9367\n:END:\n\n**** [[https://github.com/alezost/bui.el][bui.el: Buffer interface library]]\n\n#+BEGIN_QUOTE\nBUI (Buffer User Interface) is an Emacs library that can be used to make user interfaces to display some kind of entries (like packages, buffers, functions, etc.).  The intention of BUI is to be a high-level library which is convenient to be used both by:\n\npackage makers, as there is no need to bother about implementing routine details and usual features (like buffer history, filtering displayed entries, etc.);\n\nusers, as it provides familiar and intuitive interfaces with usual keys (for moving by lines, marking, sorting, switching between buttons); and what is also important, the defined interfaces are highly configurable through various generated variables.\n#+END_QUOTE\n\n** Checkers / linters                                     :linters:checkers:\n:PROPERTIES:\n:CUSTOM_ID: checkers--linters\n:END:\n\n*** [[https://github.com/gonewest818/elisp-lint][elisp-lint: basic linting for Emacs Lisp]]\n\nIncludes the following validators:\n\n+  byte-compile\n+  check-declare\n+  checkdoc\n+  fill-column\n+  indent\n+  indent-character\n+  package-format\n+  trailing-whitespace\n\n*** [[https://github.com/purcell/flycheck-package][flycheck-package: Flycheck checker for Elisp package metadata]]\n\n#+BEGIN_QUOTE\nThis library provides a =flycheck= checker for the metadata in Emacs Lisp files which are intended to be packages.  That metadata includes the package description, its dependencies and more.  The checks are performed by the separate =package-lint= library.\n#+END_QUOTE\n\n*** [[https://github.com/mattiase/relint][relint: regexp lint tool]]\n\n#+BEGIN_QUOTE\nRelint scans elisp files for mistakes in regexps, including deprecated syntax and bad practice.  It also checks the regexp-like arguments to =skip-chars-forward=, =skip-chars-backward=, =skip-syntax-forward= and =skip-syntax-backward=.\n#+END_QUOTE\n\n** Collections (lists, vectors, hash-tables, etc.)             :collections:\n:PROPERTIES:\n:TOC:      :include descendants :depth 1\n:CUSTOM_ID: collections-lists-vectors-hash-tables-etc\n:END:\n:CONTENTS:\n- [[#best-practices-0][Best practices]]\n- [[#examples][Examples]]\n- [[#libraries-1][Libraries]]\n- [[#tools-1][Tools]]\n:END:\n\n*** Best practices                                         :best_practices:\n:PROPERTIES:\n:TOC: :include descendants\n:CUSTOM_ID: best-practices-0\n:END:\n:CONTENTS:\n- [[#collecting-items-into-a-list][Collecting items into a list]]\n- [[#diffing-two-lists][Diffing two lists]]\n- [[#filtering-a-list][Filtering a list]]\n- [[#looking-up-associations][Looking up associations]]\n:END:\n\n**** Collecting items into a list                                  :lists:\n:PROPERTIES:\n:CUSTOM_ID: collecting-items-into-a-list\n:END:\n\nHere are some examples of fast ways to collect items into a list.\n\n#+CAPTION: Benchmarking code that collects items into a list.\n#+BEGIN_SRC elisp\n  (bench-multi-lexical :times 500000 :ensure-equal t\n    :forms ((\"cl-loop\" (let ((l '(1 2 3 4)))\n                         (cl-loop for val in l\n                                  collect val)))\n            (\"push-nreverse with setf/pop\" (let ((l '(1 2 3 4))\n                                                val r)\n                                            (while (setf val (pop l))\n                                              (push val r))\n                                            (nreverse r)))\n            (\"push-nreverse with when-let*/pop\" (let ((l '(1 2 3 4))\n                                                      r)\n                                                  (while (when-let* ((val (pop l)))\n                                                           (push val r)))\n                                                  (nreverse r)))\n            (\"nconc with when-let*/pop\" (let ((l '(1 2 3 4))\n                                              r)\n                                          (while (when-let* ((val (pop l)))\n                                                   (setf r (nconc r (list val)))))\n                                          r))\n            (\"nconc with setf/pop\" (let ((l '(1 2 3 4))\n                                              val r)\n                                          (while (setf val (pop l))\n                                            (setf r (nconc r (list val))))\n                                          r))))\n#+END_SRC\n\n#+RESULTS:\n| Form                             | x faster than next | Total runtime | # of GCs | Total GC runtime |\n|----------------------------------+--------------------+---------------+----------+------------------|\n| cl-loop                          |               1.01 |      0.154578 |        0 |                0 |\n| push-nreverse with setf/pop      |               1.02 |      0.155930 |        0 |                0 |\n| push-nreverse with when-let*/pop |               1.23 |      0.159211 |        0 |                0 |\n| nconc with setf/pop              |               1.06 |      0.195685 |        0 |                0 |\n| nconc with when-let*/pop         |            slowest |      0.207103 |        0 |                0 |\n\nAs is usually the case, the =cl-loop= macro expands to the most efficient code, which uses =(setq val (car ...=, =push=, and =nreverse=:\n\n#+CAPTION: Expansion of =cl-loop= form in the benchmark.\n#+BEGIN_SRC elisp\n  (cl-block nil\n    (let* ((--cl-var-- l)\n           (val nil)\n           (--cl-var-- nil))\n      (while (consp --cl-var--)\n        (setq val (car --cl-var--))\n        (push val --cl-var--)\n        (setq --cl-var-- (cdr --cl-var--)))\n      (nreverse --cl-var--)))\n#+END_SRC\n\nHowever, in some cases =cl-loop= may expand to code which uses =nconc=, which, as the benchmark shows, is much slower.  In that case, you may write the loop without =cl-loop= to avoid using =nconc=.\n\n**** Diffing two lists                                             :lists:\n:PROPERTIES:\n:CUSTOM_ID: diffing-two-lists\n:END:\n\nAs expected, =seq-difference= is the slowest, because it's a generic function that dispatches based on the types of its arguments, which is relatively slow in Emacs.  And it's not surprising that =cl-nset-difference= is generally slightly faster than =cl-set-difference=, since it's destructive.\n\nHowever, it is surprising how much faster =-difference= is than =cl-nset-difference=.\n\nIt's also nonintuitive that =-difference= suffers a large performance penalty by binding =-compare-fn= (the equivalent of the =:test= argument to =cl-set-difference=): while one might expect that setting it to =string== would give a slight performance increase, it's actually faster to let =-difference= use its default, =equal=.\n\nNote that since this benchmark compares lists of strings, =cl-nset-difference= requires setting the =:test= argument, since it uses =eql= by default, which does not work for comparing strings.\n\n#+BEGIN_SRC elisp :exports both :eval no-export\n  (defmacro test/set-lists ()\n    `(setf list1 (cl-loop for i from 0 below 1000\n                          collect (number-to-string i))\n           list2 (cl-loop for i from 500 below 1500\n                          collect (number-to-string i))))\n\n  (let (list1 list2)\n    (bench-multi-lexical :times 10 :ensure-equal t\n      :forms ((\"-difference\"\n               (progn\n                 (test/set-lists)\n                 (-difference list1 list2)))\n              (\"-difference string=\"\n               (progn\n                 ;; This is much slower because of the way `-contains?'\n                 ;; works when `-compare-fn' is non-nil.\n                 (test/set-lists)\n                 (let ((-compare-fn #'string=))\n                   (-difference list1 list2))))\n              (\"cl-set-difference equal\"\n               (progn\n                 (test/set-lists)\n                 (cl-set-difference list1 list2 :test #'equal)))\n              (\"cl-set-difference string=\"\n               (progn\n                 (test/set-lists)\n                 (cl-set-difference list1 list2 :test #'string=)))\n              (\"cl-nset-difference equal\"\n               (progn\n                 (test/set-lists)\n                 (cl-nset-difference list1 list2 :test #'equal)))\n              (\"cl-nset-difference string=\"\n               (progn\n                 (test/set-lists)\n                 (cl-nset-difference list1 list2 :test #'string=)))\n              (\"seq-difference\"\n               (progn\n                 (test/set-lists)\n                 (seq-difference list1 list2)))\n              (\"seq-difference string=\"\n               (progn\n                 (test/set-lists)\n                 (seq-difference list1 list2 #'string=))))))\n#+END_SRC\n\n#+RESULTS:\n| Form                       | x faster than next | Total runtime | # of GCs | Total GC runtime |\n|----------------------------+--------------------+---------------+----------+------------------|\n| -difference                |               7.16 |      0.084484 |        0 |                0 |\n| cl-nset-difference equal   |               1.05 |      0.605193 |        0 |                0 |\n| cl-set-difference string=  |               1.01 |      0.636973 |        0 |                0 |\n| cl-set-difference equal    |               1.01 |      0.644919 |        0 |                0 |\n| cl-nset-difference string= |               1.19 |      0.650708 |        0 |                0 |\n| -difference string=        |               1.59 |      0.773919 |        0 |                0 |\n| seq-difference             |               1.05 |      1.232616 |        0 |                0 |\n| seq-difference string=     |            slowest |      1.293030 |        0 |                0 |\n\n**** Filtering a list                                              :lists:\n:PROPERTIES:\n:CUSTOM_ID: filtering-a-list\n:END:\n\nUsing ~-select~ from =dash.el= seems to be the fastest way:\n\n#+BEGIN_SRC elisp :exports both :cache yes\n  (let ((list (cl-loop for i from 1 to 1000\n                       collect i)))\n    (bench-multi :times 100\n      :ensure-equal t\n      :forms ((\"(-non-nil (--map (when ...\" (-non-nil\n                                             (--map (when (cl-evenp it) it) list)))\n              (\"(delq nil (--map (when ...\" (delq nil\n                                                  (--map (when (cl-evenp it) it) list)))\n              (\"cl-loop\" (cl-loop for i in list\n                                  when (cl-evenp i)\n                                  collect i))\n              (\"-select\" (-select #'cl-evenp list))\n              (\"cl-remove-if-not\" (cl-remove-if-not #'cl-evenp list))\n              (\"seq-filter\" (seq-filter #'cl-evenp  list)))))\n#+END_SRC\n\n#+RESULTS[6b2e97c1ebead84a53fd771684cc3e155e7f6b1e]:\n| Form                       | x faster than next | Total runtime | # of GCs | Total GC runtime |\n|----------------------------+--------------------+---------------+----------+------------------|\n| -select                    |               1.17 |    0.01540391 |        0 |              0.0 |\n| cl-loop                    |               1.05 |    0.01808226 |        0 |              0.0 |\n| seq-filter                 |               1.13 |    0.01891708 |        0 |              0.0 |\n| (delq nil (--map (when ... |               1.15 |    0.02134727 |        0 |              0.0 |\n| cl-remove-if-not           |               1.18 |    0.02459478 |        0 |              0.0 |\n| (-non-nil (--map (when ... |            slowest |    0.02903999 |        0 |              0.0 |\n\n**** Looking up associations\n:PROPERTIES:\n:CUSTOM_ID: looking-up-associations\n:END:\n\nThere are a few options in Emacs Lisp for looking up values in associative data structures: association lists (alists), property lists (plists), and hash tables.  Which one performs best in a situation may depend on several factors.  This benchmark shows what may be a common case: looking up values using a string as the key.  We compare several combinations, including the case of prepending a prefix to the string, interning it, and looking up the resulting symbol (which might be done, e.g. when looking up a function to call based on the value of a string).\n\n#+BEGIN_SRC elisp :exports both :cache yes\n  (bench-multi-lets :times 10000 :ensure-equal t\n    :lets ((\"with 26 pairs\"\n            ((char-range (cons ?A ?Z))\n             (strings (cl-loop for char from (car char-range) to (cdr char-range)\n                               collect (concat \"prefix-\" (char-to-string char))))\n             (strings-alist (cl-loop for string in strings\n                                     collect (cons string string)))\n             (symbols-alist (cl-loop for string in strings\n                                     collect (cons (intern string) string)))\n             (strings-plist (map-into strings-alist 'plist))\n             (symbols-plist (map-into symbols-alist 'plist))\n             (strings-ht (map-into strings-alist '(hash-table :test equal)))\n             (symbols-ht-equal (map-into symbols-alist '(hash-table :test equal)))\n             (symbols-ht-eq (map-into symbols-alist '(hash-table :test eq)))))\n           (\"with 52 pairs\"\n            ((char-range (cons ?A ?z))\n             (strings (cl-loop for char from (car char-range) to (cdr char-range)\n                               collect (concat \"prefix-\" (char-to-string char))))\n             (strings-alist (cl-loop for string in strings\n                                     collect (cons string string)))\n             (symbols-alist (cl-loop for string in strings\n                                     collect (cons (intern string) string)))\n             (strings-plist (map-into strings-alist 'plist))\n             (symbols-plist (map-into symbols-alist 'plist))\n             (strings-ht (map-into strings-alist '(hash-table :test equal)))\n             (symbols-ht-equal (map-into symbols-alist '(hash-table :test equal)))\n             (symbols-ht-eq (map-into symbols-alist '(hash-table :test eq))))))\n    :forms ((\"strings/alist-get/string=\" (sort (cl-loop for string in strings\n                                                        collect (alist-get string strings-alist nil nil #'string=))\n                                               #'string\u003c))\n            (\"strings/plist\" (sort (cl-loop for string in strings\n                                            collect (plist-get strings-plist string))\n                                   #'string\u003c))\n            (\"symbols/concat/intern/plist\" (sort (cl-loop for char from (car char-range) to (cdr char-range)\n                                                          for string = (concat \"prefix-\" (char-to-string char))\n                                                          for symbol = (intern string)\n                                                          collect (plist-get symbols-plist symbol))\n                                                 #'string\u003c))\n            (\"strings/alist-get/equal\" (sort (cl-loop for string in strings\n                                                      collect (alist-get string strings-alist nil nil #'equal))\n                                             #'string\u003c))\n            (\"strings/hash-table/equal\" (sort (cl-loop for string in strings\n                                                       collect (gethash string strings-ht))\n                                              #'string\u003c))\n            (\"symbols/concat/intern/hash-table/equal\" (sort (cl-loop for char from (car char-range) to (cdr char-range)\n                                                                     for string = (concat \"prefix-\" (char-to-string char))\n                                                                     for symbol = (intern string)\n                                                                     collect (gethash symbol symbols-ht-equal))\n                                                            #'string\u003c))\n            (\"symbols/concat/intern/hash-table/eq\" (sort (cl-loop for char from (car char-range) to (cdr char-range)\n                                                                  for string = (concat \"prefix-\" (char-to-string char))\n                                                                  for symbol = (intern string)\n                                                                  collect (gethash symbol symbols-ht-eq))\n                                                         #'string\u003c))\n            (\"symbols/concat/intern/alist-get\" (sort (cl-loop for char from (car char-range) to (cdr char-range)\n                                                              for string = (concat \"prefix-\" (char-to-string char))\n                                                              for symbol = (intern string)\n                                                              collect (alist-get symbol symbols-alist))\n                                                     #'string\u003c))\n            (\"symbols/concat/intern/alist-get/equal\" (sort (cl-loop for char from (car char-range) to (cdr char-range)\n                                                                    for string = (concat \"prefix-\" (char-to-string char))\n                                                                    for symbol = (intern string)\n                                                                    collect (alist-get symbol symbols-alist nil nil #'equal))\n                                                           #'string\u003c))))\n#+END_SRC\n\n#+RESULTS[041dd7c6644612027379e3558fcf60e61eb4896a]:\n| Form                                                  | x faster than next | Total runtime | # of GCs | Total GC runtime |\n|-------------------------------------------------------+--------------------+---------------+----------+------------------|\n| with 26 pairs: strings/hash-table/equal               |               1.06 |      0.040321 |        0 |                0 |\n| with 26 pairs: strings/plist                          |               2.26 |      0.042848 |        0 |                0 |\n| with 52 pairs: strings/hash-table/equal               |               1.27 |      0.096877 |        0 |                0 |\n| with 26 pairs: strings/alist-get/equal                |               1.04 |      0.123039 |        0 |                0 |\n| with 26 pairs: strings/alist-get/string=              |               1.03 |      0.128221 |        0 |                0 |\n| with 52 pairs: strings/plist                          |               2.62 |      0.131451 |        0 |                0 |\n| with 26 pairs: symbols/concat/intern/hash-table/eq    |               1.00 |      0.344524 |        1 |         0.266744 |\n| with 26 pairs: symbols/concat/intern/hash-table/equal |               1.01 |      0.344951 |        1 |         0.267860 |\n| with 26 pairs: symbols/concat/intern/plist            |               1.02 |      0.349360 |        1 |         0.266529 |\n| with 26 pairs: symbols/concat/intern/alist-get        |               1.19 |      0.358071 |        1 |         0.267457 |\n| with 26 pairs: symbols/concat/intern/alist-get/equal  |               1.11 |      0.424895 |        1 |         0.271568 |\n| with 52 pairs: strings/alist-get/equal                |               1.03 |      0.471979 |        0 |                0 |\n| with 52 pairs: strings/alist-get/string=              |               1.50 |      0.485663 |        0 |                0 |\n| with 52 pairs: symbols/concat/intern/hash-table/equal |               1.00 |      0.730628 |        2 |         0.547082 |\n| with 52 pairs: symbols/concat/intern/hash-table/eq    |               1.05 |      0.733726 |        2 |         0.548910 |\n| with 52 pairs: symbols/concat/intern/alist-get        |               1.00 |      0.773320 |        2 |         0.545707 |\n| with 52 pairs: symbols/concat/intern/plist            |               1.36 |      0.774225 |        2 |         0.549963 |\n| with 52 pairs: symbols/concat/intern/alist-get/equal  |            slowest |      1.056641 |        2 |         0.545522 |\n\nWe see that hash-tables are generally the fastest solution.\n\nComparing alists and plists, we see that, when using string keys, plists are significantly faster than alists, even with 52 pairs.  When using symbol keys, plists are faster with 26 pairs; with 52, plists and alists (using ~alist-get~ with ~eq~ as the test function) are nearly the same in performance.\n\nAlso, perhaps surprisingly, when looking up a string in an alist, using ~equal~ as the test function may be faster than using the type-specific ~string=~ function (possibly indicating an optimization to be made in Emacs's C code).\n\n***** TODO Compare looking up interned symbols in obarray instead of hash table\n:PROPERTIES:\n:TOC:      :ignore (this)\n:END:\n\n***** TODO Compare a larger number of pairs\n:PROPERTIES:\n:TOC:      :ignore (this)\n:END:\n\n*** Examples                                                     :examples:\n:PROPERTIES:\n:CUSTOM_ID: examples\n:END:\n\n**** Alists                                                       :alists:\n\n***** Creation\n\n#+BEGIN_SRC elisp :exports code\n  ;;;; Built-in methods\n\n  (list (cons 'one 1) (cons 'two 2))  ;; =\u003e ((one . 1) (two . 2))\n\n  '((one . 1) (two . 2))  ;; =\u003e ((one . 1) (two . 2))\n\n  (let ((numbers (list)))\n    (map-put numbers 'one 1)\n    (map-put numbers 'two 2))  ;; =\u003e ((two . 2) (one . 1))\n\n\n  ;;;; Packages\n\n  ;; `a-list' from a.el is the best way to make a new alist.\n\n  (a-list 'one 1\n          'two 2)  ;; =\u003e ((one . 1) (two . 2))\n#+END_SRC\n\n***** Adding to\n\n****** Single elements\n\n#+BEGIN_SRC elisp :exports code\n  ;;;; Built-in methods\n\n  ;; `map-put' is the best built-in way.  Requires Emacs 25.1+.\n\n  (let ((numbers (list (cons 'one 1))))\n    (map-put numbers 'two 2)\n    numbers)  ; =\u003e ((two . 2) (one . 1))\n\n  ;; More primitive methods\n\n  ;; Not recommended, but not too complicated:\n  (let ((numbers (list (cons 'one 1)))\n        (more-numbers (a-list 'two 2\n                              'three 3)))\n    (append numbers more-numbers)) ;; =\u003e ((one . 1) (two . 2) (three . 3))\n\n  ;; Don't do it this way, but it does demonstrate list/cons-cell\n  ;; structure:\n  (let ((numbers (list (cons 'one 1))))\n    (cons (cons 'three 3)\n          (cons (cons 'two 2)\n                numbers)))  ;; =\u003e ((three . 3) (two . 2) (one . 1))\n#+END_SRC\n\n****** Multiple elements\n\n#+BEGIN_SRC elisp :exports code\n  ;;;; Built-in methods\n\n  ;; `map-merge': if you're restricted to built-in packages, this works\n  ;; well (requires Emacs 25.1+):\n  (let ((numbers (list (cons 'one 1)))\n        (more-numbers (a-list 'two 2\n                              'three 3)))\n    (map-merge 'list numbers more-numbers))  ;; =\u003e ((three . 3) (two . 2) (one . 1))\n\n\n  ;; Without map.el, you could use `append':\n  (let ((numbers (list (cons 'one 1)))\n        (more-numbers (a-list 'two 2\n                              'three 3)))\n    (append numbers more-numbers)) ;; =\u003e ((one . 1) (two . 2) (three . 3))\n\n  ;;;; Packages\n\n  ;; `a-merge' from a.el is probably the best way:\n  (let ((numbers (list (cons 'one 1)))\n        (more-numbers (a-list 'two 2\n                              'three 3)))\n    (a-merge numbers more-numbers))  ;; =\u003e ((three . 3) (two . 2) (one . 1))\n#+END_SRC\n\n**** Property lists (plists)                                      :plists:\n\n***** Removing properties\n\n[[https://www.reddit.com/r/emacs/comments/aupifm/what_is_the_best_way_to_do_plistremove/eh9xom5/][According to Stefan Monnier]]:\n\n#+BEGIN_QUOTE\nThe plist design in Elisp was based on the idea that you shouldn't distinguish an entry with a nil value from an entry that's absent. Hence =plist-remove= is not needed because you can do ~(plist-put PLIST PROP nil)~ instead.\n\nOf course, in the mean time, =plist-member= appeared, breaking the design, so this answer is probably not 100% satisfactory, but I still think you'll generally be better off if you can ignore the difference between =nil= and \"absent\".\n#+END_QUOTE\n\nIf you do need to remove a key and value from a plist, you could use =cl-remf= or =map-delete= (the former probably being faster).\n\n*** Libraries                                                   :libraries:\n:PROPERTIES:\n:TOC: :depth 0\n:CUSTOM_ID: libraries-1\n:END:\n\n**** [[https://github.com/plexus/a.el][a.el: functions for dealing with association lists and hash tables. Inspired by Clojure.]] :alists:hash_tables:\n\n**** [[https://github.com/troyp/asoc.el][asoc.el: alist library]]                                       :alists:\n\n**** [[https://github.com/nicferrier/emacs-kv][emacs-kv: key/value collection-type functions, for alists, hash tables and plists]] :alists:hash_tables:plists:\n\n**** [[https://github.com/Wilfred/ht.el][ht.el: The missing hash table library]]                   :hash_tables:\n:PROPERTIES:\n:ID:       22b35972-c32f-467a-92ee-f8a155920756\n:END:\n\nThis library provides a consistent and comprehensive set of functions for working with hash tables: they're named consistently, take a natural and consistent argument order, and cover operations that the standard Emacs functions don't.\n\n**** [[https://github.com/rolandwalker/list-utils][list-utils: List-manipulation utility functions]]               :lists:\n:PROPERTIES:\n:ID:       4b4cbe99-f048-4043-a946-97f9d1a4be52\n:END:\n\nSimilar to =dash.el=, but with slightly different behavior that may be useful, and some unique features.  These functions are provided:\n\n| =make-tconc=                       | =list-utils-depth=                |\n| =tconc-p=                          | =list-utils-flat-length=          |\n| =tconc-list=                       | =list-utils-flatten=              |\n| =tconc=                            | =list-utils-alist-or-flat-length= |\n| =list-utils-cons-cell-p=           | =list-utils-alist-flatten=        |\n| =list-utils-cyclic-length=         | =list-utils-insert-before=        |\n| =list-utils-improper-p=            | =list-utils-insert-after=         |\n| =list-utils-make-proper-copy=      | =list-utils-insert-before-pos=    |\n| =list-utils-make-proper-inplace=   | =list-utils-insert-after-pos=     |\n| =list-utils-make-improper-copy=    | =list-utils-and=                  |\n| =list-utils-make-improper-inplace= | =list-utils-not=                  |\n| =list-utils-linear-p=              | =list-utils-xor=                  |\n| =list-utils-linear-subseq=         | =list-utils-uniq=                 |\n| =list-utils-cyclic-p=              | =list-utils-dupes=                |\n| =list-utils-cyclic-subseq=         | =list-utils-singlets=             |\n| =list-utils-make-linear-copy=      | =list-utils-partition-dupes=      |\n| =list-utils-make-linear-inplace=   | =list-utils-plist-reverse=        |\n| =list-utils-safe-length=           | =list-utils-plist-del=            |\n| =list-utils-safe-equal=            |                                   |\n\n**** [[https://elpa.gnu.org/packages/map.html][map.el: Map manipulation functions]]   :maps:hash_tables:alists:arrays:\n\n=map= is included with Emacs, but the latest version, which may include improvements since the last Emacs release, is now available separately on [[https://elpa.gnu.org/][GNU ELPA]].\n\n**** [[https://github.com/NicolasPetton/stream][stream: Lazy sequences]]                       :streams:sequences:lazy:\n\n#+BEGIN_QUOTE\n=stream.el= provides an implementation of streams, implemented as delayed evaluation of cons cells.\n\nFunctions defined in seq.el can also take a stream as input.\n\nStreams could be created from any sequential input data:\n\n-  sequences, making operation on them lazy\n-  a set of 2 forms (first and rest), making it easy to represent infinite sequences\n-  buffers (by character)\n-  buffers (by line)\n-  buffers (by page)\n-  IO streams\n-  orgmode table cells\n-  ...\n#+END_QUOTE\n\n**** [[https://elpa.gnu.org/packages/persist.html][persist.el: Persist variables between sessions]]\n\n#+BEGIN_QUOTE\nThis package provides variables which persist across sessions.\n\nThe main entry point is `persist-defvar' which behaves like `defvar' but which persists the variables between session.  Variables are automatically saved when Emacs exits.\n\nOther useful functions are `persist-save' which saves the variable immediately, `persist-load' which loads the saved value, `persist-reset' which resets to the default value.\n\nValues are stored in a directory in `user-emacs-directory', using one file per value.  This makes it easy to delete or remove unused variables.\n#+END_QUOTE\n\n*** Tools                                                           :tools:\n:PROPERTIES:\n:TOC: :depth 0\n:CUSTOM_ID: tools-1\n:END:\n\n**** [[id:f8f0755b-c23b-45ad-98da-780d4044676a][let-alist]]\n\n**** [[id:a58f65dc-d4a4-4a40-a573-a66a28f3619c][=with-dict=, =with-plist-vals=]]\n\n** Color                                                             :color:\n:PROPERTIES:\n:CUSTOM_ID: color\n:END:\n\n*** Libraries                                                   :libraries:\n\n**** [[https://github.com/yurikhan/yk-color][yk-color: Linear RGB color manipulation]]\n\nIncludes these functions:\n\n+  =yk-color-adjust=\n+  =yk-color-adjust-rgb=\n+  =yk-color-blend=\n+  =yk-color-blend-rgb=\n+  =yk-color-contrast-ratio=\n+  =yk-color-contrast-ratio-rgb=\n+  =yk-color-from-rgb=\n+  =yk-color-relative-luminance=\n+  =yk-color-relative-luminance-rgb=\n+  =yk-color-rgb-to-srgb=\n+  =yk-color-srgb-to-rgb=\n+  =yk-color-to-rgb=\n\n** Data structure                                           :data_structure:\n:PROPERTIES:\n:TOC:      :include descendants :depth 1\n:CUSTOM_ID: data-structure\n:END:\n:CONTENTS:\n- [[#articles-1][Articles]]\n- [[#libraries-2][Libraries]]\n:END:\n\n*** Articles                                                     :articles:\n:PROPERTIES:\n:CUSTOM_ID: articles-1\n:END:\n\n**** [[http://nullprogram.com/blog/2018/02/14/][Options for Structured Data in Emacs Lisp « null program]]\n:PROPERTIES:\n:archive.today: http://archive.today/YxwP5\n:END:\n\n**** [[http://www.dr-qubit.org/emacs_data-structures.html][Toby 'qubit' Cubitt: Data structure packages]]\n\nIndividual libraries from this article are listed below.\n\n*** Libraries                                                   :libraries:\n:PROPERTIES:\n:TOC:      :include descendants\n:CUSTOM_ID: libraries-2\n:END:\n:CONTENTS:\n- [[#heapel][heap.el]]\n- [[#myers][myers]]\n- [[#queueel][queue.el]]\n- [[#tagged-non-deterministic-finite-state-automata-tnfael][Tagged Non-deterministic Finite state Automata (tNFA.el)]]\n- [[#trieel][trie.el]]\n- [[#dict-treeel][dict-tree.el]]\n- [[#extmap-externally-stored-constant-mapping][extmap: Externally-stored constant mapping]]\n:END:\n\n**** [[http://www.dr-qubit.org/emacs_data-structures.html][heap.el]]\n:PROPERTIES:\n:CUSTOM_ID: heapel\n:END:\n\n#+BEGIN_QUOTE\nA heap is a form of efficient self-sorting tree. In particular, the root node is guaranteed to be the highest-ranked entry in the tree. (The comparison function used for ranking the data can, of course, be freely defined). They are often used as priority queues, for scheduling tasks in order of importance, and for implementing efficient sorting algorithms (such as heap-sort).\n#+END_QUOTE\n\n**** [[https://elpa.gnu.org/packages/myers.html][myers]]                                                          :ELPA:\n:PROPERTIES:\n:CUSTOM_ID: myers\n:END:\n\n#+BEGIN_QUOTE\nThis package implements Eugene W. Myers's \"stacks\" which are like standard singly-linked lists, except that they also provide efficient lookup.  More specifically:\n\ncons/car/cdr are O(1), while (nthcdr N L) is O(min (N, log L))\n\nFor details, see [[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.188.9344\u0026rep=rep1\u0026type=pdf][\"An applicative random-access stack\", Eugene W. Myers, 1983, Information Processing Letters]].\n#+END_QUOTE\n\n**** [[http://www.dr-qubit.org/emacs_data-structures.html][queue.el]]                                                      :queue:\n:PROPERTIES:\n:CUSTOM_ID: queueel\n:END:\n\n#+BEGIN_QUOTE\nA queue can be used both as a first-in last-out and as a first-in first-out stack, i.e. elements can be added to and removed from the front or back of the queue. (This library is an updated re-implementation of the old Elib queue library.)\n#+END_QUOTE\n\n**** [[http://www.dr-qubit.org/emacs_data-structures.html][Tagged Non-deterministic Finite state Automata (tNFA.el)]]\n:PROPERTIES:\n:CUSTOM_ID: tagged-non-deterministic-finite-state-automata-tnfael\n:END:\n\n#+BEGIN_QUOTE\nFeatures of modern regexp implementations, including Emacs', mean they can recognise much more than regular languages. This comes with a big downside: matching certain pathological regexps is very time-consuming. (In fact, it's NP-complete.)\n\nA tagged, non-deterministic finite state automata (NFA) is an abstract computing machine that recognises regular languages. In layman's terms, they are used to decide whether a string matches a regular expression.  The \"tagged\" part lets the NFA do group-capture: it returns information about which parts of a string matched which subgroup of the regular expression.\n\nWhy re-implement regular expression matching when Emacs comes with extensive built-in support for regexps? Primarily, because some algorithms require access to the NFA states produced part way through the regular expression matching process. Secondarily, because Emacs regexps only work on strings, whereas regular expressions can equally well be used to match other Lisp sequence types.\n#+END_QUOTE\n\n**** [[http://www.dr-qubit.org/emacs_data-structures.html][trie.el]]\n:PROPERTIES:\n:CUSTOM_ID: trieel\n:END:\n\n#+BEGIN_QUOTE\nA trie stores data associated with \"strings\" (not necessarily the string data type; any ordered sequence of elements can be used). It stores them in such a way that both storage size and data lookup are reasonably space- and time- efficient, respectively. But, more importantly, advanced string queries are also very efficient, such as finding all strings with a given prefix, finding approximate matches, finding all strings matching a regular expression, returning results in alphabetical or any other order, returning only the first few results, etc.\n#+END_QUOTE\n\n**** [[http://www.dr-qubit.org/emacs_data-structures.html][dict-tree.el]]\n:PROPERTIES:\n:CUSTOM_ID: dict-treeel\n:END:\n\n#+BEGIN_QUOTE\nThe dictionary tree data structures are a hybrid between tries and hash tables. Data is stored in a trie, but results that take particularly long to retrieve are cached in hash tables, which are automatically synchronised with the trie. The dictionary package provides persistent storage of the data structures in files, and many other convenience features.\n#+END_QUOTE\n\n**** [[https://github.com/doublep/extmap][extmap: Externally-stored constant mapping]]\n:PROPERTIES:\n:CUSTOM_ID: extmap-externally-stored-constant-mapping\n:END:\n\n#+BEGIN_QUOTE\nextmap is a very simple package that lets you build a read-only, constant database that maps Elisp symbols to almost arbitrary Elisp objects. The idea is to avoid preloading all data to memory and only retrieve it when needed.  This package doesn’t use any external programs, making it a suitable dependency for smaller libraries.\n#+END_QUOTE\n\n** Date / Time                                                 :dates:times:\n:PROPERTIES:\n:CUSTOM_ID: date--time\n:END:\n\n*** Libraries                                                   :libraries:\n\n**** [[https://github.com/alphapapa/ts.el][ts.el: Timestamp and date-time library]]\n\n=ts= aids in parsing, formatting, and manipulating timestamps.\n\n#+BEGIN_QUOTE\nts is a date and time library for Emacs. It aims to be more convenient than patterns like ~(string-to-number (format-time-string \"%Y\"))~ by providing easy accessors, like ~(ts-year (ts-now))~.\n\nTo improve performance (significantly), formatted date parts are computed lazily rather than when a timestamp object is instantiated, and the computed parts are then cached for later access without recomputing. Behind the scenes, this avoids unnecessary ~(string-to-number (format-time-string...~ calls, which are surprisingly expensive.\n#+END_QUOTE\n\n***** Examples\n\nGet parts of the current date:\n\n#+BEGIN_SRC elisp\n  ;; When the current date is 2018-12-08 23:09:14 -0600:\n  (ts-year (ts-now))       ;=\u003e 2018\n  (ts-month (ts-now))      ;=\u003e 12\n  (ts-day (ts-now))        ;=\u003e 8\n  (ts-hour (ts-now))       ;=\u003e 23\n  (ts-minute (ts-now))     ;=\u003e 9\n  (ts-second (ts-now))     ;=\u003e 14\n  (ts-tz-offset (ts-now))  ;=\u003e \"-0600\"\n\n  (ts-dow (ts-now))        ;=\u003e 6\n  (ts-day-abbr (ts-now))   ;=\u003e \"Sat\"\n  (ts-day-name (ts-now))   ;=\u003e \"Saturday\"\n\n  (ts-month-abbr (ts-now)) ;=\u003e \"Dec\"\n  (ts-month-name (ts-now)) ;=\u003e \"December\"\n\n  (ts-tz-abbr (ts-now))    ;=\u003e \"CST\"\n#+END_SRC\n\nIncrement the current date:\n\n#+BEGIN_SRC elisp\n  ;; By 10 years:\n  (list :now (ts-format)\n        :future (ts-format (ts-adjust 'year 10 (ts-now))))\n  ;;=\u003e (   :now \"2018-12-15 22:00:34 -0600\"\n  ;;    :future \"2028-12-15 22:00:34 -0600\")\n\n  ;; By 10 years, 2 months, 3 days, 5 hours, and 4 seconds:\n  (list :now (ts-format)\n        :future (ts-format\n                 (ts-adjust 'year 10 'month 2 'day 3\n                            'hour 5 'second 4\n                            (ts-now))))\n  ;;=\u003e (   :now \"2018-12-15 22:02:31 -0600\"\n  ;;    :future \"2029-02-19 03:02:35 -0600\")\n#+END_SRC\n\nWhat day of the week was 2 days ago?\n\n#+BEGIN_SRC elisp\n  (ts-day-name (ts-dec 'day 2 (ts-now)))             ;=\u003e \"Thursday\"\n\n  ;; Or, with threading macros:\n  (thread-last (ts-now) (ts-dec 'day 2) ts-day-name) ;=\u003e \"Thursday\"\n  (-\u003e\u003e (ts-now) (ts-dec 'day 2) ts-day-name)         ;=\u003e \"Thursday\"\n#+END_SRC\n\nGet timestamp for this time last week:\n\n#+BEGIN_SRC elisp\n  (ts-unix (ts-adjust 'day -7 (ts-now)))\n  ;;=\u003e 1543728398.0\n\n  ;; To confirm that the difference really is 7 days:\n  (/ (- (ts-unix (ts-now))\n        (ts-unix (ts-adjust 'day -7 (ts-now))))\n     86400)\n  ;;=\u003e 7.000000567521762\n\n  ;; Or human-friendly as a list:\n  (ts-human-duration\n   (ts-difference (ts-now)\n                  (ts-dec 'day 7 (ts-now))))\n  ;;=\u003e (:years 0 :days 7 :hours 0 :minutes 0 :seconds 0)\n\n  ;; Or as a string:\n  (ts-human-format-duration\n   (ts-difference (ts-now)\n                  (ts-dec 'day 7 (ts-now))))\n  ;;=\u003e \"7 days\"\n\n  ;; Or confirm by formatting:\n  (list :now (ts-format)\n        :last-week (ts-format (ts-dec 'day 7 (ts-now))))\n  ;;=\u003e (      :now \"2018-12-08 23:31:37 -0600\"\n  ;;    :last-week \"2018-12-01 23:31:37 -0600\")\n#+END_SRC\n\n**** [[https://github.com/emacs-php/emacs-datetime][emacs-datetime]]\n:PROPERTIES:\n:ID:       45613ae9-97a2-4807-b099-a6c051f1a2c4\n:END:\n\nThe primary function provided is: ~(datetime-format SYM-OR-FMT \u0026optional TIME \u0026rest OPTION)~\n\n#+BEGIN_SRC elisp  :exports code\n  (datetime-format \"%Y-%m-%d\")  ;=\u003e \"2018-08-22\"\n  (datetime-format 'atom)  ;=\u003e \"2018-08-22T18:23:47-05:00\"\n  (datetime-format 'atom \"2112-09-03 00:00:00\" :timezone \"UTC\")  ;=\u003e \"2112-09-03T00:00:00+00:00\"\n#+END_SRC\n\nThere are several other symbols provided besides ~atom~, such as ~rfc-3339~, which formats dates according to that RFC.\n\n** Debugging                                                     :debugging:\n:PROPERTIES:\n:TOC:      :depth 2 :include descendants\n:CUSTOM_ID: debugging\n:END:\n:CONTENTS:\n- [[#tools-2][Tools]]\n  - [[#edebug][Edebug]]\n  - [[#debug-warn-macro][debug-warn macro]]\n:END:\n\n*** Tools                                                           :tools:\n:PROPERTIES:\n:CUSTOM_ID: tools-2\n:END:\n\n**** Edebug                                              :Edebug:built_in:\n:PROPERTIES:\n:CUSTOM_ID: edebug\n:END:\n\nEdebug is a built-in stepping debugger in Emacs.  It's [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Edebug.html][thoroughly documented in the =elisp= manual]].\n\n***** Declaring debug forms for keyword arguments                   :tip:\n\nDeclaring ~debug~ forms for functions and macros that take keyword arguments can be confusing.  Here's a contrived example:\n\n#+BEGIN_SRC elisp  :exports code\n  (cl-defmacro make-fn (name docstring \u0026key args bindings body)\n    (declare (indent defun)\n             (debug (\u0026define symbolp stringp\n                             \u0026rest [\u0026or [\":body\" def-form] [keywordp listp]])))\n    `(defun ,name ,args\n       ,docstring\n       (let* ,bindings\n         ,body)))\n\n  (make-fn my-fn\n    \"This is my function.\"\n    :bindings ((one 1)\n               (two 2))\n    :body (list one two))\n#+END_SRC\n\n****** TODO Submit this as an improvement to the Elisp manual\n\nProbably should first replace the ~:bindings~ part with this, which correctly matches ~let~ bindings: ~(\u0026rest \u0026or symbolp (gate symbolp \u0026optional def-form))~.\n\n**** =debug-warn= macro\n:PROPERTIES:\n:CUSTOM_ID: debug-warn-macro\n:END:\n\nThis macro simplifies print-style debugging by automatically including the names of the containing function and argument forms, rather than requiring the programmer to write =format= strings manually.  If ~warning-minimum-log-level~ is not ~:debug~ at expansion time, the macro expands to nil, which the byte-compiler eliminates, so in byte-compiled code, the macro has no overhead at runtime when not debugging.  In interpreted code, the overhead when not debugging is minimal.  When debugging, the expanded form also returns nil so, e.g. it may be used in a conditional in place of nil.  The macro is tangled to =epdh.el=, but it may also be added directly to source files.\n\nFor example, when used like:\n\n#+BEGIN_SRC elisp :exports code\n  (eval-and-compile\n    (setq-local warning-minimum-log-level :debug))\n\n  (defun argh (var)\n    (debug-warn (current-buffer) \"This is bad!\" (point) var)\n    var)\n\n  (argh 1)\n#+END_SRC\n\nThis warning would be shown in the =*Warnings*= buffer:\n\n#+BEGIN_EXAMPLE\n  Debug (argh): (CURRENT-BUFFER):*scratch* This is bad! (POINT):491845 VAR:1\n#+END_EXAMPLE\n\nBut if ~warning-minimum-log-level~ had any other value, and the buffer were recompiled, there would be no output, and none of the arguments to the macro would be evaluated at runtime.\n\nIt may even be used in place of comments!  For example, instead of:\n\n#+BEGIN_SRC elisp\n  (if (foo-p thing)\n      ;; It's a foo: frob it.\n      (frob thing)\n    ;; Not a foo: flub it.\n    (flub thing))\n#+END_SRC\n\nYou could write:\n\n#+BEGIN_SRC elisp\n  (if (foo-p thing)\n      (progn\n        (debug-warn \"It's a foo: frob it.\" thing)\n        (frob thing))\n    (debug-warn \"Not a foo: flub it.\" thing)\n    (flub thing))\n#+END_SRC\n\n#+BEGIN_SRC elisp :exports code :results silent :tangle epdh.el\n  ;; To make newer versions of `map' load for the `pcase' pattern.\n  (require 'map)\n\n  (cl-defmacro epdh/debug-warn (\u0026rest args)\n    \"Display a debug warning showing the runtime value of ARGS.\n  The warning automatically includes the name of the containing\n  function, and it is only displayed if `warning-minimum-log-level'\n  is `:debug' at expansion time (otherwise the macro expands to nil\n  and is eliminated by the byte-compiler).  When debugging, the\n  form also returns nil so, e.g. it may be used in a conditional in\n  place of nil.\n\n  Each of ARGS may be a string, which is displayed as-is, or a\n  symbol, the value of which is displayed prefixed by its name, or\n  a Lisp form, which is displayed prefixed by its first symbol.\n\n  Before the actual ARGS arguments, you can write keyword\n  arguments, i.e. alternating keywords and values.  The following\n  keywords are supported:\n\n    :buffer BUFFER   Name of buffer to pass to `display-warning'.\n    :level  LEVEL    Level passed to `display-warning', which see.\n                     Default is :debug.\"\n    ;; TODO: Can we use a compiler macro to handle this more elegantly?\n    (pcase-let* ((fn-name (when byte-compile-current-buffer\n                            (with-current-buffer byte-compile-current-buffer\n                              ;; This is a hack, but a nifty one.\n                              (save-excursion\n                                (beginning-of-defun)\n                                (cl-second (read (current-buffer)))))))\n                 (plist-args (cl-loop while (keywordp (car args))\n                                      collect (pop args)\n                                      collect (pop args)))\n                 ((map (:buffer buffer) (:level level)) plist-args)\n                 (level (or level :debug))\n                 (string (cl-loop for arg in args\n                                  concat (pcase arg\n                                           ((pred stringp) \"%S \")\n                                           ((pred symbolp)\n                                            (concat (upcase (symbol-name arg)) \":%S \"))\n                                           ((pred listp)\n                                            (concat \"(\" (upcase (symbol-name (car arg)))\n                                                    (pcase (length arg)\n                                                      (1 \")\")\n                                                      (_ \"...)\"))\n                                                    \":%S \"))))))\n      (when (eq :debug warning-minimum-log-level)\n        `(let ((fn-name ,(if fn-name\n                             `',fn-name\n                           ;; In an interpreted function: use `backtrace-frame' to get the\n                           ;; function name (we have to use a little hackery to figure out\n                           ;; how far up the frame to look, but this seems to work).\n                           `(cl-loop for frame in (backtrace-frames)\n                                     for fn = (cl-second frame)\n                                     when (not (or (subrp fn)\n                                                   (special-form-p fn)\n                                                   (eq 'backtrace-frames fn)))\n                                     return (make-symbol (format \"%s [interpreted]\" fn))))))\n           (display-warning fn-name (format ,string ,@args) ,level ,buffer)\n           nil))))\n#+END_SRC\n\n** Destructuring                                             :destructuring:\n:PROPERTIES:\n:CUSTOM_ID: destructuring\n:END:\n\nSee [[id:b699e1a1-e34c-4ce8-a5dd-41161d2a1cbf][Pattern matching]].\n\n** Documentation                                             :documentation:\n:PROPERTIES:\n:CUSTOM_ID: documentation\n:END:\n\n*** Tools                                                           :tools:\n\n** Editing                                                         :editing:\n:PROPERTIES:\n:TOC:      :include descendants :depth 2\n:CUSTOM_ID: editing\n:END:\n:CONTENTS:\n- [[#tools-3][Tools]]\n  - [[#aggressive-indent-mode-minor-mode-that-keeps-your-code-always-indented][aggressive-indent-mode: minor mode that keeps your code always indented]]\n  - [[#beginendel][beginend.el]]\n  - [[#expand-regionel-increase-selected-region-by-semantic-units][expand-region.el: Increase selected region by semantic units]]\n  - [[#helm-navi-navigate-file-sections-and-language-keywords-using-helm][helm-navi: Navigate file sections and language keywords using Helm]]\n  - [[#iedit-edit-multiple-regions-simultaneously-in-a-buffer-or-a-region][iedit: Edit multiple regions simultaneously in a buffer or a region]]\n  - [[#lispy-short-and-sweet-lisp-editing][lispy: short and sweet LISP editing]]\n  - [[#multi-line-multi-line-everything-from-function-invocations-and-definitions-to-array-and-map-literals-in-a-wide-variety-of-languages][multi-line: multi-line everything from function invocations and definitions to array and map literals in a wide variety of languages]]\n  - [[#multiple-cursorsel-multiple-cursors][multiple-cursors.el: Multiple cursors]]\n  - [[#smartparens-minor-mode--that-deals-with-parens-pairs-and-tries-to-be-smart-about-it][smartparens: Minor mode  that deals with parens pairs and tries to be smart about it]]\n:END:\n\n*** Tools                                                           :tools:\n:PROPERTIES:\n:CUSTOM_ID: tools-3\n:END:\n\n**** [[https://github.com/Malabarba/aggressive-indent-mode][aggressive-indent-mode: minor mode that keeps your code always indented]] :formatting:indentation:parentheses:\n:PROPERTIES:\n:ID:       4dc7c607-a116-4c39-b063-fe34bd20cccf\n:CUSTOM_ID: aggressive-indent-mode-minor-mode-that-keeps-your-code-always-indented\n:END:\n\n**** [[https://emacs.cafe/emacs/package/2017/08/01/beginend.html][beginend.el]] :navigation:\n:PROPERTIES:\n:ID:       a32ed391-8ce6-46b7-9367-8117829ce2e7\n:CUSTOM_ID: beginendel\n:END:\n\nThis package, by Damien Cassou and Matus Goljer, helps navigation by redefining the ~M-\u003c~ and ~M-\u003e~ keys do, depending on the major-mode.\n\n**** [[https://github.com/magnars/expand-region.el][expand-region.el: Increase selected region by semantic units]] :selection:region:\n:PROPERTIES:\n:ID:       88b496f4-8230-474e-b2ee-d8e4e8ca30d0\n:CUSTOM_ID: expand-regionel-increase-selected-region-by-semantic-units\n:END:\n\n**** [[https://github.com/emacs-helm/helm-navi][helm-navi: Navigate file sections and language keywords using Helm]] :navigation:\n:PROPERTIES:\n:CUSTOM_ID: helm-navi-navigate-file-sections-and-language-keywords-using-helm\n:END:\n\n**** [[https://github.com/victorhge/iedit][iedit: Edit multiple regions simultaneously in a buffer or a region]] :refactoring:\n:PROPERTIES:\n:CUSTOM_ID: iedit-edit-multiple-regions-simultaneously-in-a-buffer-or-a-region\n:END:\n\n=iedit= makes it easy to rename symbols within a function or in a whole buffer.  Simply activate ~iedit-mode~ with point on a symbol, and it will be highlighted in the chosen scope, and any changes you make to the symbol are made in each highlighted occurrence.  It's like a smart, purposeful version of ~multiple-cursors~.\n\nThe editor of this handbook uses ~iedit~ with these customizations:\n\n+  ~ap/iedit-or-flyspell~ :: Globally bound to @@html:\u003ckbd\u003e@@C-;@@html:\u003c/kbd\u003e@@.  In a ~prog-mode~-derived buffer, either corrects the last misspelled word with ~flyspell~ when point is in a comment or string, or activates ~iedit-mode~.  In non- ~prog-mode~-derived buffers, corrects with ~flyspell~.\n\n#+BEGIN_SRC elisp :exports code\n  (defun ap/iedit-or-flyspell ()\n    \"Call `iedit-mode' or correct misspelling with flyspell, depending...\"\n    (interactive)\n    (if (or iedit-mode\n            (and (derived-mode-p 'prog-mode)\n                 (not (or (nth 4 (syntax-ppss))\n                          (nth 3 (syntax-ppss))))))\n        ;; prog-mode is active and point is in a comment, string, or\n        ;; already in iedit-mode\n        (call-interactively #'ap/iedit-mode)\n      ;; Not prog-mode or not in comment or string\n      (if (not (equal flyspell-previous-command this-command))\n          ;; FIXME: This mostly works, but if there are two words on the\n          ;; same line that are misspelled, it doesn't work quite right\n          ;; when correcting the earlier word after correcting the later\n          ;; one\n\n          ;; First correction; autocorrect\n          (call-interactively 'flyspell-auto-correct-previous-word)\n        ;; First correction was not wanted; use popup to choose\n        (progn\n          (save-excursion\n            (undo)) ; This doesn't move point, which I think may be the problem.\n          (flyspell-region (line-beginning-position) (line-end-position))\n          (call-interactively 'flyspell-correct-previous-word-generic)))))\n#+END_SRC\n\n+  ~ap/iedit-mode~ :: Calls ~iedit-mode~ with function-local scope by default, or global scope when called with a universal prefix.\n\n#+BEGIN_SRC elisp :exports code\n  (defun ap/iedit-mode (orig-fn)\n    \"Call `iedit-mode' with function-local scope by default, or global scope if called with a universal prefix.\"\n    (interactive)\n    (pcase current-prefix-arg\n      ('nil (funcall orig-fn '(0)))\n      ('(4) (funcall orig-fn))\n      (_ (user-error \"`ap/iedit-mode' called with prefix: %s\" prefix))))\n\n  ;; Override default `iedit-mode' function with advice.\n  (advice-add #'iedit-mode :around #'ap/iedit-mode)\n#+END_SRC\n\n+  Helpful minibuffer message :: Confirms when an ~iedit~ session has started.\n\n#+BEGIN_SRC elisp :exports code\n  (advice-add 'iedit-mode :after (lambda (\u0026optional ignore)\n                                   (when iedit-mode\n                                     (minibuffer-message \"iedit session started. Press C-; to end.\"))))\n#+END_SRC\n\n***** TODO Refer to version published in =unpackaged.el=\n\n**** [[https://github.com/abo-abo/lispy][lispy: short and sweet LISP editing]]    :elisp:navigation:parentheses:\n:PROPERTIES:\n:ID:       ca3809ba-5900-4dfd-84a1-1ceecc048296\n:CUSTOM_ID: lispy-short-and-sweet-lisp-editing\n:END:\n\n**** [[https://github.com/IvanMalison/multi-line][multi-line: multi-line everything from function invocations and definitions to array and map literals in a wide variety of languages]] :formatting:\n:PROPERTIES:\n:CUSTOM_ID: multi-line-multi-line-everything-from-function-invocations-and-definitions-to-array-and-map-literals-in-a-wide-variety-of-languages\n:END:\n\n**** [[https://github.com/magnars/multiple-cursors.el][multiple-cursors.el: Multiple cursors]]             :selection:editing:\n:PROPERTIES:\n:ID:       deefcbc5-0c37-4936-a820-df99ae31a401\n:CUSTOM_ID: multiple-cursorsel-multiple-cursors\n:END:\n\n**** [[https://github.com/Fuco1/smartparens][smartparens: Minor mode  that deals with parens pairs and tries to be smart about it]] :navigation:editing:parentheses:\n:PROPERTIES:\n:ID:       e806d7f3-43e9-4260-aae4-479efbd41653\n:CUSTOM_ID: smartparens-minor-mode--that-deals-with-parens-pairs-and-tries-to-be-smart-about-it\n:END:\n\n** General                                                         :general:\n:PROPERTIES:\n:TOC:      :include descendants :depth 2\n:ID:       26708ac7-9fa3-4f21-9324-ba0e8c939bd7\n:CUSTOM_ID: general\n:END:\n:CONTENTS:\n- [[#libraries-3][Libraries]]\n  - [[#common-lisp-extensions-cl-lib][Common Lisp Extensions (cl-lib)]]\n  - [[#dashel-0][dash.el]]\n  - [[#loopel-friendly-imperative-loop-structures][loop.el: friendly imperative loop structures]]\n  - [[#subr-x][subr-x]]\n- [[#tools-4][Tools]]\n  - [[#chemacs-emacs-profile-switcher][chemacs: Emacs profile switcher]]\n  - [[#el2markdown-convert-emacs-lisp-comments-to-markdown][el2markdown: Convert Emacs Lisp comments to MarkDown]]\n  - [[#multicolumn-multiple-side-by-side-windows-support][multicolumn: Multiple side-by-side windows support]]\n  - [[#lentic-create-views-of-the-same-content-in-two-buffers][lentic: Create views of the same content in two buffers]]\n  - [[#suggestel-discover-elisp-functions-that-do-what-you-want][suggest.el: discover elisp functions that do what you want]]\n  - [[#byte-compile-and-load-directory][Byte-compile and load directory]]\n  - [[#emacs-lisp-macroreplace][emacs-lisp-macroreplace]]\n- [[#tutorials][Tutorials]]\n  - [[#wilfred-hughes-walks-through-a-function-from-lispy][Wilfred Hughes walks through a function from Lispy]]\n:END:\n\n#+BEGIN_SRC elisp :exports none :eval never :tangle epdh.el\n;;;; General tools\n\n#+END_SRC\n\n*** Libraries                                                   :libraries:\n:PROPERTIES:\n:CUSTOM_ID: libraries-3\n:END:\n\n**** [[https://www.gnu.org/software/emacs/manual/html_node/cl/index.html][Common Lisp Extensions]] (=cl-lib=)                            :built_in:\n:PROPERTIES:\n:CUSTOM_ID: common-lisp-extensions-cl-lib\n:END:\n\nThis is the built-in =cl-lib= package which implements Common Lisp functions and control structures for Emacs Lisp.\n\n**** [[https://github.com/magnars/dash.el][dash.el]]                                                        :dash:\n:PROPERTIES:\n:ID:       e85e4252-ea03-4473-b52f-9393e7527fad\n:CUSTOM_ID: dashel-0\n:END:\n\nDash is a powerful general-purpose library that provides many useful functions and macros.\n\n**** [[https://github.com/Wilfred/loop.el][loop.el: friendly imperative loop structures]]           :flow_control:\n:PROPERTIES:\n:CUSTOM_ID: loopel-friendly-imperative-loop-structures\n:END:\n\n#+BEGIN_QUOTE\nEmacs Lisp is missing loop structures familiar to users of newer languages.  This library adds a selection of popular loop structures as well as break and continue.\n#+END_QUOTE\n\n**** [[https://github.com/emacs-mirror/emacs/blob/master/lisp/emacs-lisp/subr-x.el][subr-x]]                                :built_in:strings:flow_control:\n:PROPERTIES:\n:CUSTOM_ID: subr-x\n:END:\n\n#+BEGIN_QUOTE\nLess commonly used functions that complement basic APIs, often implemented in C code (like hash-tables and strings), and are not eligible for inclusion in subr.el.\n#+END_QUOTE\n\nThis is a built-in package that provides several useful functions and macros, such as =thread-first= / =last=, =if-let= / =when-let=, hash-table functions, and string functions.  It's easy to forget about this, since:\n\n#+BEGIN_QUOTE\nDo not document these functions in the lispref.  http://lists.gnu.org/archive/html/emacs-devel/2014-01/msg01006.html\n#+END_QUOTE\n\n*** Tools                                                           :tools:\n:PROPERTIES:\n:CUSTOM_ID: tools-4\n:END:\n\n**** [[https://github.com/plexus/chemacs][chemacs: Emacs profile switcher]]                             :testing:\n:PROPERTIES:\n:CUSTOM_ID: chemacs-emacs-profile-switcher\n:END:\n\nThis package may be especially helpful for developing in one's own environment and testing in another, like default Emacs, Spacemacs, etc.\n\n#+BEGIN_QUOTE\nChemacs is an Emacs profile switcher, it makes it easy to run multiple Emacs configurations side by side.  Think of it as a bootloader for Emacs.\n\nEmacs configuration is either kept in a =~/.emacs= file or, more commonly, in a =~/.emacs.d= directory. These paths are hard-coded. If you want to try out someone else’s configuration, or run different distributions like Prelude or Spacemacs, then you either need to swap out =~/.emacs.d=, or run Emacs with a different =$HOME= directory set.  This last approach is quite common, but has some real drawbacks, since now packages will no longer know where your actual home directory is.  \n\nAll of these makes trying out different Emacs configurations and distributions needlessly cumbersome.  Various approaches to solving this have been floated over the years. There’s an Emacs patch around that adds an extra command line option, and various examples of how to add a command line option in userspace from Emacs Lisp.\n\nChemacs tries to implement this idea in a user-friendly way, taking care of the various edge cases and use cases that come up.\n#+END_QUOTE\n\n**** [[https://github.com/Lindydancer/el2markdown][el2markdown: Convert Emacs Lisp comments to MarkDown]]\n:PROPERTIES:\n:ID:       9aacf8f3-5244-4b71-8802-1c7876a9d19e\n:CUSTOM_ID: el2markdown-convert-emacs-lisp-comments-to-markdown\n:END:\n\n**** [[https://github.com/Lindydancer/multicolumn][multicolumn: Multiple side-by-side windows support]]\n:PROPERTIES:\n:ID:       267c8c25-53db-4ced-9242-176094e101e3\n:CUSTOM_ID: multicolumn-multiple-side-by-side-windows-support\n:END:\n\n**** [[https://github.com/phillord/lentic][lentic: Create views of the same content in two buffers]]\n:PROPERTIES:\n:ID:       0c220bc9-7173-4b0f-8955-e10ab6db640f\n:CUSTOM_ID: lentic-create-views-of-the-same-content-in-two-buffers\n:END:\n\n**** [[https://github.com/Wilfred/suggest.el][suggest.el: discover elisp functions that do what you want]]\n:PROPERTIES:\n:ID:       57ecc064-7291-4cc5-a545-958e2bca295b\n:CUSTOM_ID: suggestel-discover-elisp-functions-that-do-what-you-want\n:END:\n\n**** Byte-compile and load directory\n:PROPERTIES:\n:ID:       e9b527d5-ae5e-4052-95f3-781ebc1b4ce1\n:CUSTOM_ID: byte-compile-and-load-directory\n:END:\n\nByte-compile and load all elisp files in ~DIRECTORY~.  Interactively, directory defaults to ~default-directory~ and asks for confirmation.\n\n#+BEGIN_SRC elisp :exports code :tangle epdh.el\n  ;;;###autoload\n  (defun epdh/byte-compile-and-load-directory (directory)\n    \"Byte-compile and load all elisp files in DIRECTORY.\n  Interactively, directory defaults to `default-directory' and asks\n  for confirmation.\"\n    (interactive (list default-directory))\n    (if (or (not (called-interactively-p))\n            (yes-or-no-p (format \"Compile and load all files in %s?\" directory)))\n        ;; Not sure if binding `load-path' is necessary.\n        (let* ((load-path (cons directory load-path))\n               (files (directory-files directory 't (rx \".el\" eos))))\n          (dolist (file files)\n            (byte-compile-file file 'load)))))\n#+END_SRC\n\n**** =emacs-lisp-macroreplace=\n:PROPERTIES:\n:ID:       e84a8d0a-f68a-43c5-a499-f27b8ad90457\n:CUSTOM_ID: emacs-lisp-macroreplace\n:END:\n\nReplace macro form before or after point with its expansion.\n\n#+BEGIN_SRC elisp :exports code :eval no-export :tangle epdh.el\n  ;;;###autoload\n  (defun epdh/emacs-lisp-macroreplace ()\n    \"Replace macro form before or after point with its expansion.\"\n    (interactive)\n    (if-let* ((beg (point))\n              (end t)\n              (form (or (ignore-errors\n                          (save-excursion\n                            (prog1 (read (current-buffer))\n                              (setq end (point)))))\n                        (ignore-errors\n                          (forward-sexp -1)\n                          (setq beg (point))\n                          (prog1 (read (current-buffer))\n                            (setq end (point))))))\n              (expansion (macroexpand-all form)))\n        (setf (buffer-substring beg end) (pp-to-string expansion))\n      (user-error \"Unable to expand\")))\n#+END_SRC\n\n*** Tutorials                                                   :tutorials:\n:PROPERTIES:\n:CUSTOM_ID: tutorials\n:END:\n\n**** [[https://old.reddit.com/r/emacs/comments/60tl6o/tips_on_reading_dense_emacs_lisp_code/dfa92hg/][Wilfred Hughes walks through a function from Lispy]] :ATTACH:\n:PROPERTIES:\n:Attachments: https%3A%2F%2Fold.reddit.com%2Fr%2Femacs%2Fcomments%2F60tl6o%2Ftips_on_reading_dense_emacs_lisp_code%2Fdfa92hg%2F--PA7yQk.tar.xz\n:ID:       57f093b3-c2c9-436a-95d4-244ad9f64778\n:author:   Wilfred Hughes\n:CUSTOM_ID: wilfred-hughes-walks-through-a-function-from-lispy\n:END:\n\nWilfred's walkthrough is helpful for learning how to study an Elisp function and determine what it does and how.  He also shows the use of ~trace-function~.\n\n** Highlighting / font-locking                      :highlighting:font_lock:\n:PROPERTIES:\n:TOC:      :include descendants :depth 2\n:CUSTOM_ID: highlighting--font-locking\n:END:\n:CONTENTS:\n- [[#packages][Packages]]\n  - [[#lisp-extra-font-lock-highlight-bound-variables-and-quoted-expressions-in-lisp][lisp-extra-font-lock: Highlight bound variables and quoted expressions in lisp]]\n- [[#tools-5][Tools]]\n  - [[#face-explorer-library-and-tools-for-faces-and-text-properties][face-explorer: Library and tools for faces and text properties]]\n  - [[#faceup-regression-test-system-for-font-lock-keywords][faceup: Regression test system for font-lock keywords]]\n  - [[#font-lock-profiler-coverage-and-timing-tool-for-font-lock-keywords][font-lock-profiler: Coverage and timing tool for font-lock keywords]]\n  - [[#font-lock-regression-suite-regression-test-suite-for-font-lock-keywords-of-emacs-standard-modes][font-lock-regression-suite: Regression test suite for font-lock keywords of Emacs standard modes]]\n  - [[#font-lock-studio-debugger-for-font-lock-keywords][font-lock-studio: Debugger for Font Lock keywords]]\n  - [[#highlight-refontification-visualize-how-font-lock-refontifies-a-buffer][highlight-refontification: Visualize how font-lock refontifies a buffer]]\n:END:\n\n*** Packages                                                     :packages:\n:PROPERTIES:\n:CUSTOM_ID: packages\n:END:\n\nPackages that do highlighting/font-locking.\n\n**** [[https://github.com/Lindydancer/lisp-extra-font-lock][lisp-extra-font-lock: Highlight bound variables and quoted expressions in lisp]]\n:PROPERTIES:\n:ID:       5b4a9320-1d3d-441b-8505-7b35a8d323d3\n:CUSTOM_ID: lisp-extra-font-lock-highlight-bound-variables-and-quoted-expressions-in-lisp\n:END:\n\n*** Tools                                                           :tools:\n:PROPERTIES:\n:CUSTOM_ID: tools-5\n:END:\n\nTools for developing highlighting/font-locking packages.\n\n**** [[https://github.com/Lindydancer/face-explorer][face-explorer: Library and tools for faces and text properties]]\n:PROPERTIES:\n:ID:       66fef80f-0f92-4492-8199-01c24c635914\n:CUSTOM_ID: face-explorer-library-and-tools-for-faces-and-text-properties\n:END:\n\n**** [[https://github.com/Lindydancer/faceup][faceup: Regression test system for font-lock keywords]]\n:PROPERTIES:\n:ID:       5ab6c330-15ae-455a-981c-bf298d9a2788\n:CUSTOM_ID: faceup-regression-test-system-for-font-lock-keywords\n:END:\n\n**** [[https://github.com/Lindydancer/font-lock-profiler][font-lock-profiler: Coverage and timing tool for font-lock keywords]]\n:PROPERTIES:\n:ID:       0f3ba4be-949b-4efe-8301-acf3873ab345\n:CUSTOM_ID: font-lock-profiler-coverage-and-timing-tool-for-font-lock-keywords\n:END:\n\n**** [[https://github.com/Lindydancer/font-lock-regression-suite][font-lock-regression-suite: Regression test suite for font-lock keywords of Emacs standard modes]]\n:PROPERTIES:\n:ID:       e54a2697-8b4a-4b65-a971-f79e0fa22120\n:CUSTOM_ID: font-lock-regression-suite-regression-test-suite-for-font-lock-keywords-of-emacs-standard-modes\n:END:\n\n**** [[https://github.com/Lindydancer/font-lock-studio][font-lock-studio: Debugger for Font Lock keywords]]\n:PROPERTIES:\n:ID:       fb9315d1-111d-4eab-8f99-00710e39b04c\n:CUSTOM_ID: font-lock-studio-debugger-for-font-lock-keywords\n:END:\n\n**** [[https://github.com/Lindydancer/highlight-refontification][highlight-refontification: Visualize how font-lock refontifies a buffer]]\n:PROPERTIES:\n:ID:       85a2421d-6fbd-4c4d-a6f9-587258c8f625\n:CUSTOM_ID: highlight-refontification-visualize-how-font-lock-refontifies-a-buffer\n:END:\n\n** Multiprocessing (generators, threads)           :multiprocessing:\n:PROPERTIES:\n:ID:       94092c16-061c-45c9-9c66-77c5fdeceee8\n:TOC:      :include descendants :depth 2\n:CUSTOM_ID: multiprocessing-generators-threads\n:END:\n:CONTENTS:\n- [[#articles-2][Articles]]\n- [[#libraries-4][Libraries]]\n  - [[#emacs-aio-asyncawait-for-emacs-lisp][emacs-aio: async/await for Emacs Lisp]]\n- [[#manual][Manual]]\n:END:\n\n*** Articles                                                     :articles:\n:PROPERTIES:\n:TOC:      :depth 0\n:CUSTOM_ID: articles-2\n:END:\n\n**** [[https://nullprogram.com/blog/2018/05/31/][Emacs 26 Brings Generators and Threads « null program]] :threads:generators:compilation:closures:iterators:\n:PROPERTIES:\n:archive.today: http://archive.today/Irane\n:END:\n\nChris Wellons explains the new generators and threads that Emacs 26 provides.  He also shows an example of writing a ~cl-case~ form that uses the new ~switch~ jump table opcode in Emacs 26.\n\n**** [[https://nullprogram.com/blog/2013/01/14/][Turning Asynchronous into Synchronous in Elisp « null program]] :async:\n:PROPERTIES:\n:archive.today: http://archive.today/AfL0y\n:END:\n\n**** [[https://nullprogram.com/blog/2017/02/14/][Asynchronous Requests from Emacs Dynamic Modules « null program]] :modules:async:\n:PROPERTIES:\n:archive.today: http://archive.today/ZS6pU\n:END:\n\n*** Libraries                                                   :libraries:\n:PROPERTIES:\n:CUSTOM_ID: libraries-4\n:END:\n\n**** [[https://github.com/skeeto/emacs-aio][emacs-aio: async/await for Emacs Lisp]]\n:PROPERTIES:\n:CUSTOM_ID: emacs-aio-asyncawait-for-emacs-lisp\n:END:\n\n#+BEGIN_QUOTE\n=aio= is to Emacs Lisp as asyncio is to Python. This package builds upon Emacs 25 generators to provide functions that pause while they wait on asynchronous events. They do not block any thread while paused.\n#+END_QUOTE\n\n*** Manual                                                         :manual:\n:PROPERTIES:\n:TOC:      :depth 0\n:CUSTOM_ID: manual\n:END:\n\n**** [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Generators.html][GNU Emacs Lisp Reference Manual: Generators]]              :generators:\n\n**** [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Threads.html][GNU Emacs Lisp Reference Manual: Threads]]                    :threads:\n\n** Networking                                                   :networking:\n:PROPERTIES:\n:CUSTOM_ID: networking\n:END:\n\n*** HTTP                                                             :HTTP:\n\n**** Libraries                                                 :libraries:\n:PROPERTIES:\n:TOC:      :include descendants :depth 1\n:END:\n\nFor very simple use cases, the built-in [[*=url=][url]] library should be sufficient.  But for more complex cases, and for a simpler API and more reliability, it's generally recommended to use [[*\\[\\[https://github.com/alphapapa/plz.el\\]\\[plz.el: HTTP client library\\]\\]][plz]].\n\nOther libraries, such as [[*%5B%5Bhttps://github.com/tkf/emacs-request%5D%5BRequest.el%20--%20Easy%20HTTP%20requests%5D%5D][request]], can also provide improvements over ~url~.  However, in this author's experience, both ~url~ and ~request~, while mostly reliable, tend to have some obscure bugs that can occasionally be problematic.  ~plz~, while not yet as featureful as ~request~, is intended to be developed into the best all-around client, and is now a mature, reliable library.\n\n:CONTENTS:\n- [[#plzel-http-client-library][plz.el: HTTP client library]]\n- [[#url][url]]\n- [[#requestel----easy-http-requests][Request.el -- Easy HTTP requests]]\n- [[#elfeed-curl][elfeed-curl]]\n:END:\n\n***** [[https://github.com/alphapapa/plz.el][plz.el: HTTP client library]]                         :curl:GNU_ELPA:\n:PROPERTIES:\n:CUSTOM_ID: plzel-http-client-library\n:END:\n\nInspired by [[*\\[\\[https://github.com/skeeto/elfeed/blob/master/elfeed-curl.el\\]\\[elfeed-curl\\]\\]][elfeed-curl]] and endorsed by its author, ~plz~ supports both synchronous and asynchronous requests.  Its API is intended to be simple, natural, and expressive.  Its code is intended to be simple and well-organized.  Every feature is tested against [[https://httpbin.org/][httpbin]].  Written by this author, ~plz~ is available on GNU ELPA, so it's installable in Emacs by default.\n\n***** =url=                                               :url_el:built_in:\n:PROPERTIES:\n:CUSTOM_ID: url\n:END:\n\n=url= is included with Emacs and used by a variety of packages.\n\n***** [[https://github.com/tkf/emacs-request][Request.el -- Easy HTTP requests]]    :curl:url_el:NonGNU_ELPA:MELPA:\n:PROPERTIES:\n:CUSTOM_ID: requestel----easy-http-requests\n:END:\n\n=request= is the most commonly used third-party HTTP library.  It has both =curl= and =url.el= backends.\n\n***** [[https://github.com/skeeto/elfeed/blob/master/elfeed-curl.el][elfeed-curl]]                                                  :curl:\n:PROPERTIES:\n:CUSTOM_ID: elfeed-curl\n:END:\n\nNot a standalone package, but part of [[https://github.com/skeeto/elfeed/blob/master/elfeed-curl.el][Elfeed]].  A solid, well-designed library, but purpose-built for Elfeed.  Inspired the development of [[*\\[\\[https://github.com/alphapapa/plz.el\\]\\[plz.el: HTTP client library\\]\\]][plz]].\n\n** Packaging                                                     :packaging:\n:PROPERTIES:\n:TOC:      :include descendants :depth 2 :force depth\n:CUSTOM_ID: packaging\n:END:\n:CONTENTS:\n- [[#articles-3][Articles]]\n  - [[#good-style-in-modern-emacs-packages][Good Style in modern Emacs Packages]]\n- [[#best-practices-1][Best practices]]\n  - [[#autoloads][Autoloads]]\n  - [[#integration-with-other-packages][Integration with other packages]]\n  - [[#lexical-binding-0][Lexical binding]]\n  - [[#template][Template]]\n  - [[#readme][Readme]]\n  - [[#version-numbers][Version numbers]]\n- [[#libraries-5][Libraries]]\n- [[#reference][Reference]]\n  - [[#package-headers-and-structure][Package headers and structure]]\n- [[#tools-6][Tools]]\n  - [[#building--testing][Building / Testing]]\n  - [[#package-installationmanagement][Package installation/management]]\n:END:\n\n*** Articles                                                     :articles:\n:PROPERTIES:\n:CUSTOM_ID: articles-3\n:END:\n\n**** [[https://amodernist.com/texts/emacs-style.html][Good Style in modern Emacs Packages]]\n:PROPERTIES:\n:author:   Philip Kaludercic\n:CUSTOM_ID: good-style-in-modern-emacs-packages\n:END:\n\n*** Best practices                                         :best_practices:\n:PROPERTIES:\n:CUSTOM_ID: best-practices-1\n:END:\n\n**** Autoloads                                                 :autoloads:\n:PROPERTIES:\n:CUSTOM_ID: autoloads\n:END:\n\n***** TODO Autoloading macro-generated functions\n\nThis may actually be a bug, or at least an unanswered question.\n\n[[https://www.reddit.com/r/emacs/comments/63u5yn/how_to_use_autoload_cookies_for_custom_defunlike/][How to use autoload cookies for custom defun-like macros? : emacs]]:\n\n#+BEGIN_QUOTE\nSay I have a macro =deffoo= that expands to some custom kind of =defun=, and I want to use an autoload cookie to autoload the result. According to the manual,\n\n#+BEGIN_EXAMPLE\n    ;;;###autoload (deffoo bar   ...)\n#+END_EXAMPLE\n\ncopies the entire form to =autoloads.el=, and something like\n\n#+BEGIN_EXAMPLE\n    ;;;###autoload (autoload 'bar \"this-file\") (deffoo bar   ...)\n#+END_EXAMPLE\n\nshould be used instead. What confuses me is [[http://stackoverflow.com/a/38805102][this StackOverflow comment]] by who appears to be Stefan Monnier, saying that Emacs /should/ expand the macro before generating the autoload, and that it's probably a bug when this does not happen.\n\nCan anyone clear up what the intended behaviour is?\n#+END_QUOTE\n\n[2018-01-15 Mon 03:37]  The correct way to do this is documented in [[https://github.com/alphapapa/helm-org-rifle/issues/13][this bug report]].\n\n***** Articles                                                 :articles:\n\n****** [[https://www.lunaryorn.com/posts/autoloads-in-emacs-lisp][Autoloads in Emacs Lisp | Sebastian Wiesner]]\n:PROPERTIES:\n:archive.today: http://archive.today/UZHhS\n:END:\n\n**** Integration with other packages\n:PROPERTIES:\n:CUSTOM_ID: integration-with-other-packages\n:END:\n\n***** Optional support\n\nSometimes you want your package to integrate with other packages, but you don't want to require users to install those other packages.  For example, you might want your package to work with Helm, Ivy, or the built-in Emacs =completing-read=, but you don't want to declare a dependency on and =require= Helm or Ivy, which would force users to install them to use your package.\n\nThe best way to handle this is with the [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Hooks-for-Loading.html][=with-eval-after-load=]] macro.  The [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Hooks-for-Loading.html][Emacs manual]] has a page on it, and [[https://stackoverflow.com/questions/21880139/what-is-with-eval-after-load-in-emacs-lisp][this StackOverflow question]] has some more info.  You can also see an [[https://github.com/alphapapa/org-recent-headings/blob/master/org-recent-headings.el#L350][example]], which also [[https://github.com/alphapapa/org-recent-headings/blob/master/org-recent-headings.el#L377][uses]] [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Declaring-Functions.html][=declare-function=]] to prevent byte-compiler warnings.  Note as well that, according to [[https://stackoverflow.com/questions/21075092/elisp-how-to-avoid-functions-are-not-known-to-be-defined-when-byte-compiling#comment31703432_21075724][this StackOverflow comment]], when a function call is guarded by =fboundp=, it's not necessary to use =declare-function= to avoid a warning.\n\n**** [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][Lexical binding]]                            :lexical_binding:built_in:\n:PROPERTIES:\n:ID:       7247be4d-4f66-43ff-bb70-1b4a7458611b\n:CUSTOM_ID: lexical-binding-0\n:END:\n\nYou should always use lexical binding by setting the header in the first line of the file:\n\n#+BEGIN_EXAMPLE\n  ;;; filename.el --- File description  -*- lexical-binding: t; -*-\n#+END_EXAMPLE\n\n***** Articles                                                 :articles:\n\n****** [[https://yoo2080.wordpress.com/2013/09/11/emacs-lisp-lexical-binding-gotchas-and-related-best-practices/][Emacs Lisp lexical binding gotchas and related best practices | Yoo Box]]\n:PROPERTIES:\n:archive.today: http://archive.today/0nfB4\n:END:\n\n****** [[https://emacs.stackexchange.com/questions/2129/why-is-let-faster-with-lexical-scope][elisp - Why is `let' faster with lexical scope? - Emacs Stack Exchange]]\n:PROPERTIES:\n:archive.today: http://archive.today/LUtfZ\n:END:\n\nSebastian Wiesner provides a detailed explanation.\n\n****** [[https://www.emacswiki.org/emacs/DynamicBindingVsLexicalBinding][EmacsWiki: Dynamic Binding Vs Lexical Binding]]\n:PROPERTIES:\n:archive.today: http://archive.today/2VtOU\n:END:\n\nA lot of good examples and discussion.\n\n****** [[id:3659d32e-3e9e-466f-94ff-33cfed5dc49d][Some Performance Advantages of Lexical Scope « null program]]\n\n**** Template\n:PROPERTIES:\n:ID:       aacd55b6-a56f-4064-bf0d-25173ce83ef3\n:CUSTOM_ID: template\n:END:\n\nWhen you make a new package, the =auto-insert= command will insert a set of standard package headers for you.  However, here is a more comprehensive template you can use:\n\n#+BEGIN_SRC elisp :exports code\n  ;;; package-name.el --- Package description (don't include the word \"Emacs\")  -*- lexical-binding: t; -*-\n\n  ;; Copyright (C) 2017 First Last\n\n  ;; Author: First Last \u003cname@example.com\u003e\n  ;; URL: https://example.com/package-name.el\n  ;; Version: 0.1-pre\n  ;; Package-Requires: ((emacs \"25.2\"))\n  ;; Keywords: something\n\n  ;; This file is not part of GNU Emacs.\n\n  ;; This program is free software; you can redistribute it and/or modify\n  ;; it under the terms of the GNU General Public License as published by\n  ;; the Free Software Foundation, either version 3 of the License, or\n  ;; (at your option) any later version.\n\n  ;; This program is distributed in the hope that it will be useful,\n  ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n  ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n  ;; GNU General Public License for more details.\n\n  ;; You should have received a copy of the GNU General Public License\n  ;; along with this program.  If not, see \u003chttp://www.gnu.org/licenses/\u003e.\n\n  ;;; Commentary:\n\n  ;; This package allows flanges to be easily frobnicated.\n\n  ;;;; Installation\n\n  ;;;;; MELPA\n\n  ;; If you installed from MELPA, you're done.\n\n  ;;;;; Manual\n\n  ;; Install these required packages:\n\n  ;; + foo\n  ;; + bar\n\n  ;; Then put this file in your load-path, and put this in your init\n  ;; file:\n\n  ;; (require 'package-name)\n\n  ;;;; Usage\n\n  ;; Run one of these commands:\n\n  ;; `package-name-command': Frobnicate the flange.\n\n  ;;;; Tips\n\n  ;; + You can customize settings in the `package-name' group.\n\n  ;;;; Credits\n\n  ;; This package would not have been possible without the following\n  ;; packages: foo[1], which showed me how to bifurcate, and bar[2],\n  ;; which takes care of flanges.\n  ;;\n  ;;  [1] https://example.com/foo.el\n  ;;  [2] https://example.com/bar.el\n\n  ;;; Code:\n\n  ;;;; Requirements\n\n  (require 'foo)\n  (require 'bar)\n\n  ;;;; Customization\n\n  (defgroup package-name nil\n    \"Settings for `package-name'.\"\n    :link '(url-link \"https://example.com/package-name.el\"))\n\n  (defcustom package-name-something nil\n    \"This setting does something.\"\n    :type 'something)\n\n  ;;;; Variables\n\n  (defvar package-name-var nil\n    \"A variable.\")\n\n  ;;;;; Keymaps\n\n  ;; This technique makes it easier and less verbose to define keymaps\n  ;; that have many bindings.\n\n  (defvar package-name-map\n    ;; This makes it easy and much less verbose to define keys\n    (let ((map (make-sparse-keymap \"package-name map\"))\n          (maps (list\n                 ;; Mappings go here, e.g.:\n                 \"RET\" #'package-name-RET-command\n                 [remap search-forward] #'package-name-search-forward\n                 )))\n      (cl-loop for (key fn) on maps by #'cddr\n               do (progn\n                    (when (stringp key)\n                      (setq key (kbd key)))\n                    (define-key map key fn)))\n      map))\n\n  ;;;; Commands\n\n  ;;;###autoload\n  (defun package-name-command (args)\n    \"Frobnicate the flange.\"\n    (interactive)\n    (package-name-foo\n     (package-name--bar args)))\n\n  ;;;; Functions\n\n  ;;;;; Public\n\n  (defun package-name-foo (args)\n    \"Return foo for ARGS.\"\n    (foo args))\n\n  ;;;;; Private\n\n  (defun package-name--bar (args)\n    \"Return bar for ARGS.\"\n    (bar args))\n\n  ;;;; Footer\n\n  (provide 'package-name)\n\n  ;;; package-name.el ends here\n#+END_SRC\n\n**** Readme\n:PROPERTIES:\n:CUSTOM_ID: readme\n:END:\n\nYou should always include a readme with your project.  Typically it will be include most of the commentary section.  Here's a template that goes with the package template above:\n\n#+BEGIN_SRC org\n  ,#+TITLE: package-name\n\n  ,#+PROPERTY: LOGGING nil\n\n  # Note: This readme works with the org-make-toc \u003chttps://github.com/alphapapa/org-make-toc\u003e package, which automatically updates the table of contents.\n\n  [[https://melpa.org/#/package-name][file:https://melpa.org/packages/package-name-badge.svg]] [[https://stable.melpa.org/#/package-name][file:https://stable.melpa.org/packages/package-name-badge.svg]]\n\n  This is my package.  It is nice.  You should try it.\n\n  ,* Screenshots\n\n  This screenshot shows how to frobnicate the fripulator:\n\n  [[screenshot1.png]]\n\n  ,* Contents                                                         :noexport:\n  :PROPERTIES:\n  :TOC:      :include siblings\n  :END:\n  :CONTENTS:\n\n  :END:\n\n  ,* Installation\n  :PROPERTIES:\n  :TOC:      :depth 0\n  :END:\n\n  ,** MELPA\n\n  If you installed from MELPA, you're done.  Just run one of the commands below.\n\n  ,** Manual\n\n    Install these required packages:\n\n    + =foo=\n    + =bar=\n\n    Then put this file in your load-path, and put this in your init file:\n\n    ,#+BEGIN_SRC elisp\n  (require 'package-name)\n    ,#+END_SRC\n\n  ,* Usage\n  :PROPERTIES:\n  :TOC:      :depth 0\n  :END:\n\n    Run one of these commands:\n\n    + =package-name-command=: Frobnicate the flange.\n\n  ,** Tips\n\n  + You can customize settings in the =package-name= group.\n\n  ,* Changelog\n  :PROPERTIES:\n  :TOC:      :depth 0\n  :END:\n\n  ,** 1.1.0\n\n  ,*Additions*\n  +  Add command =package-name-debarnacle= to de-barnacle the hull.\n\n  ,*Changes*\n  + Command =package-name-anchor= now takes an argument, =weigh= or =let-go=.\n\n  ,*Internal*\n  +  Rewrote input parsing.\n  +  Factored out anchor-weighing.\n\n  ,** 1.0.1\n\n  ,*Fixes*\n  +  Ensure anchor is secure before returning from =package-name-anchor=.\n\n  ,** 1.0.0\n\n  Initial release.\n\n  ,* Credits\n\n    This package would not have been possible without the following packages: [[https://example.com/foo.el][foo]] which showed me how to bifurcate, and [[https://example.com/bar.el][bar]], which takes care of flanges.\n\n  ,* Development\n\n  Bug reports, feature requests, suggestions — /oh my/!\n\n  ,* License\n\n  GPLv3\n\n  # Local Variables:\n  # eval: (require 'org-make-toc)\n  # before-save-hook: org-make-toc\n  # org-export-with-properties: ()\n  # org-export-with-title: t\n  # End:\n\n#+END_SRC\n\n**** Version numbers\n:PROPERTIES:\n:CUSTOM_ID: version-numbers\n:END:\n\nVersion numbers which are valid in Emacs are those accepted by the function ~version-to-list~, which uses the variables ~version-separator~ and ~version-regexp-alist~.  See their documentation for specific, up-to-date information.  ~version-to-list~'s documentation (as of Emacs 26.1) is reproduced here for convenience:\n\n#+BEGIN_EXAMPLE\n  The version syntax is given by the following EBNF:\n\n  VERSION ::= NUMBER ( SEPARATOR NUMBER )*.\n\n  NUMBER ::= (0|1|2|3|4|5|6|7|8|9)+.\n\n  SEPARATOR ::= ‘version-separator’ (which see)\n  | ‘version-regexp-alist’ (which see).\n\n  The NUMBER part is optional if SEPARATOR is a match for an element\n  in ‘version-regexp-alist’.\n\n  Examples of valid version syntax:\n\n  1.0pre2 1.0.7.5 22.8beta3 0.9alpha1 6.9.30Beta 2.4.snapshot .5\n\n  Examples of invalid version syntax:\n\n  1.0prepre2 1.0..7.5 22.8X3 alpha3.2\n\n  Examples of version conversion:\n\n  Version String Version as a List of Integers\n  \".5\" (0 5)\n  \"0.9 alpha\" (0 9 -3)\n  \"0.9AlphA1\" (0 9 -3 1)\n  \"0.9snapshot\" (0 9 -4)\n  \"1.0-git\" (1 0 -4)\n  \"1.0.7.5\" (1 0 7 5)\n  \"1.0.cvs\" (1 0 -4)\n  \"1.0PRE2\" (1 0 -1 2)\n  \"1.0pre2\" (1 0 -1 2)\n  \"22.8 Beta3\" (22 8 -2 3)\n  \"22.8beta3\" (22 8 -2 3)\n#+END_EXAMPLE\n\n*** Libraries                                                   :libraries:\n:PROPERTIES:\n:TOC:      :depth 0\n:CUSTOM_ID: libraries-5\n:END:\n\n**** =lisp-mnt.el= (=lm=)                                           :built_in:\n:PROPERTIES:\n:TOC:      :ignore this\n:END:\n\nThis library includes functions helpful for working with and verifying the format of Emacs Lisp package files, including headers, commentary, etc.  It's easy to overlook and hard to re-discover this package because of its =lm= symbol prefix.  It's listed here because your editor keeps forgetting what it's called.\n\n*** Reference                                                   :reference:\n:PROPERTIES:\n:CUSTOM_ID: reference\n:END:\n\n**** Package headers and structure\n:PROPERTIES:\n:ID:       036e2a71-f392-4c9a-a524-c5354f291e2f\n:CUSTOM_ID: package-headers-and-structure\n:END:\n\nThe [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Simple-Packages.html][Emacs manual]] gives this example (I've added the lexical-binding part).  Also see [[id:aacd55b6-a56f-4064-bf0d-25173ce83ef3][template]].\n\n#+BEGIN_EXAMPLE\n  ;;; superfrobnicator.el --- Frobnicate and bifurcate fl","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falphapapa%2Femacs-package-dev-handbook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falphapapa%2Femacs-package-dev-handbook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falphapapa%2Femacs-package-dev-handbook/lists"}