| 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 |