Add elpa packages

This commit is contained in:
nemunaire 2026-01-24 09:39:42 +08:00
commit afd61b5209
197 changed files with 76816 additions and 0 deletions

View file

@ -0,0 +1,33 @@
;;; nix-build.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:
;;; Code:
(require 'nix)
(require 'nix-search)
;;;###autoload
(defun nix-build (&optional file attr)
"Run nix-build in a compilation buffer.
FILE the file to parse.
ATTR the attribute to build."
(interactive (list (nix-read-file) nil))
(unless attr (setq attr (nix-read-attr file)))
(setq compile-command (format "%s %s -A '%s'" nix-build-executable
file attr))
(setq-default compilation-directory default-directory)
(compilation-start compile-command nil
(apply-partially (lambda (attr _)
(format "*nix-build*<%s>" attr))
attr)))
(provide 'nix-build)
;;; nix-build.el ends here

View file

@ -0,0 +1,50 @@
;;; nix-drv-mode.el --- Major mode for viewing .drv files
;; Maintainer: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix, languages, tools, unix
;; Package-Requires: ((emacs "24.3"))
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;; A major mode for viewing Nix derivations (.drv files). See the Nix
;; manual for more information available at
;; https://nixos.org/nix/manual/.
;;; Code:
(require 'js)
(require 'nix)
;;;###autoload
(define-derived-mode nix-drv-mode js-mode "Nix-Derivation"
"Pretty print Nixs .drv files."
(let ((inhibit-read-only t))
(erase-buffer)
(insert (shell-command-to-string
(format "%s show-derivation \"%s\""
nix-executable
(buffer-file-name))))
(set-buffer-modified-p nil)
(read-only-mode 1))
(add-hook 'change-major-mode-hook #'nix-drv-mode-dejsonify-buffer nil t))
(defun nix-drv-mode-dejsonify-buffer ()
"Restore nix-drv-mode when switching to another mode."
(remove-hook 'change-major-mode-hook #'nix-drv-mode-dejsonify-buffer t)
(let ((inhibit-read-only t))
(erase-buffer)
(insert-file-contents (buffer-file-name))
(set-buffer-modified-p nil)
(read-only-mode nil)))
;;;###autoload
(add-to-list 'auto-mode-alist '("^/nix/store/.+\\.drv\\'" . nix-drv-mode))
(provide 'nix-drv-mode)
;;; nix-drv-mode.el ends here

View file

@ -0,0 +1,39 @@
;;; nix-edit.el --- Run nix commands -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix
;; Package-Requires: ((emacs "24.3"))
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;;; Code:
(require 'nix)
(require 'nix-search)
;;;###autoload
(defun nix-edit (&optional file attr)
"Open the nix log.
FILE the nix file to load from.
ATTR the attribute to find in nix expressions."
(interactive (list (nix-read-file) nil))
(unless attr (setq attr (nix-read-attr file)))
(let ((stdout (generate-new-buffer "nix-edit"))
(process-environment (cons "EDITOR=echo" process-environment))
result)
(call-process nix-executable nil (list stdout nil) nil
"edit" "-f" file attr)
(with-current-buffer stdout
(when (eq (buffer-size) 0)
(error
"Error: nix edit failed to produce any output"))
(setq result (substring (buffer-string) 0 (- (buffer-size) 1))))
(kill-buffer stdout)
(find-file result)))
(provide 'nix-edit)
;;; nix-edit.el ends here

View file

@ -0,0 +1,575 @@
;;; nix-flake.el --- Transient interface to Nix flake commands -*- lexical-binding: t -*-
;; Keywords: nix, languages, tools, unix
;; Package-Requires: ((emacs "27.1") (transient "0.3"))
;; Homepage: https://github.com/NixOS/nix-mode
;;; Commentary:
;; This library provides transient interface to experimental commands in Nix.
;; See the Nix manual for more information available at
;; https://nixos.org/manual/nix/unstable/command-ref/experimental-commands.html
;;; Code:
(require 'nix)
(require 'transient)
(defgroup nix-flake nil
"Nix flake commands."
:group 'nix)
;;;; Custom variables
(defcustom nix-flake-init-post-action 'open-flake-nix
"Action to run after successfully initializing a flake.
This action is run after a flake is successfully initialized by
`nix-flake-init` (or generally `nix-flake-dispatch`).
You can also specify a function, which should take no arguments.
It is called in the directory of the flake."
:type '(choice (const :tag "Open flake.nix" open-flake-nix)
(const :tag "Do nothing" nil)
(function :tag "User-defined function")))
(defcustom nix-flake-add-to-registry t
"Whether to add a new flake to registry.
When this variable is non-nil, every flake reference from the
interactive input is added to the flake registry, unless it is
already registered in either the user or the global registry."
:type 'boolean)
;;;; Transient classes
;;;;; flake-ref
(defclass nix-flake-ref-variable (transient-variable)
((constant-value :initarg :constant-value :initform nil)
(on-change :initarg :on-change)
(reader :initarg :reader :initform nil)))
(cl-defmethod transient-init-value ((_obj nix-flake-ref-variable))
"Set the initial value of the object.")
(cl-defmethod transient-infix-read ((obj nix-flake-ref-variable))
"Determine the new value of the infix object OBJ."
(if-let (value (oref obj constant-value))
(if (symbolp value)
(symbol-value value)
value)
(if-let (reader (oref obj reader))
(funcall reader "Flake directory: " (oref obj value))
(nix-flake--read-flake-ref nil (oref obj value)))))
(cl-defmethod transient-infix-set ((obj nix-flake-ref-variable) value)
"Set the value of infix object OBJ to VALUE."
(oset obj value value)
(when-let (func (oref obj on-change))
(funcall func value)))
(cl-defmethod transient-format-value ((_obj nix-flake-ref-variable))
"Format the object's value for display and return the result."
;; Don't show the value
"")
;;;; Utility functions
(defun nix-flake--to-list (x)
"If X is not a list, make a singleton list containing it."
(if (listp x)
x
(list x)))
;;;; Registry
;; Maybe we'll move these functions to a separate library named nix-registry.el.
(defun nix-flake--registry-list ()
"Return a list of entries from the registry."
(cl-flet
((split-entry
(s)
(split-string s "[[:space:]]+")))
(thread-last (nix--process-lines "registry" "list")
(mapcar #'split-entry))))
(defun nix-flake--registry-refs ()
"Return a list of flake refs in the registry."
(thread-last (nix-flake--registry-list)
;; I don't know if I should include flakes in the
;; system registry. It's ugly to display full
;; checksums, so I won't include them for now.
(cl-remove-if-not (pcase-lambda (`(,type . ,_))
(member type '("user" "global"))))
(mapcar (lambda (cells)
;; Both references and referees are included in the output.
;; It may be better to pick only one and show others as
;; decoration, e.g. using marginalia, but it is not supported
;; for now.
(list (nth 1 cells)
(nth 2 cells))))
(flatten-list)))
(defun nix-flake--registry-add-1 (flake-ref)
"Add FLAKE-REF to the registry with a new name."
(let ((name (read-string (format-message "Enter the registry name for %s: "
flake-ref))))
(unless (or (not name)
(string-empty-p name))
(start-process "nix registry add" "*nix registry add*"
nix-executable
"registry" "add" name flake-ref))))
;; This argument complies the standard reader interface of transient
;; just in case, but it may not be necessary.
(defun nix-flake--read-flake-ref (&optional prompt initial-input history)
"Select a flake from the registry.
For PROMPT, INITIAL-INPUT, and HISTORY, see the documentation of
readers in transient.el."
(let* ((registered-flakes (nix-flake--registry-refs))
(input (string-trim
(completing-read (or prompt "Flake URL: ")
registered-flakes
nil nil nil history initial-input))))
(prog1 input
(when (and nix-flake-add-to-registry
(not (member input registered-flakes)))
(nix-flake--registry-add-1 input)))))
;;;; nix-flake command
;;;;; Variables
(defvar nix-flake-ref nil)
;;;;; Setting the flake
(transient-define-infix nix-flake:from-registry ()
:class 'nix-flake-ref-variable
:on-change
(lambda (flake-ref)
(nix-flake--set-flake flake-ref :remote t)
(transient-update))
:description "Select a flake from the registry")
(transient-define-infix nix-flake:flake-directory ()
:class 'nix-flake-ref-variable
:reader 'nix-flake--read-directory
:on-change
(lambda (flake-ref)
(nix-flake--set-flake flake-ref)
(transient-update))
:description "Select a directory")
(defun nix-flake--read-directory (prompt &optional initial-input _history)
"Select a directory containing a flake.
For PROMPT and INITIAL-INPUT, see the documentation of transient.el."
(let ((input (string-remove-suffix "/" (read-directory-name prompt initial-input nil t))))
(prog1 (expand-file-name input)
(unless (file-exists-p (expand-file-name "flake.nix" input))
(user-error "The selected directory does not contain flake.nix"))
(when (and nix-flake-add-to-registry
(not (member (concat "path:" input)
(nix-flake--registry-refs))))
(nix-flake--registry-add-1 input)))))
;;;;; --update-input
(defclass nix-flake--update-input-class (transient-option)
())
(transient-define-infix nix-flake-arg:update-input ()
:class 'nix-flake--update-input-class
:argument "--update-input"
:reader 'nix-flake--read-input-path
:prompt "Input: "
:description "Update a specific flake path")
(cl-defmethod transient-format-value ((obj nix-flake--update-input-class))
"Format --update-input arguments from OBJ."
(let ((value (oref obj value)))
(propertize (concat (oref obj argument)
(when value
(concat " " value)))
'face (if value
'transient-value
'transient-inactive-value))))
(cl-defmethod transient-infix-value ((obj nix-flake--update-input-class))
"Return the value of the suffix object OBJ."
(when-let ((value (oref obj value)))
(list (oref obj argument) value)))
(defun nix-flake--input-names ()
"Return a list of inputs to the flake."
(thread-last (nix--process-json "flake" "info" nix-flake-ref "--json")
(alist-get 'locks)
(alist-get 'nodes)
(alist-get 'root)
(alist-get 'inputs)
(mapcar #'cdr)))
(defun nix-flake--read-input-path (prompt initial-input _history)
"Read an input name of a flake from the user.
For PROMPT and INITIAL-INPUT, see the documentation of :reader in
transient.el."
(completing-read prompt (nix-flake--input-names)
nil nil initial-input))
;;;;; Attribute names
(defvar nix-flake-outputs nil)
(defun nix-flake-system-attribute-names (types)
"Return a list of output attributes of particular TYPES."
(let ((system (intern (nix-system))))
(thread-last nix-flake-outputs
(mapcar (pcase-lambda (`(,type . ,alist))
(when (memq type types)
(mapcar #'car (alist-get system alist)))))
(apply #'append)
(cl-remove-duplicates)
(mapcar #'symbol-name))))
(defun nix-flake--run-attribute-names ()
"Return possible attribute names for run command."
(nix-flake-system-attribute-names '(apps packages)))
(defun nix-flake--build-attribute-names ()
"Return possible attribute names for build command."
(nix-flake-system-attribute-names '(packages)))
(defun nix-flake--default-run-p ()
"Return non-nil if there is the default derivation for run command."
(not (null (nix-flake-system-attribute-names '(defaultApp defaultPackage)))))
(defun nix-flake--default-build-p ()
"Return non-nil if there is the default derivation for build command."
(not (null (nix-flake-system-attribute-names '(defaultPackage)))))
;;;;; Building command lines
(defun nix-flake--options ()
"Return a list of options for `nix-flake-dispatch'."
(flatten-list (transient-args 'nix-flake-dispatch)))
(defun nix-flake--command (subcommand options flake-ref)
"Build a command line for a Nix subcommand.
SUBCOMMAND is a string or a list of strings which is a subcommand of Nix.
OPTIONS is a list of options appended after FLAKE-REF.
COMMAND-ARGUMENTS is extra arguments to the
command after the flake reference."
(concat nix-executable
" "
(mapconcat #'shell-quote-argument
`(,@(nix-flake--to-list subcommand)
,flake-ref
,@options)
" ")))
(defun nix-flake--installable-command (subcommand options flake-ref attribute
&optional extra-arguments)
"Build a command line for a Nix subcommand.
This is like `nix-flake--command', but for a subcommand which
takes an installable as an argument. See the user manual of Nix
for what installable means.
SUBCOMMAND, OPTIONS, and FLAKE-REF are the same as in the
function. ATTRIBUTE is the name of a package, app, or anything
that refers to a derivation in the flake. It must be a string
that is concatenated with the sharp symbol in the installable
reference.
EXTRA-ARGUMENTS is a list of strings passed to the Nix command
after \"--\". Note that some commands such as \"nix build\" do
not take the extra arguments."
(concat nix-executable
" "
(mapconcat #'shell-quote-argument
`(,@(nix-flake--to-list subcommand)
,(if attribute
(concat flake-ref "#" attribute)
flake-ref)
,@options)
" ")
(if extra-arguments
(concat " -- " extra-arguments)
"")))
;;;;; Individual subcommands
(defun nix-flake-run-attribute (options flake-ref attribute command-args)
"Run an app in the current flake.
OPTIONS and FLAKE-REF are the same as in other Nix commands.
ATTRIBUTE is the name of a package or app in the flake, and
COMMAND-ARGS is an optional list of strings passed to the
application."
(interactive (list (nix-flake--options)
nix-flake-ref
(completing-read "Nix app/package: "
(nix-flake--run-attribute-names))
nil))
(compile (nix-flake--installable-command "run" options flake-ref attribute
command-args)))
(defun nix-flake-run-default (options flake-ref command-args)
"Run the default app or package in the current flake.
For OPTIONS, FLAKE-REF, and COMMAND-ARGS, see the documentation of
`nix-flake-run-attribute'."
(interactive (list (nix-flake--options)
nix-flake-ref
nil))
(compile (nix-flake--installable-command "run" options flake-ref nil
command-args)))
(defun nix-flake-build-attribute (options flake-ref attribute)
"Build a derivation in the current flake.
For OPTIONS, FLAKE-REF, and ATTRIBUTE, see the documentation of
`nix-flake-run-attribute'."
(interactive (list (nix-flake--options)
nix-flake-ref
(completing-read "Nix package: "
(nix-flake--build-attribute-names))))
(compile (nix-flake--installable-command "build" options flake-ref attribute)))
(defun nix-flake-build-default (options flake-ref)
"Build the default package in the current flake.
For OPTIONS and FLAKE-REF, see the documentation of
`nix-flake-run-attribute'."
(interactive (list (nix-flake--options)
nix-flake-ref))
(compile (nix-flake--installable-command "build" options flake-ref nil)))
(defun nix-flake-check (options flake-ref)
"Check the flake.
For OPTIONS and FLAKE-REF, see the documentation of
`nix-flake-run-attribute'."
(interactive (list (nix-flake--options) nix-flake-ref))
(compile (nix-flake--command '("flake" "check") options flake-ref)))
(defun nix-flake-lock (options flake-ref)
"Create missing lock file entries.
For OPTIONS and FLAKE-REF, see the documentation of
`nix-flake-run-attribute'."
(interactive (list (nix-flake--options) nix-flake-ref))
(compile (nix-flake--command '("flake" "lock") options flake-ref)))
(defun nix-flake-update (options flake-ref)
"Update the lock file.
For OPTIONS and FLAKE-REF, see the documentation of
`nix-flake-run-attribute'."
(interactive (list (nix-flake--options) nix-flake-ref))
(compile (nix-flake--command '("flake" "update") options flake-ref)))
;;;###autoload (autoload 'nix-flake-dispatch "nix-flake" nil t)
(transient-define-prefix nix-flake-dispatch (flake-ref &optional remote)
"Run a command on a Nix flake."
:value '("--print-build-logs")
[:description
nix-flake--description
("=r" nix-flake:from-registry)
("=d" nix-flake:flake-directory)]
["Arguments"
("-i" "Allow access to mutable paths and repositories" "--impure")
("-ui" nix-flake-arg:update-input)
("-nu" "Do not allow any updates to the flake's lock file" "--no-update-lock-file")
("-cl" "Commit changes to the flake's lock file" "--commit-lock-file")
("-L" "Print build logs" "--print-build-logs")]
["Installable commands"
("r" "Run attribute" nix-flake-run-attribute)
("R" "Run default" nix-flake-run-default :if nix-flake--default-run-p)
("b" "Build attribute" nix-flake-build-attribute)
("B" "Build default" nix-flake-build-default :if nix-flake--default-build-p)]
["Flake commands"
("c" "flake check" nix-flake-check)
("l" "flake lock" nix-flake-lock)
("u" "flake update" nix-flake-update)]
(interactive (list (convert-standard-filename default-directory)))
(nix-flake--set-flake flake-ref :remote remote)
(transient-setup 'nix-flake-dispatch))
(cl-defun nix-flake--set-flake (flake-ref &key remote)
"Set the flake of the transient interface.
FLAKE-REF and REMOTE should be passed down from `nix-flake-dispatch'."
(setq nix-flake-ref flake-ref)
(setq nix-flake-outputs
(if remote
(nix--process-json "flake" "show" "--json" nix-flake-ref)
(let ((default-directory flake-ref))
(nix--process-json "flake" "show" "--json")))))
(defun nix-flake--description ()
"Describe the current flake."
(concat "Flake: " nix-flake-ref))
;; A wrapper function for ensuring existence of flake.nix and flake.lock
;; in the project directory.
;;;###autoload
(cl-defun nix-flake (dir &key flake-ref)
"Dispatch a transient interface for Nix commands.
DIR is a directory on the file system in which flake.nix resides.
Alternatively, you can specify FLAKE-REF which follows the syntax
of flake-url. It can refer to a remote url, a local file path, or
whatever supported by Nix."
(interactive (pcase current-prefix-arg
('(4) (list nil :flake-ref (nix-flake--read-flake-ref)))
('(16) (if nix-flake-ref
(list nil :flake-ref nix-flake-ref)
(user-error "Last flake is unavailable")))
(_ (list default-directory))))
(cl-assert (or (and (stringp dir) (file-directory-p dir))
flake-ref)
nil
"DIR or FLAKE-REF must be specified")
(cond
(flake-ref
(nix-flake-dispatch flake-ref t))
((file-exists-p (expand-file-name "flake.lock" dir))
(nix-flake-dispatch (nix-flake--directory-ref dir)))
((file-exists-p (expand-file-name "flake.nix" dir))
(message "You have not created flake.lock yet, so creating it...")
(let ((default-directory dir))
(nix-flake--command '("flake" "lock") nil
(nix-flake--directory-ref dir))))
(t
(nix-flake-init-dispatch))))
(defun nix-flake--directory-ref (dir)
"Return the flake ref for a local DIR."
(expand-file-name dir))
;;;; nix flake init
;;;;; Setting the template repository
(defvar nix-flake-template-repository nil
"Flake reference to the current template sets.")
(defvar nix-flake-template-name nil
"Attribute name of the last used template.")
(defun nix-flake--init-source ()
"Describe the current template repository for init command."
(format "Template repository: %s" nix-flake-template-repository))
(transient-define-infix nix-flake-init:from-registry ()
:class 'nix-flake-ref-variable
:variable 'nix-flake-template-repository
:description "Select from the registry")
(transient-define-infix nix-flake-init:default-templates ()
:class 'nix-flake-ref-variable
:variable 'nix-flake-template-repository
:constant-value "flake:templates"
:description "Use the default template set")
;;;;; Running the command
(defun nix-flake--init (flake-ref template-name)
"Initialize a flake from a template.
FLAKE-REF must be a reference to a flake which contains the
template, TEMPLATE-NAME is the name of the template."
;; Save the selection state for later use.
(setq nix-flake-template-repository flake-ref
nix-flake-template-name template-name)
(let ((proc (start-process "nix flake init"
"*nix flake init*"
nix-executable
"flake"
"init"
"-t"
(concat flake-ref "#" template-name))))
(set-process-sentinel proc
(lambda (process _event)
(when (eq 'exit (process-status process))
(if (= 0 (process-exit-status process))
(nix-flake-init-post-action)
(message "Returned non-zero from nix flake init")))))
proc))
(defun nix-flake-init-post-action ()
"Perform an post-process action depending on the configuration.
See `nix-flake-init-post-action' variable for details."
(pcase nix-flake-init-post-action
('open-flake-nix
(find-file "flake.nix"))
((pred functionp)
(funcall nix-flake-init-post-action))))
;;;;; Selecting a template
(defun nix-flake--templates (flake-ref)
"Return a list of templates in FLAKE-REF."
(thread-last (nix--process-json "flake" "show" "--json" flake-ref)
(alist-get 'templates)
(mapcar #'car)
(mapcar #'symbol-name)))
;; It might be better to use `transient-define-suffix', but I don't know for
;; sure.
(defun nix-flake-init-select-template ()
"Select a template and initialize a flake."
(interactive)
(let* ((flake-ref (or nix-flake-template-repository
(nix-flake--read-flake-ref "Template repository: ")))
(template-name (completing-read
(format-message "Select a template from %s: " flake-ref)
(nix-flake--templates flake-ref))))
(nix-flake--init flake-ref template-name)))
;;;;; The transient interface
;;;###autoload (autoload 'nix-flake-init "nix-flake" nil t)
(transient-define-prefix nix-flake-init-dispatch (&optional flake-ref)
"Scaffold a project from a template."
[:description "Initialize a flake"]
[:description
nix-flake--init-source
("=r" nix-flake-init:from-registry)
("=d" nix-flake-init:default-templates)]
["Initialize a flake"
("t" "Select template" nix-flake-init-select-template)]
(interactive (list nil))
(when flake-ref
(setq nix-flake-template-repository flake-ref))
(transient-setup 'nix-flake-init-dispatch))
;;;###autoload
(defun nix-flake-init ()
"Run \"nix flake init\" command via a transient interface."
(interactive)
(let* ((root (locate-dominating-file default-directory ".git"))
(default-directory
(if (and root
(not (file-equal-p root default-directory))
(yes-or-no-p (format-message
"The directory %s is not the repository root. Change to %s?"
default-directory root)))
root
default-directory)))
(if (file-exists-p "flake.nix")
(user-error "The directory already contains a flake")
(nix-flake-init-dispatch))))
(provide 'nix-flake)
;;; nix-flake.el ends here

View file

@ -0,0 +1,55 @@
;;; nix-format.el --- Nix formatter -*- lexical-binding: t -*-
;; This file is NOT part of GNU Emacs.
;; Homepage: https://github.com/NixOS/nix-mode
;; Package-Requires: ((emacs "24.1"))
;;; Commentary:
;;; Code:
(defcustom nix-nixfmt-bin "nixfmt"
"Path to nixfmt executable."
:group 'nix
:type 'string)
(if (fboundp 'replace-buffer-contents)
(defun nix--replace-buffer-contents (src dst)
(with-current-buffer dst (replace-buffer-contents src)))
(defun nix--replace-buffer-contents (src dst)
(if (not (string= (with-current-buffer src (buffer-string))
(with-current-buffer dst (buffer-string))))
(with-current-buffer src
(copy-to-buffer dst (point-min) (point-max))))))
(defun nix--format-call (buf nixfmt-bin)
"Format BUF using nixfmt."
(with-current-buffer (get-buffer-create "*nixfmt*")
(erase-buffer)
(insert-buffer-substring buf)
(if (zerop (call-process-region (point-min) (point-max) nixfmt-bin t t nil))
(nix--replace-buffer-contents (current-buffer) buf)
(error "Nixfmt failed, see *nixfmt* buffer for details"))))
(defun nix--find-nixfmt ()
"Find the nixfmt binary, or error if it's missing."
(let ((nixfmt-bin (executable-find nix-nixfmt-bin)))
(unless nixfmt-bin
(error "Could not locate executable %S" nix-nixfmt-bin))
nixfmt-bin))
(defun nix-format-buffer ()
"Format the current buffer using nixfmt."
(interactive)
(nix--format-call (current-buffer) (nix--find-nixfmt))
(message "Formatted buffer with nixfmt."))
;;;###autoload
(defun nix-format-before-save ()
"Add this to `before-save-hook' to run nixfmt when saving."
(when (derived-mode-p 'nix-mode)
(nix-format-buffer)))
(provide 'nix-format)
;;; nix-format.el ends here

View file

@ -0,0 +1,95 @@
;;; nix-instantiate.el --- Run nix commands -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Package-Requires: ((emacs "25.1"))
;; Keywords: nix
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;;; Code:
(require 'nix)
(require 'json)
(defun nix-instantiate--parsed (drv)
"Get the parsed version of the .drv file.
DRV file to load from."
(cdar
(nix--process-json "show-derivation" drv)))
(defun nix-instantiate (nix-file &optional attribute parse)
"Run nix-instantiate on a Nix expression.
NIX-FILE the file to instantiate.
ATTRIBUTE an attribute of the Nix file to use.
PARSE whether to parse nix-instantiate output."
(interactive (list (read-file-name "Nix file: ") nil t))
(let ((stdout (generate-new-buffer "nix-instantiate"))
result)
(if attribute
(call-process nix-instantiate-executable nil (list stdout nil) nil
nix-file "-A" attribute)
(call-process nix-instantiate-executable nil (list stdout nil) nil
nix-file))
(with-current-buffer stdout
(when (eq (buffer-size) 0)
(error
"Error: nix-instantiate %s failed to produce any output"
nix-file))
(setq result (substring (buffer-string) 0 (- (buffer-size) 1)))
(when parse
(setq result (nix-instantiate--parsed result))))
(kill-buffer stdout)
result))
(defvar nix-instantiate--running-processes nil)
(defun nix-instantiate--sentinel (prop err proc event)
"Make a nix-instantiate process.
PROP the prop name of nix-instantiate--running-processes.
ERR the error buffer.
PROC the process that has been run.
EVENT the event that was fired."
(when (string= event "finished\n")
(with-current-buffer (process-buffer proc)
(unless (eq (buffer-size) 0)
(let ((drv (nix-instantiate--parsed
(substring (buffer-string) 0 (- (buffer-size) 1)))))
(dolist
(callback (lax-plist-get nix-instantiate--running-processes prop))
(funcall callback drv)))))
(setq nix-instantiate--running-processes
(lax-plist-put nix-instantiate--running-processes prop nil)))
(unless (process-live-p proc)
(kill-buffer (process-buffer proc))
(kill-buffer err)))
(defun nix-instantiate-async (callback nix-file &optional attribute)
"Run nix-instantiate on a Nix expression, asynchronously.
CALLBACK the function to call when instantiate completes.
NIX-FILE the file to instantiate
ATTRIBUTE an attribute of the Nix file to use."
(setq nix-file (expand-file-name nix-file))
(let* ((prop (if attribute
(expand-file-name attribute nix-file) nix-file))
(data (lax-plist-get nix-instantiate--running-processes prop))
(stdout (generate-new-buffer "nix-instantiate"))
(stderr (generate-new-buffer "nix-instantiate error")))
(setq nix-instantiate--running-processes
(lax-plist-put nix-instantiate--running-processes
prop (cons callback data)))
(make-process
:name "nix-instantiate"
:buffer stdout
:command (append (list nix-instantiate-executable nix-file)
(when attribute (list "-A" attribute)))
:noquery t
:sentinel (apply-partially 'nix-instantiate--sentinel prop stderr)
:stderr stderr)))
(provide 'nix-instantiate)
;;; nix-instantiate.el ends here

View file

@ -0,0 +1,41 @@
;;; nix-log.el --- Run nix commands -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Package-Requires: ((emacs "24.1"))
;; Keywords: nix
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;;; Code:
(require 'nix)
(require 'nix-instantiate)
(require 'files)
(defun nix-log-path (drv-file)
"Get the nix log of path a derivation"
(let* ((drv-name (file-relative-name drv-file nix-store-dir))
(log-file (format "%s/log/nix/drvs/%s/%s.bz2"
nix-state-dir
(substring drv-name 0 2) (substring drv-name 2))))
(if (file-exists-p log-file) log-file
(error "No log is available for derivation"))))
;;;###autoload
(defun nix-log (file attr)
"Open the nix log.
FILE nix file to parse.
ATTR attribute to load the log of."
(interactive (list (nix-read-file) nil))
(unless attr (setq attr (nix-read-attr file)))
(let* ((drv-file (nix-instantiate file attr))
(log-file (nix-log-path drv-file)))
(find-file log-file)))
(provide 'nix-log)
;;; nix-log.el ends here

View file

@ -0,0 +1,285 @@
;;; nix-mode-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code:
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
;;; Generated autoloads from nix.el
(autoload 'pcomplete/nix "nix" "\
Completion for the nix command.")
(register-definition-prefixes "nix" '("nix-"))
;;; Generated autoloads from nix-build.el
(autoload 'nix-build "nix-build" "\
Run nix-build in a compilation buffer.
FILE the file to parse.
ATTR the attribute to build.
(fn &optional FILE ATTR)" t)
;;; Generated autoloads from nix-drv-mode.el
(autoload 'nix-drv-mode "nix-drv-mode" "\
Pretty print Nixs .drv files.
(fn)" t)
(add-to-list 'auto-mode-alist '("^/nix/store/.+\\.drv\\'" . nix-drv-mode))
(register-definition-prefixes "nix-drv-mode" '("nix-drv-mode-dejsonify-buffer"))
;;; Generated autoloads from nix-edit.el
(autoload 'nix-edit "nix-edit" "\
Open the nix log.
FILE the nix file to load from.
ATTR the attribute to find in nix expressions.
(fn &optional FILE ATTR)" t)
;;; Generated autoloads from nix-flake.el
(autoload 'nix-flake-dispatch "nix-flake" nil t)
(autoload 'nix-flake "nix-flake" "\
Dispatch a transient interface for Nix commands.
DIR is a directory on the file system in which flake.nix resides.
Alternatively, you can specify FLAKE-REF which follows the syntax
of flake-url. It can refer to a remote url, a local file path, or
whatever supported by Nix.
(fn DIR &key FLAKE-REF)" t)
(autoload 'nix-flake-init "nix-flake" nil t)
(autoload 'nix-flake-init "nix-flake" "\
Run \"nix flake init\" command via a transient interface." t)
(register-definition-prefixes "nix-flake" '("nix-flake-"))
;;; Generated autoloads from nix-format.el
(autoload 'nix-format-before-save "nix-format" "\
Add this to `before-save-hook' to run nixfmt when saving.")
(register-definition-prefixes "nix-format" '("nix-"))
;;; Generated autoloads from nix-instantiate.el
(register-definition-prefixes "nix-instantiate" '("nix-instantiate"))
;;; Generated autoloads from nix-log.el
(autoload 'nix-log "nix-log" "\
Open the nix log.
FILE nix file to parse.
ATTR attribute to load the log of.
(fn FILE ATTR)" t)
(register-definition-prefixes "nix-log" '("nix-log-path"))
;;; Generated autoloads from nix-mode.el
(autoload 'nix-mode-format "nix-mode" "\
Format the entire `nix-mode' buffer." t)
(autoload 'nix-indent-line "nix-mode" "\
Indent current line in a Nix expression." t)
(autoload 'nix-indent-region "nix-mode" "\
Indent on a whole region. Enabled by default.
START where to start in region.
END where to end the region.
(fn START END)" t)
(autoload 'nix-mode-ffap-nixpkgs-path "nix-mode" "\
Support `ffap' for <nixpkgs> declarations.
If STR contains brackets, call `nix-instantiate' to find the
location of STR. If `nix-instantiate' has a nonzero exit code,
dont do anything
(fn STR)")
(autoload 'nix-mode "nix-mode" "\
Major mode for editing Nix expressions.
The following commands may be useful:
'\\[newline-and-indent]'
Insert a newline and move the cursor to align with the previous
non-empty line.
'\\[fill-paragraph]'
Refill a paragraph so that all lines are at most `fill-column'
lines long. This should do the right thing for comments beginning
with `#'. However, this command doesn't work properly yet if the
comment is adjacent to code (i.e., no intervening empty lines).
In that case, select the text to be refilled and use
`\\[fill-region]' instead.
The hook `nix-mode-hook' is run when Nix mode is started.
\\{nix-mode-map}
(fn)" t)
(add-to-list 'auto-mode-alist '("\\.nix\\'" . nix-mode))
(register-definition-prefixes "nix-mode" '("nix-"))
;;; Generated autoloads from nix-prettify-mode.el
(autoload 'nix-prettify-mode "nix-prettify-mode" "\
Toggle Nix Prettify mode.
With a prefix argument ARG, enable Nix Prettify mode if ARG is
positive, and disable it otherwise. If called from Lisp, enable
the mode if ARG is omitted or nil.
When Nix Prettify mode is enabled, hash-parts of the Nix store
file names (see `nix-prettify-regexp') are prettified,
i.e. displayed as `nix-prettify-char' character. This mode can
be enabled programmatically using hooks:
(add-hook 'shell-mode-hook 'nix-prettify-mode)
It is possible to enable the mode in any buffer, however not any
buffer's highlighting may survive after adding new elements to
`font-lock-keywords' (see `nix-prettify-special-modes' for
details).
Also you can use `global-nix-prettify-mode' to enable Nix
Prettify mode for all modes that support font-locking.
(fn &optional ARG)" t)
(put 'nix-prettify-global-mode 'globalized-minor-mode t)
(defvar nix-prettify-global-mode nil "\
Non-nil if Nix-Prettify-Global mode is enabled.
See the `nix-prettify-global-mode' command
for a description of this minor mode.
Setting this variable directly does not take effect;
either customize it (see the info node `Easy Customization')
or call the function `nix-prettify-global-mode'.")
(custom-autoload 'nix-prettify-global-mode "nix-prettify-mode" nil)
(autoload 'nix-prettify-global-mode "nix-prettify-mode" "\
Toggle Nix-Prettify mode in all buffers.
With prefix ARG, enable Nix-Prettify-Global mode if ARG is positive;
otherwise, disable it.
If called from Lisp, toggle the mode if ARG is `toggle'.
Enable the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.
Nix-Prettify mode is enabled in all buffers where
`nix-prettify-turn-on' would do it.
See `nix-prettify-mode' for more information on Nix-Prettify mode.
(fn &optional ARG)" t)
(define-obsolete-function-alias 'global-nix-prettify-mode 'nix-prettify-global-mode "v1.2.2")
(register-definition-prefixes "nix-prettify-mode" '("nix-prettify-"))
;;; Generated autoloads from nix-repl.el
(autoload 'nix-repl "nix-repl" "\
Load the Nix-REPL." t)
(autoload 'nix-repl-completion-at-point "nix-repl" "\
Completion at point function for Nix using \"nix-repl\".
See `completion-at-point-functions'.")
(register-definition-prefixes "nix-repl" '("nix-"))
;;; Generated autoloads from nix-search.el
(autoload 'nix-search--search "nix-search" "\
(fn SEARCH FILE &optional NO-CACHE USE-FLAKES)")
(autoload 'nix-search--display "nix-search" "\
(fn RESULTS &optional DISPLAY-BUFFER USE-FLAKES SEARCH FILE)")
(autoload 'nix-search "nix-search" "\
Run nix search.
SEARCH a search term to use.
FILE a Nix expression to search in.
(fn SEARCH &optional FILE DISPLAY-BUFFER)" t)
(register-definition-prefixes "nix-search" '("nix-search-"))
;;; Generated autoloads from nix-shebang.el
(register-definition-prefixes "nix-shebang" '("nix-shebang-"))
;;; Generated autoloads from nix-shell.el
(autoload 'nix-shell-unpack "nix-shell" "\
Run Nixs unpackPhase.
FILE is the file to unpack from.
ATTR is the attribute to unpack.
(fn FILE ATTR)" t)
(autoload 'nix-shell-configure "nix-shell" "\
Run Nixs configurePhase.
FILE is the file to configure from.
ATTR is the attribute to configure.
(fn FILE ATTR)" t)
(autoload 'nix-shell-build "nix-shell" "\
Run Nixs buildPhase.
FILE is the file to build from.
ATTR is the attribute to build.
(fn FILE ATTR)" t)
(autoload 'nix-eshell-with-packages "nix-shell" "\
Create an Eshell buffer that has the shell environment in it.
PACKAGES a list of packages to pull in.
PKGS-FILE a file to use to get the packages.
(fn PACKAGES &optional PKGS-FILE)")
(autoload 'nix-eshell "nix-shell" "\
Create an Eshell buffer that has the shell environment in it.
FILE the .nix expression to create a shell for.
ATTR attribute to instantiate in NIX-FILE.
(fn FILE &optional ATTR)" t)
(autoload 'nix-shell-with-string "nix-shell" "\
A nix-shell emulator in Emacs from a string.
STRING the nix expression to use.
(fn STRING)")
(autoload 'nix-shell "nix-shell" "\
A nix-shell emulator in Emacs.
FILE the file to instantiate.
ATTR an attribute of the Nix file to use.
(fn FILE &optional ATTR)" t)
(register-definition-prefixes "nix-shell" '("nix-"))
;;; Generated autoloads from nix-store.el
(register-definition-prefixes "nix-store" '("nix-"))
;;; End of scraped data
(provide 'nix-mode-autoloads)
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End:
;;; nix-mode-autoloads.el ends here

View file

@ -0,0 +1,11 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "nix-mode" "1.5.0"
"Major mode for editing .nix files."
'((emacs "25.1")
(magit-section "0")
(transient "0.3"))
:url "https://github.com/NixOS/nix-mode"
:commit "54e5626829168e22126b233e079f04dff3c71b90"
:revdesc "54e562682916"
:keywords '("nix" "languages" "tools" "unix")
:maintainers '(("Matthew Bauer" . "mjbauer95@gmail.com")))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,181 @@
;;; nix-prettify-mode.el --- Prettify Nix store file names -*- lexical-binding: t -*-
;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
;; Modified by Matthew Bauer for use in nix-mode
;; Author: Alex Kost
;; Maintainer: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix
;; Package-Requires: ((emacs "24.3"))
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;; This package provides minor-mode for prettifying Nix store file
;; names — i.e., after enabling `nix-prettify-mode',
;; '/nix/store/72f54nfp6g1hz873w8z3gfcah0h4nl9p-foo-0.1' names will be
;; replaced with '/nix/store/…-foo-0.1' in the current buffer. There is
;; also `global-nix-prettify-mode' for global prettifying.
;; To install, add the following to your Emacs init file:
;;
;; (add-to-list 'load-path "/path/to/dir-with-nix-prettify")
;; (autoload 'nix-prettify-mode "nix-prettify" nil t)
;; (autoload 'global-nix-prettify-mode "nix-prettify" nil t)
;; If you want to enable/disable composition after "M-x font-lock-mode",
;; use the following setting:
;;
;; (setq font-lock-extra-managed-props
;; (cons 'composition font-lock-extra-managed-props))
;; Credits:
;;
;; Thanks to Ludovic Courtès for the idea of this package.
;;
;; Thanks to the authors of `prettify-symbols-mode' (part of Emacs 24.4)
;; and "pretty-symbols.el" <http://github.com/drothlis/pretty-symbols>
;; for the code. It helped to write this package.
;;; Code:
(defgroup nix-prettify nil
"Prettify Nix store file names."
:prefix "nix-prettify-"
:group 'nix
:group 'font-lock
:group 'convenience)
(defcustom nix-prettify-char ?…
"Character used for prettifying."
:type 'character
:group 'nix-prettify)
(defcustom nix-prettify-regexp
;; The following file names / URLs should be abbreviated:
;; /nix/store/…-foo-0.1
;; http://hydra.nixos.org/nar/…-foo-0.1
;; http://hydra.nixos.org/log/…-foo-0.1
(rx "/" (or "store" "nar" "log") "/"
;; Hash-parts do not include "e", "o", "u" and "t". See base32Chars
;; at <https://github.com/NixOS/nix/blob/master/src/libutil/hash.cc>
(group (= 32 (any "0-9" "a-d" "f-n" "p-s" "v-z"))))
"Regexp matching file names for prettifying.
Disable `nix-prettify-mode' before modifying this variable and
make sure to modify `nix-prettify-regexp-group' if needed.
Example of a \"deeper\" prettifying:
(setq nix-prettify-regexp \"store/[[:alnum:]]\\\\\\={32\\\\}\"
nix-prettify-regexp-group 0)
This will transform
'/nix/store/72f54nfp6g1hz873w8z3gfcah0h4nl9p-foo-0.1' into
'/nix/-foo-0.1'"
:type 'regexp
:group 'nix-prettify)
(defcustom nix-prettify-regexp-group 1
"Regexp group in `nix-prettify-regexp' for prettifying."
:type 'integer
:group 'nix-prettify)
(defvar nix-prettify-special-modes
'(nix-info-mode ibuffer-mode)
"List of special modes that support font-locking.
By default, \\[global-nix-prettify-mode] enables prettifying in
all buffers except the ones where `font-lock-defaults' is
nil (see Info node `(elisp) Font Lock Basics'), because it may
break the existing highlighting.
Modes from this list and all derived modes are exceptions
\(`global-nix-prettify-mode' enables prettifying there).")
(defvar nix-prettify-flush-function
(cond ((fboundp 'font-lock-flush) #'font-lock-flush)
((fboundp 'jit-lock-refontify) #'jit-lock-refontify))
"Function used to refontify buffer.
This function is called without arguments after
enabling/disabling `nix-prettify-mode'. If nil, do nothing.")
(defun nix-prettify-compose ()
"Compose matching region in the current buffer."
(let ((beg (match-beginning nix-prettify-regexp-group))
(end (match-end nix-prettify-regexp-group)))
(compose-region beg end nix-prettify-char 'decompose-region))
;; Return nil because we're not adding any face property.
nil)
(defun nix-prettify-decompose-buffer ()
"Remove file names compositions from the current buffer."
(with-silent-modifications
(let ((inhibit-read-only t))
(remove-text-properties (point-min)
(point-max)
'(composition nil)))))
;;;###autoload
(define-minor-mode nix-prettify-mode
"Toggle Nix Prettify mode.
With a prefix argument ARG, enable Nix Prettify mode if ARG is
positive, and disable it otherwise. If called from Lisp, enable
the mode if ARG is omitted or nil.
When Nix Prettify mode is enabled, hash-parts of the Nix store
file names (see `nix-prettify-regexp') are prettified,
i.e. displayed as `nix-prettify-char' character. This mode can
be enabled programmatically using hooks:
(add-hook 'shell-mode-hook 'nix-prettify-mode)
It is possible to enable the mode in any buffer, however not any
buffer's highlighting may survive after adding new elements to
`font-lock-keywords' (see `nix-prettify-special-modes' for
details).
Also you can use `global-nix-prettify-mode' to enable Nix
Prettify mode for all modes that support font-locking."
:init-value nil
:lighter ""
(let ((keywords `((,nix-prettify-regexp
(,nix-prettify-regexp-group
(nix-prettify-compose))))))
(if nix-prettify-mode
;; Turn on.
(font-lock-add-keywords nil keywords)
;; Turn off.
(font-lock-remove-keywords nil keywords)
(nix-prettify-decompose-buffer))
(and nix-prettify-flush-function
(funcall nix-prettify-flush-function))))
(defun nix-prettify-supported-p ()
"Return non-nil, if the mode can be harmlessly enabled in current buffer."
(or font-lock-defaults
(apply #'derived-mode-p nix-prettify-special-modes)))
(defun nix-prettify-turn-on ()
"Enable `nix-prettify-mode' in the current buffer if needed.
See `nix-prettify-special-modes' for details."
(and (not nix-prettify-mode)
(nix-prettify-supported-p)
(nix-prettify-mode)))
;;;###autoload
(define-globalized-minor-mode nix-prettify-global-mode
nix-prettify-mode nix-prettify-turn-on)
;;;###autoload
(define-obsolete-function-alias 'global-nix-prettify-mode 'nix-prettify-global-mode "v1.2.2")
(provide 'nix-prettify-mode)
;;; nix-prettify-mode.el ends here

View file

@ -0,0 +1,222 @@
;;; nix-repl.el --- Nix repl -*- lexical-binding: t -*-
;; This file is NOT part of GNU Emacs.
;; Homepage: https://github.com/NixOS/nix-mode
;; Package-Requires: ((emacs "24.4"))
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;;; Code:
(defvar nix-prompt-regexp "nix-repl> ")
(require 'comint)
(require 'nix)
(defgroup nix-repl nil
"Nix-repl customizations."
:group 'nix)
(defcustom nix-repl-executable-args '("repl")
"Arguments to provide to nix-repl."
:type '(repeat string))
(defvar nix-repl-completion-redirect-buffer
" *nix-repl completions redirect*"
"Buffer to be used to redirect output of readline commands.")
(defcustom nix-repl-completion-output-timeout 1.0
"Time in seconds to wait for completion output before giving up."
:type 'float)
(defvar nix-repl-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "\t" 'completion-at-point)
map))
(defun nix-repl-save-all-histories ()
"Call `comint-write-input-ring' for all `nix-repl-mode' buffers."
(dolist (buf (buffer-list))
(with-current-buffer buf
(when (eq major-mode 'nix-repl-mode)
(comint-write-input-ring)))))
(define-derived-mode nix-repl-mode comint-mode "Nix-REPL"
"Interactive prompt for Nix."
:interactive nil
(setq-local comint-prompt-regexp nix-prompt-regexp)
(setq-local comint-prompt-read-only t)
(let* ((is-remote (file-remote-p default-directory))
(maybe-xdg-data-home (if is-remote
(shell-command-to-string "echo -n $XDG_DATA_HOME")
(or (getenv "XDG_DATA_HOME")
"")))
(path-prefix (if (string-empty-p maybe-xdg-data-home)
"~/.local/share"
maybe-xdg-data-home))
(history-path (concat
is-remote
path-prefix
"/nix/repl-history")))
(setq-local comint-input-ring-file-name history-path))
(comint-read-input-ring t)
(add-hook 'kill-buffer-hook #'comint-write-input-ring nil 'local)
(add-hook 'kill-emacs-hook #'nix-repl-save-all-histories nil 'local)
(add-hook 'completion-at-point-functions
#'nix-repl-completion-at-point nil 'local))
(defmacro nix--with-temp-process-filter (proc &rest body)
"Use temp process PROC filter on BODY."
(declare (indent defun))
`(let* ((buf (generate-new-buffer " *temp-process-output*"))
(proc-filter-saved (process-filter ,proc))
(proc-marker (with-current-buffer buf (point-marker))))
(set-process-filter ,proc (nix--process-filter buf proc-marker))
(unwind-protect
(with-current-buffer buf
,@body)
(set-process-filter ,proc proc-filter-saved)
(kill-buffer buf))))
;;;###autoload
(defun nix-repl ()
"Load the Nix-REPL."
(interactive)
(pop-to-buffer-same-window
(get-buffer-create "*Nix-REPL*"))
(unless (comint-check-proc (current-buffer))
(nix--make-repl-in-buffer (current-buffer))
(nix-repl-mode)))
(defalias 'nix-repl-show 'nix-repl)
(defun nix--make-repl-in-buffer (buffer)
"Make Nix Repl in BUFFER."
(apply
'make-comint-in-buffer
(append `("Nix-REPL" ,buffer ,nix-executable nil)
nix-repl-executable-args)))
(defun nix-get-completions (process input)
"Get completions for INPUT using native readline for PROCESS."
(with-current-buffer (process-buffer process)
(let* ((original-filter-fn (process-filter process))
(redirect-buffer (get-buffer-create
nix-repl-completion-redirect-buffer))
(trigger "\t")
(new-input (concat input trigger))
(input-length
(save-excursion
(+ (- (point-max) (comint-bol)) (length new-input))))
(delete-line-command (make-string input-length ?\b))
(input-to-send (concat new-input delete-line-command)))
;; Ensure restoring the process filter, even if the user quits
;; or there's some other error.
(unwind-protect
(with-current-buffer redirect-buffer
;; Cleanup the redirect buffer
(erase-buffer)
;; Mimic `comint-redirect-send-command', unfortunately it
;; can't be used here because it expects a newline in the
;; command and that's exactly what we are trying to avoid.
(let ((comint-redirect-echo-input nil)
(comint-redirect-completed nil)
(comint-redirect-perform-sanity-check nil)
(comint-redirect-insert-matching-regexp t)
(comint-redirect-finished-regexp nix-prompt-regexp)
(comint-redirect-output-buffer redirect-buffer))
(set-process-filter
process (apply-partially
#'comint-redirect-filter original-filter-fn))
(process-send-string process input-to-send)
;; Grab output until our dummy completion used as
;; output end marker is found.
(when (nix--accept-process-output
process nix-repl-completion-output-timeout
comint-redirect-finished-regexp)
(beginning-of-line)
(if (eq (char-after) ?\r)
(cdr
(split-string
(buffer-substring-no-properties
(line-beginning-position) (point-min))
"[ \f\t\n\r\v]+" t))
(search-forward "" nil t)
(backward-char)
(if (eq (char-before) ?\a)
nil
(list (buffer-substring-no-properties (line-beginning-position) (point))))))))
(set-process-filter process original-filter-fn)))))
(defun nix--accept-process-output (process &optional timeout regexp)
"Accept PROCESS output with TIMEOUT until REGEXP is found.
Optional argument TIMEOUT is the timeout argument to
`accept-process-output' calls. Optional argument REGEXP
overrides the regexp to match the end of output, defaults to
`comint-prompt-regexp'. Returns non-nil when output was
properly captured.
This utility is useful in situations where the output may be
received in chunks, since `accept-process-output' gives no
guarantees they will be grabbed in a single call."
(let ((regexp (or regexp comint-prompt-regexp)))
(catch 'found
(while t
(when (not (accept-process-output process timeout))
(throw 'found nil))
(when (progn (re-search-backward regexp nil t))
(throw 'found t))))))
;;;###autoload
(defun nix-repl-completion-at-point ()
"Completion at point function for Nix using \"nix-repl\".
See `completion-at-point-functions'."
(save-excursion
(let* ((proc (get-buffer-process (current-buffer)))
(prefix (and (derived-mode-p 'nix-repl-mode)
proc
(executable-find nix-executable)
(nix--prefix-bounds))))
(pcase prefix
(`(,beg . ,end)
(list beg end
(nix-get-completions
proc
(buffer-substring beg end))
:exclusive 'no))))))
(defun nix--prefix-bounds ()
"Get bounds of Nix attribute path at point as a (BEG . END) pair, or nil."
(save-excursion
(when (< (skip-chars-backward "a-zA-Z0-9'\\-_\\.") 0)
(cons (point) (+ (point) (skip-chars-forward "a-zA-Z0-9'\\-_\\."))))))
(defun nix--send-repl (input &optional process mute)
"Send INPUT to PROCESS.
MUTE if true then dont alert user."
(let ((proc (or process (get-buffer-process (current-buffer)))))
(if mute
(nix--with-temp-process-filter proc
(process-send-string proc input))
(process-send-string proc input))))
(defun nix--char-with-ctrl (char)
"Generate control character CHAR."
(char-to-string (logand #b10011111 char)))
(defun nix--process-filter (buf marker)
"Process filter for Nix-rel buffer BUF at MARKER."
(lambda (_proc string)
(when (buffer-live-p buf)
(with-current-buffer buf
(save-excursion
(goto-char marker)
(insert string)
(set-marker marker (point)))))))
(provide 'nix-repl)
;;; nix-repl.el ends here

View file

@ -0,0 +1,135 @@
;;; nix-search.el --- Run nix commands -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix
;; Package-Requires: ((emacs "25.1"))
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;;; Code:
(require 'nix)
(require 'nix-instantiate)
(require 'nix-shell)
(require 'json)
;;;###autoload
(defun nix-search--search (search file &optional no-cache use-flakes)
(nix--process-json-nocheck "search" "--json"
(unless use-flakes "--file") file
(when no-cache "--no-cache")
(unless (string= "" search) search)))
(defface nix-search-pname
'((t :height 1.5
:weight bold))
"Face used for package names."
:group 'nix-mode)
(defface nix-search-version
'((((class color) (background dark))
:foreground "light blue")
(((class color) (background light))
:foreground "blue"))
"Face used for package version."
:group 'nix-mode)
(defface nix-search-description
'((t))
"Face used for package description."
:group 'nix-mode)
(defvar nix-search-mode-menu (make-sparse-keymap "Nix")
"Menu for Nix Search mode.")
(defvar nix-search-mode-map (make-sparse-keymap)
"Local keymap used for Nix Search mode.")
(defvar-local nix-search--filter nil
"Search filter used for current buffer")
(defvar-local nix-search---file nil
"File/flake used for current buffer")
(defun nix-search--refresh ()
"Refresh Nix Search buffer"
(interactive)
(let ((results (nix-search--search nix-search--filter nix-search--file nil use-flakes)))
(nix-search--display results (current-buffer) use-flakes nix-search--filter nix-search--file)))
(defun nix-search-create-keymap ()
"Create the keymap associated with the Nix Search mode.")
(defun nix-search-create-menu ()
"Create the Nix Search menu as shown in the menu bar."
(let ((m '("Nix Search"
["Refresh" nix-search--refresh t])))
(easy-menu-define nix-search-mode-menu nix-search-mode-map "Menu keymap for Nix mode" m)))
(nix-search-create-keymap)
(nix-search-create-menu)
(define-derived-mode nix-search-mode view-mode "Nix Search"
"Major mode for showing Nix search results.
\\{nix-search-mode-map}"
:interactive nil
:group 'nix-mode
(easy-menu-add nix-search-mode-menu)
(read-only-mode 1))
;;;###autoload
(defun nix-search--display (results &optional display-buffer use-flakes search file)
(unless display-buffer (setq display-buffer (generate-new-buffer "*nix search*")))
(with-current-buffer display-buffer
(setq-local nix-search--filter search)
(setq-local nix-search--file file)
(unless (derived-mode-p 'nix-search-mode)
(nix-search-mode))
(let ((inhibit-read-only t))
(erase-buffer)
(insert "-------------------------------------------------------------------------------\n")
(dolist (entry results)
(let ((pname (if use-flakes
(alist-get 'pname (cdr entry))
(alist-get 'pkgName (cdr entry))))
(version (alist-get 'version (cdr entry)))
(description (alist-get 'description (cdr entry))))
(put-text-property 0 (length pname) 'face 'nix-search-pname pname)
(put-text-property 0 (length version) 'face 'nix-search-version version)
(put-text-property 0 (length description) 'face 'nix-search-description description)
(insert (format "* %s (%s)\n%s\n" pname version description))
(insert "-------------------------------------------------------------------------------\n")
))))
(display-buffer display-buffer))
;;;###autoload
(defun nix-search (search &optional file display-buffer)
"Run nix search.
SEARCH a search term to use.
FILE a Nix expression to search in."
(interactive "snix-search> \n")
(setq use-flakes (nix-has-flakes))
(setq file (or file (if use-flakes (nix-read-flake) (nix-read-file))))
(let ((results (nix-search--search search file nil use-flakes)))
(when (called-interactively-p 'any)
(nix-search--display results display-buffer use-flakes search file))
results))
(defun nix-search-read-attr (file)
"Read from a list of attributes.
FILE the nix file to look in."
(let ((collection
(sort (mapcar (lambda (x) (symbol-name (car x)))
(nix-search "" file))
'string<))
(read (cond ((fboundp 'ivy-read) 'ivy-read)
(t 'completing-read))))
(funcall read "Attribute: " collection)))
(provide 'nix-search)
;;; nix-search.el ends here

View file

@ -0,0 +1,46 @@
;;; nix-shebang.el --- Handle nix shebang header -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix, languages, tools, unix
;; Package-Requires: ((emacs "24.3"))
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;; This detects file headers that look like:
;; #!/usr/bin/env nix-shell
;; #!nix-shell -i bash
;; and correctly detects their file modes.
;;; Code:
(require 'files)
(defvar nix-shebang-interpreter-regexp "#!\s*nix-shell -i \\([^ \t\n]+\\)"
"Regexp for nix-shell -i header.")
(defun nix-shebang-get-interpreter ()
"Get interpreter string from nix-shell -i file."
(save-excursion
(goto-char (point-min))
(forward-line 1)
(when (looking-at nix-shebang-interpreter-regexp)
(match-string 1))))
(defun nix-shebang-mode ()
"Detect and run files interpreter mode."
(let ((mode (nix-shebang-get-interpreter)))
(when mode
(funcall (assoc-default mode
(mapcar (lambda (e)
(cons
(format "\\`%s\\'" (car e))
(cdr e)))
interpreter-mode-alist)
#'string-match-p)))))
(provide 'nix-shebang)
;;; nix-shebang.el ends here

View file

@ -0,0 +1,294 @@
;;; nix-shell.el --- Run nix commands -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix, processes
;; Package-Requires: ((emacs "25.1"))
;; 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 'nix)
(require 'nix-instantiate)
(require 'nix-store)
;; Tell the byte compiler these are dynamically bound
(defvar woman-manpath)
(defvar Man-header-file-path)
(defvar irony-additional-clang-options)
(defvar eshell-path-env)
(defvar ffap-c-path)
(defgroup nix-shell nil
"All nix-shell options."
:group 'nix)
(defcustom nix-shell-inputs '(buildInputs
depsBuildBuild
depsBuildBuildPropagated
nativeBuildInputs
propagatedNativeBuildInputs
depsBuildTarget
depsBuildTargetPropagated)
"List of inputs to collect for nix-shell."
:type 'list
:group 'nix-shell)
(defcustom nix-shell-clear-environment nil
"Whether to clear the old exec-path & environment.
Similar to --pure argument in command line nix-shell."
:type 'boolean
:group 'nix-shell)
(defcustom nix-shell-auto-realise t
"Whether we can realise paths in the built .drv file."
:type 'boolean
:group 'nix-shell)
(defcustom nix-file nil
"Nix file to build expressions from.
Should only be set in dir-locals.el file."
:type 'stringp
:group 'nix-shell)
(defcustom nix-flake nil
"Nix flake to build expressions from.
Should only be set in dir-locals.el file."
:type 'stringp
:group 'nix-shell)
(defcustom nix-attr nil
"Nix attribute path to use.
Should only be set in dir-locals.el file."
:type 'stringp
:group 'nix-shell)
;;;###autoload
(defun nix-shell-unpack (file attr)
"Run Nixs unpackPhase.
FILE is the file to unpack from.
ATTR is the attribute to unpack."
(interactive (list (nix-read-file) nil))
(unless attr (setq attr (nix-read-attr file)))
(nix-shell--run-phase "unpack" file attr))
(defun nix-read-attr (_)
"Get nix attribute from user."
(read-string "Nix attr: "))
(defun nix-read-flake ()
"Get nix flake from user."
(cond
(nix-flake nix-flake)
((and (nix-has-flakes) (file-exists-p "flake.nix")) ".")
(t (read-string "Nix flake: " "nixpkgs"))))
(defun nix-read-file ()
"Get nix file from user."
(cond
(nix-file nix-file)
((file-exists-p "shell.nix") "shell.nix")
((file-exists-p "default.nix") "default.nix")
(t (read-file-name "Nix file: " nil "<nixpkgs>"))))
;;;###autoload
(defun nix-shell-configure (file attr)
"Run Nixs configurePhase.
FILE is the file to configure from.
ATTR is the attribute to configure."
(interactive (list (nix-read-file) nil))
(unless attr (setq attr (nix-read-attr file)))
(nix-shell--run-phase "configure" file attr))
;;;###autoload
(defun nix-shell-build (file attr)
"Run Nixs buildPhase.
FILE is the file to build from.
ATTR is the attribute to build."
(interactive (list (nix-read-file) nil))
(unless attr (setq attr (nix-read-attr file)))
(nix-shell--run-phase "build" file attr))
(defun nix-shell--run-phase (phase file attr)
"Get source from a Nix derivation.
PHASE phase to run.
FILE used for base of Nix expresions.
ATTR from NIX-FILE to get Nix expressions from."
(shell-command
(format "%s '%s' -A '%s' --run 'if [ -z \"$%sPhase\" ]; then eval %sPhase; else eval \"$%sPhase\"; fi' &"
nix-shell-executable
file attr phase phase phase)))
(declare-function flycheck-buffer "flycheck")
(defun nix-shell--callback (buffer drv)
"Run the nix-shell callback to setup the buffer.
The BUFFER to run in.
The DRV file to use."
(let* ((env (alist-get 'env drv))
(stdenv (alist-get 'stdenv env))
(system (alist-get 'system env))
(inputs (remove nil
(apply 'append
(mapcar (lambda (prop)
(split-string (alist-get prop env)))
nix-shell-inputs))))
;; This attribute is in `mkShell' — ideally, we'd only check this variable in those cases.
(ld-library-path (alist-get 'LD_LIBRARY_PATH env)))
;; Prevent accidentally rebuilding the world.
(unless (file-directory-p stdenv)
(error
"Your stdenv at %s has not been built. Please run: nix-store -r %s"
stdenv stdenv))
;; Make sure this .drv file can actually be built here.
(unless (string= system (nix-system))
(error
"Your system (%s) does not match .drvs build system (%s)"
(nix-system) system))
(with-current-buffer buffer
(when nix-shell-clear-environment
(setq-local exec-path nil)
(setq-local eshell-path-env "")
;; (setq-local process-environment nil)
)
;; Set the LD_LIBRARY_PATH where applicable
(when ld-library-path
(make-local-variable 'process-environment)
(setq process-environment
(cons
(let*
((var "LD_LIBRARY_PATH")
(current-path (getenv var)))
(if current-path
;; LD_LIBRARY_PATH defined in derivation takes precedence
(format "%s=%s:%s" var ld-library-path current-path)
(format "%s=%s" var ld-library-path)))
process-environment)))
(dolist (input inputs)
(when (and (not (file-directory-p input))
nix-shell-auto-realise)
(nix-store-realise input))
(let ((bin (expand-file-name "bin" input))
(man (expand-file-name "share/man" input))
(include (expand-file-name "include" input)))
(add-to-list 'exec-path bin)
(setq-local eshell-path-env
(format "%s:%s" bin eshell-path-env))
(when (boundp 'woman-manpath)
(add-to-list 'woman-manpath man))
(add-to-list 'ffap-c-path include)
(add-to-list 'Man-header-file-path include)
(when (boundp 'irony-additional-clang-options)
(add-to-list 'irony-additional-clang-options
(format "-I%s" include)))))
(when (bound-and-true-p flycheck-mode)
(flycheck-buffer)))))
(defun nix-shell-with-packages (packages &optional pkgs-file)
"Create a nix shell environment from the listed package.
PACKAGES a list of packages to use.
PKGS-FILE the Nix file to get the packages from."
(nix-instantiate-async (apply-partially 'nix-shell--callback
(current-buffer))
(nix-shell--with-packages-file packages pkgs-file)))
(defun nix-shell--with-packages-file (packages &optional pkgs-file)
"Get a .nix file from the packages list.
PACKAGES to put in the .nix file.
PKGS-FILE package set to pull from."
(unless pkgs-file (setq pkgs-file "<nixpkgs>"))
(let ((nix-file (make-temp-file "nix-shell" nil ".nix")))
(with-temp-file nix-file
(insert (format "with import %s { };\n" pkgs-file))
(insert "runCommandCC \"shell\" {\n")
(insert " nativeBuildInputs = [\n")
(mapc (lambda (x) (insert (format " %s\n" x))) packages)
(insert " ];\n")
(insert "} \"\"\n"))
nix-file))
;;;###autoload
(defun nix-eshell-with-packages (packages &optional pkgs-file)
"Create an Eshell buffer that has the shell environment in it.
PACKAGES a list of packages to pull in.
PKGS-FILE a file to use to get the packages."
(let ((buffer (generate-new-buffer "*nix-eshell*")))
(pop-to-buffer-same-window buffer)
(setq-local nix-shell-clear-environment t)
;; We must start this before the callback otherwise the path is cleared
(eshell-mode)
(nix-shell--callback
(current-buffer)
(nix-instantiate
(nix-shell--with-packages-file packages pkgs-file) nil t))
buffer))
;;;###autoload
(defun nix-eshell (file &optional attr)
"Create an Eshell buffer that has the shell environment in it.
FILE the .nix expression to create a shell for.
ATTR attribute to instantiate in NIX-FILE."
(interactive (list (nix-read-file) nil))
(unless attr (setq attr (nix-read-attr nix-file)))
(let ((buffer (generate-new-buffer "*nix-eshell*")))
(pop-to-buffer-same-window buffer)
(setq-local nix-shell-clear-environment t)
;; We must start this before the callback otherwise the path is cleared
(eshell-mode)
(nix-shell--callback
(current-buffer)
(nix-instantiate file attr t))
buffer))
;;;###autoload
(defun nix-shell-with-string (string)
"A nix-shell emulator in Emacs from a string.
STRING the nix expression to use."
(let ((file (make-temp-file "nix-shell" nil ".nix")))
(with-temp-file file (insert string))
(nix-instantiate-async (apply-partially 'nix-shell--callback
(current-buffer))
file)))
;;;###autoload
(defun nix-shell (file &optional attr)
"A nix-shell emulator in Emacs.
FILE the file to instantiate.
ATTR an attribute of the Nix file to use."
(interactive (list (nix-read-file) nil))
(unless attr (setq attr (nix-read-attr file)))
(nix-instantiate-async (apply-partially 'nix-shell--callback
(current-buffer))
file attr))
(provide 'nix-shell)
;;; nix-shell.el ends here

View file

@ -0,0 +1,232 @@
;;; nix-store.el --- Run nix commands -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix
;; Package-Requires: ((emacs "25.1") (magit-section "3.3.0"))
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;;; Code:
(require 'eieio)
(require 'nix)
(require 'nix-log)
(require 'magit-section)
(eval-when-compile
(require 'cl-lib))
(defgroup nix-store nil
"Nix-store customizations."
:group 'nix)
(defun nix-store-realise (path)
"Realise a path asynchronously.
PATH the path within /nix/store to realise"
(make-process
:buffer nil
:command (list nix-store-executable "--realise" path)
:noquery t
:name (format "*nix-store*<%s>" path)))
(defvar-local nix-buffer-store-path nil "Buffer-local object holding an `nix-store-path` object.")
(defclass nix-store-path ()
((path :initarg :path :accessor nix-store-path-path)
(status :initarg :status :accessor nix-store-path-status)
(hash :initarg :hash :accessor nix-store-path-hash)
(size :initarg :size :accessor nix-store-path-size)
(derivers :initarg :derivers :accessor nix-store-path-derivers)
(outputs :initarg :outputs :accessor nix-store-path-outputs)
(references :initarg :references :accessor nix-store-path-references)
(referrers :initarg :referrers :accessor nix-store-path-referrers)
(requisites :initarg :requisites :accessor nix-store-path-requisites))
"Nix-Store-Path Class holds all information of the path that
is displayed")
(cl-defmethod nix-store-fill-data ((object nix-store-path))
"Query the nix store via `nix-store-executable' and save that data into OBJECT."
(oset object :size (nix-store--query 'size (nix-store-path-path object)))
(oset object :hash (nix-store--query 'hash (nix-store-path-path object)))
(oset object :derivers (nix-store--query 'deriver (nix-store-path-path object)))
(oset object :outputs (nix-store--query 'outputs (nix-store-path-path object)))
(oset object :referrers (nix-store--query 'referrers (nix-store-path-path object)))
(oset object :requisites (nix-store--query 'requisites (nix-store-path-path object)))
(oset object :references (nix-store--query 'references (nix-store-path-path object)))
(oset object :status (file-exists-p (car (nix-store-path-outputs object))))
object)
(cl-defun nix-store--query (argument &optional (path (nix-store-path-path nix-buffer-store-path)))
"Query the nix-store for information.
ARGUMENT is given to the executable as an argument. See
nix-store(1) for possibilities. PATH is the store object that is
being queried. Runs `nix-store-executable' to get that
information."
(let ((nix-executable nix-store-executable))
(cond
((eq 'deriver argument)
;; Special treatment for 'derivers', we want to treat a single entry
;; with this string as an empty list
(remove "unknown-deriver"
(nix--process-lines "--query" "--deriver" path )))
((eq 'size argument) (string-to-number (nix--process-string "--query" "--size" path )))
((eq 'hash argument) (nix--process-string "--query" "--hash" path ))
((eq 'requisites argument) (nix--process-lines "--query" "--requisites" path ))
((eq 'references argument) (nix--process-lines "--query" "--references" path ))
((eq 'referrers argument) (nix--process-lines "--query" "--referrers" path ))
((eq 'outputs argument)
(ignore-errors
;; This can fail for non-derivation paths
(nix--process-lines "--query" "--outputs" path )))
(t (error "Unknown argument to nix-store --query: %s" argument)))))
(cl-defun nix-store-path-insert-path (&optional (store-path nix-buffer-store-path))
"Insert a section showing the path of STORE-PATH."
(magit-insert-section (path (nix-store-path-path store-path))
(magit-insert-heading (propertize (format "%-11s" "Path:") 'face 'magit-section-heading)
(propertize (oref store-path path)
'face (if (file-exists-p (nix-store-path-path store-path))
'nix-store-path-realised-face
'nix-store-path-unrealised-face) ))))
(cl-defun nix-store-path-insert-size (&optional (store-path nix-buffer-store-path))
"Insert a section showing the size of STORE-PATH."
(magit-insert-section (size (nix-store-path-size store-path))
(magit-insert-heading (propertize (format "%-11s" "Size:") 'face 'magit-section-heading)
(format "%s" (oref store-path size)))))
(cl-defun nix-store-path-insert-hash (&optional (store-path nix-buffer-store-path))
"Insert a section showing the hash of STORE-PATH."
(magit-insert-section (hash (nix-store-path-hash store-path))
(magit-insert-heading (propertize (format "%-11s" "Hash:") 'face 'magit-section-heading)
(format "%s" (oref store-path hash)))))
(cl-defun nix-store-path-insert-status (&optional (store-path nix-buffer-store-path))
"Insert a section showing the status of STORE-PATH."
(magit-insert-section (status (nix-store-path-status store-path))
(magit-insert-heading (propertize (format "%-11s" "Status:") 'face 'magit-section-heading)
(if (nix-store-path-status store-path) "realised" "unrealised"))))
(defmacro nix-store--magit-insert-section-list (type value label)
"Helper macro for inserting a list as a magit-section.
TYPE and VALUE will be used as the type and value of the section
respectively. The LABEL is the text displayed."
`(let ((value ,value))
(when (and (listp value) (> (length value) 0))
(magit-insert-section (,type value)
(magit-insert-heading ,label)
(cl-loop for x in value
for exists = (file-exists-p x)
do
(magit-insert-section (store-path x)
(insert
(propertize x 'face (if exists 'nix-store-path-realised-face 'nix-store-path-unrealised-face))
?\n)))
(insert ?\n)
(magit-insert-child-count (magit-current-section))))))
(cl-defun nix-store-path-insert-derivers (&optional (store-path nix-buffer-store-path))
"Insert sections showing all derivers of STORE-PATH."
(nix-store--magit-insert-section-list derivers (nix-store-path-derivers store-path) "Derivers:"))
(cl-defun nix-store-path-insert-outputs (&optional (store-path nix-buffer-store-path))
"Insert sections showing all outputs of STORE-PATH."
(nix-store--magit-insert-section-list outputs (nix-store-path-outputs store-path) "Outputs:"))
(cl-defun nix-store-path-insert-references (&optional (store-path nix-buffer-store-path))
"Insert sections showing all references of STORE-PATH."
(nix-store--magit-insert-section-list references (nix-store-path-references store-path) "References:"))
(cl-defun nix-store-path-insert-referrers (&optional (store-path nix-buffer-store-path))
"Insert sections showing all referrers of STORE-PATH."
(nix-store--magit-insert-section-list referrers (nix-store-path-referrers store-path) "Referrers:"))
(cl-defun nix-store-path-insert-requisites (&optional (store-path nix-buffer-store-path))
"Insert sections showing all requisites of STORE-PATH."
(nix-store--magit-insert-section-list requisites (nix-store-path-requisites store-path) "Requisites:"))
(defcustom nix-store-path-headers-hook
'(nix-store-path-insert-path
nix-store-path-insert-status
nix-store-path-insert-hash
nix-store-path-insert-size)
"Hook run to insert headers into the nix-store buffer.
A list of function that each take one argument, the store path object."
:group 'nix-store
:type 'hook
:options '(nix-store-path-insert-path
nix-store-path-insert-status
nix-store-path-insert-hash
nix-store-path-insert-size))
(defcustom nix-store-path-sections-hook
'(nix-store-path-insert-derivers
nix-store-path-insert-outputs
nix-store-path-insert-references
nix-store-path-insert-referrers
nix-store-path-insert-requisites)
"Hook run to insert sections into a nix-store buffer.
A list of function that each take one argument, the store path object."
:group 'nix-store
:type 'hook)
(defun nix-store-show-path (path)
"Show a nix-store PATH.
If you want to change the order of the section lists (or even
implement your own ones) you can customize the variable
`nix-store-path-headers-hook' and
`nix-store-path-sections-hook'."
(interactive "FNix-Store-Path: ")
(setq path (expand-file-name path default-directory))
(switch-to-buffer (format "Nix Store Path: %s" path))
(nix-store-path-mode)
(setq nix-buffer-store-path (nix-store-fill-data (make-instance 'nix-store-path :path path))
list-buffers-directory path)
(when (file-directory-p path)
(setq default-directory path))
(let ((inhibit-read-only t))
(erase-buffer)
(magit-insert-section (store-path)
(magit-insert-headers 'nix-store-path-headers-hook)
(magit-run-section-hook 'nix-store-path-sections-hook))
(goto-char (point-min))))
(defun nix-store-path-at-point ()
"Return the nix-store path at point."
;; TODO extract this via magit-section values
(substring-no-properties (thing-at-point 'filename)))
(defun nix-store-show-path-at-point ()
"Opens the nix-store-path at point.
It uses \\[nix-store-show-path] to display the store path."
(interactive)
(nix-store-show-path (nix-store-path-at-point)))
(defun nix-store-show-log ()
"Opens the log file for the derivation of the nix-store path."
(interactive)
(let ((drv-path (car (nix-store-path-derivers nix-buffer-store-path))))
(if (not drv-path)
(message "This store path has no associated derivation.")
(find-file (nix-log-path drv-path)))))
(defvar nix-store-path-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "RET") 'nix-store-show-path-at-point)
(define-key map (kbd "l") 'nix-store-show-log)
map))
(defun nix-store--revert-buffer-function (&rest _ignore)
"Helper function to be called by `revert-buffer'."
(nix-store-show-path (nix-store-path-path nix-buffer-store-path)))
(define-derived-mode nix-store-path-mode magit-section-mode "Nix Store Path"
(setq-local revert-buffer-function #'nix-store--revert-buffer-function)
(read-only-mode 1))
(provide 'nix-store)
;;; nix-store.el ends here

368
elpa/nix-mode-1.5.0/nix.el Normal file
View file

@ -0,0 +1,368 @@
;;; 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