1
0
Fork 0
cl-sites/lispcookbook.github.io/cl-cookbook/emacs-ide.html

1253 lines
55 KiB
HTML
Raw Normal View History

2023-10-25 11:23:21 +02:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content=
"HTML Tidy for HTML5 for Linux version 5.2.0">
2024-05-15 18:18:38 +02:00
<title>Using Emacs as an IDE</title>
2023-10-25 11:23:21 +02:00
<meta charset="utf-8">
<meta name="description" content="A collection of examples of using Common Lisp">
<meta name="viewport" content=
"width=device-width, initial-scale=1">
<link rel="icon" href=
"assets/cl-logo-blue.png"/>
<link rel="stylesheet" href=
"assets/style.css">
<script type="text/javascript" src=
"assets/highlight-lisp.js">
</script>
<script type="text/javascript" src=
"assets/jquery-3.2.1.min.js">
</script>
<script type="text/javascript" src=
"assets/jquery.toc/jquery.toc.min.js">
</script>
<script type="text/javascript" src=
"assets/toggle-toc.js">
</script>
<link rel="stylesheet" href=
"assets/github.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
2024-05-15 18:18:38 +02:00
<h1 id="title-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Using Emacs as an IDE</h1>
2023-10-25 11:23:21 +02:00
<div id="logo-container">
<a href="index.html">
<img id="logo" src="assets/cl-logo-blue.png"/>
</a>
<div id="searchform-container">
<form onsubmit="duckSearch()" action="javascript:void(0)">
<input id="searchField" type="text" value="" placeholder="Search...">
</form>
</div>
<div id="toc-container" class="toc-close">
<div id="toc-title">Table of Contents</div>
<ul id="toc" class="list-unstyled"></ul>
</div>
</div>
<div id="content-container">
2024-05-15 18:18:38 +02:00
<h1 id="title-non-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Using Emacs as an IDE</h1>
2023-10-25 11:23:21 +02:00
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
2024-05-15 18:18:38 +02:00
<!-- <p class="announce"> -->
<!-- 📢 🤶 ⭐ -->
<!-- <a style="font-size: 120%" href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPY-XMAS2023" title="This course is under a paywall on the Udemy platform. Several videos are freely available so you can judge before diving in. vindarel is (I am) the main contributor to this Cookbook."> Discover our contributor's Lisp course with this Christmas coupon.</a> -->
<!-- <strong> -->
<!-- Recently added: 18 videos on MACROS. -->
<!-- </strong> -->
<!-- <a style="font-size: 90%" href="https://github.com/vindarel/common-lisp-course-in-videos/">Learn more</a>. -->
<!-- </p> -->
<p class="announce">
📢 New videos: <a href="https://www.youtube.com/watch?v=h_noB1sI_e8">web dev demo part 1</a>, <a href="https://www.youtube.com/watch?v=xnwc7irnc8k">dynamic page with HTMX</a>, <a href="https://www.youtube.com/watch?v=Zpn86AQRVN8">Weblocks demo</a>
</p>
2023-10-25 11:23:21 +02:00
<p class="announce-neutral">
📕 <a href="index.html#download-in-epub">Get the EPUB and PDF</a>
</p>
<div id="content"
2024-05-15 18:18:38 +02:00
<p>This page is meant to provide an introduction to using <a href="https://www.gnu.org/software/emacs/">Emacs</a> as a Lisp IDE.</p>
2024-01-12 09:23:31 +01:00
2024-05-15 18:18:38 +02:00
<p>We divided it roughly into 2 sections: how to use Slime or Sly, and complementary information on built-in Emacs commands to work with Lisp code.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>We want to bring <a href="https://shinmera.github.io/portacle/">Portacle</a> to your attention. It is a portable and
multi-platform CL development environment shipping Emacs, Slime, SBCL, git and
2024-01-12 09:23:31 +01:00
necessary extensions. It is a straightforward way to get going.</p>
2023-10-25 11:23:21 +02:00
2024-01-12 09:23:31 +01:00
<p><img src="assets/emacs-teaser.png" alt="" /></p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<!-- todo: C-u M-x slime and its configuration to work with multiple implementations -->
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h2 id="why-use-emacs">Why Use Emacs?</h2>
2023-10-25 11:23:21 +02:00
<ul>
<li>Emacs has fantastic support for working with Lisp code</li>
<li>Not tying yourself into a single CL vendors editor</li>
<li>Runs on virtually every OS and CL implementation</li>
<li>Emacs will probably always be around</li>
<li>Emacs works well either with a mouse or without a mouse</li>
<li>Emacs works well either in GUI mode or in the terminal</li>
<li>Emacs has a large user base with multiple newsgroups</li>
2024-01-12 09:23:31 +01:00
<li>Built-in tree-sitter and LSP support</li>
<li>Excellent vim mode</li>
2023-10-25 11:23:21 +02:00
<li>Because <a href="http://orgmode.org">Org-mode</a></li>
<li>Because <a href="https://magit.vc/">Magit</a></li>
<li>Because <a href="http://emacsrocks.com">Emacs Rocks !</a></li>
2024-01-12 09:23:31 +01:00
<li>Vast number of extensions: <a href="https://github.com/emacs-tw/awesome-emacs">awesome-emacs</a>.</li>
2023-10-25 11:23:21 +02:00
</ul>
2024-05-15 18:18:38 +02:00
<h2 id="slime-superior-lisp-interaction-mode-for-emacs">SLIME: Superior Lisp Interaction Mode for Emacs</h2>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><a href="http://common-lisp.net/project/slime/">SLIME</a> is the goto major mode
for CL programming. It has a lot of features that make it a powerful, integrated and very interactive development environment.</p>
2024-01-12 09:23:31 +01:00
2023-10-25 11:23:21 +02:00
<ul>
2024-05-15 18:18:38 +02:00
<li>it provides a REPL which is hooked to the running image, directly in Emacs,</li>
<li>it integrates the Common Lisp debugger with an Emacs interface</li>
<li>it provides symbol completion,</li>
<li>code evaluation, compilation, macroexpansion</li>
<li>cross-referencing,</li>
<li>breaking, stepping, tracing,</li>
<li>go to definition,</li>
<li>online documentation,</li>
<li>fuzzy searching functions and symbols, system names, documentation,</li>
<li>an interactive object inspector,</li>
<li>it supports every common Common Lisp implementation,</li>
<li>multiple connections and multiple listener buffers (mrepl)</li>
<li>it is readily available from MELPA</li>
<li>it is actively maintained.</li>
2024-01-12 09:23:31 +01:00
</ul>
2024-05-15 18:18:38 +02:00
<h2 id="sly-sylvester-the-cats-common-lisp-ide">SLY: Sylvester the Cats Common Lisp IDE</h2>
<p><a href="https://github.com/joaotavora/sly">SLY</a> is a SLIME fork that contains
the following improvements:</p>
2024-01-12 09:23:31 +01:00
<ul>
2024-05-15 18:18:38 +02:00
<li>Completely redesigned REPL based on Emacss own full-featured comint.el.</li>
<li>Live code annotations via the <a href="https://joaotavora.github.io/sly/#Stickers">Stickers</a> feature.</li>
<li>Consistent interactive button interface. Everything can be copied to the REPL.</li>
<li>Multiple REPLs.</li>
<li>Multiple inspectors with independent history.</li>
<li>Regexp-capable <code>M-x sly-apropos</code>.</li>
<li>Contribs are first class SLY citizens, enabled by default, loaded with ASDF on demand:
<ul>
<li><a href="https://github.com/joaotavora/sly-named-readtables">NAMED-READTABLES</a> support</li>
<li><a href="https://github.com/joaotavora/sly-macrostep">macrostep.el</a></li>
<li><a href="https://github.com/joaotavora/sly-quicklisp">Quicklisp</a></li>
<li><a href="https://github.com/mmgeorge/sly-asdf">ASDF</a></li>
<li><a href="https://git.sr.ht/~fosskers/sly-overlay">Evaluation Overlays</a></li>
</ul>
</li>
2023-10-25 11:23:21 +02:00
</ul>
2024-05-15 18:18:38 +02:00
<p>Sly is shipped by default in <a href="https://github.com/doomemacs/doomemacs/">Doom Emacs</a>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h2 id="installing-slime-or-sly">Installing SLIME or SLY</h2>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="manually">Manually</h3>
<p>On Ubuntu, SLIME is easily installed alongside Emacs and SBCL:</p>
<pre><code>sudo apt install emacs slime sbcl
</code></pre>
<p>Otherwise, install SLIME by adding this code to your <code>~/.emacs.d/init.el</code> file:</p>
<pre><code class="language-lisp">(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(dolist (package '(slime))
(unless (package-installed-p package)
(package-install package)))
(require 'slime)
</code></pre>
<p>assuming youve also instealled Emacs and SBCL.</p>
<p>Since SLIME is heavily modular and the defaults only do the bare minimum (not
even the SLIME REPL), you might want to enable more features with</p>
<pre><code class="language-lisp">(require 'slime)
(slime-setup '(slime-fancy slime-quicklisp slime-asdf slime-mrepl))
</code></pre>
<p>After this you can press Alt-X on your keyboard and type <code>slime</code> and try Common Lisp!</p>
<p>(Alt-X is often written <code>M-x</code> in Emacs-world.)</p>
<p>For more details, consult the
<a href="https://common-lisp.net/project/slime/doc/html/">documentation</a> (also available
as an Info page).</p>
<p>Now you can run SLIME with, as mentioned, <code>M-x slime</code> and/or <code>M-x slime-connect</code>.</p>
<p>See also:</p>
2023-10-25 11:23:21 +02:00
<ul>
2024-05-15 18:18:38 +02:00
<li><a href="https://github.com/susam/emacs4cl">https://github.com/susam/emacs4cl</a> - a minimal Emacs configuration to get new users up and running quickly, with a tutorial.</li>
<li><a href="https://wikemacs.org/wiki/SLIME">https://wikemacs.org/wiki/SLIME</a> - configuration examples and extensions.</li>
2023-10-25 11:23:21 +02:00
</ul>
2024-05-15 18:18:38 +02:00
<h3 id="portacle">Portacle</h3>
<p><a href="https://shinmera.github.io/portacle/">Portacle</a> is a portable and
multi-platform CL development environment with which you can start
developping in Lisp in a few clicks. Portacle includes Emacs, SBCL, Slime, git, and useful Emacs extensions (which-key, treeview…).</p>
<p>It is a straightforward way to get going.</p>
<h3 id="doom-emacs">Doom Emacs</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><a href="https://github.com/doomemacs/doomemacs/">Doom Emacs</a> is a popular Emacs configuration. You can easily enable its Sly integration.</p>
<h3 id="slime-fancy-and-contrib-packages">SLIME fancy and contrib packages</h3>
2023-10-25 11:23:21 +02:00
<p>SLIMEs functionalities live in packages and so-called <a href="https://common-lisp.net/project/slime/doc/html/Contributed-Packages.html">contrib
modules</a>
2024-05-15 18:18:38 +02:00
must be loaded to add further functionalities. The afored mentioned
2023-10-25 11:23:21 +02:00
<code>slime-fancy</code> includes:</p>
<ul>
<li>slime-autodoc</li>
<li>slime-c-p-c</li>
<li>slime-editing-commands</li>
<li>slime-fancy-inspector</li>
<li>slime-fancy-trace</li>
<li>slime-fontifying-fu</li>
<li>slime-fuzzy</li>
<li>slime-mdot-fu</li>
<li>slime-macrostep</li>
<li>slime-presentations</li>
<li>slime-references</li>
<li>slime-repl</li>
<li>slime-scratch</li>
<li>slime-package-fu</li>
<li>slime-trace-dialog</li>
2024-05-15 18:18:38 +02:00
<li><a href="https://slime.common-lisp.dev/doc/html/slime_002dmrepl.html#slime_002dmrepl">slime-mrepl</a> (multiple REPLs)</li>
2023-10-25 11:23:21 +02:00
</ul>
<p>SLIME also has some nice extensions like
<a href="https://github.com/emacs-helm/helm-slime">Helm-SLIME</a> which features, among
others:</p>
<ul>
<li>Fuzzy completion,</li>
<li>REPL and connection listing,</li>
<li>Fuzzy-search of the REPL history,</li>
<li>Fuzzy-search of the <em>apropos</em> documentation.</li>
</ul>
2024-05-15 18:18:38 +02:00
<h2 id="working-with-slime-or-sly">Working with SLIME (or SLY)</h2>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>One of the first things you might want to do is to compile and load some Lisp code. Use <code>C-c C-c</code> on a function or <code>C-c C-k</code> to compile a whole file. But thats not all, read on.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Note that we give function names for SLIME. They are most of the time similar with SLY.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="code-completion">Code completion</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use the built-in <code>C-c TAB</code> to complete symbols in SLIME. You can get tooltips
with <a href="http://company-mode.github.io/">company-mode</a>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><img src="assets/emacs-company-elisp.png" alt="" title="Lisp symbols completion with company-mode tooltips." /></p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>In the <strong>REPL</strong>, its simply <strong>TAB</strong>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use Emacs hippie-expand, bound to <code>M-/</code>, to complete any string present in other open buffers.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="evaluating-and-compiling-lisp-in-slime">Evaluating and Compiling Lisp in SLIME</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Compile the entire <strong>buffer</strong> by pressing <code>C-c C-k</code> (<code>slime-compile-and-load-file</code>).</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Compile a <strong>region</strong> with <code>M-x slime-compile-region</code>.</p>
<p>Compile a <strong>defun</strong> by putting the cursor inside it and pressing <code>C-c C-c</code> (<code>slime-compile-defun</code>).</p>
<p>Once you compiled some code, you can try it, for example on the REPL.</p>
<p>To <strong>evaluate</strong> rather than compile:</p>
2023-10-25 11:23:21 +02:00
<ul>
2024-05-15 18:18:38 +02:00
<li>evaluate the <strong>sexp</strong> before the point by putting the cursor after
its closing paren and pressing <code>C-x C-e</code>
(<code>slime-eval-last-expression</code>). The result is printed in the minibuffer.</li>
<li>similarly, use <code>C-c C-p</code> (<code>slime-pprint-eval-last-expression</code>) to eval and pretty-print the expression before point. It shows the result in a new “slime-description” buffer.</li>
<li>use <code>M-x slime-eval-print-last-expression</code> (unbound by default) to print the result in the same file, under the cursor.</li>
<li>evaluate a region with <code>C-c C-r</code>,</li>
<li>evaluate a defun with <code>C-M-x</code>,</li>
<li>type <code>C-c C-e</code> (<code>slime-interactive-eval</code>) to get a prompt that asks for code to eval in the current context. It prints the result in the minibuffer. With a prefix argument, insert the result into the current buffer.</li>
<li>type <code>C-c C-j</code> (<code>slime-eval-last-expression-in-repl</code>), when the cursor is after the closing parenthesis of an expression, to send this expression to the REPL and evaluate it.</li>
2023-10-25 11:23:21 +02:00
</ul>
2024-05-15 18:18:38 +02:00
<p>See also other commands in the menu.</p>
<p>But whats the difference between evaluating and compiling some code?</p>
<h3 id="evaluation-vs-compilation">evaluation VS compilation</h3>
<p>There are a couple of pragmatic differences when choosing between compiling or evaluating.
In general, it is better to <em>compile</em> top-level forms, for two reasons:</p>
2023-10-25 11:23:21 +02:00
<ul>
2024-05-15 18:18:38 +02:00
<li>Compiling a top-level form highlights warnings and errors in the editor, whereas evaluation does not.</li>
<li>SLIME keeps track of line-numbers of compiled forms, but when a top-level form is evaluated, the file line number information is lost. Thats problematic for code navigation afterwards.</li>
2023-10-25 11:23:21 +02:00
</ul>
2024-05-15 18:18:38 +02:00
<p><code>eval</code> is still useful to observe results from individual non top-level forms. For example, say you have this function:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(defun foo ()
(let ((f (open "/home/mariano/test.lisp")))
...))
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Go to the end of the OPEN expression and evaluate it (<code>C-x C-e</code>), to observe the result:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code>=&gt; #&lt;SB-SYS:FD-STREAM for "file /mnt/e6b00b8f-9dad-4bf4-bd40-34b1e6d31f0a/home/marian/test.lisp" {1003AAAB53}&gt;
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Or on this example, with the cursor on the last parentheses, press <code>C-x C-e</code> to evaluate the <code>let</code>:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(let ((n 20))
(loop for i from 0 below n
do (print i)))
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>You should see numbers printed in the REPL.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>See also <a href="https://github.com/kaz-yos/eval-in-repl">eval-in-repl</a> to send any form to the repl.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="debugging">Debugging</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>We cover debugging commands in its own <a href="debugging.html">debugging</a> chapter.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="go-to-definition">Go to definition</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Put the cursor on any symbol and press <code>M-.</code> (<code>slime-edit-definition</code>) to go to its
definition. Press <code>M-,</code> to come back.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="go-to-any-symbol-list-symbols-in-current-source">Go to any symbol, list symbols in current source</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use <code>C-u M-.</code> (<code>slime-edit-definition</code> with a prefix argument, also available as <code>M-- M-.</code>) to autocomplete the symbol and navigate to it.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>This command always asks for a symbol even if the cursor is on one. It works with any loaded definition. Heres a little <a href="https://www.youtube.com/watch?v=ZAEt73JHup8">demonstration video</a>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>You can think of it as a <code>imenu</code> completion that always work for any Lisp symbol. Add in <a href="https://common-lisp.net/project/slime/doc/html/Fuzzy-Completion.html">Slimes fuzzy completion</a> for maximum powerness!</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="argument-lists">Argument lists</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>When you put the cursor on a function, SLIME will show its signature
in the minibuffer.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>If you want to see them better, try <code>C-c C-s</code> after a function name.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>For example, you forgot how to use <code>with-open-file</code>. Write it:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(with-open-file
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>now press <code>C-c C-s</code> (<code>slime-complete-form</code>) and youll get:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(with-open-file (stream filespec :direction direction
:element-type element-type
:if-exists if-exists
:if-does-not-exist if-does-not-exist
:external-format external-format
:class class
)
body...)
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>written in your source file (or in the REPL).</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>The minibuffer will show you the default values of the arguments.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="documentation-lookup">Documentation lookup</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>The main shortcut to know is:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><strong>C-c C-d d</strong> shows the symbols documentation on a new window (same result as using <code>describe</code>).</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Other bindings which may be useful:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><strong>C-c C-d f</strong> describes a function</li>
<li><strong>C-c C-d h</strong> looks up the symbol documentation in CLHS by opening the web browser. But it works only on symbols, so there are two more bindings:</li>
<li><strong>C-c C-d #</strong> for reader macros</li>
<li><strong>C-c C-d ~</strong> for format directives</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>You can enhance the help buffer with the Slime extension <a href="https://github.com/mmontone/slime-doc-contribs">slime-doc-contribs</a>. It will show more information in a nice looking buffer, and it will add choices to the documentation command:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><strong>slime-help-package</strong> will display information about a CL package: it will nicely show its exported variables, conditions, classes, generic functions, functions and macros, with their documentation. It is a great way to see at a glance what a package provides.</li>
<li><strong>slime-help-system</strong> does the same for a <em>system</em>.</li>
<li><strong>slime-help-apropos-documentation</strong> will show symbols whose documentation contains matches for “PATTERN”, which is a great way to lookup for functions.</li>
<li>and more.</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><img src="https://github.com/mmontone/slime-doc-contribs/raw/master/slime-help.png" alt="" /></p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="inspector">Inspector</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>You can call <code>(inspect 'symbol)</code> from the REPL or call it with <code>C-c I</code> from a source file.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Learn to use with <a href="https://slime.common-lisp.dev/doc/html/Inspector.html#Inspector">its documentation</a>: use <code>l</code> to come back to the previous object, <code>*</code> to copy the object at point… and more.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="macroexpand">Macroexpand</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use <code>C-c M-m</code> to macroexpand a macro call</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="crossreferencing-find-whos-calling-referencing-setting-a-symbol">Crossreferencing: find whos calling, referencing, setting a symbol</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Slime has nice cross-referencing facilities. For example, you can ask
what calls a particular function, what expands a macro, or where a global variable is being used.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Results are presented in a new buffer, listing the places which reference a particular entity.
From there, we can press Enter to go to the corresponding source line,
or more interestingly we can recompile the place at point by pressing <strong>C-c C-c</strong> on that
line. Likewise, <strong>C-c C-k</strong> will recompile all the references. This is useful when
modifying macros, inline functions, or constants.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>The bindings are the following (they are also shown in Slimes menu):</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><strong>C-c C-w c</strong> (<code>slime-who-calls</code>) callers of a function</li>
<li><strong>C-c C-w m</strong> (<code>slime-who-macroexpands</code>) places where a macro is expanded</li>
<li><strong>C-c C-w r</strong> (<code>slime-who-references</code>) global variable references</li>
<li><strong>C-c C-w b</strong> (<code>slime-who-bind</code>) global variable bindings</li>
<li><strong>C-c C-w s</strong> (<code>slime-who-sets</code>) global variable setters</li>
<li><strong>C-c C-w a</strong> (<code>slime-who-specializes</code>) methods specialized on a symbol</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>And when the <code>slime-asdf</code> contrib is enabled,
<strong>C-c C-w d</strong> (<code>slime-who-depends-on</code>) lists dependent ASDF systems</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>And a general binding: <strong>M-?</strong> or <strong>M-_</strong> (<code>slime-edit-uses</code>) combines all
of the above, it lists every kind of references.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="systems-interactions">Systems interactions</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>In Slime, you can use the usual <code>C-c C-k</code> in an .asd file to compile and load it, then <code>ql:quickload</code> (or <code>asdf:load-system</code>) to effectively load the system. SLIME offers more interactive commands to interact with Lisp systems:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><code>M-x slime-load-system</code>: offers a prompt to <strong>select an ASDF system</strong>, with <strong>autocompletion</strong> of projects collected from where ASDF sees Common Lisp projects, then compile and load the system. The default system name is taken from the first file matching *.asd in the current buffers working directory.
<ul>
<li>note that the system name is inferred from the .asd file name. The real system name defined inside may be different.</li>
<li>to understand where ASDF looks for Lisp systems, read the <a href="getting-started.html">getting started</a> page, section “How to load an existing project”.</li>
</ul>
</li>
<li><code>M-x slime-open-system</code>: this opens a new buffer for all source files of a given system.</li>
<li><code>M-x slime-browse-system</code>: this command opens a Dired buffer to browse the files of a system.</li>
<li><code>M-x slime-rgrep-system</code>: run <code>rgrep</code> on the base directory of a system.</li>
<li><code>M-x slime-isearch-system</code>: run <code>isearch</code> on the files of a system.</li>
<li><code>M-x slime-query-replace-system</code>: run <code>query-replace</code> on an ASDF system.</li>
<li><code>M-x slime-save-system</code>: save all files belongign to a system.</li>
<li><code>M-x slime-delete-system-fasls</code>: this deletes the cached .fasl files for this system.</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Sly users have a more featureful <code>sly-load-system</code> command that will search the .asd file on the current directory and in parent directories.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="repl-interactions">REPL interactions</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>From the SLIME REPL, press <code>,</code> to prompt for commands. There is completion
over the available systems and packages. Examples:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><code>,load-system</code></li>
<li><code>,reload-system</code></li>
<li><code>,in-package</code> (also <code>C-c M-p</code> in a .lisp file)</li>
<li><code>,restart-inferior-lisp</code></li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>and many more. Usually the interactive commands given in the previous section have a REPL shortcut.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>With the <code>slime-quicklisp</code> contrib, we can use <code>,ql</code> to
autocomplete a system to install, from all systems available for
installation.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>In addition, we can use the <a href="https://github.com/mmontone/quicklisp-systems">Quicklisp-systems</a> Slime extension to search, browse and load Quicklisp systems from Emacs.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="sending-code-to-the-repl">Sending code to the REPL</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>You can write code in the REPL, but you can also interact with code directly from the source file.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>We saw <strong>C-c C-j</strong>, that sends the expression at point to the REPL and evaluates it.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><strong>C-c C-y</strong> (<code>slime-call-defun</code>): send code to the REPL.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>When the point is inside a defun and C-c C-y is pressed (below Ill use [] as an indication where the cursor is)</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(defun foo ()
nil[])
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>then <code>(foo [])</code> will be inserted into the REPL, so that you can write
additional arguments and run it.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>If <code>foo</code> was in a different package than the package of the REPL,
<code>(package:foo )</code> or <code>(package::foo )</code> will be inserted.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>This feature is very useful for testing a function you just wrote.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>That works not only for a <code>defun</code>, but also for <code>defgeneric</code>, <code>defmethod</code>,
<code>defmacro</code>, and <code>define-compiler-macro</code> in the same fashion as for defun.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>For <code>defvar</code>, <code>defparameter</code>, <code>defconstant</code>: <code>[] *foo*</code> will be inserted
(the cursor is positioned before the symbol so that you can easily
wrap it into a function call).</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>For defclass: <code>(make-instance class-name )</code>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><strong>Inserting calls to frames in the debugger</strong></p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><strong>C-y</strong> in SLDB on a frame will insert a call to that frame into the REPL, e.g.,</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code>(/ 0) =&gt;
1: (CCL::INTEGER-/-INTEGER 1 0)
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><strong>C-y</strong> will insert <code>(CCL::INTEGER-/-INTEGER 1 0)</code>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>(thanks to <a href="https://slime-tips.tumblr.com/page/2">Slime tips</a>)</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="synchronizing-packages">Synchronizing packages</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><strong>C-c ~</strong> (<code>slime-sync-package-and-default-directory</code>): When run in a
buffer with a lisp file it will change the current package of the REPL
to the package of that file and also set the current directory of the REPL
to the parent directory of the file.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="exporting-symbols">Exporting symbols</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Slime provides a shortcut to add export declarations to your package, effectively exporting one or many symbol(s), or on the contrary un-exporting it.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><strong>C-c x</strong> (<em>slime-export-symbol-at-point</em>) from the <code>slime-package-fu</code>
contrib: takes the symbol at point and modifies the <code>:export</code> clause of
the corresponding defpackage form. It also exports the symbol. When
called with a negative argument (C-u C-c x) it will remove the symbol
from <code>:export</code> and unexport it.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><strong>M-x slime-export-class</strong> does the same but with symbols defined
by a structure or a class, like accessors, constructors, and so on.
It works on structures only on SBCL and Clozure CL so far.
Classes should work everywhere with MOP.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Customization</p>
<p>There are different styles of how symbols are presented in
<code>defpackage</code>, the default is to use uninterned symbols (<code>#:foo</code>).
This can be changed:</p>
<p>to use keywords, add this to your Emacs init file:</p>
<pre><code class="language-lisp">(setq slime-export-symbol-representation-function
(lambda (n) (format ":%s" n)))
2023-10-25 11:23:21 +02:00
</code></pre>
2024-05-15 18:18:38 +02:00
<p>or strings:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(setq slime-export-symbol-representation-function
(lambda (n) (format "\"%s\"" (upcase n))))
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="optional-consult-the-hyper-spec-clhs-offline">(optional) Consult the Hyper Spec (CLHS) offline</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>The <a href="http://www.lispworks.com/documentation/common-lisp.html">Common Lisp Hyper Spec</a> is the
official online version of the ANSI Common Lisp standard. We can start
browsing it from <a href="http://www.lispworks.com/documentation/HyperSpec/Front/StartPts.htm">starting points</a>:
a shortened <a href="http://www.lispworks.com/documentation/HyperSpec/Front/Hilights.htm">table of contents of highlights</a>,
a <a href="http://www.lispworks.com/documentation/HyperSpec/Front/Hilights.htm">symbols index</a>,
a glossary, a master index.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Since January of 2023, we have the Common Lisp Community Spec: <a href="https://cl-community-spec.github.io/pages/index.html">https://cl-community-spec.github.io/pages/index.html</a>, a new web rendering of the specification. It is a more modern rendering:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li>it has a <em>search box</em></li>
<li>it has <em>syntax highlihgting</em></li>
<li>it is hosted on GitHub and we have the right to modify it: https://github.com/fonol/cl-community-spec</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>If you want other tools to do a quick look-up of symbols on the CLHS,
since the official website doesnt have a search bar, you can use:</p>
<ul>
<li>Xachs website search utility: <a href="https://www.xach.com/clhs?q=with-open-file">https://www.xach.com/clhs?q=with-open-file</a></li>
<li>the l1sp.org website: <a href="http://l1sp.org/search?q=with-open-file">http://l1sp.org/search?q=with-open-file</a>,</li>
<li>and we can use Duckduckgos or Brave Searchs <code>!clhs</code> “bang”.</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>We can <strong>browse the CLHS offline</strong> with <a href="https://kapeli.com/dash">Dash</a> on MacOS, <a href="https://zealdocs.org/">Zeal</a> on GNU/Linux and <a href="https://velocity.silverlakesoftware.com/">Velocity</a> on Windows.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>But we can also browse it offline from Emacs. We have to install a CL package and to configure the Emacs side with one command:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(ql:quickload "clhs")
(clhs:install-clhs-use-local)
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Then add this to your Emacs configuration:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(load "~/quicklisp/clhs-use-local.el" 'noerror)
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Now, you can use <code>C-c C-d h</code> to look-up the symbol at point in the
HyperSpec. This will open your browser, but look at its URL starting
with “file://home/”: it opens a local file.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Other commands are available:</p>
<ul>
<li>when you want to look-up a reader macro, such as <code>#'</code>
(sharpsign-quote) or <code>(</code> (left-parenthesis), use
<code>M-x common-lisp-hyperspec-lookup-reader-macro</code>, bound to <code>C-c C-d #</code>.</li>
<li>to look-up a <code>format</code> directive, such as <code>~A</code>, use <code>M-x
common-lisp-hyperspec-format</code>, bound to <code>C-c C-d ~</code>.
<ul>
<li>of course, you can TAB-complete on Emacs minibuffer prompt to see all the available format directives.</li>
</ul>
</li>
<li>you can also look-up glossary terms (for example, you can look-up “function” instead of “defun”), use <code>M-x common-lisp-hyperspec-glossary-term</code>, bound to <code>C-c C-d g</code>.</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h2 id="working-with-emacs">Working with Emacs</h2>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>In this section well learn the most useful Emacs commands to work with Lisp code in general, or to perform common actions.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Well start by how to find your way into Emacs built-in documentation. If there is a skill you should learn, that is the one.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Dont forget that Emacs both GUI and terminal interfaces have menus, they help in discovering all available commands. If you dont see one, ensure that your emacs configuration doesnt hide it. Display the menu with <code>M-x menu-bar-mode</code>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="built-in-documentation">Built-in documentation</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Emacs comes with built-in tutorials and documentation. Moreover, it is
a self-documented and self-discoverable editor, capable of introspection to let you
know about the current keybindings, to let you search about function documentation,
available variables,source code, tutorials, etc. Whenever you ask yourself questions like
“what are the available shortcuts to do x” or “what does this
keybinding really do”, the answer is most probably a keystroke away,
right inside Emacs. You should learn a few keybindings to be able to
discover Emacs with Emacs flawlessly.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>The help on the topic is here:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Help.html#Help">Help page: commands for asking Emacs about its commands</a></li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>The help keybindings start with either <code>C-h</code> or <code>F1</code>. Important ones are:</p>
2023-10-25 11:23:21 +02:00
<ul>
2024-05-15 18:18:38 +02:00
<li><code>C-h k &lt;keybinding&gt;</code>: what function does this keybinding call?</li>
<li><code>C-h f &lt;function name&gt;</code>: what keybinding is linked to this function?</li>
<li><code>C-h a &lt;topic&gt;</code>: show a list of commands whose name match the given <em>topic</em>. It accepts a keyword, a list of keywords or a regular expression.</li>
<li><code>C-h i</code>: show the Info page, a menu of major topics.</li>
2023-10-25 11:23:21 +02:00
</ul>
2024-05-15 18:18:38 +02:00
<p>Some Emacs packages give even more help.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="more-help-and-discoverability-packages">More help and discoverability packages</h3>
<p>Sometimes, you start typing a key sequence but you cant remember it
completely. Or, you wonder what other keybindings are related. Comes
<a href="https://github.com/justbur/emacs-which-key">which-key-mode</a>. This
packages will display all possible keybindings starting with the key(s) you just typed.</p>
<p>For example, I know there are useful keybindings under <code>C-x</code> but I dont remember which ones… I just type <code>C-x</code>, I wait for half a second, and which-key shows all the ones available.</p>
<p><img src="assets/emacs-which-key-minibuffer.png" alt="" /></p>
<p>Just try it with <code>C-h</code> too!</p>
<p>See also <a href="https://github.com/Wilfred/helpful">Helpful</a>, an alternative to the built-in Emacs help that provides much more contextual information.</p>
<p><img src="assets/emacs-helpful.png" style="height: 450px" /></p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="built-in-tutorial">Built-in tutorial</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Emacs ships its own tutorial. You should give it a look to learn the most important keybindings and concepts.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Call it with <code>M-x help-with-tutorial</code> (where <code>M-x</code> is <code>alt-x</code>).</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="editing">Editing</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Emacs has, of course, built-in commands to deal with s-expressions.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h4 id="forwardbackwardupdown-movement-and-selection-by-s-expressions">Forward/Backward/Up/Down movement and selection by s-expressions</h4>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use <code>C-M-f</code> and <code>C-M-b</code> (<code>forward-sexp</code> and <code>backward-sexp</code>) to move
in units of s-expressions.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use <code>C-M-t</code> to swap
the first addition sexp and the second one. Put the cursor on the open
parens of “(+ x” in defun c and press</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use <code>C-M-@</code> to highlight an entire sexp. Then press <code>C-M-u</code> to expand
the selection “upwards” and <code>C-M-d</code> to move forward down one level of
parentheses.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h4 id="deleting-s-expressions">Deleting s-expressions</h4>
2024-01-12 09:23:31 +01:00
2024-05-15 18:18:38 +02:00
<p>Use <code>C-M-k</code> (<code>kill-sexp</code>) and <code>C-M-backspace</code> (<code>backward-kill-sexp</code>) (but caution: this keybinding may restart the system on GNU/Linux).</p>
2024-01-12 09:23:31 +01:00
2024-05-15 18:18:38 +02:00
<p>For example, if point is before <code>(progn</code> (Ill use [] as an indication where the cursor is):</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(defun d ()
(if t
(+ 3 3)
[](progn
(+ 1 1)
(if t
(+ 2 2)
(+ 3 3)))
(+ 4 4)))
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>and you press <code>C-M-k</code>, you get:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(defun d ()
(if t
(+ 3 3)
[]
(+ 4 4)))
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h4 id="indenting-s-expressions">Indenting s-expressions</h4>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Indentation is automatic for Lisp forms.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Pressing TAB will indent incorrectly indented code. For example, put
the point at the beginning of the <code>(+ 3 3)</code> form and press TAB:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(progn
(+ 3 3))
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>you correctly get</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(progn
(+ 3 3))
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use <code>C-M-q</code> (<code>slime-reindent-defun</code>) to indent the current function definition:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">;; Put the cursor on the open parens of "(defun ..."
;; and press "C-M-q" to indent the code:
(defun e ()
"A badly indented function."
(let ((x 20))
(loop for i from 0 to x
do (loop for j from 0 below 10
do (print j))
(if (&lt; i 10)
(let ((z nil) )
(setq z (format t "x=~d" i))
(print z))))))
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
;; This is the result:
(defun e ()
"A badly indented function (now correctly indented)."
(let ((x 20))
(loop for i from 0 to x
do (loop for j from 0 below 10
do (print j))
(if (&lt; i 10)
(let ((z nil) )
(setq z (format t "x=~d" i))
(print z))))))
2023-10-25 11:23:21 +02:00
</code></pre>
2024-05-15 18:18:38 +02:00
<p>You can also select a region and call <code>M-x indent-region</code>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h4 id="open-and-close-parenthesis">Open and close parenthesis</h4>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>When you are in a Slime REPL, you can use <code>C-return</code> or <code>M-return</code>
(<code>slime-repl-closing-return</code>) to close the remaining parenthesis and
evaluate your input string.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>In files, use <code>M-(</code> to insert a pair of parenthesis (<code>()</code>) and the same
keybinding with a prefix argument, <code>C-u M-(</code>, to enclose the
expression in front of the cursor with a pair of parens.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>For example, we start with the cursor before the first paren:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">CL-USER&gt; |(- 2 2)
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Press <code>C-u M-(</code> to enclose it with parens:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">CL-USER&gt; (|(- 2 2))
;; now write anything.
CL-USER&gt; (zerop (- 2 2))
</code></pre>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>With a numbered prefix argument (<code>C-u 2 M-(</code>), wrap around this number of s-expressions.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Additionnaly, use <code>M-x check-parens</code> to spot malformed s-exps and <code>C-c
C-]</code> (<code>slime-close-all-parens-in-sexp</code>) to insert the required number
of closing parenthesis.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>There are additional packages that can make your use of parens easier:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><code>M-x show-paren-mode</code>, a built-in Emacs mode: it toggles the
visualization of matching parenthesis. When enabled, place the
cursor on a paren and youll see the other paren it matches
with. You can initialize it in your Emacs init file with
<code>(show-paren-mode t)</code>. It is a global minor mode (it will work for
all buffers, all languages).</li>
<li>when evil-mode (the vim layer) is enabled, you can use the <code>%</code> key to go to the matchin paren.</li>
<li><code>M-x electric-pair-mode</code>, a built-in Emacs mode: when enabled,
typing an open parenthesis automatically inserts the corresponding
closing parenthesis, and vice versa. (Likewise for brackets, etc.).
If the region is active, the parentheses (brackets, etc.) are inserted
around the region instead.</li>
<li>you could use <a href="http://danmidwood.com/content/2014/11/21/animated-paredit.html">Paredit (animated guide)</a> to automatically insert parentheses in pairs,</li>
<li>or <a href="https://github.com/abo-abo/lispy">lispy-mode</a>, like Paredit, but a key triggers an action when the cursor is placed right before or right after a parentheses.</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h4 id="hidingshowing-code">Hiding/showing code</h4>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use <code>C-x n n</code> (narrow-to-region) and <code>C-x n w</code> to widen back.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>See also <a href="http://wikemacs.org/wiki/Folding">code folding</a> with external packages.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h4 id="comments">Comments</h4>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Insert a comment or comment a region with <code>M-;</code>, adjust text with <code>M-q</code>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="optional-packages-for-structured-editing">(optional) Packages for structured editing</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>In addition to the built-in Emacs commands, you have several packages at your disposal
that will help to keep the parens and/or the indentation balanced.
The list below is somewhat sorted by age of the
extension, according to the
<a href="https://github.com/shaunlebron/history-of-lisp-editing">history of Lisp editing</a>:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<ul>
<li><a href="https://www.emacswiki.org/emacs/ParEdit">Paredit</a> - Paredit is a
classic. It defines the must-have commands (move, kill, split, join
a sexp,…).
(<a href="http://danmidwood.com/content/2014/11/21/animated-paredit.html">visual tutorial</a>)</li>
<li><a href="https://github.com/Fuco1/smartparens">Smartparens</a> - Smartparens
not only deals with parens but with everything that comes in pairs
(html tags,…) and thus has features for non-lispy languages.</li>
<li><a href="https://github.com/abo-abo/lispy">Lispy</a> - Lispy reimagines Paredit
with the goal to have the shortest bindings (mostly one key) that
only act depending on the point position.</li>
<li><a href="https://github.com/promethial/paxedit">Paxedit</a> - Paxedit adds
commands based on the context (in a symbol, a sexp,… ) and puts
efforts on whitespace cleanup and context refactoring.</li>
<li><a href="http://shaunlebron.github.io/parinfer/">Parinfer</a> - Parinfer
automatically fixes the parens depending on the indentation, or the
other way round (or both !).</li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>We personally advice to try Parinfer and the famous Paredit, then to
go up the list. See explanations and even more on
<a href="http://wikemacs.org/wiki/Lisp_editing">Wikemacs</a>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="search-and-replace">Search and replace</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h4 id="isearch-forwardbackward-regexp-searches-searchreplace">isearch forward/backward, regexp searches, search/replace</h4>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><code>C-s</code> does an incremental search forward (e.g. - as each key is
the search string is entered, the source file is searched for the
first match. This can make finding specific text much quicker as
you only need to type in the unique characters. Repeat searches
(using the same search characters) can be done by repeatedly
pressing <code>C-s</code></p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><code>C-r</code> does an incremental search backward</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><code>C-s RET</code> and <code>C-r RET</code> both do conventional string searches
(forward and backward respectively)</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><code>C-M-s</code> and <code>C-M-r</code> both do regular expression searches (forward
and backward respectively)</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><code>M-%</code> does a search/replace while <code>C-M-%</code> does a regular
expression search/replace</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h4 id="finding-occurrences-occur-grep">Finding occurrences (occur, grep)</h4>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Use <code>M-x grep</code>, <code>rgrep</code>, <code>occur</code></p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>See also interactive versions with
<a href="http://wikemacs.org/wiki/Helm-swoop">helm-swoop</a>, helm-occur,
<a href="https://github.com/Wilfred/ag.el">ag.el</a>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h2 id="questionsanswers">Questions/Answers</h2>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="emacs-lisp-vs-common-lisp">Emacs Lisp vs Common Lisp</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>It isnt necessary to write Emacs Lisp in order to use Emacs with Slime or Sly for Common Lisp.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>However learning Emacs Lisp can be useful and is similar (but different) from CL:</p>
2023-10-25 11:23:21 +02:00
<ul>
2024-05-15 18:18:38 +02:00
<li>Dynamic scope is everywhere</li>
<li>There are no reader (or reader-related) functions</li>
<li>Does not support all the types that are supported in CL</li>
<li>Incomplete implementation of CLOS (with the add-on EIEIO package)</li>
<li>No numerical tower support</li>
2023-10-25 11:23:21 +02:00
</ul>
2024-05-15 18:18:38 +02:00
<p>Some good Emacs Lisp learning resources:</p>
<ul>
<li><a href="https://www.gnu.org/software/emacs/manual/eintr.html">An Introduction to Programming in Emacs Lisp</a></li>
<li><a href="http://www.oreilly.com/catalog/gnuext/">Writing GNU Emacs Extensions</a></li>
<li><a href="http://wikemacs.org/wiki/Category:Emacs_Lisp">Wikemacs</a></li>
</ul>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="what-about-lsp-language-server-protocol">What about LSP (Language Server Protocol)?</h3>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>LSP server and client ports for Common Lisp exist, but we dont <em>need</em> them to have a high quality IDE integration. In fact, Slime/Swank follow a client/server architecture, like LSP, but Slime predates LSP by decades, and still offers much more features for lispers than LSP.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="utf-8-encoding">utf-8 encoding</h3>
2023-10-25 11:23:21 +02:00
<p>You might want to set this to your init file:</p>
<pre><code class="language-lisp">(set-language-environment "UTF-8")
(setenv "LC_CTYPE" "en_US.UTF-8")
</code></pre>
<p>and for Sly:</p>
2024-01-12 09:23:31 +01:00
<pre><code class="language-lisp">(setf sly-lisp-implementations
'((sbcl ("/usr/local/bin/sbcl") :coding-system utf-8-unix)
))
2023-10-25 11:23:21 +02:00
</code></pre>
<p>This will avoid getting <code>ascii stream decoding error</code>s when you have
non-ascii characters in files you evaluate with SLIME.</p>
2024-05-15 18:18:38 +02:00
<h3 id="default-cutcopypaste-keybindings">Default cut/copy/paste keybindings</h3>
2023-10-25 11:23:21 +02:00
<p><em>I am so used to C-c, C-v and friends to copy and paste text that
the default Emacs shortcuts dont make any sense to me.</em></p>
<p>Luckily, you have a solution! Install <a href="http://www.emacswiki.org/cgi-bin/wiki.pl?CuaMode">cua-mode</a> and you can continue to use these shortcuts.</p>
<pre><code class="language-lisp">;; C-z=Undo, C-c=Copy, C-x=Cut, C-v=Paste (needs cua.el)
(require 'cua) (CUA-mode t)
</code></pre>
2024-05-15 18:18:38 +02:00
<h2 id="appendix">Appendix</h2>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h3 id="all-slime-repl-shortcuts">All Slime REPL shortcuts</h3>
2023-10-25 11:23:21 +02:00
<p>Here is the reference of all Slime shortcuts that work in the REPL.</p>
<p>To see them, go in a REPL, type <code>C-h m</code> and go to the Slime REPL map section.</p>
<pre><code>REPL mode defined in slime-repl.el:
Major mode for interacting with a superior Lisp.
key binding
--- -------
C-c Prefix Command
C-j slime-repl-newline-and-indent
RET slime-repl-return
C-x Prefix Command
ESC Prefix Command
SPC slime-space
(that binding is currently shadowed by another mode)
, slime-handle-repl-shortcut
DEL backward-delete-char-untabify
&lt;C-return&gt; slime-repl-closing-return
2024-05-15 18:18:38 +02:00
&lt;C-down&gt; slime-repl-forward-input
2023-10-25 11:23:21 +02:00
&lt;C-up&gt; slime-repl-backward-input
&lt;return&gt; slime-repl-return
C-x C-e slime-eval-last-expression
C-c C-c slime-interrupt
C-c C-n slime-repl-next-prompt
C-c C-o slime-repl-clear-output
C-c C-p slime-repl-previous-prompt
C-c C-s slime-complete-form
C-c C-u slime-repl-kill-input
C-c C-z other-window
C-c ESC Prefix Command
C-c I slime-repl-inspect
M-RET slime-repl-closing-return
M-n slime-repl-next-input
M-p slime-repl-previous-input
M-r slime-repl-previous-matching-input
M-s previous-line
C-c C-z run-lisp
(that binding is currently shadowed by another mode)
C-M-x lisp-eval-defun
C-M-q indent-sexp
C-M-q prog-indent-sexp
(that binding is currently shadowed by another mode)
C-c M-e macrostep-expand
C-c M-i slime-fuzzy-complete-symbol
C-c M-o slime-repl-clear-buffer
</code></pre>
2024-05-15 18:18:38 +02:00
<h3 id="all-other-slime-shortcuts">All other Slime shortcuts</h3>
<p>There is more to what we showed! Slime has shortcuts to disassemble the function definition of the symbol at point, learn how to navigate the inspector, toggle functions profiling, learn its indentation or completion strategies, use multiple Lisp connections, learn how to <a href="https://slime.common-lisp.dev/doc/html/Presentations.html#Presentations">manipulate presentations</a></p>
2023-10-25 11:23:21 +02:00
<p>Here are all the default keybindings defined by Slime mode.</p>
<p>To see them, go in a .lisp file, type <code>C-h m</code> and go to the Slime section.</p>
<pre><code>Commands to compile the current buffers source file and visually
highlight any resulting compiler notes and warnings:
C-c C-k - Compile and load the current buffers file.
C-c M-k - Compile (but not load) the current buffers file.
C-c C-c - Compile the top-level form at point.
Commands for visiting compiler notes:
M-n - Goto the next form with a compiler note.
M-p - Goto the previous form with a compiler note.
C-c M-c - Remove compiler-note annotations in buffer.
Finding definitions:
M-.
- Edit the definition of the function called at point.
M-,
- Pop the definition stack to go back from a definition.
Documentation commands:
C-c C-d C-d - Describe symbol.
C-c C-d C-a - Apropos search.
C-c M-d - Disassemble a function.
Evaluation commands:
C-M-x - Evaluate top-level from containing point.
C-x C-e - Evaluate sexp before point.
C-c C-p - Evaluate sexp before point, pretty-print result.
Full set of commands:
key binding
--- -------
C-c Prefix Command
C-x Prefix Command
ESC Prefix Command
SPC slime-space
C-c C-c slime-compile-defun
C-c C-j slime-eval-last-expression-in-repl
C-c C-k slime-compile-and-load-file
C-c C-s slime-complete-form
C-c C-y slime-call-defun
C-c ESC Prefix Command
C-c C-] slime-close-all-parens-in-sexp
C-c x slime-export-symbol-at-point
C-c ~ slime-sync-package-and-default-directory
C-M-a slime-beginning-of-defun
C-M-e slime-end-of-defun
M-n slime-next-note
M-p slime-previous-note
C-M-, slime-previous-location
C-M-. slime-next-location
C-c TAB completion-at-point
C-c RET slime-expand-1
C-c C-p slime-pprint-eval-last-expression
C-c C-u slime-undefine-function
C-c ESC Prefix Command
C-c C-b slime-interrupt
C-c C-d slime-doc-map
C-c C-e slime-interactive-eval
C-c C-l slime-load-file
C-c C-r slime-eval-region
C-c C-t slime-toggle-fancy-trace
C-c C-v Prefix Command
C-c C-w slime-who-map
C-c C-x Prefix Command
C-c C-z slime-switch-to-output-buffer
C-c ESC Prefix Command
C-c : slime-interactive-eval
C-c &lt; slime-list-callers
C-c &gt; slime-list-callees
C-c E slime-edit-value
C-c I slime-inspect
C-x C-e slime-eval-last-expression
C-x 4 Prefix Command
C-x 5 Prefix Command
C-M-x slime-eval-defun
M-, slime-pop-find-definition-stack
M-. slime-edit-definition
M-? slime-edit-uses
M-_ slime-edit-uses
C-c M-c slime-remove-notes
C-c M-e macrostep-expand
C-c M-i slime-fuzzy-complete-symbol
C-c M-k slime-compile-file
C-c M-q slime-reindent-defun
C-c M-m slime-macroexpand-all
C-c C-v C-d slime-describe-presentation-at-point
C-c C-v TAB slime-inspect-presentation-at-point
C-c C-v C-n slime-next-presentation
C-c C-v C-p slime-previous-presentation
C-c C-v C-r slime-copy-presentation-at-point-to-repl
C-c C-v C-w slime-copy-presentation-at-point-to-kill-ring
C-c C-v ESC Prefix Command
C-c C-v SPC slime-mark-presentation
C-c C-v d slime-describe-presentation-at-point
C-c C-v i slime-inspect-presentation-at-point
C-c C-v n slime-next-presentation
C-c C-v p slime-previous-presentation
C-c C-v r slime-copy-presentation-at-point-to-repl
C-c C-v w slime-copy-presentation-at-point-to-kill-ring
C-c C-v C-SPC slime-mark-presentation
C-c C-w C-a slime-who-specializes
C-c C-w C-b slime-who-binds
C-c C-w C-c slime-who-calls
C-c C-w RET slime-who-macroexpands
C-c C-w C-r slime-who-references
C-c C-w C-s slime-who-sets
C-c C-w C-w slime-calls-who
C-c C-w a slime-who-specializes
C-c C-w b slime-who-binds
C-c C-w c slime-who-calls
C-c C-w d slime-who-depends-on
C-c C-w m slime-who-macroexpands
C-c C-w r slime-who-references
C-c C-w s slime-who-sets
C-c C-w w slime-calls-who
C-c C-d C-a slime-apropos
C-c C-d C-d slime-describe-symbol
C-c C-d C-f slime-describe-function
C-c C-d C-g common-lisp-hyperspec-glossary-term
C-c C-d C-p slime-apropos-package
C-c C-d C-z slime-apropos-all
C-c C-d # common-lisp-hyperspec-lookup-reader-macro
C-c C-d a slime-apropos
C-c C-d d slime-describe-symbol
C-c C-d f slime-describe-function
C-c C-d g common-lisp-hyperspec-glossary-term
C-c C-d h slime-documentation-lookup
C-c C-d p slime-apropos-package
C-c C-d z slime-apropos-all
C-c C-d ~ common-lisp-hyperspec-format
C-c C-d C-# common-lisp-hyperspec-lookup-reader-macro
C-c C-d C-~ common-lisp-hyperspec-format
C-c C-x c slime-list-connections
C-c C-x n slime-next-connection
C-c C-x p slime-prev-connection
C-c C-x t slime-list-threads
C-c M-d slime-disassemble-symbol
C-c M-p slime-repl-set-package
C-x 5 . slime-edit-definition-other-frame
C-x 4 . slime-edit-definition-other-window
C-c C-v M-o slime-clear-presentations
</code></pre>
2024-05-15 18:18:38 +02:00
<h2 id="see-also">See also</h2>
2023-10-25 11:23:21 +02:00
<ul>
2024-05-15 18:18:38 +02:00
<li><a href="https://slime.common-lisp.dev/doc/html/">SLIMEs documentation</a></li>
<li><strong><a href="https://www.youtube.com/watch?v=sBcPNr1CKKw">Slime video tutorial</a></strong> (and the authors channel, full of great stuff)</li>
<li>Marco Baringers <a href="https://www.youtube.com/watch?v=NUpAvqa5hQw">Slime tutorial</a></li>
<li><a href="https://bnmcgn.github.io/lisp-guide/lisp-exploration.html">Common Lisp REPL exploration guide</a>, a concise and curated set of highlights to find ones way in the REPL.</li>
<li><a href="https://github.com/susam/emacs4cl">Emacs4CL</a>, a tiny DIY kit to set up vanilla Emacs for Common Lisp programming.</li>
<li><a href="https://github.com/mmontone/slime-star">slime-star</a>, a collection of extensions for SLIME:
<ul>
<li>doc contribs: richer slime-help and slime-info buffers to display documentation.</li>
<li>Quicklisp systems: autocompletion to load Quicklisp systems from the REPL.</li>
<li>quicksearch integration: search for Common Lisp repositories on Quicklisp, Github and Cliki.</li>
<li>Slime breakpoints: set breakpoints visually without code annotation, get buttons to step through code.</li>
<li>Quicklisp apropos: “apropos” across Quicklisp libraries.</li>
<li>Slime critic: get the Slime critic gently critique your code.</li>
<li>interactive print and trace buffers</li>
<li>dedicated Emacs buffers for output streams</li>
<li>access to the ANSICL specification in Emacs Info format.</li>
<li>Lisp system browser: a (work in progress) Smalltalk-like system browser for Common Lisp, where one can get different panes to browse available packages and their functions, variables, macros, classes, generic functions.</li>
</ul>
</li>
2023-10-25 11:23:21 +02:00
</ul>
<p class="page-source">
Page source: <a href="https://github.com/LispCookbook/cl-cookbook/blob/master/emacs-ide.md">emacs-ide.md</a>
</p>
</div>
<script type="text/javascript">
// Don't write the TOC on the index.
if (window.location.pathname != "/cl-cookbook/") {
$("#toc").toc({
content: "#content", // will ignore the first h1 with the site+page title.
headings: "h1,h2,h3,h4"});
}
$("#two-cols + ul").css({
"column-count": "2",
});
$("#contributors + ul").css({
"column-count": "4",
});
</script>
<div>
<footer class="footer">
<hr/>
&copy; 2002&ndash;2023 the Common Lisp Cookbook Project
<div>
2024-05-15 18:18:38 +02:00
📹 Discover <a style="color: darkgrey; text-decoration: underline", href="https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358">our contributor's Common Lisp video course on Udemy</a>
2023-10-25 11:23:21 +02:00
</div>
</footer>
</div>
<div id="toc-btn">T<br>O<br>C</div>
</div>
<script text="javascript">
HighlightLisp.highlight_auto({className: null});
</script>
<script type="text/javascript">
function duckSearch() {
var searchField = document.getElementById("searchField");
if (searchField && searchField.value) {
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
window.location.href = "https://duckduckgo.com/?kj=b2&kf=-1&ko=1&q=" + query;
// https://duckduckgo.com/params
// kj=b2: blue header in results page
// kf=-1: no favicons
}
}
</script>
<script async defer data-domain="lispcookbook.github.io/cl-cookbook" src="https://plausible.io/js/plausible.js"></script>
</body>
</html>