Skip to content

talyz/fromElisp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 

Repository files navigation

fromElisp

An Emacs Lisp reader in Nix. Yes, it’s necessary.

nix-repl> :p fromElisp "(use-package lsp-mode :ensure :commands lsp)"
[ [ "use-package" "lsp-mode" ":ensure" ":commands" "lsp" ] ]

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,

    (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"))
        

    is read as

    [[ "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" ]]]
        
  • 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

    (setq mouse-wheel-scroll-amount '(3 ((shift) . 1)))
        

    would be

    [{ 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; }
                 ];
               }
             ];
           };
         }
       ];
     }]
        
  • 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.

with (import (builtins.fetchGit {
  url = "https://github.com/talyz/fromElisp.git";
  ref = "master";
  # rev = "c13d6035666f36ca940db996f1dbaf83cb4e8453";
}));
# ... code ...

niv

If you use niv to manage your Nix dependencies, simply run

$ niv add talyz/fromElisp

to add fromElisp to your dependencies and import it as follows:

with (import (import ./nix/sources.nix).fromElisp {});
# ... code ...

Git submodule

If you plan on contributing to fromElisp and want to do it from your own source, you can import it as a 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 Emacs overlay to implement the functionality of emacsWithPackagesFromUsePackage.