emacs: Add minibuffer readers.
[jackhill/guix/guix.git] / emacs / guix-read.el
1 ;;; guix-read.el --- Minibuffer readers
2
3 ;; Copyright © 2015 Alex Kost <alezost@gmail.com>
4
5 ;; This file is part of GNU Guix.
6
7 ;; GNU Guix is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, either version 3 of the License, or
10 ;; (at your option) any later version.
11
12 ;; GNU Guix is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
16
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 ;;; Commentary:
21
22 ;; This file provides functions to prompt a user for packages, system
23 ;; types, hash formats and other guix related stuff.
24
25 ;;; Code:
26
27 (require 'guix-help-vars)
28 (require 'guix-utils)
29 (require 'guix-base)
30
31 (defun guix-read-file-name (prompt &optional dir default-filename
32 mustmatch initial predicate)
33 "Read file name.
34 This function is similar to `read-file-name' except it also
35 expands the file name."
36 (expand-file-name (read-file-name prompt dir default-filename
37 mustmatch initial predicate)))
38
39 (defmacro guix-define-reader (name read-fun completions prompt)
40 "Define NAME function to read from minibuffer.
41 READ-FUN may be `completing-read', `completing-read-multiple' or
42 another function with the same arguments."
43 `(defun ,name (&optional prompt initial-contents)
44 (,read-fun ,(if prompt
45 `(or prompt ,prompt)
46 'prompt)
47 ,completions nil nil initial-contents)))
48
49 (defmacro guix-define-readers (&rest args)
50 "Define reader functions.
51
52 ARGS should have a form [KEYWORD VALUE] ... The following
53 keywords are available:
54
55 - `completions-var' - variable used to get completions.
56
57 - `completions-getter' - function used to get completions.
58
59 - `single-reader', `single-prompt' - name of a function to read
60 a single value, and a prompt for it.
61
62 - `multiple-reader', `multiple-prompt' - name of a function to
63 read multiple values, and a prompt for it.
64
65 - `multiple-separator' - if specified, another
66 `<multiple-reader-name>-string' function returning a string
67 of multiple values separated the specified separator will be
68 defined."
69 (let (completions-var
70 completions-getter
71 single-reader
72 single-prompt
73 multiple-reader
74 multiple-prompt
75 multiple-separator)
76
77 ;; Process the keyword args.
78 (while (keywordp (car args))
79 (pcase (pop args)
80 (`:completions-var (setq completions-var (pop args)))
81 (`:completions-getter (setq completions-getter (pop args)))
82 (`:single-reader (setq single-reader (pop args)))
83 (`:single-prompt (setq single-prompt (pop args)))
84 (`:multiple-reader (setq multiple-reader (pop args)))
85 (`:multiple-prompt (setq multiple-prompt (pop args)))
86 (`:multiple-separator (setq multiple-separator (pop args)))
87 (_ (pop args))))
88
89 (let ((completions
90 (cond ((and completions-var completions-getter)
91 `(or ,completions-var
92 (setq ,completions-var
93 (funcall ',completions-getter))))
94 (completions-var
95 completions-var)
96 (completions-getter
97 `(funcall ',completions-getter)))))
98 `(progn
99 ,(when (and completions-var
100 (not (boundp completions-var)))
101 `(defvar ,completions-var nil))
102
103 ,(when single-reader
104 `(guix-define-reader ,single-reader completing-read
105 ,completions ,single-prompt))
106
107 ,(when multiple-reader
108 `(guix-define-reader ,multiple-reader completing-read-multiple
109 ,completions ,multiple-prompt))
110
111 ,(when (and multiple-reader multiple-separator)
112 (let ((name (intern (concat (symbol-name multiple-reader)
113 "-string"))))
114 `(defun ,name (&optional prompt initial-contents)
115 (guix-concat-strings
116 (,multiple-reader prompt initial-contents)
117 ,multiple-separator))))))))
118
119 (guix-define-readers
120 :completions-var guix-help-system-types
121 :single-reader guix-read-system-type
122 :single-prompt "System type: ")
123
124 (guix-define-readers
125 :completions-var guix-help-source-types
126 :single-reader guix-read-source-type
127 :single-prompt "Source type: ")
128
129 (guix-define-readers
130 :completions-var guix-help-hash-formats
131 :single-reader guix-read-hash-format
132 :single-prompt "Hash format: ")
133
134 (guix-define-readers
135 :completions-var guix-help-refresh-subsets
136 :single-reader guix-read-refresh-subset
137 :single-prompt "Refresh subset: ")
138
139 (guix-define-readers
140 :completions-var guix-help-key-policies
141 :single-reader guix-read-key-policy
142 :single-prompt "Key policy: ")
143
144 (guix-define-readers
145 :completions-var guix-help-elpa-archives
146 :single-reader guix-read-elpa-archive
147 :single-prompt "ELPA archive: ")
148
149 (guix-define-readers
150 :completions-var guix-help-verify-options
151 :multiple-reader guix-read-verify-options
152 :multiple-prompt "Verify option,s: "
153 :multiple-separator ",")
154
155 (guix-define-readers
156 :completions-getter guix-graph-type-names
157 :single-reader guix-read-graph-type
158 :single-prompt "Graph node type: ")
159
160 (guix-define-readers
161 :completions-getter guix-lint-checker-names
162 :multiple-reader guix-read-lint-checker-names
163 :multiple-prompt "Linter,s: "
164 :multiple-separator ",")
165
166 (guix-define-readers
167 :completions-getter guix-package-names
168 :single-reader guix-read-package-name
169 :single-prompt "Package: "
170 :multiple-reader guix-read-package-names
171 :multiple-prompt "Package,s: "
172 :multiple-separator " ")
173
174 (provide 'guix-read)
175
176 ;;; guix-read.el ends here