-- encoding:utf-8 Mode: POLY-ORG; -- ---
May 28, 2026 ยท View on GitHub
#+Startup: noindent #+PROPERTY: literate-lang lisp #+PROPERTY: literate-load yes #+PROPERTY: literate-insert-header no
[[http://quickdocs.org/literate-lisp/][file:http://quickdocs.org/badge/literate-lisp.svg]] [[https://github.com/jingtaozf/literate-lisp/actions][file:https://github.com/jingtaozf/literate-lisp/workflows/Continous%20Integration/badge.svg]]
- Introduction [[https://github.com/jingtaozf/literate-lisp][literate-lisp]] provides an easy way to use [[http://www.literateprogramming.com/][literal programming]] in Common Lisp language. It extends the Common Lisp [[https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node187.html][reader syntax]] so a Common Lisp vendor can read Org files as Common Lisp source files.
By using this package ([[https://github.com/jingtaozf/literate-lisp][literate-lisp]]), Emacs [[https://orgmode.org/][Org mode]], and Emacs Lisp library [[https://polymode.github.io/][polymode]], literate programming can be very easy, with one Org file containing both documentation and source code, and this Org file can interact well with [[https://common-lisp.net/project/slime/][SLIME]].
The implementation detail of [[https://github.com/jingtaozf/literate-lisp][literate-lisp]] is in file [[./literate-lisp.org]] ([[./literate-lisp.pdf][pdf version]]).
This library contains the following files:
- [[./literate-lisp.org]] \ The implementation and documentation of literate lisp reader.
- [[./lisp]] \ This directory contains the tangled code of literate lisp reader, generated from [[./literate-lisp.org]]
- [[./literate-lisp.pdf]] \ The weaved documentation, generated from [[./literate-lisp.org]] by Org mode's [[https://orgmode.org/manual/Triggering-publication.html#Triggering-publication][publish feature]].
- [[./readme.org]] \ This file contains introduction and demo code for how to do literate lisp in an Org file.
- [[./puzzle.org]] \ This file contains a puzzle solver to show how to do literate lisp in an Org file.
- [[./.github/workflows/continuous-integration.yml][continuous-integration.yml]] \ The config file used by Web service [[https://github.com/jingtaozf/literate-lisp/actions][GitHub actions]] to test this library.
- [[./literate-lisp.asd]] \ The ASDF definition for literate-lisp project.
- [[./literate-demo.asd]] \ The ASDF definition for literate demo project.
- Tutorial ** The restriction to the Org file The Org file should start with a comment character and a space character("# "), to drive lisp reader into Org syntax. Actually it can be a convenient way for us to specify some local variables, for example I often put them in the first line of an Org file: #+BEGIN_SRC org
-- encoding:utf-8 Mode: POLY-ORG; -- ---
#+END_SRC Which make Emacs open file with utf-8 encoding and [[https://github.com/polymode/poly-org][poly-org-mode]]. ** Installing polymode in Emacs It's better to edit the Org file with [[https://polymode.github.io/][polymode]], which will make code block use its native file mode. The following Emacs Lisp scripts in .emacs will install it. #+BEGIN_SRC elisp (use-package poly-org :ensure t) #+END_SRC ** How to insert code block quickly Please have a look of the section [[https://github.com/jingtaozf/literate-elisp/blob/master/literate-elisp.org#how-to-insert-code-block-in-org-file][How to insert code block in Org file]] in library [[https://github.com/jingtaozf/literate-elisp][literate-elisp]].
Please note that =literate-lisp= now support parsing Org property values ([[https://orgmode.org/manual/Property-Syntax.html][property syntax]]), so there is no need to insert =:load no= in header argument now, you can set them as Org properties.
To disable insertion of unnecessary header argument,
you can set Org property =literate-insert-header= to =no=.
** The load code block header argument
Please have a look of the section [[./literate-lisp.org#new-defined-header-argument-load][new defined header argument load]] in [[./literate-lisp.org]].
** Reference named blocks as global parameters
If a [[https://orgmode.org/manual/Blocks.html][block]] has a named for it, that is, with a =#+NAME:= before it like this:
#+begin_example
,#+NAME: js-demo-code
,#+BEGIN_SRC js
document.getElementById("demo").innerHTML = "Hello JavaScript";
,#+END_SRC
#+end_example
Then after loading, a global parameter =js-demo-code= will contain the string in above block.
It is more friendly than write this string in lisp directly, because =org-mode= can provide syntax for it and =poly-mode= can even enable us edit this code block in =js-mode=.
You can visit these named blocks by Emacs Lisp function [[https://orgmode.org/worg/orgcard.html#org11fbe72][org-babel-goto-named-src-block]], or by hacking [[https://github.com/joaotavora/sly][sly]] like this: #+BEGIN_SRC elisp :load no (defun sly-edit-definition-of-named-block (&optional name method) (when (string-prefix-p "#+END_" (string-trim (buffer-substring (line-beginning-position) (line-end-position))) t) (let ((case-fold-search t)) (search-forward-regexp (format "#\+NAME:\s+%s" name)) (forward-line 2) (goto-char (line-beginning-position))))) (eval-after-load "sly" '(advice-add 'sly-edit-definition :after #'sly-edit-definition-of-named-block)) #+END_SRC You can hack [[https://common-lisp.net/project/slime/][slime]] the same way.
NOTE You have to install literate-lisp to active =readtable= in [[https://github.com/joaotavora/sly][sly]] when using SBCL to make above patch work, because
the SBCL backend in =sly= will [[https://github.com/joaotavora/sly/blob/master/slynk/backend/sbcl.lisp#L423][read the source code inside file]] when find definitions.
#+BEGIN_SRC lisp :load no
(literate-lisp:install-globally)
#+END_SRC
** How to debug Org file in LispWorks IDE
You have to add the following code in your .lispworks to enable the debug facility in Lispworks Editor.
#+BEGIN_SRC lisp :load no
(defun check-org-mode (buffer truename)
(when (and truename (equal (pathname-type truename) "org"))
(setf (editor:buffer-major-mode buffer) "Lisp")))
(editor:add-global-hook editor::read-file-hook 'check-org-mode)
#+END_SRC
Thanks for Martin Simmons in [[http://www.lispworks.com/][LispWorks]] to support the above configuration code.
** How to integrate with namded-readtables
You may find that [[https://github.com/melisgl/named-readtables][named-readtables]] is friendly to define the syntax for literate-lisp in your code [[https://github.com/jingtaozf/literate-lisp/issues/12#issuecomment-710256276][like this]]:
#+BEGIN_SRC lisp :load no
(named-readtables:defreadtable literate-lisp
(:merge :standard)
(:dispatch-macro-char ## #\space #'literate-lisp::sharp-space)
(:dispatch-macro-char ## #+ #'literate-lisp::sharp-plus))
#+END_SRC
** How to write user initialization file with literate programming style
You can put all initialization code in an Org source file, all you need is to load literate-lisp firstly.
For example, you can put the following code in file [[http://www.sbcl.org/manual/#Initialization-Files][$HOME/.sbclrc]] for SBCL.
#+BEGIN_SRC lisp :load no
(require :asdf)
#-quicklisp
(let ((quicklisp-init "/quicklisp/setup.lisp")
(quicklisp-install "/quicklisp.lisp"))
(cond ((probe-file quicklisp-init)
(format terminal-io "loading quicklisp...%")
(load quicklisp-init)
(format terminal-io "loading quicklisp...done%"))
((probe-file quicklisp-install)
(load quicklisp-install)
(funcall (intern "INSTALL" :quicklisp-quickstart)))))
(load "/projects/common-lisp/literate-lisp/literate-lisp.asd")
(ql:quickload :literate-lisp)
(literate-lisp:with-literate-syntax
(load "/projects/common-lisp/config/init-lisp.org"))
#+END_SRC
I find it useful for various Lisp vendors so all initialization code for them can be in just one file.
** How to include Org code with ASDF package-inferred-system extension The [[https://common-lisp.net/project/asdf/asdf.html#The-package_002dinferred_002dsystem-extension][ASDF package-inferred-system extension]] is wonderful, in which each file is its own system, and dependencies are deduced from the defpackage form or its variant, uiop:define-package. You can also use literate-lisp to make a package inferred system by writing an ASD definition like this: #+BEGIN_SRC lisp :load no (asdf:defsystem literate-libraries :serial t :defsystem-depends-on (:literate-lisp) :default-component-class :org :class :package-inferred-system) #+END_SRC Here =:class :package-inferred-system= enables the package-inferred-system extension, and =:default-component-class :org= means that ASDF will look for all Org files to find out a system and load it.
For example, you can create an Org file in the same directory of above ASD definition file named as utilities.org and contains the following code #+begin_example
-- encoding:utf-8 Mode: POLY-ORG; -- ---
- Create a package for this package inferred system ,#+BEGIN_SRC lisp (defpackage literate-libraries/utilities (:use :cl) (:import-from :flexi-streams :octet :make-flexi-stream) (:import-from :log4cl :log-config) (:documentation "a utility module.")) ,#+END_SRC
- implementation ... ... #+end_example After loading the above ASD definition file, you can load system literate-libraries/utilities in your REPL. #+BEGIN_SRC lisp :load no (load "/some/path/literate-libraries.asd") (ql:quickload :literate-libraries/utilities) #+END_SRC
Please upgrade to ASDF 3.3.4.5 or later, it is not supported in earlier ASDF versions.
** How to tangle to a bundle of lisp files from one Org file Yes, now you can tangle one Org file to a bundle of lisp files, so to share it to team members with more clear interface.
Please have a look of [[./literate-lisp.org#tangle-to-multiple-files-for-one-org-file][tangle to multiple files for one Org file]] or the usage of Org property =LITERATE_EXPORT_PACKAGE= and =LITERATE_EXPORT_NAME= in file [[./literate-lisp.org]].
** Packages written by literate-lisp
- [[https://github.com/jingtaozf/s-graphviz][s-graphviz]] an S-expression presentation of GraphViz DOT Language ** A demo literate application *** The ASD file We use the original ASD definition file, and extend the ASDF syntax(The documentation of extended ASDF syntax can be found in [[https://github.com/jingtaozf/literate-lisp/blob/master/literate-lsp.org#make-asdf-handle-org-file-correctly][literate-lisp.org]]).
In a short word, we should load literate-lisp by ASDF keyword :defsystem-depends-on and
declare the Org source file with new ASDF keyword :org.
Now let's define the ASDF system file [[./literate-demo.asd]] for this demo package #+BEGIN_SRC elisp :load no (asdf:defsystem literate-demo :author "Xu Jingtao jingtaozf@gmail.com" :version "0.1" :licence "MIT" :serial t :description "a demo project of literate-lisp" :defsystem-depends-on ("literate-lisp") :depends-on (:iterate #+dev :clgplot) :components ((:module :demo :pathname "./" :components ((:org "puzzle") (:org "readme")))) :properties ((version "0.1"))) #+END_SRC Which will load [[./puzzle.org]] and this file directly as a lisp source file.
The whole content of ASDF definition file is in [[./literate-demo.asd]]. *** A demo package for this file #+BEGIN_SRC lisp (defpackage :literate-demo (:use :cl) (:export )) (in-package :literate-demo) #+END_SRC *** Test cases :PROPERTIES: :literate-load: test :END: **** Preparation The [[https://common-lisp.net/project/fiveam/][FiveAM]] library is used to test. #+BEGIN_SRC lisp (eval-when (:compile-toplevel :load-toplevel :execute) (unless (find-package :fiveam) #+quicklisp (ql:quickload :fiveam) #-quicklisp (asdf:load-system :fiveam))) (5am:def-suite literate-demo-suite :description "The test suite of literate-demo.") (5am:in-suite literate-demo-suite) #+END_SRC **** test case for named block Let's define a named code block for some javascript code: #+NAME: js-demo-code-1 #+begin_src js { console.log("Hello"); } #+end_src Then try to read it in our test case #+BEGIN_SRC lisp (5am:test named-block (5am:is (stringp js-demo-code-1)) (5am:is (not (null (position #" js-demo-code-1 :test #'char=))))) #+END_SRC **** run all tests in this library This function is the entry point to run all tests and return true if all test cases pass. #+BEGIN_SRC lisp (defun run-test () (5am:run! 'literate-demo-suite)) #+END_SRC