guix-ui-messages.el 10 KB

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