Skip to content
a literate programming tool to load Emacs Lisp codes from org mode file directly
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitignore
.travis.yml
literate-elisp.el
literate-elisp.org
literate-elisp.pdf
readme.org

readme.org

https://melpa.org/packages/literate-elisp-badge.svg https://stable.melpa.org/packages/literate-elisp-badge.svg https://travis-ci.com/jingtaozf/literate-elisp.svg?branch=master

Table of Contents

Introduction

literate-elisp is an Emacs lisp library to provide an easy way to use literal programming in Emacs lisp.

It extends the Emacs load mechanism so Emacs can load org files as lisp source files directly.

The implementation details of literate-elisp is in file ./literate-elisp.org (pdf version).

This library export an elisp function literate-elisp-load and this function can load elisp codes in all elisp code blocks surrounded by #+begin_src elisp and #+end_src in an org file directly.

For example, if you have an org file and it contains such elisp code block:

#+BEGIN_SRC elisp :load yes
(defun test ()
 (message "this is a test from org file.~%"))
#+END_SRC

Then you can load this org file like this:

(load "~/projects/literate-elisp/literate-elisp.el")
(literate-elisp-load "test.org")

Now the elisp function test is ready to use, and you can jump to the definition of test in the org file by using Emacs library find-func directly without tangling them to an elisp file(.el).

You can also open an org file by polymode when edit,which will switch elisp code block to Emacs elisp mode.

So you will have a perfect literate environment which can write elisp codes in an org file, and load it directly without tangling an org file to an elisp file. Emacs lisp’s source code editing and navigation feature work well to this org file.

This library contains the following files:

Tutorial

install Polymode in Emacs

The org file can open as polymode,the following Emacs lisp scripts should add in .emacs

(use-package poly-org
    :ensure t)

install literate-elisp.el

(load "~/projects/literate-elisp/literate-elisp.el")

load an org file

To load an org file, we can use Emacs interactive command literate-elisp-load.

For example, This org file can load directly with the following code.

(literate-elisp-load "readme.org")

If you want to load an org file with a Emacs command, please press “Alt-X” and type literate-elisp-load-file.

If you want to load an org file in batch mode, please use function literate-elisp-batch-load.

byte compile an org file

To byte compile an org file to an elc file, we can use Emacs interactive command literate-elisp-byte-compile-file. For example, This org file can be compiled with the following code.

(literate-elisp-byte-compile-file "readme.org")

Now the target file readme.org.elc is ready to use.

a new code block header argument load

There are a lot of different elisp codes occur in one org file, some for function implementation, some for demo, and some for test, so an org code block header argument load to decide to read them or not should define,and it has two meanings:

  • yes
    It means that current code block should load normally, it is the default mode when the header argument load is not provided.
    #+BEGIN_SRC elisp :load yes
    (defun a-function-to-load ()
     (message "this function will be loaded by literate-elisp.~%"))
    #+END_SRC
        
  • no
    It means that current code block should ignore by elisp reader.
    #+BEGIN_SRC elisp :load no
    (defun a-function-to-ignore ()
     (message "this function will be ingored by literate-elisp.~%"))
    #+END_SRC
        
  • test
    It means that current code block should load only when variable literate-elisp-test-p is true.
    #+BEGIN_SRC elisp :load test
    (defun a-function-to-test ()
     (message "this function will be loaded by literate-elisp only if literate-elisp-test-p is true.~%"))
    #+END_SRC
        

demo routines

a demo macro

As a demo org file, we write a simple demo macro aif here.

Sometimes we want to use the expression value of if condition form when it yields non-nil. That’s the purpose of aif which will bind variable it to the value of if condition form.

We will use some common lisp macros, so let’s load this library now.

(require 'cl)

Let’s implement if-bind firstly, which can bind the value of if condition form to any specified variable..

(defmacro if-bind (var test &rest then/else)
  "Anaphoric IF control structure.

VAR (a symbol) will be bound to the primary value of TEST. If
TEST returns a true value then THEN will be executed, otherwise
ELSE will be executed."
  (cl-assert (car then/else)
             (then/else)
             "IF-BIND missing THEN clause.")
  (cl-destructuring-bind (then &optional else)
      then/else
    `(lexical-let ((,var ,test))
       (if ,var ,then ,else))))

Now aif is easy to finish.

(defmacro aif (test then &optional else)
    "Just like IF-BIND but the var is always IT."
    `(if-bind it ,test ,then ,else))

You can use it like this

(aif (and (y-or-n-p "Try it")
            10)
    (message "it is %s" it))

After loading this org file by function literate-elisp-load, you can use macro aif directly in your other elisp files.

a demo Emacs configuration

Of course the one purpose of this library is to write Emacs configuration directly in an org file.
Here we give a demo configuration and the way to load such org config file.

a demo configuration

enable org mode for org files

(add-to-list 'auto-mode-alist '("\\.\\(org\\|org_archive\\)$" . org-mode))  

load this org file in .emacs

Then to load routines and configurations in this org file, I add the following codes in my .emacs

(load "~/projects/literate-elisp/literate-elisp.el")
(literate-elisp-load "~/projects/literate-elisp/readme.org")

Test

Introduction

We use ERT library to define and run tests. Web service travis ci will load config file ./.travis.yml to run these tests automatically every time there is a new git change.

test macro aif

(ert-deftest literate-demo-aif ()
  "A spec of macro aif."
  (should (equal (aif 10 it 9) 10)))

test org mode configuration

(ert-deftest literate-demo-org-mode ()
  "A spec of macro aif."
  (should (equal (cl-loop for (x . y) in auto-mode-alist
                          if (eq y 'org-mode)
                          return x)
                 "\\.\\(org\\|org_archive\\)$")))

Copyright and license

Code and documentation copyright 2018-2019 Jingtao Xu.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

You can’t perform that action at this time.