Code Monkey home page Code Monkey logo

literate-elisp's Introduction

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 https://github.com/jingtaozf/literate-elisp/workflows/Continous%20Integration/badge.svg

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 Emacs Lisp function literate-elisp-load and this function can load Emacs Lisp codes in all Emacs Lisp 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 Emacs Lisp 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 Emacs Lisp 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 Emacs Lisp file(.el).

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

So you will have a perfect literate environment which can write Emacs Lisp codes in an org file, and load it directly without tangling an org file to an Emacs Lisp 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

literate-lisp is available on the two major package.el community maintained repos - MELPA Stable and MELPA. You can install literate-elisp, or more commonly a specific literate-elisp, interactively

M-x package-install [RET] literate-elisp [RET]

Or you can install it from source directly

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

how to insert code block quickly

Please have a look of the section How to insert code block in org file.

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

Source blocks in a literate program can serve a variety of purposes—implementation, examples, testing, and so on—so we define a load Org code block header argument to decide whether to read them or not, which accepts the following values -

  • yes
    The code block should be loaded normally. This is the default 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
    The code block should be ignored by the Emacs Lisp reader.
    #+BEGIN_SRC elisp :load no
    (defun a-function-to-ignore ()
     (message "this function will be ingored by literate-elisp.~%"))
    #+END_SRC
        
  • test
    The code block should be loaded only when the 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
        
  • the name of a variable or function
    The code block is loaded if the value of the variable or the return value of the function is non-nil.

compatibility with other libraries

We have some extension to keep compatibility with other libraries, the following sections show how to setup them.

support for Emacs Lisp-Refs

;; ;; To make `elisp-refs' work with `literate-elisp', we need to add an advice to `elisp-refs--read-all-buffer-forms'.
(eval-after-load "elisp-refs"
  '(advice-add 'elisp-refs--read-all-buffer-forms :around #'literate-elisp-refs--read-all-buffer-forms))

;; To make `elisp-refs' work with `literate-elisp', we need to add an advice to `elisp-refs--loaded-paths'.
(eval-after-load "elisp-refs"
  '(advice-add 'elisp-refs--loaded-paths :filter-return #'literate-elisp-refs--loaded-paths))

support for library helpful

;; To make `helpful' work with `literate-elisp', we need to add an advice to `helpful--find-by-macroexpanding'.
(with-eval-after-load 'helpful
  (advice-add 'helpful--find-by-macroexpanding :around #'literate-elisp-helpful--find-by-macroexpanding))

FAQ

What can I do when it failed to load some file

  • try to use Emacs command check-parens.
  • toggle on the debug mode of literate-elisp
(setf literate-elisp-debug-p t)

Can I use autoload for a Elisp routine in an org file?

Yes you can, just like the original function in a elisp source file.

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 Emacs Lisp 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")

packages written by literate-elisp

  • helm-q Manage remote q sessions with Helm and q-mode

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

literate-elisp's People

Contributors

akater avatar contrapunctus-1 avatar jingtaozf avatar wasamasa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

literate-elisp's Issues

loading with lexical-binding

Hi. I was trying to load a literate org file with lexical-binding
set to t, but the obvious

(let ((lexical-binding t))
  (literate-elisp-load-file "file.org"))

still seems to be evaluating the elisp in file.org with lexical
binding disabled. Is there any way of accomplishing this?

By the way, thanks a lot for this project: it's made me finally
embrace literate programming for elisp in earnest! :)

get-file-char error when calling literate-elisp-byte-compile

I'm getting an error when running literate-elisp-byte-compile-file on the latest master of jabber.el - jabber.org:2290:1:Error: Wrong number of arguments: #<subr get-file-char>, 1.

I don't get a backtrace for this when I enable toggle-debug-on-error, and I have not yet figured out just what is calling get-file-char (this function is not directly called by literate-elisp or bytecomp...).

I have not noticed any issues with calling literate-elisp-load on the same file, however.

I'm running GNU Emacs 27.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.5, cairo version 1.16.0) of 2021-02-10, modified by Debian, and the latest Git master of literate-elisp (commit 6979fc6).

Please add permission statement to elisp library

This allows the tools that I use to maintain the Emacsmirror to extract the license. Alternatively you could add a LICENSE file, but since people who use your package will likely use itself as inspiration I would prefer the former. (While I might be wrong about this I have a feeling they would be more likely to not follow the example of adding such a file than they would be of not following the example of putting the permission statement where it is put by convention when writing the library directly in a source file.

Thanks!

Autoloading

How would one lazy load using literate-elisp? I tried (autoload 'foo "/path/to/foo.org"), but got eval-buffer: Invalid read syntax: #

On a related note, could you please implement a literate-elisp extension for use-package? Perhaps as a new keyword, or ideally transparently detecting an Org file and preferring to load that.

Interop with describe-*/Helpful/xref

I tried using literate-elisp-load to load my init.org. Given a function I've defined in init.org -

  1. describe-function does not print a link to jump to its source in init.org
  2. helpful-function says that this function is 'without a source file', and like #1 does not print a link to the source.
  3. xref-find-definitions says No definitions found for: ...

Can literate-elisp load Org files while maintaining interoperability with the rest of Emacs? If not, can it be extended to do so?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.