conf-emacs/elpa/nix-mode-1.5.0/nix.el

368 lines
12 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; nix.el -- run nix commands in Emacs -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;; To use this just run:
;; M-x RET nix-shell RET
;; This will give you some
;;; Code:
(require 'pcomplete)
(require 'json)
(eval-when-compile
(require 'let-alist))
(defgroup nix nil
"Nix-related customizations."
:group 'languages)
(defcustom nix-executable "nix"
"Nix executable location."
:group 'nix
:type 'string)
(defcustom nix-build-executable "nix-build"
"Nix-build executable location."
:group 'nix
:type 'string)
(defcustom nix-instantiate-executable "nix-instantiate"
"Nix-instantiate executable location."
:group 'nix
:type 'string)
(defcustom nix-store-executable "nix-store"
"Nix-store executable location."
:group 'nix
:type 'string)
(defcustom nix-shell-executable "nix-shell"
"Location of nix-shell executable."
:group 'nix
:type 'string)
(defcustom nix-store-dir "/nix/store"
"Nix store directory."
:group 'nix
:type 'directory)
(defcustom nix-state-dir "/nix/var"
"Nix state directory."
:group 'nix
:type 'directory)
(defun nix-system ()
"Get the current system tuple."
(nix--process-string "eval"
"--raw"
(if (nix-is-24) "--impure" )
(if (nix-is-24) "--expr" )
"(builtins.currentSystem)"))
(defvar nix-version nil)
(defun nix-version ()
"Get the version of Nix."
(or nix-version (nix--process-string "--version")))
(defun nix-show-config ()
"Show nix config."
(nix--process-json "show-config" "--json"))
(defconst nix-commands
'("add-to-store"
"build"
"cat-nar"
"cat-store"
"copy"
"copy-sigs"
"dump-path"
"edit"
"eval"
"hash-file"
"hash-path"
"log"
"ls-nar"
"ls-store"
"optimise-store"
"path-info"
"ping-store"
"repl"
"run"
"search"
"show-config"
"show-derivation"
"sign-paths"
"to-base16"
"to-base32"
"to-base64"
"upgrade-nix"
"verify"
"why-depends"))
(defconst nix-toplevel-options
'("-v"
"--verbose"
"-h"
"--help"
"--debug"
"--help-config"
"--option"
"--version"))
(defconst nix-config-options
'("allowed-uris"
"allow-import-from-derivation"
"allow-new-priveleges"
"allowed-users"
"auto-optimise-store"
"builders"
"builders-use-substitutes"
"build-users-group"
"compress-build-log"
"connect-timeout"
"cores"
"extra-sandbox-paths"
"extra-substituters"
"fallback"
"fsync-metadata"
"hashed-mirrors"
"http-connections"
"keep-build-log"
"keep-derivations"
"keep-env-derivations"
"keep-outputs"
"max-build-log-size"
"max-jobs"
"max-silent-time"
"netrc-file"
"plugin-files"
"pre-build-hook"
"repeat"
"require-sigs"
"restrict-eval"
"sandbox"
"sandbox-dev-shm-size"
"sandbox-paths"
"secret-key-files"
"show-trace"
"substitute"
"substituters"
"system"
"timeout"
"trusted-public-keys"
"trusted-subtituters"
"trusted-users"))
(defun nix--pcomplete-flags (options)
"Complete flags to the Nix command.
OPTIONS a list of options to accept."
(while (pcomplete-match "^-" 0)
(pcomplete-here options)
(let ((last-arg (nth (1- pcomplete-index) pcomplete-args)))
(cond
((string= "--option" last-arg)
(pcomplete-here nix-config-options)
(pcomplete-here))
((or (string= "-f" last-arg) (string= "--file" last-arg))
(pcomplete-here (pcomplete-entries nil 'file-exists-p)))
((or (string= "--arg" last-arg) (string= "--argstr" last-arg))
(pcomplete-here)
(pcomplete-here))
((or (string= "-I" last-arg) (string= "--include" last-arg))
(pcomplete-here (pcomplete-entries nil 'file-exists-p)))
((or (string= "-k" last-arg) (string= "--keep" last-arg))
(pcomplete-here))
((or (string= "-u" last-arg) (string= "--unset" last-arg))
(pcomplete-here))
((or (string= "-s" last-arg) (string= "--substituter" last-arg))
(pcomplete-here))))))
(defun nix-is-24 ()
"Whether Nix is a version with Flakes support."
(let ((version (nix-version)))
(save-match-data
(when (string-match (rx bol "nix (Nix) " (group (+ digit) (? "." (+ digit))))
version)
(version<= "2.4" (match-string 1 version))))))
(defun nix-has-flakes ()
"Whether Nix is a version with Flakes support."
;; earlier versions reported as 3, now its just nix-2.4
(and (nix-is-24)
(let-alist (nix-show-config)
(or
(seq-contains-p .experimental-features.value 2)
(seq-contains-p .experimental-features.value "flakes")))))
;;;###autoload
(defun pcomplete/nix ()
"Completion for the nix command."
(if (nix-is-24)
(let ((stdout (generate-new-buffer "nix-completions"))
(process-environment
(cons (format "NIX_GET_COMPLETIONS=%s" (1- (length pcomplete-args)))
process-environment))
result)
(apply 'call-process nix-executable nil (list stdout nil) nil
(cdr pcomplete-args))
(with-current-buffer stdout (setq result (buffer-string)))
(kill-buffer stdout)
(let ((lines (split-string result "\n"))
completions)
(dolist (val (cdr lines))
(unless (string= val "")
(setq completions (cons (car (split-string val "\t")) completions))))
(dolist (val (cddr pcomplete-args))
(pcomplete-here))
(pcomplete-here completions nil t)))
(progn
(nix--pcomplete-flags nix-toplevel-options)
(pcomplete-here nix-commands)
(pcase (nth (1- pcomplete-index) pcomplete-args)
("run"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr" "-c" "--command"
"-f" "--file" "-i" "-I" "--include"
"-k" "--keep" "-u" "--unset"))))
("build"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr" "--dry-run"
"-f" "--file" "-I" "--include"
"--no-link" "-o" "--out-link"))))
("add-to-store"
(nix--pcomplete-flags
(append nix-toplevel-options '("--dry-run" "-n" "--name"))))
("copy"
(nix--pcomplete-flags
(append nix-toplevel-options '("--all" "--arg" "--argstr"
"-f" "--file" "--from"
"-I" "--include" "--no-check-sigs"
"--no-recursive" "-s" "--substitute"
"--to"))))
("copy-sigs"
(nix--pcomplete-flags
(append nix-toplevel-options '("--all" "--arg" "--argstr"
"-f" "--file" "-I" "--include"
"-r" "--recursive" "-s" "--substituter"))))
("dump-path"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr"
"-f" "--file" "-I" "--include"))))
("edit"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr"
"-f" "--file" "-I" "--include"))))
("eval"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr"
"-f" "--file" "-I" "--include"
"--json" "--raw"))))
("hash-file"
(nix--pcomplete-flags
(append nix-toplevel-options '("--base16" "--base32"
"--base64" "--type"))))
("hash-path"
(nix--pcomplete-flags
(append nix-toplevel-options '("--base16" "--base32"
"--base64" "--type"))))
("log"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr"
"-f" "--file" "-I" "--include"
"--json" "--raw"))))
("ls-nar"
(nix--pcomplete-flags
(append nix-toplevel-options '("-d" "--directory"
"--json" "-l" "--long"
"-R" "--recursive"))))
("ls-store"
(nix--pcomplete-flags
(append nix-toplevel-options '("-d" "--directory"
"--json" "-l" "--long"
"-R" "--recursive"))))
("repl"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr"
"-I" "--include"))))
("search"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr"
"-f" "--file"
"-I" "--include"
"--json" "--no-cache"
"-u" "--update-cache"))))
("show-config"
(nix--pcomplete-flags
(append nix-toplevel-options '("--json"))))
("show-derivation"
(nix--pcomplete-flags
(append nix-toplevel-options '("--arg" "--argstr"
"-f" "--file"
"-I" "--include"
"-r" "--recursive"))))
("sign-paths"
(nix--pcomplete-flags
(append nix-toplevel-options '("--all" "--arg" "--argstr"
"-f" "--file" "-I" "--include"
"-k" "--key-file" "-r" "--recursive"))))
("upgrade-nix"
(nix--pcomplete-flags
(append nix-toplevel-options '("-p" "--profile"))))
("verify"
(nix--pcomplete-flags
(append nix-toplevel-options '("--all" "--arg" "--argstr"
"-f" "--file" "-I" "--include"
"--no-contents" "--no-trust"
"-r" "--recursive" "-n" "--sigs-needed"
"-s" "--substuter"))))
("why-depends"
(nix--pcomplete-flags
(append nix-toplevel-options '("-a" "--all" "--arg" "--argstr"
"-f" "--file" "-I" "--include"))))
(_ (nix--pcomplete-flags nix-toplevel-options)))
(pcomplete-here (pcomplete-entries)))))
(defun nix--process (&rest args)
(with-temp-buffer
(let* ((tmpfile (make-temp-file "nix--process-stderr"))
(cleaned-args (seq-filter #'stringp args))
(exitcode (apply #'call-process `(,nix-executable nil (t ,tmpfile) nil ,@cleaned-args )))
(stderr (with-temp-buffer
(insert-file-contents tmpfile)
(buffer-string))))
(delete-file tmpfile)
(list (buffer-string) stderr exitcode))))
(defun nix--process-string (&rest args)
(cl-multiple-value-bind (stdout stderr exitcode) (apply #'nix--process args)
(if (not (eq exitcode 0))
(error stderr))
;; cut-off the trailing newline
(string-trim-right stdout)))
(defun nix--process-json (&rest args)
(json-read-from-string
(apply #'nix--process-string args)))
(defun nix--process-lines (&rest args)
(seq-filter (lambda (el) (not (string= "" el)))
(split-string
(apply #'nix--process-string args) "\n")))
(defun nix--process-json-nocheck (&rest args)
;; No checking of exitcode is possible here until
;; https://github.com/NixOS/nix/issues/2474 is resolved
(let ((result (apply #'nix--process args)))
(json-read-from-string (car result))))
(provide 'nix)
;;; nix.el ends here