2014-08-27 08:44:17 -04:00
|
|
|
|
;;; guix-list.el --- List buffers for displaying entries -*- lexical-binding: t -*-
|
|
|
|
|
|
2015-08-16 00:11:57 -04:00
|
|
|
|
;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
;; This file is part of GNU Guix.
|
|
|
|
|
|
|
|
|
|
;; GNU Guix is free software; you can redistribute it and/or modify
|
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
;; (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
;; GNU Guix is distributed in the hope that it will be useful,
|
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
|
|
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
|
|
;; This file provides a list-like buffer for displaying information
|
|
|
|
|
;; about Guix packages and generations.
|
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
(require 'cl-lib)
|
|
|
|
|
(require 'tabulated-list)
|
|
|
|
|
(require 'guix-info)
|
|
|
|
|
(require 'guix-base)
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(require 'guix-entry)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(require 'guix-utils)
|
2015-11-20 04:38:31 -05:00
|
|
|
|
(require 'guix-ui)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defgroup guix-list nil
|
|
|
|
|
"General settings for list buffers."
|
|
|
|
|
:prefix "guix-list-"
|
|
|
|
|
:group 'guix)
|
|
|
|
|
|
2015-09-14 16:32:53 -04:00
|
|
|
|
(defgroup guix-list-faces nil
|
|
|
|
|
"Faces for list buffers."
|
|
|
|
|
:group 'guix-list
|
|
|
|
|
:group 'guix-faces)
|
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(defface guix-list-file-path
|
|
|
|
|
'((t :inherit guix-info-file-path))
|
|
|
|
|
"Face used for file paths."
|
2015-09-14 16:32:53 -04:00
|
|
|
|
:group 'guix-list-faces)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-17 13:46:31 -05:00
|
|
|
|
(defface guix-list-time
|
|
|
|
|
'((t :inherit guix-info-time))
|
|
|
|
|
"Face used for time stamps."
|
|
|
|
|
:group 'guix-list-faces)
|
|
|
|
|
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(defun guix-list-describe (&optional mark-names)
|
|
|
|
|
"Describe entries marked with a general mark.
|
|
|
|
|
'Describe' means display entries in 'info' buffer.
|
|
|
|
|
If no entries are marked, describe the current entry.
|
|
|
|
|
With prefix argument, describe entries marked with any mark."
|
|
|
|
|
(interactive (list (unless current-prefix-arg '(general))))
|
|
|
|
|
(let* ((ids (or (apply #'guix-list-get-marked-id-list mark-names)
|
|
|
|
|
(list (guix-list-current-id))))
|
|
|
|
|
(count (length ids))
|
|
|
|
|
(entry-type guix-entry-type))
|
|
|
|
|
(when (or (<= count (guix-list-describe-warning-count entry-type))
|
|
|
|
|
(y-or-n-p (format "Do you really want to describe %d entries? "
|
|
|
|
|
count)))
|
|
|
|
|
(guix-list-describe-entries entry-type ids))))
|
|
|
|
|
|
2015-11-19 03:03:48 -05:00
|
|
|
|
|
|
|
|
|
;;; Wrappers for 'list' variables
|
|
|
|
|
|
|
|
|
|
(defvar guix-list-data nil
|
|
|
|
|
"Alist with 'list' data.
|
2015-11-20 04:38:31 -05:00
|
|
|
|
This alist is filled by `guix-list-define-interface' macro.")
|
2015-11-19 03:03:48 -05:00
|
|
|
|
|
|
|
|
|
(defun guix-list-value (entry-type symbol)
|
|
|
|
|
"Return SYMBOL's value for ENTRY-TYPE from `guix-list-data'."
|
|
|
|
|
(symbol-value (guix-assq-value guix-list-data entry-type symbol)))
|
|
|
|
|
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(defun guix-list-param-title (entry-type param)
|
|
|
|
|
"Return column title of an ENTRY-TYPE parameter PARAM."
|
2015-11-21 03:35:43 -05:00
|
|
|
|
(guix-buffer-param-title 'list entry-type param))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(defun guix-list-format (entry-type)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
"Return column format for ENTRY-TYPE."
|
2015-11-19 08:56:19 -05:00
|
|
|
|
(guix-list-value entry-type 'format))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(defun guix-list-displayed-params (entry-type)
|
|
|
|
|
"Return a list of ENTRY-TYPE parameters that should be displayed."
|
|
|
|
|
(mapcar #'car (guix-list-format entry-type)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-19 08:19:47 -05:00
|
|
|
|
(defun guix-list-sort-key (entry-type)
|
|
|
|
|
"Return sort key for ENTRY-TYPE."
|
|
|
|
|
(guix-list-value entry-type 'sort-key))
|
|
|
|
|
|
2015-11-19 03:03:48 -05:00
|
|
|
|
(defun guix-list-additional-marks (entry-type)
|
|
|
|
|
"Return alist of additional marks for ENTRY-TYPE."
|
|
|
|
|
(guix-list-value entry-type 'marks))
|
|
|
|
|
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(defun guix-list-describe-warning-count (entry-type)
|
|
|
|
|
"Return the maximum number of ENTRY-TYPE entries to describe."
|
|
|
|
|
(guix-list-value entry-type 'describe-count))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-describe-entries (entry-type ids)
|
|
|
|
|
"Describe ENTRY-TYPE entries with IDS in 'info' buffer"
|
|
|
|
|
(funcall (guix-list-value entry-type 'describe)
|
|
|
|
|
ids))
|
|
|
|
|
|
2015-11-19 03:03:48 -05:00
|
|
|
|
|
|
|
|
|
;;; Tabulated list internals
|
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(defun guix-list-sort-numerically (column a b)
|
|
|
|
|
"Compare COLUMN of tabulated entries A and B numerically.
|
2015-11-18 02:39:42 -05:00
|
|
|
|
This function is used for sort predicates for `tabulated-list-format'.
|
2014-08-27 08:44:17 -04:00
|
|
|
|
Return non-nil, if B is bigger than A."
|
|
|
|
|
(cl-flet ((num (entry)
|
|
|
|
|
(string-to-number (aref (cadr entry) column))))
|
|
|
|
|
(> (num b) (num a))))
|
|
|
|
|
|
2015-11-18 02:39:42 -05:00
|
|
|
|
(defmacro guix-list-define-numerical-sorter (column)
|
|
|
|
|
"Define numerical sort predicate for COLUMN.
|
|
|
|
|
See `guix-list-sort-numerically' for details."
|
|
|
|
|
(let ((name (intern (format "guix-list-sort-numerically-%d" column)))
|
|
|
|
|
(doc (format "\
|
|
|
|
|
Predicate to sort tabulated list by column %d numerically.
|
|
|
|
|
See `guix-list-sort-numerically' for details."
|
|
|
|
|
column)))
|
|
|
|
|
`(defun ,name (a b)
|
|
|
|
|
,doc
|
|
|
|
|
(guix-list-sort-numerically ,column a b))))
|
|
|
|
|
|
|
|
|
|
(defmacro guix-list-define-numerical-sorters (n)
|
|
|
|
|
"Define numerical sort predicates for columns from 0 to N.
|
|
|
|
|
See `guix-list-define-numerical-sorter' for details."
|
|
|
|
|
`(progn
|
|
|
|
|
,@(mapcar (lambda (i)
|
|
|
|
|
`(guix-list-define-numerical-sorter ,i))
|
|
|
|
|
(number-sequence 0 n))))
|
|
|
|
|
|
|
|
|
|
(guix-list-define-numerical-sorters 9)
|
|
|
|
|
|
2015-11-19 08:19:47 -05:00
|
|
|
|
(defun guix-list-tabulated-sort-key (entry-type)
|
|
|
|
|
"Return ENTRY-TYPE sort key for `tabulated-list-sort-key'."
|
|
|
|
|
(let ((sort-key (guix-list-sort-key entry-type)))
|
|
|
|
|
(and sort-key
|
|
|
|
|
(cons (guix-list-param-title entry-type (car sort-key))
|
|
|
|
|
(cdr sort-key)))))
|
2015-11-18 03:36:27 -05:00
|
|
|
|
|
|
|
|
|
(defun guix-list-tabulated-vector (entry-type fun)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
"Call FUN on each column specification for ENTRY-TYPE.
|
|
|
|
|
|
2015-11-18 03:44:52 -05:00
|
|
|
|
FUN is applied to column specification as arguments (see
|
|
|
|
|
`guix-list-format').
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
Return a vector made of values of FUN calls."
|
|
|
|
|
(apply #'vector
|
|
|
|
|
(mapcar (lambda (col-spec)
|
2015-11-18 03:44:52 -05:00
|
|
|
|
(apply fun col-spec))
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(guix-list-format entry-type))))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(defun guix-list-tabulated-format (entry-type)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
"Return ENTRY-TYPE list specification for `tabulated-list-format'."
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(guix-list-tabulated-vector
|
2014-08-27 08:44:17 -04:00
|
|
|
|
entry-type
|
2015-11-18 03:44:52 -05:00
|
|
|
|
(lambda (param _ &rest rest-spec)
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(cons (guix-list-param-title entry-type param)
|
2015-11-18 03:44:52 -05:00
|
|
|
|
rest-spec))))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-list-insert-entries (entries entry-type)
|
|
|
|
|
"Display ENTRIES of ENTRY-TYPE in the current list buffer.
|
|
|
|
|
ENTRIES should have a form of `guix-entries'."
|
|
|
|
|
(setq tabulated-list-entries
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(guix-list-tabulated-entries entries entry-type))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(tabulated-list-print))
|
|
|
|
|
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(defun guix-list-tabulated-entries (entries entry-type)
|
|
|
|
|
"Return a list of ENTRY-TYPE values for `tabulated-list-entries'."
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(mapcar (lambda (entry)
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(list (guix-entry-id entry)
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(guix-list-tabulated-entry entry entry-type)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
entries))
|
|
|
|
|
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(defun guix-list-tabulated-entry (entry entry-type)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
"Return array of values for `tabulated-list-entries'.
|
2015-11-18 03:36:27 -05:00
|
|
|
|
Parameters are taken from ENTRY-TYPE ENTRY."
|
|
|
|
|
(guix-list-tabulated-vector
|
2014-08-27 08:44:17 -04:00
|
|
|
|
entry-type
|
2015-11-18 03:44:52 -05:00
|
|
|
|
(lambda (param fun &rest _)
|
|
|
|
|
(let ((val (guix-entry-value entry param)))
|
2014-10-10 15:29:24 -04:00
|
|
|
|
(if fun
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(funcall fun val entry)
|
|
|
|
|
(guix-get-string val))))))
|
|
|
|
|
|
2014-10-10 15:29:24 -04:00
|
|
|
|
(defun guix-list-get-one-line (val &optional _)
|
|
|
|
|
"Return one-line string from a multi-line string VAL.
|
|
|
|
|
VAL may be nil."
|
|
|
|
|
(if val
|
|
|
|
|
(guix-get-one-line val)
|
|
|
|
|
(guix-get-string nil)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-list-get-time (seconds &optional _)
|
|
|
|
|
"Return formatted time string from SECONDS."
|
2015-11-17 13:46:31 -05:00
|
|
|
|
(guix-get-string (guix-get-time-string seconds)
|
|
|
|
|
'guix-list-time))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-list-get-file-path (path &optional _)
|
|
|
|
|
"Return PATH button specification for `tabulated-list-entries'."
|
|
|
|
|
(list path
|
|
|
|
|
'face 'guix-list-file-path
|
|
|
|
|
'action (lambda (btn) (find-file (button-label btn)))
|
|
|
|
|
'follow-link t
|
|
|
|
|
'help-echo "Find file"))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-current-id ()
|
|
|
|
|
"Return ID of the current entry."
|
|
|
|
|
(or (tabulated-list-get-id)
|
|
|
|
|
(user-error "No entry here")))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-current-entry ()
|
|
|
|
|
"Return alist of the current entry info."
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(guix-entry-by-id (guix-list-current-id) guix-entries))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-list-for-each-line (fun &rest args)
|
|
|
|
|
"Call FUN with ARGS for each entry line."
|
|
|
|
|
(or (derived-mode-p 'guix-list-mode)
|
|
|
|
|
(error "The current buffer is not in Guix List mode"))
|
|
|
|
|
(save-excursion
|
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
(while (not (eobp))
|
|
|
|
|
(apply fun args)
|
|
|
|
|
(forward-line))))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-fold-lines (fun init)
|
|
|
|
|
"Fold over entry lines in the current list buffer.
|
|
|
|
|
Call FUN with RESULT as argument for each line, using INIT as
|
|
|
|
|
the initial value of RESULT. Return the final result."
|
|
|
|
|
(let ((res init))
|
|
|
|
|
(guix-list-for-each-line
|
|
|
|
|
(lambda () (setq res (funcall fun res))))
|
|
|
|
|
res))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Marking and sorting
|
|
|
|
|
|
|
|
|
|
(defvar-local guix-list-marked nil
|
|
|
|
|
"List of the marked entries.
|
|
|
|
|
Each element of the list has a form:
|
|
|
|
|
|
|
|
|
|
(ID MARK-NAME . ARGS)
|
|
|
|
|
|
|
|
|
|
ID is an entry ID.
|
2015-11-19 03:03:48 -05:00
|
|
|
|
MARK-NAME is a symbol from `guix-list-marks'.
|
2014-08-27 08:44:17 -04:00
|
|
|
|
ARGS is a list of additional values.")
|
|
|
|
|
|
2015-11-19 03:03:48 -05:00
|
|
|
|
(defvar-local guix-list-marks nil
|
|
|
|
|
"Alist of available mark names and mark characters.")
|
|
|
|
|
|
|
|
|
|
(defvar guix-list-default-marks
|
2014-08-27 08:44:17 -04:00
|
|
|
|
'((empty . ?\s)
|
|
|
|
|
(general . ?*))
|
2015-11-19 03:03:48 -05:00
|
|
|
|
"Alist of default mark names and mark characters.")
|
|
|
|
|
|
|
|
|
|
(defun guix-list-marks (entry-type)
|
|
|
|
|
"Return alist of available marks for ENTRY-TYPE."
|
|
|
|
|
(append guix-list-default-marks
|
|
|
|
|
(guix-list-additional-marks entry-type)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-19 03:03:48 -05:00
|
|
|
|
(defun guix-list-get-mark (name)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
"Return mark character by its NAME."
|
2015-11-19 03:03:48 -05:00
|
|
|
|
(or (guix-assq-value guix-list-marks name)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(error "Mark '%S' not found" name)))
|
|
|
|
|
|
2015-11-19 03:03:48 -05:00
|
|
|
|
(defun guix-list-get-mark-string (name)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
"Return mark string by its NAME."
|
|
|
|
|
(string (guix-list-get-mark name)))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-current-mark ()
|
|
|
|
|
"Return mark character of the current line."
|
|
|
|
|
(char-after (line-beginning-position)))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-get-marked (&rest mark-names)
|
|
|
|
|
"Return list of specs of entries marked with any mark from MARK-NAMES.
|
|
|
|
|
Entry specs are elements from `guix-list-marked' list.
|
|
|
|
|
If MARK-NAMES are not specified, use all marks from
|
2015-11-19 03:03:48 -05:00
|
|
|
|
`guix-list-marks' except the `empty' one."
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(or mark-names
|
|
|
|
|
(setq mark-names
|
|
|
|
|
(delq 'empty
|
2015-11-19 03:03:48 -05:00
|
|
|
|
(mapcar #'car guix-list-marks))))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(cl-remove-if-not (lambda (assoc)
|
|
|
|
|
(memq (cadr assoc) mark-names))
|
|
|
|
|
guix-list-marked))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-get-marked-args (mark-name)
|
|
|
|
|
"Return list of (ID . ARGS) elements from lines marked with MARK-NAME.
|
|
|
|
|
See `guix-list-marked' for the meaning of ARGS."
|
|
|
|
|
(mapcar (lambda (spec)
|
|
|
|
|
(let ((id (car spec))
|
|
|
|
|
(args (cddr spec)))
|
|
|
|
|
(cons id args)))
|
|
|
|
|
(guix-list-get-marked mark-name)))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-get-marked-id-list (&rest mark-names)
|
|
|
|
|
"Return list of IDs of entries marked with any mark from MARK-NAMES.
|
|
|
|
|
See `guix-list-get-marked' for details."
|
|
|
|
|
(mapcar #'car (apply #'guix-list-get-marked mark-names)))
|
|
|
|
|
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(defun guix-list--mark (mark-name &optional advance &rest args)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
"Put a mark on the current line.
|
|
|
|
|
Also add the current entry to `guix-list-marked' using its ID and ARGS.
|
2015-11-19 03:03:48 -05:00
|
|
|
|
MARK-NAME is a symbol from `guix-list-marks'.
|
2015-05-27 09:51:25 -04:00
|
|
|
|
If ADVANCE is non-nil, move forward by one line after marking."
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(let ((id (guix-list-current-id)))
|
|
|
|
|
(if (eq mark-name 'empty)
|
|
|
|
|
(setq guix-list-marked (assq-delete-all id guix-list-marked))
|
|
|
|
|
(let ((assoc (assq id guix-list-marked))
|
|
|
|
|
(val (cons mark-name args)))
|
|
|
|
|
(if assoc
|
|
|
|
|
(setcdr assoc val)
|
|
|
|
|
(push (cons id val) guix-list-marked)))))
|
|
|
|
|
(tabulated-list-put-tag (guix-list-get-mark-string mark-name)
|
|
|
|
|
advance))
|
|
|
|
|
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(defun guix-list-mark (&optional arg)
|
|
|
|
|
"Mark the current line and move to the next line.
|
|
|
|
|
With ARG, mark all lines."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(if arg
|
|
|
|
|
(guix-list-mark-all)
|
|
|
|
|
(guix-list--mark 'general t)))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-mark-all (&optional mark-name)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
"Mark all lines with MARK-NAME mark.
|
2015-11-19 03:03:48 -05:00
|
|
|
|
MARK-NAME is a symbol from `guix-list-marks'.
|
2014-08-27 08:44:17 -04:00
|
|
|
|
Interactively, put a general mark on all lines."
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(interactive)
|
|
|
|
|
(or mark-name (setq mark-name 'general))
|
|
|
|
|
(guix-list-for-each-line #'guix-list--mark mark-name))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(defun guix-list-unmark (&optional arg)
|
|
|
|
|
"Unmark the current line and move to the next line.
|
|
|
|
|
With ARG, unmark all lines."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(if arg
|
|
|
|
|
(guix-list-unmark-all)
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(guix-list--mark 'empty t)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-list-unmark-backward ()
|
|
|
|
|
"Move up one line and unmark it."
|
|
|
|
|
(interactive)
|
|
|
|
|
(forward-line -1)
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(guix-list--mark 'empty))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-list-unmark-all ()
|
|
|
|
|
"Unmark all lines."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-list-mark-all 'empty))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-restore-marks ()
|
2015-11-19 03:03:48 -05:00
|
|
|
|
"Put marks according to `guix-list-marked'."
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(guix-list-for-each-line
|
|
|
|
|
(lambda ()
|
2015-08-16 00:11:57 -04:00
|
|
|
|
(let ((mark-name (car (guix-assq-value guix-list-marked
|
|
|
|
|
(guix-list-current-id)))))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(tabulated-list-put-tag
|
|
|
|
|
(guix-list-get-mark-string (or mark-name 'empty)))))))
|
|
|
|
|
|
|
|
|
|
(defun guix-list-sort (&optional n)
|
|
|
|
|
"Sort guix list entries by the column at point.
|
|
|
|
|
With a numeric prefix argument N, sort the Nth column.
|
|
|
|
|
Same as `tabulated-list-sort', but also restore marks after sorting."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(tabulated-list-sort n)
|
|
|
|
|
(guix-list-restore-marks))
|
|
|
|
|
|
|
|
|
|
|
2015-11-19 08:43:10 -05:00
|
|
|
|
;;; Major mode and interface definer
|
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(defvar guix-list-mode-map
|
|
|
|
|
(let ((map (make-sparse-keymap)))
|
2015-06-24 03:36:18 -04:00
|
|
|
|
(set-keymap-parent
|
2015-11-21 04:25:19 -05:00
|
|
|
|
map (make-composed-keymap guix-buffer-map
|
2015-06-24 03:36:18 -04:00
|
|
|
|
tabulated-list-mode-map))
|
2014-09-17 09:52:08 -04:00
|
|
|
|
(define-key map (kbd "RET") 'guix-list-describe)
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(define-key map (kbd "i") 'guix-list-describe)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(define-key map (kbd "m") 'guix-list-mark)
|
|
|
|
|
(define-key map (kbd "*") 'guix-list-mark)
|
|
|
|
|
(define-key map (kbd "u") 'guix-list-unmark)
|
|
|
|
|
(define-key map (kbd "DEL") 'guix-list-unmark-backward)
|
|
|
|
|
(define-key map [remap tabulated-list-sort] 'guix-list-sort)
|
|
|
|
|
map)
|
2015-11-19 08:43:10 -05:00
|
|
|
|
"Keymap for `guix-list-mode' buffers.")
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(define-derived-mode guix-list-mode tabulated-list-mode "Guix-List"
|
2015-11-19 08:43:10 -05:00
|
|
|
|
"Parent mode for displaying data in 'list' form.")
|
|
|
|
|
|
|
|
|
|
(defun guix-list-mode-initialize (entry-type)
|
|
|
|
|
"Set up the current 'list' buffer for displaying ENTRY-TYPE entries."
|
|
|
|
|
(setq tabulated-list-padding 2
|
|
|
|
|
tabulated-list-format (guix-list-tabulated-format entry-type)
|
|
|
|
|
tabulated-list-sort-key (guix-list-tabulated-sort-key entry-type))
|
|
|
|
|
(setq-local guix-list-marks (guix-list-marks entry-type))
|
|
|
|
|
(tabulated-list-init-header))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-20 04:38:31 -05:00
|
|
|
|
(defmacro guix-list-define-interface (entry-type &rest args)
|
|
|
|
|
"Define 'list' interface for displaying ENTRY-TYPE entries.
|
2015-11-19 08:56:19 -05:00
|
|
|
|
Remaining arguments (ARGS) should have a form [KEYWORD VALUE] ...
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-19 08:56:19 -05:00
|
|
|
|
Required keywords:
|
|
|
|
|
|
|
|
|
|
- `:format' - default value of the generated
|
|
|
|
|
`guix-ENTRY-TYPE-list-format' variable.
|
|
|
|
|
|
|
|
|
|
Optional keywords:
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-19 08:19:47 -05:00
|
|
|
|
- `:sort-key' - default value of the generated
|
|
|
|
|
`guix-ENTRY-TYPE-list-sort-key' variable.
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-19 07:58:19 -05:00
|
|
|
|
- `:describe-function' - default value of the generated
|
|
|
|
|
`guix-ENTRY-TYPE-describe-function' variable.
|
|
|
|
|
|
2015-11-19 03:03:48 -05:00
|
|
|
|
- `:marks' - default value of the generated
|
|
|
|
|
`guix-ENTRY-TYPE-list-marks' variable.
|
2015-11-20 04:38:31 -05:00
|
|
|
|
|
|
|
|
|
The rest keyword arguments are passed to
|
|
|
|
|
`guix-buffer-define-interface' macro."
|
|
|
|
|
(declare (indent 1))
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(let* ((entry-type-str (symbol-name entry-type))
|
|
|
|
|
(prefix (concat "guix-" entry-type-str "-list"))
|
|
|
|
|
(group (intern prefix))
|
|
|
|
|
(mode-str (concat prefix "-mode"))
|
|
|
|
|
(init-fun (intern (concat prefix "-mode-initialize")))
|
|
|
|
|
(describe-var (intern (concat prefix "-describe-function")))
|
|
|
|
|
(describe-count-var (intern (concat prefix
|
|
|
|
|
"-describe-warning-count")))
|
2015-11-19 08:56:19 -05:00
|
|
|
|
(format-var (intern (concat prefix "-format")))
|
2015-11-19 08:19:47 -05:00
|
|
|
|
(sort-key-var (intern (concat prefix "-sort-key")))
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(marks-var (intern (concat prefix "-marks"))))
|
2015-11-18 14:28:13 -05:00
|
|
|
|
(guix-keyword-args-let args
|
2015-11-19 07:58:19 -05:00
|
|
|
|
((describe-val :describe-function)
|
|
|
|
|
(describe-count-val :describe-count 10)
|
2015-11-19 08:56:19 -05:00
|
|
|
|
(format-val :format)
|
2015-11-19 08:19:47 -05:00
|
|
|
|
(sort-key-val :sort-key)
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(marks-val :marks))
|
2015-11-18 14:28:13 -05:00
|
|
|
|
`(progn
|
2015-11-19 08:56:19 -05:00
|
|
|
|
(defcustom ,format-var ,format-val
|
|
|
|
|
,(format "\
|
|
|
|
|
List of format values of the displayed columns.
|
|
|
|
|
Each element of the list has a form:
|
|
|
|
|
|
|
|
|
|
(PARAM VALUE-FUN WIDTH SORT . PROPS)
|
|
|
|
|
|
|
|
|
|
PARAM is a name of '%s' entry parameter.
|
|
|
|
|
|
|
|
|
|
VALUE-FUN may be either nil or a function returning a value that
|
|
|
|
|
will be inserted. The function is called with 2 arguments: the
|
|
|
|
|
first one is the value of the parameter; the second one is an
|
|
|
|
|
entry (alist of parameter names and values).
|
|
|
|
|
|
|
|
|
|
For the meaning of WIDTH, SORT and PROPS, see
|
|
|
|
|
`tabulated-list-format'."
|
|
|
|
|
entry-type-str)
|
|
|
|
|
:type 'sexp
|
|
|
|
|
:group ',group)
|
|
|
|
|
|
2015-11-19 08:19:47 -05:00
|
|
|
|
(defcustom ,sort-key-var ,sort-key-val
|
|
|
|
|
,(format "\
|
|
|
|
|
Default sort key for 'list' buffer with '%s' entries.
|
|
|
|
|
Should be nil (no sort) or have a form:
|
|
|
|
|
|
|
|
|
|
(PARAM . FLIP)
|
|
|
|
|
|
|
|
|
|
PARAM is the name of '%s' entry parameter. For the meaning of
|
|
|
|
|
FLIP, see `tabulated-list-sort-key'."
|
|
|
|
|
entry-type-str entry-type-str)
|
|
|
|
|
:type '(choice (const :tag "No sort" nil)
|
|
|
|
|
(cons symbol boolean))
|
|
|
|
|
:group ',group)
|
|
|
|
|
|
2015-11-19 03:03:48 -05:00
|
|
|
|
(defvar ,marks-var ,marks-val
|
|
|
|
|
,(format "\
|
|
|
|
|
Alist of additional marks for 'list' buffer with '%s' entries.
|
|
|
|
|
Marks from this list are used along with `guix-list-default-marks'."
|
|
|
|
|
entry-type-str))
|
2015-11-18 14:28:13 -05:00
|
|
|
|
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(defcustom ,describe-count-var ,describe-count-val
|
|
|
|
|
,(format "\
|
|
|
|
|
The maximum number of '%s' entries to describe without a warning.
|
|
|
|
|
If a user wants to describe more than this number of marked
|
|
|
|
|
entries, he will be prompted for confirmation.
|
|
|
|
|
See also `guix-list-describe'."
|
|
|
|
|
entry-type-str)
|
|
|
|
|
:type 'integer
|
|
|
|
|
:group ',group)
|
|
|
|
|
|
|
|
|
|
(defvar ,describe-var ,describe-val
|
|
|
|
|
,(format "Function used to describe '%s' entries."
|
|
|
|
|
entry-type-str))
|
|
|
|
|
|
2015-11-18 14:28:13 -05:00
|
|
|
|
(defun ,init-fun ()
|
|
|
|
|
,(concat "Initial settings for `" mode-str "'.")
|
2015-11-19 08:43:10 -05:00
|
|
|
|
(guix-list-mode-initialize ',entry-type))
|
2015-11-19 03:03:48 -05:00
|
|
|
|
|
|
|
|
|
(guix-alist-put!
|
2015-11-19 07:58:19 -05:00
|
|
|
|
'((describe . ,describe-var)
|
|
|
|
|
(describe-count . ,describe-count-var)
|
2015-11-19 08:56:19 -05:00
|
|
|
|
(format . ,format-var)
|
2015-11-19 08:19:47 -05:00
|
|
|
|
(sort-key . ,sort-key-var)
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(marks . ,marks-var))
|
2015-11-20 04:38:31 -05:00
|
|
|
|
'guix-list-data ',entry-type)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2015-11-20 04:38:31 -05:00
|
|
|
|
(guix-buffer-define-interface list ,entry-type
|
|
|
|
|
,@%foreign-args)))))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Displaying packages
|
|
|
|
|
|
2015-11-20 04:38:31 -05:00
|
|
|
|
(guix-ui-list-define-interface package
|
2015-11-19 08:56:19 -05:00
|
|
|
|
:format '((name guix-package-list-get-name 20 t)
|
|
|
|
|
(version nil 10 nil)
|
|
|
|
|
(outputs nil 13 t)
|
|
|
|
|
(installed guix-package-list-get-installed-outputs 13 t)
|
|
|
|
|
(synopsis guix-list-get-one-line 30 nil))
|
2015-11-19 08:19:47 -05:00
|
|
|
|
:sort-key '(name)
|
2015-11-19 03:03:48 -05:00
|
|
|
|
:marks '((install . ?I)
|
|
|
|
|
(upgrade . ?U)
|
|
|
|
|
(delete . ?D)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2014-09-06 04:08:42 -04:00
|
|
|
|
(defface guix-package-list-installed
|
|
|
|
|
'((t :inherit guix-package-info-installed-outputs))
|
|
|
|
|
"Face used if there are installed outputs for the current package."
|
2015-09-14 16:32:53 -04:00
|
|
|
|
:group 'guix-package-list-faces)
|
2014-09-06 04:08:42 -04:00
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(defface guix-package-list-obsolete
|
|
|
|
|
'((t :inherit guix-package-info-obsolete))
|
|
|
|
|
"Face used if a package is obsolete."
|
2015-09-14 16:32:53 -04:00
|
|
|
|
:group 'guix-package-list-faces)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defcustom guix-package-list-generation-marking-enabled nil
|
|
|
|
|
"If non-nil, allow putting marks in a list with 'generation packages'.
|
|
|
|
|
|
|
|
|
|
By default this is disabled, because it may be confusing. For
|
|
|
|
|
example a package is installed in some generation, so a user can
|
|
|
|
|
mark it for deletion in the list of packages from this
|
|
|
|
|
generation, but the package may not be installed in the latest
|
|
|
|
|
generation, so actually it cannot be deleted.
|
|
|
|
|
|
|
|
|
|
If you managed to understand the explanation above or if you
|
|
|
|
|
really know what you do or if you just don't care, you can set
|
|
|
|
|
this variable to t. It should not do much harm anyway (most
|
|
|
|
|
likely)."
|
|
|
|
|
:type 'boolean
|
|
|
|
|
:group 'guix-package-list)
|
|
|
|
|
|
|
|
|
|
(let ((map guix-package-list-mode-map))
|
2015-11-19 12:09:16 -05:00
|
|
|
|
(define-key map (kbd "e") 'guix-package-list-edit)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(define-key map (kbd "x") 'guix-package-list-execute)
|
|
|
|
|
(define-key map (kbd "i") 'guix-package-list-mark-install)
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(define-key map (kbd "d") 'guix-package-list-mark-delete)
|
|
|
|
|
(define-key map (kbd "U") 'guix-package-list-mark-upgrade)
|
|
|
|
|
(define-key map (kbd "^") 'guix-package-list-mark-upgrades))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-package-list-get-name (name entry)
|
|
|
|
|
"Return NAME of the package ENTRY.
|
2014-09-06 04:08:42 -04:00
|
|
|
|
Colorize it with `guix-package-list-installed' or
|
|
|
|
|
`guix-package-list-obsolete' if needed."
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(guix-get-string name
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(cond ((guix-entry-value entry 'obsolete)
|
2014-09-06 04:08:42 -04:00
|
|
|
|
'guix-package-list-obsolete)
|
2015-10-22 03:08:42 -04:00
|
|
|
|
((guix-entry-value entry 'installed)
|
2014-09-06 04:08:42 -04:00
|
|
|
|
'guix-package-list-installed))))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-package-list-get-installed-outputs (installed &optional _)
|
|
|
|
|
"Return string with outputs from INSTALLED entries."
|
|
|
|
|
(guix-get-string
|
|
|
|
|
(mapcar (lambda (entry)
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(guix-entry-value entry 'output))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
installed)))
|
|
|
|
|
|
|
|
|
|
(defun guix-package-list-marking-check ()
|
|
|
|
|
"Signal an error if marking is disabled for the current buffer."
|
|
|
|
|
(when (and (not guix-package-list-generation-marking-enabled)
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(or (derived-mode-p 'guix-package-list-mode)
|
|
|
|
|
(derived-mode-p 'guix-output-list-mode))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(eq guix-search-type 'generation))
|
|
|
|
|
(error "Action marks are disabled for lists of 'generation packages'")))
|
|
|
|
|
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(defun guix-package-list-mark-outputs (mark default
|
|
|
|
|
&optional prompt available)
|
|
|
|
|
"Mark the current package with MARK and move to the next line.
|
|
|
|
|
If PROMPT is non-nil, use it to ask a user for outputs from
|
|
|
|
|
AVAILABLE list, otherwise mark all DEFAULT outputs."
|
|
|
|
|
(let ((outputs (if prompt
|
|
|
|
|
(guix-completing-read-multiple
|
|
|
|
|
prompt available nil t)
|
|
|
|
|
default)))
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(apply #'guix-list--mark mark t outputs)))
|
2014-09-06 10:00:45 -04:00
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(defun guix-package-list-mark-install (&optional arg)
|
|
|
|
|
"Mark the current package for installation and move to the next line.
|
|
|
|
|
With ARG, prompt for the outputs to install (several outputs may
|
|
|
|
|
be separated with \",\")."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(guix-package-list-marking-check)
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(let* ((entry (guix-list-current-entry))
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(all (guix-entry-value entry 'outputs))
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(installed (guix-package-installed-outputs entry))
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(available (cl-set-difference all installed :test #'string=)))
|
|
|
|
|
(or available
|
|
|
|
|
(user-error "This package is already installed"))
|
|
|
|
|
(guix-package-list-mark-outputs
|
|
|
|
|
'install '("out")
|
|
|
|
|
(and arg "Output(s) to install: ")
|
|
|
|
|
available)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-package-list-mark-delete (&optional arg)
|
|
|
|
|
"Mark the current package for deletion and move to the next line.
|
|
|
|
|
With ARG, prompt for the outputs to delete (several outputs may
|
|
|
|
|
be separated with \",\")."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(guix-package-list-marking-check)
|
|
|
|
|
(let* ((entry (guix-list-current-entry))
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(installed (guix-package-installed-outputs entry)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(or installed
|
|
|
|
|
(user-error "This package is not installed"))
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(guix-package-list-mark-outputs
|
|
|
|
|
'delete installed
|
|
|
|
|
(and arg "Output(s) to delete: ")
|
|
|
|
|
installed)))
|
|
|
|
|
|
|
|
|
|
(defun guix-package-list-mark-upgrade (&optional arg)
|
|
|
|
|
"Mark the current package for upgrading and move to the next line.
|
|
|
|
|
With ARG, prompt for the outputs to upgrade (several outputs may
|
|
|
|
|
be separated with \",\")."
|
|
|
|
|
(interactive "P")
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(guix-package-list-marking-check)
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(let* ((entry (guix-list-current-entry))
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(installed (guix-package-installed-outputs entry)))
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(or installed
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(user-error "This package is not installed"))
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(when (or (guix-entry-value entry 'obsolete)
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(y-or-n-p "This package is not obsolete. Try to upgrade it anyway? "))
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(guix-package-list-mark-outputs
|
|
|
|
|
'upgrade installed
|
|
|
|
|
(and arg "Output(s) to upgrade: ")
|
|
|
|
|
installed))))
|
|
|
|
|
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(defun guix-list-mark-package-upgrades (fun)
|
|
|
|
|
"Mark all obsolete packages for upgrading.
|
|
|
|
|
Use FUN to perform marking of the current line. FUN should
|
|
|
|
|
accept an entry as argument."
|
2014-09-06 10:00:45 -04:00
|
|
|
|
(guix-package-list-marking-check)
|
|
|
|
|
(let ((obsolete (cl-remove-if-not
|
|
|
|
|
(lambda (entry)
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(guix-entry-value entry 'obsolete))
|
2014-09-06 10:00:45 -04:00
|
|
|
|
guix-entries)))
|
|
|
|
|
(guix-list-for-each-line
|
|
|
|
|
(lambda ()
|
|
|
|
|
(let* ((id (guix-list-current-id))
|
|
|
|
|
(entry (cl-find-if
|
|
|
|
|
(lambda (entry)
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(equal id (guix-entry-id entry)))
|
2014-09-06 10:00:45 -04:00
|
|
|
|
obsolete)))
|
|
|
|
|
(when entry
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(funcall fun entry)))))))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(defun guix-package-list-mark-upgrades ()
|
|
|
|
|
"Mark all obsolete packages for upgrading."
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(interactive)
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(guix-list-mark-package-upgrades
|
|
|
|
|
(lambda (entry)
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(apply #'guix-list--mark
|
2014-09-19 01:57:36 -04:00
|
|
|
|
'upgrade nil
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(guix-package-installed-outputs entry)))))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-list-execute-package-actions (fun)
|
|
|
|
|
"Perform actions on the marked packages.
|
|
|
|
|
Use FUN to define actions suitable for `guix-process-package-actions'.
|
|
|
|
|
FUN should accept action-type as argument."
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(let ((actions (delq nil
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(mapcar fun '(install delete upgrade)))))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(if actions
|
emacs: Improve interface for working with multiple profiles.
Suggested by David Thompson, Ludovic Courtès and Mathieu Lirzin.
* emacs/guix-base.el (guix-profile-prompt): New procedure.
(guix-set-current-profile): Use it.
(guix-buffer-name-simple, guix-buffer-name-default, guix-buffer-name): New
procedures.
(guix-buffer-name-function, guix-profile): New variables.
(guix-set-vars, guix-get-entries, guix-get-show-entries, guix-set-buffer,
guix-history-call, guix-process-package-actions,
guix-continue-package-operation-p, guix-delete-generations,
guix-switch-to-generation): Add 'profile' argument.
* emacs/guix.el (guix-get-show-packages, guix-get-show-generations,
guix-search-by-name, guix-search-by-regexp, guix-installed-packages,
guix-obsolete-packages, guix-all-available-packages,
guix-newest-available-packages, guix-generations, guix-generations-by-time):
Likewise.
(guix-last-generations): New command.
* emacs/guix-info.el: Adjust for using 'profile' argument where needed.
* emacs/guix-list.el: Likewise.
* doc/emacs.texi (Emacs Commands): Document 'guix-last-generations' and using
"C-u" for commands.
(Emacs Buffer Names): Document 'guix-buffer-name-function'.
2014-10-17 14:21:32 -04:00
|
|
|
|
(guix-process-package-actions
|
|
|
|
|
guix-profile actions (current-buffer))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(user-error "No operations specified"))))
|
|
|
|
|
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(defun guix-package-list-execute ()
|
|
|
|
|
"Perform actions on the marked packages."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-list-execute-package-actions #'guix-package-list-make-action))
|
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(defun guix-package-list-make-action (action-type)
|
|
|
|
|
"Return action specification for the packages marked with ACTION-TYPE.
|
|
|
|
|
Return nil, if there are no packages marked with ACTION-TYPE.
|
|
|
|
|
The specification is suitable for `guix-process-package-actions'."
|
|
|
|
|
(let ((specs (guix-list-get-marked-args action-type)))
|
|
|
|
|
(and specs (cons action-type specs))))
|
|
|
|
|
|
2015-11-19 12:09:16 -05:00
|
|
|
|
(defun guix-package-list-edit ()
|
|
|
|
|
"Go to the location of the current package."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-edit (guix-list-current-id)))
|
|
|
|
|
|
2014-09-19 01:57:36 -04:00
|
|
|
|
|
|
|
|
|
;;; Displaying outputs
|
|
|
|
|
|
2015-11-20 04:38:31 -05:00
|
|
|
|
(guix-ui-list-define-interface output
|
2015-06-19 14:47:31 -04:00
|
|
|
|
:buffer-name "*Guix Package List*"
|
2015-11-19 07:58:19 -05:00
|
|
|
|
:describe-function 'guix-output-list-describe
|
2015-11-19 08:56:19 -05:00
|
|
|
|
:format '((name guix-package-list-get-name 20 t)
|
|
|
|
|
(version nil 10 nil)
|
|
|
|
|
(output nil 9 t)
|
|
|
|
|
(installed nil 12 t)
|
|
|
|
|
(synopsis guix-list-get-one-line 30 nil))
|
2015-11-20 04:38:31 -05:00
|
|
|
|
:required '(package-id)
|
2015-11-19 08:19:47 -05:00
|
|
|
|
:sort-key '(name)
|
2015-11-19 03:03:48 -05:00
|
|
|
|
:marks '((install . ?I)
|
|
|
|
|
(upgrade . ?U)
|
|
|
|
|
(delete . ?D)))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
|
|
|
|
|
(let ((map guix-output-list-mode-map))
|
2015-11-19 12:09:16 -05:00
|
|
|
|
(define-key map (kbd "e") 'guix-output-list-edit)
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(define-key map (kbd "x") 'guix-output-list-execute)
|
|
|
|
|
(define-key map (kbd "i") 'guix-output-list-mark-install)
|
|
|
|
|
(define-key map (kbd "d") 'guix-output-list-mark-delete)
|
|
|
|
|
(define-key map (kbd "U") 'guix-output-list-mark-upgrade)
|
|
|
|
|
(define-key map (kbd "^") 'guix-output-list-mark-upgrades))
|
|
|
|
|
|
|
|
|
|
(defun guix-output-list-mark-install ()
|
|
|
|
|
"Mark the current output for installation and move to the next line."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-package-list-marking-check)
|
|
|
|
|
(let* ((entry (guix-list-current-entry))
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(installed (guix-entry-value entry 'installed)))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(if installed
|
|
|
|
|
(user-error "This output is already installed")
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(guix-list--mark 'install t))))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-output-list-mark-delete ()
|
|
|
|
|
"Mark the current output for deletion and move to the next line."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-package-list-marking-check)
|
|
|
|
|
(let* ((entry (guix-list-current-entry))
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(installed (guix-entry-value entry 'installed)))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(if installed
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(guix-list--mark 'delete t)
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(user-error "This output is not installed"))))
|
|
|
|
|
|
|
|
|
|
(defun guix-output-list-mark-upgrade ()
|
|
|
|
|
"Mark the current output for deletion and move to the next line."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-package-list-marking-check)
|
|
|
|
|
(let* ((entry (guix-list-current-entry))
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(installed (guix-entry-value entry 'installed)))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(or installed
|
|
|
|
|
(user-error "This output is not installed"))
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(when (or (guix-entry-value entry 'obsolete)
|
2014-09-19 01:57:36 -04:00
|
|
|
|
(y-or-n-p "This output is not obsolete. Try to upgrade it anyway? "))
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(guix-list--mark 'upgrade t))))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-output-list-mark-upgrades ()
|
|
|
|
|
"Mark all obsolete package outputs for upgrading."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-list-mark-package-upgrades
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(lambda (_) (guix-list--mark 'upgrade))))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-output-list-execute ()
|
|
|
|
|
"Perform actions on the marked outputs."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-list-execute-package-actions #'guix-output-list-make-action))
|
|
|
|
|
|
|
|
|
|
(defun guix-output-list-make-action (action-type)
|
|
|
|
|
"Return action specification for the outputs marked with ACTION-TYPE.
|
|
|
|
|
Return nil, if there are no outputs marked with ACTION-TYPE.
|
|
|
|
|
The specification is suitable for `guix-process-output-actions'."
|
|
|
|
|
(let ((ids (guix-list-get-marked-id-list action-type)))
|
|
|
|
|
(and ids (cons action-type
|
2015-11-18 03:36:27 -05:00
|
|
|
|
(mapcar #'guix-package-id-and-output-by-output-id
|
2014-09-19 01:57:36 -04:00
|
|
|
|
ids)))))
|
|
|
|
|
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(defun guix-output-list-describe (ids)
|
|
|
|
|
"Describe outputs with IDS (list of output identifiers).
|
|
|
|
|
See `guix-package-info-type'."
|
2014-09-28 01:32:41 -04:00
|
|
|
|
(if (eq guix-package-info-type 'output)
|
2015-11-19 07:58:19 -05:00
|
|
|
|
(apply #'guix-get-show-entries
|
|
|
|
|
guix-profile 'info 'output 'id ids)
|
|
|
|
|
(let ((pids (mapcar (lambda (oid)
|
|
|
|
|
(car (guix-package-id-and-output-by-output-id
|
|
|
|
|
oid)))
|
|
|
|
|
ids)))
|
|
|
|
|
(apply #'guix-get-show-entries
|
|
|
|
|
guix-profile 'info 'package 'id
|
|
|
|
|
(cl-remove-duplicates pids)))))
|
2014-09-19 01:57:36 -04:00
|
|
|
|
|
2015-11-19 12:09:16 -05:00
|
|
|
|
(defun guix-output-list-edit ()
|
|
|
|
|
"Go to the location of the current package."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-edit (guix-entry-value (guix-list-current-entry)
|
|
|
|
|
'package-id)))
|
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
;;; Displaying generations
|
|
|
|
|
|
2015-11-20 04:38:31 -05:00
|
|
|
|
(guix-ui-list-define-interface generation
|
2015-11-19 08:56:19 -05:00
|
|
|
|
:format '((number nil 5 guix-list-sort-numerically-0 :right-align t)
|
|
|
|
|
(current guix-generation-list-get-current 10 t)
|
|
|
|
|
(time guix-list-get-time 20 t)
|
|
|
|
|
(path guix-list-get-file-path 30 t))
|
2015-11-21 03:35:43 -05:00
|
|
|
|
:titles '((number . "N."))
|
2015-11-19 08:19:47 -05:00
|
|
|
|
:sort-key '(number . t)
|
2015-11-19 03:03:48 -05:00
|
|
|
|
:marks '((delete . ?D)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
|
|
|
|
(let ((map guix-generation-list-mode-map))
|
|
|
|
|
(define-key map (kbd "RET") 'guix-generation-list-show-packages)
|
emacs: Add interface for comparing generations.
Suggested by Ludovic Courtès.
* doc/emacs.texi (Emacs List buffer): Document new key bindings.
* emacs/guix-base.el (guix-generation-packages-buffer-name-function,
guix-generation-packages-update-buffer, guix-output-name-width): New
variables.
(guix-generation-file, guix-manifest-file, guix-generation-packages,
guix-generation-packages-buffer-name-default,
guix-generation-packages-buffer-name-long,
guix-generation-packages-buffer-name, guix-generation-packages-buffer,
guix-generation-insert-package, guix-generation-insert-packages,
guix-profile-generation-manifest-file,
guix-profile-generation-packages-buffer): New procedures.
* emacs/guix-list.el: Add key bindings for comparing generations.
(guix-generation-list-generations-to-compare,
guix-generation-list-show-added-packages,
guix-generation-list-show-removed-packages, guix-generation-list-compare,
guix-generation-list-ediff-manifests, guix-generation-list-diff-manifests,
guix-generation-list-ediff-packages, guix-generation-list-diff-packages,
guix-generation-list-ediff, guix-generation-list-diff): New procedures.
* emacs/guix-messages.el (guix-messages): Add 'generation-diff' search type.
(guix-message-outputs-by-diff): New procedure.
* emacs/guix-utils.el (guix-diff-switches): New variable.
(guix-diff): New procedure.
* emacs/guix-main.scm (package/output-sexps): Handle 'generation-diff' search
type.
(manifest-entry->package-specification,
manifest-entries->package-specifications, generation-package-specifications,
generation-package-specifications+paths, generation-difference): New
procedures.
2014-11-02 05:58:21 -05:00
|
|
|
|
(define-key map (kbd "+") 'guix-generation-list-show-added-packages)
|
|
|
|
|
(define-key map (kbd "-") 'guix-generation-list-show-removed-packages)
|
|
|
|
|
(define-key map (kbd "=") 'guix-generation-list-diff)
|
|
|
|
|
(define-key map (kbd "D") 'guix-generation-list-diff)
|
|
|
|
|
(define-key map (kbd "e") 'guix-generation-list-ediff)
|
2014-10-05 04:31:23 -04:00
|
|
|
|
(define-key map (kbd "x") 'guix-generation-list-execute)
|
2014-10-10 15:58:30 -04:00
|
|
|
|
(define-key map (kbd "s") 'guix-generation-list-switch)
|
2014-10-05 04:31:23 -04:00
|
|
|
|
(define-key map (kbd "d") 'guix-generation-list-mark-delete))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
2014-10-10 15:50:15 -04:00
|
|
|
|
(defun guix-generation-list-get-current (val &optional _)
|
|
|
|
|
"Return string from VAL showing whether this generation is current.
|
|
|
|
|
VAL is a boolean value."
|
|
|
|
|
(if val "(current)" ""))
|
|
|
|
|
|
2014-10-10 15:58:30 -04:00
|
|
|
|
(defun guix-generation-list-switch ()
|
|
|
|
|
"Switch current profile to the generation at point."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let* ((entry (guix-list-current-entry))
|
2015-10-22 03:08:42 -04:00
|
|
|
|
(current (guix-entry-value entry 'current))
|
|
|
|
|
(number (guix-entry-value entry 'number)))
|
2014-10-10 15:58:30 -04:00
|
|
|
|
(if current
|
|
|
|
|
(user-error "This generation is already the current one")
|
emacs: Improve interface for working with multiple profiles.
Suggested by David Thompson, Ludovic Courtès and Mathieu Lirzin.
* emacs/guix-base.el (guix-profile-prompt): New procedure.
(guix-set-current-profile): Use it.
(guix-buffer-name-simple, guix-buffer-name-default, guix-buffer-name): New
procedures.
(guix-buffer-name-function, guix-profile): New variables.
(guix-set-vars, guix-get-entries, guix-get-show-entries, guix-set-buffer,
guix-history-call, guix-process-package-actions,
guix-continue-package-operation-p, guix-delete-generations,
guix-switch-to-generation): Add 'profile' argument.
* emacs/guix.el (guix-get-show-packages, guix-get-show-generations,
guix-search-by-name, guix-search-by-regexp, guix-installed-packages,
guix-obsolete-packages, guix-all-available-packages,
guix-newest-available-packages, guix-generations, guix-generations-by-time):
Likewise.
(guix-last-generations): New command.
* emacs/guix-info.el: Adjust for using 'profile' argument where needed.
* emacs/guix-list.el: Likewise.
* doc/emacs.texi (Emacs Commands): Document 'guix-last-generations' and using
"C-u" for commands.
(Emacs Buffer Names): Document 'guix-buffer-name-function'.
2014-10-17 14:21:32 -04:00
|
|
|
|
(guix-switch-to-generation guix-profile number (current-buffer)))))
|
2014-10-10 15:58:30 -04:00
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(defun guix-generation-list-show-packages ()
|
|
|
|
|
"List installed packages for the generation at point."
|
|
|
|
|
(interactive)
|
emacs: Improve interface for working with multiple profiles.
Suggested by David Thompson, Ludovic Courtès and Mathieu Lirzin.
* emacs/guix-base.el (guix-profile-prompt): New procedure.
(guix-set-current-profile): Use it.
(guix-buffer-name-simple, guix-buffer-name-default, guix-buffer-name): New
procedures.
(guix-buffer-name-function, guix-profile): New variables.
(guix-set-vars, guix-get-entries, guix-get-show-entries, guix-set-buffer,
guix-history-call, guix-process-package-actions,
guix-continue-package-operation-p, guix-delete-generations,
guix-switch-to-generation): Add 'profile' argument.
* emacs/guix.el (guix-get-show-packages, guix-get-show-generations,
guix-search-by-name, guix-search-by-regexp, guix-installed-packages,
guix-obsolete-packages, guix-all-available-packages,
guix-newest-available-packages, guix-generations, guix-generations-by-time):
Likewise.
(guix-last-generations): New command.
* emacs/guix-info.el: Adjust for using 'profile' argument where needed.
* emacs/guix-list.el: Likewise.
* doc/emacs.texi (Emacs Commands): Document 'guix-last-generations' and using
"C-u" for commands.
(Emacs Buffer Names): Document 'guix-buffer-name-function'.
2014-10-17 14:21:32 -04:00
|
|
|
|
(guix-get-show-entries guix-profile 'list guix-package-list-type
|
|
|
|
|
'generation (guix-list-current-id)))
|
2014-08-27 08:44:17 -04:00
|
|
|
|
|
emacs: Add interface for comparing generations.
Suggested by Ludovic Courtès.
* doc/emacs.texi (Emacs List buffer): Document new key bindings.
* emacs/guix-base.el (guix-generation-packages-buffer-name-function,
guix-generation-packages-update-buffer, guix-output-name-width): New
variables.
(guix-generation-file, guix-manifest-file, guix-generation-packages,
guix-generation-packages-buffer-name-default,
guix-generation-packages-buffer-name-long,
guix-generation-packages-buffer-name, guix-generation-packages-buffer,
guix-generation-insert-package, guix-generation-insert-packages,
guix-profile-generation-manifest-file,
guix-profile-generation-packages-buffer): New procedures.
* emacs/guix-list.el: Add key bindings for comparing generations.
(guix-generation-list-generations-to-compare,
guix-generation-list-show-added-packages,
guix-generation-list-show-removed-packages, guix-generation-list-compare,
guix-generation-list-ediff-manifests, guix-generation-list-diff-manifests,
guix-generation-list-ediff-packages, guix-generation-list-diff-packages,
guix-generation-list-ediff, guix-generation-list-diff): New procedures.
* emacs/guix-messages.el (guix-messages): Add 'generation-diff' search type.
(guix-message-outputs-by-diff): New procedure.
* emacs/guix-utils.el (guix-diff-switches): New variable.
(guix-diff): New procedure.
* emacs/guix-main.scm (package/output-sexps): Handle 'generation-diff' search
type.
(manifest-entry->package-specification,
manifest-entries->package-specifications, generation-package-specifications,
generation-package-specifications+paths, generation-difference): New
procedures.
2014-11-02 05:58:21 -05:00
|
|
|
|
(defun guix-generation-list-generations-to-compare ()
|
|
|
|
|
"Return a sorted list of 2 marked generations for comparing."
|
|
|
|
|
(let ((numbers (guix-list-get-marked-id-list 'general)))
|
|
|
|
|
(if (/= (length numbers) 2)
|
|
|
|
|
(user-error "2 generations should be marked for comparing")
|
|
|
|
|
(sort numbers #'<))))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-show-added-packages ()
|
|
|
|
|
"List package outputs added to the latest marked generation.
|
|
|
|
|
If 2 generations are marked with \\[guix-list-mark], display
|
|
|
|
|
outputs installed in the latest marked generation that were not
|
|
|
|
|
installed in the other one."
|
|
|
|
|
(interactive)
|
|
|
|
|
(apply #'guix-get-show-entries
|
|
|
|
|
guix-profile 'list 'output 'generation-diff
|
|
|
|
|
(reverse (guix-generation-list-generations-to-compare))))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-show-removed-packages ()
|
|
|
|
|
"List package outputs removed from the latest marked generation.
|
|
|
|
|
If 2 generations are marked with \\[guix-list-mark], display
|
|
|
|
|
outputs not installed in the latest marked generation that were
|
|
|
|
|
installed in the other one."
|
|
|
|
|
(interactive)
|
|
|
|
|
(apply #'guix-get-show-entries
|
|
|
|
|
guix-profile 'list 'output 'generation-diff
|
|
|
|
|
(guix-generation-list-generations-to-compare)))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-compare (diff-fun gen-fun)
|
|
|
|
|
"Run GEN-FUN on the 2 marked generations and run DIFF-FUN on the results."
|
|
|
|
|
(cl-multiple-value-bind (gen1 gen2)
|
|
|
|
|
(guix-generation-list-generations-to-compare)
|
|
|
|
|
(funcall diff-fun
|
|
|
|
|
(funcall gen-fun gen1)
|
|
|
|
|
(funcall gen-fun gen2))))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-ediff-manifests ()
|
|
|
|
|
"Run Ediff on manifests of the 2 marked generations."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-generation-list-compare
|
|
|
|
|
#'ediff-files
|
|
|
|
|
#'guix-profile-generation-manifest-file))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-diff-manifests ()
|
|
|
|
|
"Run Diff on manifests of the 2 marked generations."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-generation-list-compare
|
|
|
|
|
#'guix-diff
|
|
|
|
|
#'guix-profile-generation-manifest-file))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-ediff-packages ()
|
|
|
|
|
"Run Ediff on package outputs installed in the 2 marked generations."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-generation-list-compare
|
|
|
|
|
#'ediff-buffers
|
|
|
|
|
#'guix-profile-generation-packages-buffer))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-diff-packages ()
|
|
|
|
|
"Run Diff on package outputs installed in the 2 marked generations."
|
|
|
|
|
(interactive)
|
|
|
|
|
(guix-generation-list-compare
|
|
|
|
|
#'guix-diff
|
|
|
|
|
#'guix-profile-generation-packages-buffer))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-ediff (arg)
|
|
|
|
|
"Run Ediff on package outputs installed in the 2 marked generations.
|
|
|
|
|
With ARG, run Ediff on manifests of the marked generations."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(if arg
|
|
|
|
|
(guix-generation-list-ediff-manifests)
|
|
|
|
|
(guix-generation-list-ediff-packages)))
|
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-diff (arg)
|
|
|
|
|
"Run Diff on package outputs installed in the 2 marked generations.
|
|
|
|
|
With ARG, run Diff on manifests of the marked generations."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(if arg
|
|
|
|
|
(guix-generation-list-diff-manifests)
|
|
|
|
|
(guix-generation-list-diff-packages)))
|
|
|
|
|
|
2014-10-05 04:31:23 -04:00
|
|
|
|
(defun guix-generation-list-mark-delete (&optional arg)
|
|
|
|
|
"Mark the current generation for deletion and move to the next line.
|
|
|
|
|
With ARG, mark all generations for deletion."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(if arg
|
|
|
|
|
(guix-list-mark-all 'delete)
|
2015-05-27 09:51:25 -04:00
|
|
|
|
(guix-list--mark 'delete t)))
|
2014-10-05 04:31:23 -04:00
|
|
|
|
|
|
|
|
|
(defun guix-generation-list-execute ()
|
|
|
|
|
"Delete marked generations."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let ((marked (guix-list-get-marked-id-list 'delete)))
|
|
|
|
|
(or marked
|
|
|
|
|
(user-error "No generations marked for deletion"))
|
emacs: Improve interface for working with multiple profiles.
Suggested by David Thompson, Ludovic Courtès and Mathieu Lirzin.
* emacs/guix-base.el (guix-profile-prompt): New procedure.
(guix-set-current-profile): Use it.
(guix-buffer-name-simple, guix-buffer-name-default, guix-buffer-name): New
procedures.
(guix-buffer-name-function, guix-profile): New variables.
(guix-set-vars, guix-get-entries, guix-get-show-entries, guix-set-buffer,
guix-history-call, guix-process-package-actions,
guix-continue-package-operation-p, guix-delete-generations,
guix-switch-to-generation): Add 'profile' argument.
* emacs/guix.el (guix-get-show-packages, guix-get-show-generations,
guix-search-by-name, guix-search-by-regexp, guix-installed-packages,
guix-obsolete-packages, guix-all-available-packages,
guix-newest-available-packages, guix-generations, guix-generations-by-time):
Likewise.
(guix-last-generations): New command.
* emacs/guix-info.el: Adjust for using 'profile' argument where needed.
* emacs/guix-list.el: Likewise.
* doc/emacs.texi (Emacs Commands): Document 'guix-last-generations' and using
"C-u" for commands.
(Emacs Buffer Names): Document 'guix-buffer-name-function'.
2014-10-17 14:21:32 -04:00
|
|
|
|
(guix-delete-generations guix-profile marked (current-buffer))))
|
2014-10-05 04:31:23 -04:00
|
|
|
|
|
2015-11-20 04:38:31 -05:00
|
|
|
|
|
|
|
|
|
(defvar guix-list-font-lock-keywords
|
|
|
|
|
(eval-when-compile
|
|
|
|
|
`((,(rx "(" (group "guix-list-define-interface")
|
|
|
|
|
symbol-end)
|
|
|
|
|
. 1))))
|
|
|
|
|
|
|
|
|
|
(font-lock-add-keywords 'emacs-lisp-mode guix-list-font-lock-keywords)
|
|
|
|
|
|
2014-08-27 08:44:17 -04:00
|
|
|
|
(provide 'guix-list)
|
|
|
|
|
|
|
|
|
|
;;; guix-list.el ends here
|