Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/talyz/fromelisp

An Emacs Lisp reader in Nix.
https://github.com/talyz/fromelisp

elisp emacs nix nixos

Last synced: 4 months ago
JSON representation

An Emacs Lisp reader in Nix.

Awesome Lists containing this project

README

        

#+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~.