summaryrefslogtreecommitdiff
path: root/emacs
diff options
context:
space:
mode:
Diffstat (limited to 'emacs')
-rw-r--r--emacs/guix-backend.el24
-rw-r--r--emacs/guix-base.el62
-rw-r--r--emacs/guix-config.el.in2
-rw-r--r--emacs/guix-license.el103
-rw-r--r--emacs/guix-location.el79
-rw-r--r--emacs/guix-main.scm42
-rw-r--r--emacs/guix-messages.el15
-rw-r--r--emacs/guix-read.el11
-rw-r--r--emacs/guix-ui-license.el150
-rw-r--r--emacs/guix-ui-location.el83
-rw-r--r--emacs/guix-ui-package.el41
-rw-r--r--emacs/guix-ui.el33
-rw-r--r--emacs/guix-utils.el28
-rw-r--r--emacs/local.mk76
14 files changed, 574 insertions, 175 deletions
diff --git a/emacs/guix-backend.el b/emacs/guix-backend.el
index 8afbc9ed48..6341aacae1 100644
--- a/emacs/guix-backend.el
+++ b/emacs/guix-backend.el
@@ -82,7 +82,7 @@ If you have a slow system, try to increase this time."
:type 'string
:group 'guix-repl)
-(defcustom guix-after-start-repl-hook ()
+(defcustom guix-after-start-repl-hook '(guix-set-directory)
"Hook called after Guix REPL is started."
:type 'hook
:group 'guix-repl)
@@ -337,6 +337,28 @@ additional internal REPL if it exists."
(geiser-repl--switch-to-buffer (guix-get-repl-buffer internal)))
+;;; Guix directory
+
+(defvar guix-directory nil
+ "Default directory with Guix source.
+If it is not set by a user, it is set after starting Guile REPL.
+This directory is used to define package locations.")
+
+(defun guix-read-directory ()
+ "Return `guix-directory' or prompt for it.
+This function is intended for using in `interactive' forms."
+ (if current-prefix-arg
+ (read-directory-name "Directory with Guix modules: "
+ guix-directory)
+ guix-directory))
+
+(defun guix-set-directory ()
+ "Set `guix-directory' if needed."
+ (or guix-directory
+ (setq guix-directory
+ (guix-eval-read "%guix-dir"))))
+
+
;;; Evaluating expressions
(defvar guix-operation-buffer nil
diff --git a/emacs/guix-base.el b/emacs/guix-base.el
index 75d19cbfe0..888836428f 100644
--- a/emacs/guix-base.el
+++ b/emacs/guix-base.el
@@ -48,53 +48,7 @@
(when output (concat ":" output))))
-;;; Location of packages, profiles and manifests
-
-(defvar guix-directory nil
- "Default Guix directory.
-If it is not set by a user, it is set after starting Guile REPL.
-This directory is used to define location of the packages.")
-
-(defun guix-read-directory ()
- "Return `guix-directory' or prompt for it.
-This function is intended for using in `interactive' forms."
- (if current-prefix-arg
- (read-directory-name "Directory with Guix modules: "
- guix-directory)
- guix-directory))
-
-(defun guix-set-directory ()
- "Set `guix-directory' if needed."
- (or guix-directory
- (setq guix-directory
- (guix-eval-read "%guix-dir"))))
-
-(add-hook 'guix-after-start-repl-hook 'guix-set-directory)
-
-(defun guix-find-location (location &optional directory)
- "Go to LOCATION of a package.
-LOCATION is a string of the form:
-
- \"PATH:LINE:COLUMN\"
-
-If PATH is relative, it is considered to be relative to
-DIRECTORY (`guix-directory' by default)."
- (cl-multiple-value-bind (path line col)
- (split-string location ":")
- (let ((file (expand-file-name path (or directory guix-directory)))
- (line (string-to-number line))
- (col (string-to-number col)))
- (find-file file)
- (goto-char (point-min))
- (forward-line (- line 1))
- (move-to-column col)
- (recenter 1))))
-
-(defun guix-package-location (id-or-name)
- "Return location of a package with ID-OR-NAME.
-For the meaning of location, see `guix-find-location'."
- (guix-eval-read (guix-make-guile-expression
- 'package-location-string id-or-name)))
+;;; Location of profiles and manifests
(defun guix-generation-file (profile generation)
"Return the file name of a PROFILE's GENERATION."
@@ -120,20 +74,6 @@ See `guix-packages-profile'."
(expand-file-name "manifest"
(guix-packages-profile profile generation system?)))
-;;;###autoload
-(defun guix-edit (id-or-name &optional directory)
- "Edit (go to location of) package with ID-OR-NAME.
-See `guix-find-location' for the meaning of package location and
-DIRECTORY.
-Interactively, with prefix argument, prompt for DIRECTORY."
- (interactive
- (list (guix-read-package-name)
- (guix-read-directory)))
- (let ((loc (guix-package-location id-or-name)))
- (if loc
- (guix-find-location loc directory)
- (message "Couldn't find package location."))))
-
;;; Actions on packages and generations
diff --git a/emacs/guix-config.el.in b/emacs/guix-config.el.in
index bd821596c4..d03df9ce63 100644
--- a/emacs/guix-config.el.in
+++ b/emacs/guix-config.el.in
@@ -24,7 +24,7 @@
(replace-regexp-in-string "${prefix}" "@prefix@" "@emacsuidir@"))
(defconst guix-config-state-directory
- ;; This must match `NIX_STATE_DIR' as defined in `daemon.am'.
+ ;; This must match `NIX_STATE_DIR' as defined in `nix/local.mk'.
(or (getenv "NIX_STATE_DIR") "@guix_localstatedir@/guix"))
(defconst guix-config-guile-program "@GUILE@"
diff --git a/emacs/guix-license.el b/emacs/guix-license.el
index a99d7af98d..6003a21aac 100644
--- a/emacs/guix-license.el
+++ b/emacs/guix-license.el
@@ -23,14 +23,15 @@
;;; Code:
-(require 'guix-buffer)
-(require 'guix-list)
-(require 'guix-info)
(require 'guix-read)
(require 'guix-backend)
(require 'guix-guile)
-(guix-define-entry-type license)
+(defun guix-license-file (&optional directory)
+ "Return name of the file with license definitions.
+DIRECTORY is a directory with Guix source (`guix-directory' by default)."
+ (expand-file-name "guix/licenses.scm"
+ (or directory guix-directory)))
(defun guix-lookup-license-url (license)
"Return URL of a LICENSE."
@@ -38,80 +39,20 @@
'lookup-license-uri license))
(error "Hm, I don't know URL of '%s' license" license)))
-(defun guix-license-get-entries (search-type &rest args)
- "Receive 'license' entries.
-SEARCH-TYPE may be one of the following symbols: `all', `id', `name'."
- (guix-eval-read
- (apply #'guix-make-guile-expression
- 'license-entries search-type args)))
-
-(defun guix-license-get-display (search-type &rest args)
- "Search for licenses and show results."
- (apply #'guix-list-get-display-entries
- 'license search-type args))
-
-
-;;; License 'info'
-
-(guix-info-define-interface license
- :buffer-name "*Guix License Info*"
- :get-entries-function 'guix-license-get-entries
- :format '((name ignore (simple guix-info-heading))
- ignore
- guix-license-insert-packages-button
- (url ignore (simple guix-url))
- guix-license-insert-comment)
- :titles '((url . "URL")))
-
-(declare-function guix-packages-by-license "guix-ui-package")
-
-(defun guix-license-insert-packages-button (entry)
- "Insert button to display packages by license ENTRY."
- (guix-info-insert-action-button
- "Packages"
- (lambda (btn)
- (guix-packages-by-license (button-get btn 'license)))
- "Show packages with this license"
- 'license (guix-entry-value entry 'name)))
-
-(defun guix-license-insert-comment (entry)
- "Insert 'comment' of a license ENTRY."
- (let ((comment (guix-entry-value entry 'comment)))
- (if (and comment
- (string-match-p "^http" comment))
- (guix-info-insert-value-simple comment 'guix-url)
- (guix-info-insert-title-simple
- (guix-info-param-title 'license 'comment))
- (guix-info-insert-value-indent comment))))
-
-
-;;; License 'list'
-
-(guix-list-define-interface license
- :buffer-name "*Guix Licenses*"
- :get-entries-function 'guix-license-get-entries
- :describe-function 'guix-license-list-describe
- :format '((name nil 40 t)
- (url guix-list-get-url 50 t))
- :titles '((name . "License"))
- :sort-key '(name))
-
-(let ((map guix-license-list-mode-map))
- (define-key map (kbd "RET") 'guix-license-list-show-packages))
-
-(defun guix-license-list-describe (ids)
- "Describe licenses with IDS (list of identifiers)."
- (guix-buffer-display-entries
- (guix-entries-by-ids ids (guix-buffer-current-entries))
- 'info 'license (cl-list* 'id ids) 'add))
-
-(defun guix-license-list-show-packages ()
- "Display packages with the license at point."
- (interactive)
- (guix-packages-by-license (guix-list-current-id)))
-
-
-;;; Interactive commands
+;;;###autoload
+(defun guix-find-license-definition (license &optional directory)
+ "Open licenses file from DIRECTORY and move to the LICENSE definition.
+See `guix-license-file' for the meaning of DIRECTORY.
+Interactively, with prefix argument, prompt for DIRECTORY."
+ (interactive
+ (list (guix-read-license-name)
+ (guix-read-directory)))
+ (find-file (guix-license-file directory))
+ (goto-char (point-min))
+ (when (re-search-forward (concat "\"" (regexp-quote license) "\"")
+ nil t)
+ (beginning-of-defun)
+ (recenter 1)))
;;;###autoload
(defun guix-browse-license-url (license)
@@ -119,12 +60,6 @@ SEARCH-TYPE may be one of the following symbols: `all', `id', `name'."
(interactive (list (guix-read-license-name)))
(browse-url (guix-lookup-license-url license)))
-;;;###autoload
-(defun guix-licenses ()
- "Display licenses of the Guix packages."
- (interactive)
- (guix-license-get-display 'all))
-
(provide 'guix-license)
;;; guix-license.el ends here
diff --git a/emacs/guix-location.el b/emacs/guix-location.el
new file mode 100644
index 0000000000..81396b4017
--- /dev/null
+++ b/emacs/guix-location.el
@@ -0,0 +1,79 @@
+;;; guix-location.el --- Package locations
+
+;; Copyright © 2016 Alex Kost <alezost@gmail.com>
+
+;; 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 Location as published by
+;; the Free Software Foundation, either version 3 of the Location, 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 Location for more details.
+
+;; You should have received a copy of the GNU General Public Location
+;; along with this program. If not, see <http://www.gnu.org/locations/>.
+
+;;; Commentary:
+
+;; This file provides the code to work with locations of Guix packages.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'guix-backend)
+(require 'guix-read)
+(require 'guix-guile)
+
+(defun guix-package-location (id-or-name)
+ "Return location of a package with ID-OR-NAME.
+For the meaning of location, see `guix-find-location'."
+ (guix-eval-read (guix-make-guile-expression
+ 'package-location-string id-or-name)))
+
+;;;###autoload
+(defun guix-find-location (location &optional directory)
+ "Go to LOCATION of a package.
+LOCATION is a string of the form:
+
+ \"FILE:LINE:COLUMN\"
+
+If FILE is relative, it is considered to be relative to
+DIRECTORY (`guix-directory' by default).
+
+Interactively, prompt for LOCATION. With prefix argument, prompt
+for DIRECTORY as well."
+ (interactive
+ (list (guix-read-package-location)
+ (guix-read-directory)))
+ (cl-multiple-value-bind (file line column)
+ (split-string location ":")
+ (find-file (expand-file-name file (or directory guix-directory)))
+ (when (and line column)
+ (let ((line (string-to-number line))
+ (column (string-to-number column)))
+ (goto-char (point-min))
+ (forward-line (- line 1))
+ (move-to-column column)
+ (recenter 1)))))
+
+;;;###autoload
+(defun guix-edit (id-or-name &optional directory)
+ "Edit (go to location of) package with ID-OR-NAME.
+See `guix-find-location' for the meaning of package location and
+DIRECTORY.
+Interactively, with prefix argument, prompt for DIRECTORY."
+ (interactive
+ (list (guix-read-package-name)
+ (guix-read-directory)))
+ (let ((loc (guix-package-location id-or-name)))
+ (if loc
+ (guix-find-location loc directory)
+ (message "Couldn't find package location."))))
+
+(provide 'guix-location)
+
+;;; guix-location.el ends here
diff --git a/emacs/guix-main.scm b/emacs/guix-main.scm
index c62044056f..5358f3bfa4 100644
--- a/emacs/guix-main.scm
+++ b/emacs/guix-main.scm
@@ -684,6 +684,8 @@ ENTRIES is a list of installed manifest entries."
(license-proc (lambda (_ license-name)
(packages-by-license
(lookup-license license-name))))
+ (location-proc (lambda (_ location)
+ (packages-by-location-file location)))
(all-proc (lambda _ (all-available-packages)))
(newest-proc (lambda _ (newest-available-packages))))
`((package
@@ -693,6 +695,7 @@ ENTRIES is a list of installed manifest entries."
(obsolete . ,(apply-to-first obsolete-package-patterns))
(regexp . ,regexp-proc)
(license . ,license-proc)
+ (location . ,location-proc)
(all-available . ,all-proc)
(newest-available . ,newest-proc))
(output
@@ -702,6 +705,7 @@ ENTRIES is a list of installed manifest entries."
(obsolete . ,(apply-to-first obsolete-output-patterns))
(regexp . ,regexp-proc)
(license . ,license-proc)
+ (location . ,location-proc)
(all-available . ,all-proc)
(newest-available . ,newest-proc)))))
@@ -1097,3 +1101,41 @@ Return #t if the shell command was executed successfully."
(define (license-entries search-type . search-values)
(map license->sexp
(apply find-licenses search-type search-values)))
+
+
+;;; Package locations
+
+(define-values (packages-by-location-file
+ package-location-files)
+ (let* ((table (delay (fold-packages
+ (lambda (package table)
+ (let ((file (location-file
+ (package-location package))))
+ (vhash-cons file package table)))
+ vlist-null)))
+ (files (delay (vhash-fold
+ (lambda (file _ result)
+ (if (member file result)
+ result
+ (cons file result)))
+ '()
+ (force table)))))
+ (values
+ (lambda (file)
+ "Return the (possibly empty) list of packages defined in location FILE."
+ (vhash-fold* cons '() file (force table)))
+ (lambda ()
+ "Return the list of file names of all package locations."
+ (force files)))))
+
+(define %package-location-param-alist
+ `((id . ,identity)
+ (location . ,identity)
+ (number-of-packages . ,(lambda (location)
+ (length (packages-by-location-file location))))))
+
+(define package-location->sexp
+ (object-transformer %package-location-param-alist))
+
+(define (package-location-entries)
+ (map package-location->sexp (package-location-files)))
diff --git a/emacs/guix-messages.el b/emacs/guix-messages.el
index de0331fff8..7ebe7e8b5c 100644
--- a/emacs/guix-messages.el
+++ b/emacs/guix-messages.el
@@ -40,6 +40,10 @@
,(lambda (_ entries licenses)
(apply #'guix-message-packages-by-license
entries 'package licenses)))
+ (location
+ ,(lambda (_ entries locations)
+ (apply #'guix-message-packages-by-location
+ entries 'package locations)))
(regexp
(0 "No packages matching '%s'." val)
(1 "A single package matching '%s'." val)
@@ -72,6 +76,10 @@
,(lambda (_ entries licenses)
(apply #'guix-message-packages-by-license
entries 'output licenses)))
+ (location
+ ,(lambda (_ entries locations)
+ (apply #'guix-message-packages-by-location
+ entries 'output locations)))
(regexp
(0 "No package outputs matching '%s'." val)
(1 "A single package output matching '%s'." val)
@@ -174,6 +182,13 @@ Try \"M-x guix-search-by-name\"."
(str-end (format "with license '%s'" license)))
(message "%s %s." str-beg str-end)))
+(defun guix-message-packages-by-location (entries entry-type location)
+ "Display a message for packages or outputs searched by LOCATION."
+ (let* ((count (length entries))
+ (str-beg (guix-message-string-entries count entry-type))
+ (str-end (format "placed in '%s'" location)))
+ (message "%s %s." str-beg str-end)))
+
(defun guix-message-generations-by-time (profile entries times)
"Display a message for generations searched by TIMES."
(let* ((count (length entries))
diff --git a/emacs/guix-read.el b/emacs/guix-read.el
index a1a6b86364..5423c9bcfa 100644
--- a/emacs/guix-read.el
+++ b/emacs/guix-read.el
@@ -62,6 +62,12 @@
"Return a list of names of available licenses."
(guix-eval-read (guix-make-guile-expression 'license-names)))
+(guix-memoized-defun guix-package-locations ()
+ "Return a list of available package locations."
+ (sort (guix-eval-read (guix-make-guile-expression
+ 'package-location-files))
+ #'string<))
+
;;; Readers
@@ -131,6 +137,11 @@
:single-reader guix-read-license-name
:single-prompt "License: ")
+(guix-define-readers
+ :completions-getter guix-package-locations
+ :single-reader guix-read-package-location
+ :single-prompt "Location: ")
+
(provide 'guix-read)
;;; guix-read.el ends here
diff --git a/emacs/guix-ui-license.el b/emacs/guix-ui-license.el
new file mode 100644
index 0000000000..cf1b5cd357
--- /dev/null
+++ b/emacs/guix-ui-license.el
@@ -0,0 +1,150 @@
+;;; guix-ui-license.el --- Interface for displaying licenses
+
+;; Copyright © 2016 Alex Kost <alezost@gmail.com>
+
+;; 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 'list'/'info' interface for displaying licenses of
+;; Guix packages.
+
+;;; Code:
+
+(require 'guix-buffer)
+(require 'guix-list)
+(require 'guix-info)
+(require 'guix-backend)
+(require 'guix-guile)
+(require 'guix-license)
+
+(guix-define-entry-type license)
+
+(defun guix-license-get-entries (search-type &rest args)
+ "Receive 'license' entries.
+SEARCH-TYPE may be one of the following symbols: `all', `id', `name'."
+ (guix-eval-read
+ (apply #'guix-make-guile-expression
+ 'license-entries search-type args)))
+
+(defun guix-license-get-display (search-type &rest args)
+ "Search for licenses and show results."
+ (apply #'guix-list-get-display-entries
+ 'license search-type args))
+
+(defun guix-license-message (entries search-type &rest args)
+ "Display a message after showing license ENTRIES."
+ ;; Some objects in (guix licenses) module are procedures (e.g.,
+ ;; 'non-copyleft' or 'x11-style'). Such licenses cannot be "described".
+ (when (null entries)
+ (if (cdr args)
+ (message "Unknown licenses.")
+ (message "Unknown license."))))
+
+
+;;; License 'info'
+
+(guix-info-define-interface license
+ :buffer-name "*Guix License Info*"
+ :get-entries-function 'guix-license-get-entries
+ :message-function 'guix-license-message
+ :format '((name ignore (simple guix-info-heading))
+ ignore
+ guix-license-insert-packages-button
+ (url ignore (simple guix-url))
+ guix-license-insert-comment
+ ignore
+ guix-license-insert-file)
+ :titles '((url . "URL")))
+
+(declare-function guix-packages-by-license "guix-ui-package")
+
+(defun guix-license-insert-packages-button (entry)
+ "Insert button to display packages by license ENTRY."
+ (let ((license (guix-entry-value entry 'name)))
+ (guix-info-insert-action-button
+ "Packages"
+ (lambda (btn)
+ (guix-packages-by-license (button-get btn 'license)))
+ (format "Display packages with license '%s'" license)
+ 'license license)))
+
+(defun guix-license-insert-comment (entry)
+ "Insert 'comment' of a license ENTRY."
+ (let ((comment (guix-entry-value entry 'comment)))
+ (if (and comment
+ (string-match-p "^http" comment))
+ (guix-info-insert-value-simple comment 'guix-url)
+ (guix-info-insert-title-simple
+ (guix-info-param-title 'license 'comment))
+ (guix-info-insert-value-indent comment))))
+
+(defun guix-license-insert-file (entry)
+ "Insert button to open license definition."
+ (let ((license (guix-entry-value entry 'name)))
+ (guix-insert-button
+ (guix-license-file) 'guix-file
+ 'help-echo (format "Open definition of license '%s'" license)
+ 'action (lambda (btn)
+ (guix-find-license-definition (button-get btn 'license)))
+ 'license license)))
+
+
+;;; License 'list'
+
+(guix-list-define-interface license
+ :buffer-name "*Guix Licenses*"
+ :get-entries-function 'guix-license-get-entries
+ :describe-function 'guix-license-list-describe
+ :message-function 'guix-license-message
+ :format '((name nil 40 t)
+ (url guix-list-get-url 50 t))
+ :titles '((name . "License"))
+ :sort-key '(name))
+
+(let ((map guix-license-list-mode-map))
+ (define-key map (kbd "e") 'guix-license-list-edit)
+ (define-key map (kbd "RET") 'guix-license-list-show-packages))
+
+(defun guix-license-list-describe (ids)
+ "Describe licenses with IDS (list of identifiers)."
+ (guix-buffer-display-entries
+ (guix-entries-by-ids ids (guix-buffer-current-entries))
+ 'info 'license (cl-list* 'id ids) 'add))
+
+(defun guix-license-list-show-packages ()
+ "Display packages with the license at point."
+ (interactive)
+ (guix-packages-by-license (guix-list-current-id)))
+
+(defun guix-license-list-edit (&optional directory)
+ "Go to the location of the current license definition.
+See `guix-license-file' for the meaning of DIRECTORY."
+ (interactive (list (guix-read-directory)))
+ (guix-find-license-definition (guix-list-current-id) directory))
+
+
+;;; Interactive commands
+
+;;;###autoload
+(defun guix-licenses ()
+ "Display licenses of the Guix packages."
+ (interactive)
+ (guix-license-get-display 'all))
+
+(provide 'guix-ui-license)
+
+;;; guix-ui-license.el ends here
diff --git a/emacs/guix-ui-location.el b/emacs/guix-ui-location.el
new file mode 100644
index 0000000000..0027c1fba8
--- /dev/null
+++ b/emacs/guix-ui-location.el
@@ -0,0 +1,83 @@
+;;; guix-ui-location.el --- Interface for displaying package locations
+
+;; Copyright © 2016 Alex Kost <alezost@gmail.com>
+
+;; 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 Location as published by
+;; the Free Software Foundation, either version 3 of the Location, 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 Location for more details.
+
+;; You should have received a copy of the GNU General Public Location
+;; along with this program. If not, see <http://www.gnu.org/locations/>.
+
+;;; Commentary:
+
+;; This file provides a 'list' interface for displaying locations of Guix
+;; packages.
+
+;;; Code:
+
+(require 'guix-buffer)
+(require 'guix-list)
+(require 'guix-location)
+(require 'guix-backend)
+
+(guix-define-entry-type location)
+
+(defun guix-location-get-entries ()
+ "Receive 'package location' entries."
+ (guix-eval-read "(package-location-entries)"))
+
+
+;;; Location 'list'
+
+(guix-list-define-interface location
+ :buffer-name "*Guix Package Locations*"
+ :get-entries-function 'guix-location-get-entries
+ :format '((location guix-location-list-file-name-specification 50 t)
+ (number-of-packages nil 10 guix-list-sort-numerically-1
+ :right-align t))
+ :sort-key '(location))
+
+(let ((map guix-location-list-mode-map))
+ (define-key map (kbd "RET") 'guix-location-list-show-packages)
+ ;; "Location Info" buffer is not defined (it would be useless), so
+ ;; unbind "i" key (by default, it is used to display Info buffer).
+ (define-key map (kbd "i") nil))
+
+(defun guix-location-list-file-name-specification (location &optional _)
+ "Return LOCATION button specification for `tabulated-list-entries'."
+ (list location
+ 'face 'guix-list-file-name
+ 'action (lambda (btn)
+ (guix-find-location (button-get btn 'location)))
+ 'follow-link t
+ 'help-echo (concat "Find location: " location)
+ 'location location))
+
+(declare-function guix-packages-by-location "guix-ui-package")
+
+(defun guix-location-list-show-packages ()
+ "Display packages placed in the location at point."
+ (interactive)
+ (guix-packages-by-location (guix-list-current-id)))
+
+
+;;; Interactive commands
+
+;;;###autoload
+(defun guix-locations ()
+ "Display locations of the Guix packages."
+ (interactive)
+ (guix-list-get-display-entries 'location))
+
+(provide 'guix-ui-location)
+
+;;; guix-ui-location.el ends here
diff --git a/emacs/guix-ui-package.el b/emacs/guix-ui-package.el
index df5f8d12d1..38f0c08fc7 100644
--- a/emacs/guix-ui-package.el
+++ b/emacs/guix-ui-package.el
@@ -1,6 +1,6 @@
;;; guix-ui-package.el --- Interface for displaying packages -*- lexical-binding: t -*-
-;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
+;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
;; This file is part of GNU Guix.
@@ -38,6 +38,7 @@
(require 'guix-hydra-build)
(require 'guix-read)
(require 'guix-license)
+(require 'guix-location)
(require 'guix-profiles)
(guix-ui-define-entry-type package)
@@ -222,7 +223,7 @@ ENTRIES is a list of package entries to get info about packages."
ignore
(outputs simple guix-package-info-insert-outputs)
(source simple guix-package-info-insert-source)
- (location format (format guix-package-location))
+ (location simple guix-package-info-insert-location)
(home-url format (format guix-url))
(license format (format guix-package-license))
(systems format guix-package-info-insert-systems)
@@ -345,9 +346,13 @@ formatted with this string, an action button is inserted.")
(define-button-type 'guix-package-license
:supertype 'guix
'face 'guix-package-info-license
- 'help-echo "Browse license URL"
+ 'help-echo "Display license info"
'action (lambda (btn)
- (guix-browse-license-url (button-label btn))))
+ (require 'guix-ui-license)
+ (guix-buffer-get-display-entries
+ 'info 'license
+ (list 'name (button-label btn))
+ 'add)))
(define-button-type 'guix-package-name
:supertype 'guix
@@ -382,6 +387,22 @@ formatted with this string, an action button is inserted.")
'guix-package-heading
'spec (guix-package-entry->name-specification entry)))
+(defun guix-package-info-insert-location (location &optional _)
+ "Insert package LOCATION at point."
+ (if (null location)
+ (guix-format-insert nil)
+ (let ((location-file (car (split-string location ":"))))
+ (guix-info-insert-value-indent location 'guix-package-location)
+ (guix-info-insert-indent)
+ (guix-info-insert-action-button
+ "Packages"
+ (lambda (btn)
+ (guix-package-get-display (guix-ui-current-profile)
+ 'location
+ (button-get btn 'location)))
+ (format "Display packages from location '%s'" location-file)
+ 'location location-file))))
+
(defun guix-package-info-insert-systems (systems entry)
"Insert supported package SYSTEMS at point."
(guix-info-insert-value-format
@@ -797,7 +818,7 @@ for all ARGS."
(source simple guix-package-info-insert-source)
(path simple (indent guix-file))
(dependencies simple (indent guix-file))
- (location format (format guix-package-location))
+ (location simple guix-package-info-insert-location)
(home-url format (format guix-url))
(license format (format guix-package-license))
(systems format guix-package-info-insert-systems)
@@ -970,6 +991,16 @@ Interactively with prefix, prompt for PROFILE."
(guix-package-get-display profile 'license license))
;;;###autoload
+(defun guix-packages-by-location (location &optional profile)
+ "Display Guix packages placed in LOCATION file.
+If PROFILE is nil, use `guix-current-profile'.
+Interactively with prefix, prompt for PROFILE."
+ (interactive
+ (list (guix-read-package-location)
+ (guix-ui-read-profile)))
+ (guix-package-get-display profile 'location location))
+
+;;;###autoload
(defun guix-search-by-regexp (regexp &optional params profile)
"Search for Guix packages by REGEXP.
PARAMS are package parameters that should be searched.
diff --git a/emacs/guix-ui.el b/emacs/guix-ui.el
index 9a88efc286..1b696314cd 100644
--- a/emacs/guix-ui.el
+++ b/emacs/guix-ui.el
@@ -1,6 +1,6 @@
;;; guix-ui.el --- Common code for Guix package management interface -*- lexical-binding: t -*-
-;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
+;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
;; This file is part of GNU Guix.
@@ -105,10 +105,11 @@ If `all', update all Guix buffers (not recommended)."
:group 'guix-ui)
(defcustom guix-ui-buffer-name-function
- #'guix-ui-buffer-name-default
+ #'guix-ui-buffer-name-full
"Function used to define a name of a Guix buffer.
The function is called with 2 arguments: BASE-NAME and PROFILE."
- :type '(choice (function-item guix-ui-buffer-name-default)
+ :type '(choice (function-item guix-ui-buffer-name-full)
+ (function-item guix-ui-buffer-name-short)
(function-item guix-ui-buffer-name-simple)
(function :tag "Other function"))
:group 'guix-ui)
@@ -117,26 +118,14 @@ The function is called with 2 arguments: BASE-NAME and PROFILE."
"Return BASE-NAME."
base-name)
-;; TODO separate '*...*' logic from the real profile appending. Also add
-;; another function to return '*Guix ...: /full/path/to/profile*' name.
-(defun guix-ui-buffer-name-default (base-name profile)
+(defun guix-ui-buffer-name-short (base-name profile)
"Return buffer name by appending BASE-NAME and PROFILE's base file name."
- (let ((profile-name (file-name-base (directory-file-name profile)))
- (re (rx string-start
- (group (? "*"))
- (group (*? any))
- (group (? "*"))
- string-end)))
- (or (string-match re base-name)
- (error "Unexpected error in defining guix buffer name"))
- (let ((first* (match-string 1 base-name))
- (name-body (match-string 2 base-name))
- (last* (match-string 3 base-name)))
- ;; Handle the case when buffer name is wrapped by '*'.
- (if (and (string= "*" first*)
- (string= "*" last*))
- (concat "*" name-body ": " profile-name "*")
- (concat base-name ": " profile-name)))))
+ (guix-compose-buffer-name base-name
+ (file-name-base (directory-file-name profile))))
+
+(defun guix-ui-buffer-name-full (base-name profile)
+ "Return buffer name by appending BASE-NAME and PROFILE's full name."
+ (guix-compose-buffer-name base-name profile))
(defun guix-ui-buffer-name (base-name profile)
"Return Guix buffer name based on BASE-NAME and profile.
diff --git a/emacs/guix-utils.el b/emacs/guix-utils.el
index 8c1a5b42de..ea9933f5c3 100644
--- a/emacs/guix-utils.el
+++ b/emacs/guix-utils.el
@@ -1,6 +1,6 @@
;;; guix-utils.el --- General utility functions -*- lexical-binding: t -*-
-;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
+;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
;; This file is part of GNU Guix.
@@ -223,6 +223,32 @@ If NO-MESSAGE? is non-nil, do not display a message about it."
See also `guix-copy-as-kill'."
(guix-copy-as-kill (guix-command-string args) no-message?))
+(defun guix-compose-buffer-name (base-name postfix)
+ "Return buffer name by appending BASE-NAME and POSTFIX.
+
+In a simple case the result is:
+
+ BASE-NAME: POSTFIX
+
+If BASE-NAME is wrapped by '*', then the result is:
+
+ *BASE-NAME: POSTFIX*"
+ (let ((re (rx string-start
+ (group (? "*"))
+ (group (*? any))
+ (group (? "*"))
+ string-end)))
+ (or (string-match re base-name)
+ (error "Unexpected error in defining buffer name"))
+ (let ((first* (match-string 1 base-name))
+ (name-body (match-string 2 base-name))
+ (last* (match-string 3 base-name)))
+ ;; Handle the case when buffer name is wrapped by '*'.
+ (if (and (string= "*" first*)
+ (string= "*" last*))
+ (concat "*" name-body ": " postfix "*")
+ (concat base-name ": " postfix)))))
+
(defun guix-completing-read (prompt table &optional predicate
require-match initial-input
hist def inherit-input-method)
diff --git a/emacs/local.mk b/emacs/local.mk
new file mode 100644
index 0000000000..62e33e4fd2
--- /dev/null
+++ b/emacs/local.mk
@@ -0,0 +1,76 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
+# Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
+#
+# 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 GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+AUTOLOADS = emacs/guix-autoloads.el
+
+ELFILES = \
+ emacs/guix-backend.el \
+ emacs/guix-base.el \
+ emacs/guix-build-log.el \
+ emacs/guix-buffer.el \
+ emacs/guix-command.el \
+ emacs/guix-devel.el \
+ emacs/guix-emacs.el \
+ emacs/guix-entry.el \
+ emacs/guix-external.el \
+ emacs/guix-geiser.el \
+ emacs/guix-guile.el \
+ emacs/guix-help-vars.el \
+ emacs/guix-history.el \
+ emacs/guix-hydra.el \
+ emacs/guix-hydra-build.el \
+ emacs/guix-hydra-jobset.el \
+ emacs/guix-info.el \
+ emacs/guix-init.el \
+ emacs/guix-license.el \
+ emacs/guix-list.el \
+ emacs/guix-location.el \
+ emacs/guix-messages.el \
+ emacs/guix-pcomplete.el \
+ emacs/guix-popup.el \
+ emacs/guix-prettify.el \
+ emacs/guix-profiles.el \
+ emacs/guix-read.el \
+ emacs/guix-ui.el \
+ emacs/guix-ui-license.el \
+ emacs/guix-ui-location.el \
+ emacs/guix-ui-package.el \
+ emacs/guix-ui-generation.el \
+ emacs/guix-ui-system-generation.el \
+ emacs/guix-utils.el
+
+if HAVE_EMACS
+
+dist_lisp_DATA = $(ELFILES)
+
+nodist_lisp_DATA = \
+ emacs/guix-config.el \
+ $(AUTOLOADS)
+
+$(AUTOLOADS): $(ELFILES)
+ $(AM_V_EMACS)$(EMACS) --batch --eval \
+ "(let ((backup-inhibited t) \
+ (generated-autoload-file \
+ (expand-file-name \"$(AUTOLOADS)\" \"$(builddir)\"))) \
+ (update-directory-autoloads \
+ (expand-file-name \"emacs\" \"$(srcdir)\")))"
+
+CLEANFILES += $(AUTOLOADS)
+
+endif HAVE_EMACS