fromElisp
fromElisp copied to clipboard
An Emacs Lisp reader in Nix.
#+TITLE: fromElisp
An Emacs Lisp reader in Nix. Yes, it's /necessary/.
#+begin_example nix-repl> :p fromElisp "(use-package lsp-mode :ensure :commands lsp)" [ [ "use-package" "lsp-mode" ":ensure" ":commands" "lsp" ] ] #+end_example
-
Functionality
~fromElisp~ provides four main functions: ~fromElisp~, ~parseElisp~, ~fromOrgModeBabelElisp~ and ~parseOrgModeBabelElisp~.
-
fromElisp /elisp/ (string)
Takes a string argument and tries to convert the Elisp read from it to the closest equivalent data type in Nix.
For example, #+begin_src emacs-lisp :tangle yes (use-package highlight-symbol :ensure t :hook (((python-mode emacs-lisp-mode nix-mode) . highlight-symbol-mode) ((python-mode emacs-lisp-mode nix-mode) . highlight-symbol-nav-mode)) :config (highlight-symbol-nav-mode) (setq highlight-symbol-idle-delay 0.5) (set-face-attribute 'highlight-symbol-face nil :background "dark cyan")) #+end_src is read as #+begin_src nix :tangle yes [[ "use-package" "highlight-symbol" ":ensure" true ":hook" [[[ "python-mode" "emacs-lisp-mode" "nix-mode" ] "highlight-symbol-mode" ] [[ "python-mode" "emacs-lisp-mode" "nix-mode" ] "highlight-symbol-nav-mode" ]] ":config" [ "highlight-symbol-nav-mode" ] [ "setq" "highlight-symbol-idle-delay" 0.5 ] [ "set-face-attribute" [ "quote" "highlight-symbol-face" ] [ ] ":background" "dark cyan" ]]] #+end_src
-
parseElisp /elisp/ (string)
Takes a string argument and provides an AST with additional structural info, such as object type, line number and list depth.
The AST provided for the code #+begin_src emacs-lisp :tangle yes (setq mouse-wheel-scroll-amount '(3 ((shift) . 1))) #+end_src would be #+begin_src nix :tangle yes [{ depth = 0; line = 1; type = "list"; value = [ { line = 1; type = "symbol"; value = "setq"; } { line = 1; type = "symbol"; value = "mouse-wheel-scroll-amount"; } { line = 1; type = "quote"; value = { depth = 1; line = 1; type = "list"; value = [ { line = 1; type = "integer"; value = 3; } { depth = 2; line = 1; type = "list"; value = [ { depth = 3; line = 1; type = "list"; value = [ { line = 1; type = "symbol"; value = "shift"; } ]; } { line = 1; type = "integer"; value = 1; } ]; } ]; }; } ]; }] #+end_src
-
fromOrgModeBabelElisp /text/ (string)
~fromElisp~, but for Org mode babel files. Runs ~fromElisp~ on the result of tangling all Elisp code blocks with ~:tangle yes~ set. Tangling is done internally, not by Org mode.
-
parseOrgModeBabelElisp /text/ (string)
~parseElisp~, but for Org mode babel files. Runs ~parseElisp~ on the result of tangling all Elisp code blocks with ~:tangle yes~ set. Tangling is done internally, not by Org mode.
-
*** Other functions
- *tokenizeElisp* /elisp/ (string)
Takes a string argument and produces a list of tokens from the
Elisp read from it. Used internally by ~fromElisp~ and ~parseElisp~.
- *tokenizeElisp'* /args/ (attrs)
An alternate version of ~tokenizeElisp~ allowing the specification
of the starting line number.
/args/ is an attribute set with the following attributes:
- /elisp/ (string, required)
The string of Elisp to tokenize.
- /startLineNumber/ (int, optional)
The line number to use for the first line of /elisp/. Useful if
/elisp/ is a block of code from a larger file and you want line
numbers to be correct.
- *parseElisp'* /tokens/ (list)
An alternate version of ~parseElisp~ which takes as its argument a
list of tokens produced by ~tokenizeElisp~.
- *fromElisp'* /ast/ (list)
An alternate version of ~fromElisp~ which takes as its argument an
AST produced by ~parseElisp~.
- *tokenizeOrgModeBabelElisp* /text/ (string)
Run tokenizeElisp' on all Elisp code blocks (with ~:tangle yes~
set) from Org mode babel text /text/.
- *tokenizeOrgModeBabelElisp'* /defaultArgs/ (attrs) /text/ (string)
An alternate version of ~tokenizeOrgModeBabelElisp~ which allows
the specification of default arguments for Org babel
headers. Currently only ~:tangle~ is supported.
- *parseOrgBabelElisp'* /defaultArgs/ (attrs) /text/ (string)
An alternate version of ~parseOrgBabelElisp~ which allows
the specification of default arguments for Org babel
headers. Currently only ~:tangle~ is supported.
- *fromOrgBabelElisp'* /defaultArgs/ (attrs) /text/ (string)
An alternate version of ~fromOrgModeBabelElisp~ which allows
the specification of default arguments for Org babel
headers. Currently only ~:tangle~ is supported.
-
Usage
You can use ~fromElisp~ in your code in multiple ways.
*** fetchGit
You can use ~fetchGit~ without a ~rev~ attribute to try it out quickly
and then add the ~rev~ when you want reproducibility.
#+begin_src nix :tangle yes
with (import (builtins.fetchGit {
url = "https://github.com/talyz/fromElisp.git";
ref = "master";
# rev = "c13d6035666f36ca940db996f1dbaf83cb4e8453";
}));
# ... code ...
#+end_src
*** niv
If you use [[https://github.com/nmattia/niv][niv]] to manage your Nix dependencies, simply run
#+begin_src shell :tangle yes
$ niv add talyz/fromElisp
#+end_src
to add ~fromElisp~ to your dependencies and import it as follows:
#+begin_src nix :tangle yes
with (import (import ./nix/sources.nix).fromElisp {});
# ... code ...
#+end_src
*** Git submodule
If you plan on contributing to ~fromElisp~ and want to do it from
your own source, you can import it as a [[https://git-scm.com/book/en/v2/Git-Tools-Submodules][Git submodule]].
-
Limitations
-
No Unicode support
Nix doesn't support Unicode, so we can't either.
-
No evaluation
This is a /reader/ and not an /evaluator/. You can make some pretty reasonable assumptions from the structure of the code, though: it's, for example, used in the [[https://github.com/nix-community/emacs-overlay][Emacs overlay]] to implement the functionality of ~emacsWithPackagesFromUsePackage~.
-