guix-ui-messages.el 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. ;;; guix-ui-messages.el --- Minibuffer messages for Guix package management interface
  2. ;; Copyright © 2014–2019 Alex Kost <alezost@gmail.com>
  3. ;; This file is part of Emacs-Guix.
  4. ;; Emacs-Guix is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  8. ;;
  9. ;; Emacs-Guix is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with Emacs-Guix. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This file provides `guix-result-message' function used to show a
  18. ;; minibuffer message after displaying packages/generations in a
  19. ;; list/info buffer.
  20. ;;; Code:
  21. (require 'cl-lib)
  22. (require 'bui-utils)
  23. (defvar guix-messages
  24. `((package
  25. (id
  26. ,(lambda (_ entries ids)
  27. (guix-message-packages-by-id entries 'package ids)))
  28. (name
  29. ,(lambda (_ entries names)
  30. (guix-message-packages-by-name entries 'package names)))
  31. (license
  32. ,(lambda (_ entries licenses)
  33. (apply #'guix-message-packages-by-license
  34. entries 'package licenses)))
  35. (location
  36. ,(lambda (_ entries locations)
  37. (apply #'guix-message-packages-by-location
  38. entries 'package locations)))
  39. (from-file
  40. (0 "No package in file '%s'." val)
  41. (1 "Package from file '%s'." val))
  42. (from-os-file
  43. (0 "No packages in OS file '%s'." val)
  44. (1 "Package from OS file '%s'." val)
  45. (many "%d packages from OS file '%s'." count val))
  46. (regexp
  47. (0 "No packages matching '%s'." val)
  48. (1 "A single package matching '%s'." val)
  49. (many "%d packages matching '%s'." count val))
  50. (all
  51. (0 "No packages are available for some reason.")
  52. (1 "A single available package (that's strange).")
  53. (many "%d available packages." count))
  54. (installed
  55. (0 "No packages installed in profile '%s'." profile)
  56. (1 "A single package installed in profile '%s'." profile)
  57. (many "%d packages installed in profile '%s'." count profile))
  58. (superseded
  59. (0 "No packages are superseded.")
  60. (1 "A single package is superseded.")
  61. (many "%d packages are superseded." count))
  62. (hidden
  63. (0 "No packages are hidden currently.")
  64. (1 "A single package is hidden.")
  65. (many "%d packages are hidden." count))
  66. (dependent
  67. ,(lambda (_ entries values)
  68. (guix-message-dependent-packages
  69. entries 'package (car values) (cadr values))))
  70. (unknown
  71. (0 "No obsolete packages in profile '%s'." profile)
  72. (1 "A single obsolete or unknown package in profile '%s'." profile)
  73. (many "%d obsolete or unknown packages in profile '%s'."
  74. count profile)))
  75. (output
  76. (id
  77. ,(lambda (_ entries ids)
  78. (guix-message-packages-by-id entries 'output ids)))
  79. (name
  80. ,(lambda (_ entries names)
  81. (guix-message-packages-by-name entries 'output names)))
  82. (license
  83. ,(lambda (_ entries licenses)
  84. (apply #'guix-message-packages-by-license
  85. entries 'output licenses)))
  86. (location
  87. ,(lambda (_ entries locations)
  88. (apply #'guix-message-packages-by-location
  89. entries 'output locations)))
  90. (from-file
  91. (0 "No package in file '%s'." val)
  92. (1 "Package from file '%s'." val)
  93. (many "Package outputs from file '%s'." val))
  94. (from-os-file
  95. (0 "No packages in OS file '%s'." val)
  96. (1 "Package from OS file '%s'." val)
  97. (many "%d package outputs from OS file '%s'." count val))
  98. (regexp
  99. (0 "No package outputs matching '%s'." val)
  100. (1 "A single package output matching '%s'." val)
  101. (many "%d package outputs matching '%s'." count val))
  102. (all
  103. (0 "No package outputs are available for some reason.")
  104. (1 "A single available package output (that's strange).")
  105. (many "%d available package outputs." count))
  106. (installed
  107. (0 "No package outputs installed in profile '%s'." profile)
  108. (1 "A single package output installed in profile '%s'." profile)
  109. (many "%d package outputs installed in profile '%s'." count profile))
  110. (superseded
  111. (0 "No packages are superseded.")
  112. (1 "A single package is superseded.")
  113. (many "%d package outputs are superseded." count))
  114. (hidden
  115. (0 "No packages are hidden currently.")
  116. (1 "A single package is hidden.")
  117. (many "%d package outputs are hidden." count))
  118. (dependent
  119. ,(lambda (_ entries values)
  120. (guix-message-dependent-packages
  121. entries 'package (car values) (cadr values))))
  122. (unknown
  123. (0 "No obsolete package outputs in profile '%s'." profile)
  124. (1 "A single obsolete or unknown package output in profile '%s'."
  125. profile)
  126. (many "%d obsolete or unknown package outputs in profile '%s'."
  127. count profile))
  128. (profile-diff
  129. guix-message-outputs-by-diff))
  130. (generation
  131. (id
  132. (0 "Generations not found.")
  133. (1 "")
  134. (many "%d generations." count))
  135. (last
  136. (0 "No generations in profile '%s'." profile)
  137. (1 "The last generation of profile '%s'." profile)
  138. (many "%d last generations of profile '%s'." count profile))
  139. (all
  140. (0 "No generations in profile '%s'." profile)
  141. (1 "A single generation available in profile '%s'." profile)
  142. (many "%d generations available in profile '%s'." count profile))
  143. (time
  144. guix-message-generations-by-time))))
  145. (defun guix-message-string-name (name)
  146. "Return a quoted name string."
  147. (concat "'" name "'"))
  148. (defun guix-message-string-entry-type (entry-type &optional plural)
  149. "Return a string denoting an ENTRY-TYPE."
  150. (cl-ecase entry-type
  151. (package
  152. (if plural "packages" "package"))
  153. (output
  154. (if plural "package outputs" "package output"))
  155. (generation
  156. (if plural "generations" "generation"))))
  157. (defun guix-message-string-entries (count entry-type)
  158. "Return a string denoting the COUNT of ENTRY-TYPE entries."
  159. (cl-case count
  160. (0 (concat "No "
  161. (guix-message-string-entry-type
  162. entry-type 'plural)))
  163. (1 (concat "A single "
  164. (guix-message-string-entry-type
  165. entry-type)))
  166. (t (format "%d %s"
  167. count
  168. (guix-message-string-entry-type
  169. entry-type 'plural)))))
  170. (defun guix-message-packages-by-id (entries entry-type ids)
  171. "Display a message for packages or outputs searched by IDS."
  172. (let ((count (length entries)))
  173. (if (= 0 count)
  174. (message (substitute-command-keys "\
  175. No packages with ID %s.
  176. Most likely, Guix REPL was restarted, so IDs are not actual
  177. anymore, because they live only during the REPL process.
  178. Or it may be some package variant that cannot be handled by
  179. Emacs-Guix. For example, it may be so called 'canonical package'
  180. used by '%%base-packages' in an operating-system declaration.
  181. Try \"\\[guix-packages-by-name-regexp]\" to find this package.")
  182. (bui-get-string (car ids)))
  183. (message ""))))
  184. (defun guix-message-packages-by-name (entries entry-type names)
  185. "Display a message for packages or outputs searched by NAMES."
  186. (let* ((count (length entries))
  187. (str-beg (guix-message-string-entries count entry-type))
  188. (str-end (if (cdr names)
  189. (concat "matching the following names: "
  190. (mapconcat #'guix-message-string-name
  191. names ", "))
  192. (concat "with name "
  193. (guix-message-string-name (car names))))))
  194. (message "%s %s." str-beg str-end)))
  195. (defun guix-message-packages-by-license (entries entry-type license)
  196. "Display a message for packages or outputs searched by LICENSE."
  197. (let* ((count (length entries))
  198. (str-beg (guix-message-string-entries count entry-type))
  199. (str-end (format "with license '%s'" license)))
  200. (message "%s %s." str-beg str-end)))
  201. (defun guix-message-packages-by-location (entries entry-type location)
  202. "Display a message for packages or outputs searched by LOCATION."
  203. (let* ((count (length entries))
  204. (str-beg (guix-message-string-entries count entry-type))
  205. (str-end (format "placed in '%s'" location)))
  206. (message "%s %s." str-beg str-end)))
  207. (defun guix-message-dependent-packages (entries entry-type
  208. depend-type packages)
  209. "Display a message for packages or outputs searched by PACKAGES.
  210. DEPEND-TYPE should a symbol `direct' or `all'."
  211. (let* ((count (length entries))
  212. (str-beg (guix-message-string-entries count entry-type))
  213. (str-end (concat (if (eq depend-type 'direct)
  214. "directly "
  215. "")
  216. "depending on: "
  217. (mapconcat #'guix-message-string-name
  218. packages ", "))))
  219. (message "%s %s." str-beg str-end)))
  220. (defun guix-message-generations-by-time (profile entries times)
  221. "Display a message for generations searched by TIMES."
  222. (let* ((count (length entries))
  223. (str-beg (guix-message-string-entries count 'generation))
  224. (time-beg (bui-get-time-string (car times)))
  225. (time-end (bui-get-time-string (cadr times))))
  226. (message (concat "%s of profile '%s'\n"
  227. "matching time period '%s' - '%s'.")
  228. str-beg profile time-beg time-end)))
  229. (defun guix-message-outputs-by-diff (_ entries profiles)
  230. "Display a message for outputs searched by PROFILES difference."
  231. (let* ((count (length entries))
  232. (str-beg (guix-message-string-entries count 'output))
  233. (profile1 (car profiles))
  234. (profile2 (cadr profiles)))
  235. (cl-multiple-value-bind (new old str-action)
  236. (if (string-lessp profile2 profile1)
  237. (list profile1 profile2 "added to")
  238. (list profile2 profile1 "removed from"))
  239. (message "%s %s profile '%s' comparing with profile '%s'."
  240. str-beg str-action new old))))
  241. (defun guix-result-message (profile entries entry-type
  242. search-type search-vals)
  243. "Display an appropriate message after displaying ENTRIES."
  244. (let* ((type-spec (bui-assq-value guix-messages
  245. (if (eq entry-type 'system-generation)
  246. 'generation
  247. entry-type)
  248. search-type))
  249. (fun-or-count-spec (car type-spec)))
  250. (if (functionp fun-or-count-spec)
  251. (funcall fun-or-count-spec profile entries search-vals)
  252. (let* ((count (length entries))
  253. (count-key (if (> count 1) 'many count))
  254. (msg-spec (bui-assq-value type-spec count-key))
  255. (msg (car msg-spec))
  256. (args (cdr msg-spec)))
  257. (mapc (lambda (subst)
  258. (setq args (cl-substitute (cdr subst) (car subst) args)))
  259. `((count . ,count)
  260. (val . ,(car search-vals))
  261. (profile . ,profile)))
  262. (apply #'message msg args)))))
  263. (provide 'guix-ui-messages)
  264. ;;; guix-ui-messages.el ends here