guix-ui-messages.el 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. ;;; guix-ui-messages.el --- Minibuffer messages for Guix package management interface
  2. ;; Copyright © 2014–2017 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-available
  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. (newest-available
  55. (0 "No packages are available for some reason.")
  56. (1 "A single newest available package (that's strange).")
  57. (many "%d newest available packages." count))
  58. (installed
  59. (0 "No packages installed in profile '%s'." profile)
  60. (1 "A single package installed in profile '%s'." profile)
  61. (many "%d packages installed in profile '%s'." count profile))
  62. (superseded
  63. (0 "No packages are superseded.")
  64. (1 "A single package is superseded.")
  65. (many "%d packages are superseded." count))
  66. (unknown
  67. (0 "No obsolete packages in profile '%s'." profile)
  68. (1 "A single obsolete or unknown package in profile '%s'." profile)
  69. (many "%d obsolete or unknown packages in profile '%s'."
  70. count profile)))
  71. (output
  72. (id
  73. ,(lambda (_ entries ids)
  74. (guix-message-packages-by-id entries 'output ids)))
  75. (name
  76. ,(lambda (_ entries names)
  77. (guix-message-packages-by-name entries 'output names)))
  78. (license
  79. ,(lambda (_ entries licenses)
  80. (apply #'guix-message-packages-by-license
  81. entries 'output licenses)))
  82. (location
  83. ,(lambda (_ entries locations)
  84. (apply #'guix-message-packages-by-location
  85. entries 'output locations)))
  86. (from-file
  87. (0 "No package in file '%s'." val)
  88. (1 "Package from file '%s'." val)
  89. (many "Package outputs from file '%s'." val))
  90. (from-os-file
  91. (0 "No packages in OS file '%s'." val)
  92. (1 "Package from OS file '%s'." val)
  93. (many "%d package outputs from OS file '%s'." count val))
  94. (regexp
  95. (0 "No package outputs matching '%s'." val)
  96. (1 "A single package output matching '%s'." val)
  97. (many "%d package outputs matching '%s'." count val))
  98. (all-available
  99. (0 "No package outputs are available for some reason.")
  100. (1 "A single available package output (that's strange).")
  101. (many "%d available package outputs." count))
  102. (newest-available
  103. (0 "No package outputs are available for some reason.")
  104. (1 "A single newest available package output (that's strange).")
  105. (many "%d newest 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. (unknown
  115. (0 "No obsolete package outputs in profile '%s'." profile)
  116. (1 "A single obsolete or unknown package output in profile '%s'."
  117. profile)
  118. (many "%d obsolete or unknown package outputs in profile '%s'."
  119. count profile))
  120. (profile-diff
  121. guix-message-outputs-by-diff))
  122. (generation
  123. (id
  124. (0 "Generations not found.")
  125. (1 "")
  126. (many "%d generations." count))
  127. (last
  128. (0 "No generations in profile '%s'." profile)
  129. (1 "The last generation of profile '%s'." profile)
  130. (many "%d last generations of profile '%s'." count profile))
  131. (all
  132. (0 "No generations in profile '%s'." profile)
  133. (1 "A single generation available in profile '%s'." profile)
  134. (many "%d generations available in profile '%s'." count profile))
  135. (time
  136. guix-message-generations-by-time))))
  137. (defun guix-message-string-name (name)
  138. "Return a quoted name string."
  139. (concat "'" name "'"))
  140. (defun guix-message-string-entry-type (entry-type &optional plural)
  141. "Return a string denoting an ENTRY-TYPE."
  142. (cl-ecase entry-type
  143. (package
  144. (if plural "packages" "package"))
  145. (output
  146. (if plural "package outputs" "package output"))
  147. (generation
  148. (if plural "generations" "generation"))))
  149. (defun guix-message-string-entries (count entry-type)
  150. "Return a string denoting the COUNT of ENTRY-TYPE entries."
  151. (cl-case count
  152. (0 (concat "No "
  153. (guix-message-string-entry-type
  154. entry-type 'plural)))
  155. (1 (concat "A single "
  156. (guix-message-string-entry-type
  157. entry-type)))
  158. (t (format "%d %s"
  159. count
  160. (guix-message-string-entry-type
  161. entry-type 'plural)))))
  162. (defun guix-message-packages-by-id (entries entry-type ids)
  163. "Display a message for packages or outputs searched by IDS."
  164. (let* ((count (length entries))
  165. (str-beg (guix-message-string-entries count entry-type))
  166. (str-end (if (> count 1)
  167. (concat "with the following IDs: "
  168. (mapconcat #'bui-get-string ids ", "))
  169. (concat "with ID " (bui-get-string (car ids))))))
  170. (if (zerop count)
  171. (message (substitute-command-keys "%s %s.
  172. Most likely, Guix REPL was restarted, so IDs are not actual
  173. anymore, because they live only during the REPL process.
  174. Or it may be some package variant that cannot be handled by
  175. Emacs-Guix. For example, it may be so called 'canonical package'
  176. used by '%%base-packages' in an operating-system declaration.
  177. Try \"\\[guix-search-by-name]\" to find this package.")
  178. str-beg str-end)
  179. (message "%s %s." str-beg str-end))))
  180. (defun guix-message-packages-by-name (entries entry-type names)
  181. "Display a message for packages or outputs searched by NAMES."
  182. (let* ((count (length entries))
  183. (str-beg (guix-message-string-entries count entry-type))
  184. (str-end (if (cdr names)
  185. (concat "matching the following names: "
  186. (mapconcat #'guix-message-string-name
  187. names ", "))
  188. (concat "with name "
  189. (guix-message-string-name (car names))))))
  190. (message "%s %s." str-beg str-end)))
  191. (defun guix-message-packages-by-license (entries entry-type license)
  192. "Display a message for packages or outputs searched by LICENSE."
  193. (let* ((count (length entries))
  194. (str-beg (guix-message-string-entries count entry-type))
  195. (str-end (format "with license '%s'" license)))
  196. (message "%s %s." str-beg str-end)))
  197. (defun guix-message-packages-by-location (entries entry-type location)
  198. "Display a message for packages or outputs searched by LOCATION."
  199. (let* ((count (length entries))
  200. (str-beg (guix-message-string-entries count entry-type))
  201. (str-end (format "placed in '%s'" location)))
  202. (message "%s %s." str-beg str-end)))
  203. (defun guix-message-generations-by-time (profile entries times)
  204. "Display a message for generations searched by TIMES."
  205. (let* ((count (length entries))
  206. (str-beg (guix-message-string-entries count 'generation))
  207. (time-beg (bui-get-time-string (car times)))
  208. (time-end (bui-get-time-string (cadr times))))
  209. (message (concat "%s of profile '%s'\n"
  210. "matching time period '%s' - '%s'.")
  211. str-beg profile time-beg time-end)))
  212. (defun guix-message-outputs-by-diff (_ entries profiles)
  213. "Display a message for outputs searched by PROFILES difference."
  214. (let* ((count (length entries))
  215. (str-beg (guix-message-string-entries count 'output))
  216. (profile1 (car profiles))
  217. (profile2 (cadr profiles)))
  218. (cl-multiple-value-bind (new old str-action)
  219. (if (string-lessp profile2 profile1)
  220. (list profile1 profile2 "added to")
  221. (list profile2 profile1 "removed from"))
  222. (message "%s %s profile '%s' comparing with profile '%s'."
  223. str-beg str-action new old))))
  224. (defun guix-result-message (profile entries entry-type
  225. search-type search-vals)
  226. "Display an appropriate message after displaying ENTRIES."
  227. (let* ((type-spec (bui-assq-value guix-messages
  228. (if (eq entry-type 'system-generation)
  229. 'generation
  230. entry-type)
  231. search-type))
  232. (fun-or-count-spec (car type-spec)))
  233. (if (functionp fun-or-count-spec)
  234. (funcall fun-or-count-spec profile entries search-vals)
  235. (let* ((count (length entries))
  236. (count-key (if (> count 1) 'many count))
  237. (msg-spec (bui-assq-value type-spec count-key))
  238. (msg (car msg-spec))
  239. (args (cdr msg-spec)))
  240. (mapc (lambda (subst)
  241. (setq args (cl-substitute (cdr subst) (car subst) args)))
  242. `((count . ,count)
  243. (val . ,(car search-vals))
  244. (profile . ,profile)))
  245. (apply #'message msg args)))))
  246. (provide 'guix-ui-messages)
  247. ;;; guix-ui-messages.el ends here