(defvar ambrevar/guix-checkout-directory (expand-file-name "~/projects/guix")) (with-eval-after-load 'geiser-guile (when (require 'yasnippet nil t) (yas-global-mode 1) ;; This is not enough since COMMIT_MSG is not in scheme-mode. ;; TODO: Add to find-file-hook instead and check if parent folder is ~/projects/guix. ;; (add-hook 'scheme-mode-hook 'yas-minor-mode) (with-eval-after-load 'yasnippet (add-to-list 'yas-snippet-dirs (expand-file-name "etc/snippets" ambrevar/guix-checkout-directory)))) (add-to-list 'geiser-guile-load-path ambrevar/guix-checkout-directory)) ;; To use package declaration from the local checkout: ;; (setq guix-load-path ambrevar/guix-checkout-directory) (defun ambrevar/init-guix () (and buffer-file-name (string-match "\\" buffer-file-name) (guix-devel-mode))) (add-hook 'scheme-mode-hook 'ambrevar/init-guix) (defun ambrevar/guix-debbugs-gnu (&optional severities packages archivedp suppress tags) "Like `debbugs-gnu' but for the Guix project." (interactive) (let ((debbugs-gnu-default-packages '("guix-patches" "guix"))) (if (called-interactively-p) (call-interactively 'debbugs-gnu) (debbugs-gnu severities packages archivedp suppress tags)))) (require 'guix nil 'noerror) (defun ambrevar/guix-generations-list-diff-this () "List guix-generation-list-diff but compare generation at point with previous." (interactive) (let ((diff-fun #'guix-diff) (gen-fun #'guix-profile-generation-packages-buffer)) (funcall diff-fun (funcall gen-fun (1- (bui-list-current-id))) (funcall gen-fun (bui-list-current-id))))) (with-eval-after-load 'guix-ui-generation (define-key guix-generation-list-mode-map "=" #'ambrevar/guix-generations-list-diff-this)) (defvar ambrevar/guix-extra-channels "~/.guix-extra-channels") (defvar ambrevar/guix-extra-profiles "~/.guix-extra-profiles") (defvar ambrevar/guix-manifest-directory "~/.package-lists") (defvar ambrevar/guix-channel-spec-directory "~/.package-lists") (defvar ambrevar/guix-always-use-channel-specs nil "If non-nil, automatically use a channel specification matching the chosen manifest. The channel specification is looked up in `ambrevar/guix-channel-spec-directory'.") (cl-defun ambrevar/guix-query-file (&key file directory (filter ".") (prompt "File: ") (name-function #'identity)) "Query a file matching FILTER in DIRECTORY. Return (NAME FILE). If FILE is non-nil, then this function is useful to derive the name of the manifest. NAME-FUNCTION take the file base name as argument and returns NAME." (cl-flet ((name (file) (replace-regexp-in-string "-?guix-?" "" (funcall name-function (file-name-base file))))) (if file (list (name file) file) (let ((files (mapcar (lambda (file) (list (name file) file)) (directory-files directory 'full filter)))) (assoc (completing-read prompt (mapcar #'first files)) files))))) (defun ambrevar/guix-query-manifest (&optional manifest) "Query a manifest as found in `ambrevar/guix-manifest-directory'. Return (NAME FILE). If MANIFEST is non-nil, then this function is useful to derive the name of the manifest." (ambrevar/guix-query-file :file manifest :directory ambrevar/guix-manifest-directory :filter "manifest" :prompt "Manifest: " :name-function (lambda (name) (replace-regexp-in-string "-?manifest-?" "" name)))) (defun ambrevar/guix-query-channel-spec (&optional channel-spec) "Query a channel specification as found in `ambrevar/guix-channel-spec-directory'. Return (NAME FILE). If CHANNEL-SPEC is non-nil, then this function is useful to derive the name of the channel specification." (ambrevar/guix-query-file :file channel-spec :directory ambrevar/guix-channel-spec-directory :filter "channels" :prompt "Channel specification: " :name-function (lambda (name) (replace-regexp-in-string "-?channels?-?" "" name)))) (defun ambrevar/guix-edit-manifest (&optional manifest) "Edit MANIFEST. If MANIFEST is nil, it is queried from the manifests found in `ambrevar/guix-manifest-directory'." (interactive) (setq manifest (second (ambrevar/guix-query-manifest manifest))) (find-file manifest)) (global-set-key (kbd "C-x c g") #'ambrevar/guix-edit-manifest) (with-eval-after-load 'evil ;; For some reason `global-set-key' does not work for Evil at this point. (dolist (mode '(normal insert)) (evil-global-set-key mode (kbd "C-x c g") #'ambrevar/guix-edit-manifest))) (defun ambrevar/guix-save-channel-specs (dest) "Save current Guix channel specification to DEST." (call-process "guix" nil `(:file ,dest) nil "describe" "--format=channels")) (defun ambrevar/guix-find-channel-from-manifest (pattern) "Return the channel specification file matching PATTERN in `ambrevar/guix-channel-spec-directory'." (first (directory-files ambrevar/guix-channel-spec-directory 'full (concat pattern "-channel")))) (defun ambrevar/guix-install-manifest (&optional manifest channel) "Install Guix manifest to `ambrevar/guix-extra-profiles'. Manifest is queried from those found in `ambrevar/guix-manifest-directory'. Guix channel specification is stored in `ambrevar/guix-channel-spec-directory'. With a prefix argument, query for a channel specification file. If CHANNEL is nil and `ambrevar/guix-always-use-channel-specs' is non-nil, then try to use a channel specification file from `ambrevar/guix-channel-spec-directory' if any." (interactive) (let* ((manifest-pair (ambrevar/guix-query-manifest manifest)) (manifest-name (first manifest-pair)) (manifest (second manifest-pair)) (channel (or channel (and current-prefix-arg (second (ambrevar/guix-query-channel-spec))) (and ambrevar/guix-always-use-channel-specs (ambrevar/guix-find-channel-from-manifest manifest-name)))) (guix (if channel (let ((dest (expand-file-name manifest-name ambrevar/guix-extra-channels))) (make-directory dest 'parents) (format "guix pull --channels=%s --profile=%s/guix && %s/guix/bin/guix" (shell-quote-argument channel) (shell-quote-argument dest) (shell-quote-argument dest))) "guix"))) (make-directory (expand-file-name manifest-name ambrevar/guix-extra-profiles) 'parents) (let ((eshell-buffer-name "*guix*")) (eshell) (when (eshell-interactive-process) (eshell t)) (eshell-interrupt-process) (insert guix " package" (concat " --manifest=" manifest) (if (string= "default" manifest-name) "" (concat " --profile=" (expand-file-name ambrevar/guix-extra-profiles) "/" manifest-name "/" manifest-name))) (eshell-send-input)) (unless channel ;; TODO: Only do this when manifest install has succeeded. (ambrevar/guix-save-channel-specs (format "%s/guix-%s-channels.scm" ambrevar/guix-channel-spec-directory manifest-name))))) (global-set-key (kbd "C-x c G") #'ambrevar/guix-install-manifest) (with-eval-after-load 'evil (dolist (mode '(normal insert)) (evil-global-set-key mode (kbd "C-x c G") #'ambrevar/guix-install-manifest))) ;; TODO: See `guix-apply-manifest' and expand on it. ;; TODO: Use --max-jobs=N. (provide 'init-guix)