guix-about.el 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. ;;; guix-about.el --- Various info about Guix and Emacs-Guix -*- lexical-binding: t -*-
  2. ;; Copyright © 2016–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 the code to display various info about Guix (e.g., its
  18. ;; version).
  19. ;;; Code:
  20. (require 'bui)
  21. (require 'guix nil t)
  22. (require 'guix-utils)
  23. (require 'guix-config)
  24. (declare-function guix-eval-read "guix-repl" (str))
  25. ;;;###autoload
  26. (defun guix-version ()
  27. "Display Emacs-Guix and Guix versions in the echo area."
  28. (interactive)
  29. (require 'guix-repl)
  30. (message "%s %s\n%s %s"
  31. (guix-eval-read "(@ (guix config) %guix-package-name)")
  32. (guix-eval-read "(@ (guix config) %guix-version)")
  33. guix-config-name
  34. guix-config-version))
  35. ;;; "Help" buffer
  36. (guix-define-groups help
  37. :group-doc "Settings for '\\[guix-about]' and '\\[guix-help]'."
  38. :faces-group-doc "Faces for '\\[guix-about]' and '\\[guix-help]'.")
  39. (defcustom guix-help-buffer-name "*Guix Help*"
  40. "Buffer name for '\\[guix-help]'."
  41. :type 'string
  42. :group 'guix-help)
  43. (defcustom guix-help-doc-column 40
  44. "Column at which 'doc' button is inserted."
  45. :type 'integer
  46. :group 'guix-help)
  47. (defface guix-help-heading
  48. '((t :inherit bui-info-heading))
  49. "Face for headings in `guix-help-buffer-name' buffer."
  50. :group 'guix-help-faces)
  51. (defvar guix-help-specifications
  52. '("Show packages"
  53. guix-all-available-packages
  54. guix-newest-available-packages
  55. guix-installed-user-packages
  56. guix-installed-system-packages
  57. guix-installed-packages
  58. guix-obsolete-packages
  59. guix-packages-by-name
  60. guix-packages-by-license
  61. guix-packages-by-location
  62. guix-package-from-file
  63. guix-search-by-name
  64. guix-search-by-regexp
  65. "Show profiles"
  66. guix-profiles
  67. "Show profile generations"
  68. guix-generations
  69. guix-last-generations
  70. guix-generations-by-time
  71. guix-system-generations
  72. guix-last-system-generations
  73. guix-system-generations-by-time
  74. "Show/browse package licenses"
  75. guix-licenses
  76. guix-browse-license-url
  77. guix-find-license-definition
  78. "Show/find package locations"
  79. guix-locations
  80. guix-find-location
  81. guix-edit
  82. "Magit-like interface"
  83. guix
  84. "Show Hydra builds and jobsets"
  85. guix-hydra-latest-builds
  86. guix-hydra-queued-builds
  87. guix-hydra-jobsets
  88. "Hide hash parts in \"/gnu/store/…-foo\" file names"
  89. (guix-prettify-mode nil t)
  90. global-guix-prettify-mode
  91. "Highlighting for package build logs"
  92. (guix-build-log-mode nil t)
  93. (guix-build-log-minor-mode nil t)
  94. "Highlighting for Guix .scm files"
  95. (guix-devel-mode nil t)
  96. "Miscellaneous commands"
  97. ;; `guix-emacs-autoload-packages' is available in Emacs installed
  98. ;; with Guix.
  99. (guix-emacs-autoload-packages t nil)
  100. guix-set-current-profile
  101. guix-pull
  102. guix-apply-manifest
  103. (guix-about t nil)
  104. (guix-version t nil))
  105. "List of command specifications for '\\[guix-help]'.
  106. Each specification can have one of the following forms:
  107. TITLE
  108. COMMAND-NAME
  109. (COMMAND-NAME COMMAND-BUTTON? INFO-BUTTON?)
  110. TITLE is a string.
  111. COMMAND-NAME is a symbol.
  112. COMMAND-BUTTON? is a boolean value; it defines whether
  113. COMMAND-NAME is buttonized or not.
  114. INFO-BUTTON? is a boolean value; it defines whether 'info' button
  115. should be displayed or not.")
  116. (defvar guix-help-mode-map
  117. (let ((map (make-sparse-keymap)))
  118. (set-keymap-parent map (make-composed-keymap button-buffer-map
  119. special-mode-map)))
  120. "Keymap for Emacs-Guix Help and About buffers.")
  121. (define-derived-mode guix-help-mode special-mode "Help"
  122. "Major mode for '\\[guix-about]' and '\\[guix-help]' buffers.
  123. \\{help-mode-map}")
  124. (defun guix-insert-info-button (label info-node)
  125. "Insert button with LABEL to open texinfo manual.
  126. INFO-NODE is the name passed to `info' function."
  127. (bui-insert-button
  128. label 'button
  129. 'action (lambda (button)
  130. (info (button-get button 'node)))
  131. 'node info-node))
  132. (defun guix-insert-info-command-button (label name)
  133. "Insert button with LABEL to open texinfo manual for command NAME."
  134. (bui-insert-button
  135. label 'button
  136. 'help-echo (format "Display info manual for '%S'" name)
  137. 'action (lambda (button)
  138. (guix-goto-command-index-topic
  139. (symbol-name (button-get button 'name))))
  140. 'name name))
  141. (defun guix-insert-doc-button (label symbol)
  142. "Insert button with LABEL to open the docstring of SYMBOL."
  143. (bui-insert-button
  144. label 'button
  145. 'help-echo (format "Display documentation of '%S'" symbol)
  146. 'action (lambda (button)
  147. (describe-symbol (button-get button 'symbol)))
  148. 'symbol symbol))
  149. (defun guix-insert-command-button (command)
  150. "Insert button to run 'M-x COMMAND'."
  151. (let ((command-string (symbol-name command)))
  152. (bui-insert-button
  153. command-string 'button
  154. 'help-echo (format "Call 'M-x %s'" command-string)
  155. 'action (lambda (button)
  156. (call-interactively (button-get button 'command)))
  157. 'command command)))
  158. (declare-function Info-follow-nearest-node "info" t)
  159. (defun guix-goto-index-topic (index-node topic)
  160. "Open TOPIC of INDEX-NODE in the Emacs-Guix manual."
  161. (require 'info)
  162. (info (concat "(emacs-guix)" index-node))
  163. (goto-char (point-min))
  164. (unless (re-search-forward (concat "\\* +" (regexp-quote topic))
  165. nil t)
  166. (user-error "No such index topic: %s" topic))
  167. (Info-follow-nearest-node))
  168. (defun guix-goto-command-index-topic (topic)
  169. "Open TOPIC of Command index in the Emacs-Guix manual."
  170. (guix-goto-index-topic "Command Index" topic))
  171. (defun guix-help-insert-specification (spec)
  172. "Insert command specification SPEC at point.
  173. See `guix-help-specifications' for the meaning of SPEC."
  174. (pcase spec
  175. ((pred symbolp)
  176. (guix-help-insert-specification (list spec t t)))
  177. ((pred stringp)
  178. (bui-newline)
  179. (bui-format-insert spec 'guix-help-heading)
  180. (bui-newline 2))
  181. (`(,name ,command-button? ,info-button?)
  182. (when (fboundp name)
  183. (bui-with-indent bui-indent
  184. (if command-button?
  185. (guix-insert-command-button name)
  186. (insert (symbol-name name)))
  187. (indent-to guix-help-doc-column 2)
  188. (guix-insert-doc-button "doc" name)
  189. (when info-button?
  190. (insert " ")
  191. (guix-insert-info-command-button "info" name)))
  192. (bui-newline)))
  193. (_
  194. (insert "<unknown specification>")
  195. (bui-newline))))
  196. (defun guix-help-reinsert-content (content-function)
  197. "Erase the current buffer and call CONTENT-FUNCTION to fill it."
  198. (let ((inhibit-read-only t))
  199. (erase-buffer)
  200. (funcall content-function)))
  201. (defun guix-help-make-revert-function (content-function)
  202. "Return a revert function for `revert-buffer-function'."
  203. (lambda (_ignore-auto noconfirm)
  204. (when (or noconfirm
  205. (y-or-n-p (format "Revert %s buffer? " (buffer-name))))
  206. (guix-help-reinsert-content content-function))))
  207. (defun guix-help-display-buffer (buffer-name content-function)
  208. "Display BUFFER-NAME buffer and call CONTENT-FUNCTION to fill it."
  209. (with-current-buffer (get-buffer-create buffer-name)
  210. (guix-help-mode)
  211. (setq-local revert-buffer-function
  212. (guix-help-make-revert-function content-function))
  213. (guix-help-reinsert-content content-function))
  214. (switch-to-buffer buffer-name))
  215. (defun guix-help-insert-content ()
  216. "Insert summary of Emacs-Guix commands into the current buffer."
  217. (setq header-line-format
  218. " Summary of the available M-x commands")
  219. (mapc #'guix-help-insert-specification
  220. guix-help-specifications)
  221. ;; Remove an extra newline in the beginning of buffer.
  222. (goto-char (point-min))
  223. (delete-char 1))
  224. (defun guix-help-show ()
  225. "Display a summary of the available Emacs-Guix commands.
  226. Unlike `guix-help', this command always recreates
  227. `guix-help-buffer-name' buffer."
  228. (interactive)
  229. (guix-help-display-buffer guix-help-buffer-name
  230. #'guix-help-insert-content))
  231. ;;;###autoload
  232. (defun guix-help ()
  233. "Display a summary of the available Emacs-Guix commands.
  234. Switch to `guix-help-buffer-name' buffer if it already exists."
  235. (interactive)
  236. (guix-switch-to-buffer-or-funcall
  237. guix-help-buffer-name #'guix-help-show))
  238. ;;; "About" buffer
  239. (defcustom guix-about-buffer-name "*Guix About*"
  240. "Buffer name for '\\[guix-about]'."
  241. :type 'string
  242. :group 'guix-help)
  243. (defvar guix-about-specifications
  244. `("GNU Guix: "
  245. :link ("https://www.gnu.org/software/guix/"
  246. ,(lambda (button)
  247. (browse-url (button-label button))))
  248. "\nEmacs-Guix: "
  249. :link ("https://github.com/alezost/guix.el"
  250. ,(lambda (button)
  251. (browse-url (button-label button))))
  252. "\n\n"
  253. :link ("GNU Guix Manual"
  254. ,(lambda (_button) (info "(guix)")))
  255. "\n"
  256. :link ("Emacs Guix Manual"
  257. ,(lambda (_button) (info "(emacs-guix)")))
  258. "\n"
  259. "\nAvailable commands: "
  260. :link ("M-x guix-help"
  261. ,(lambda (_button) (guix-help)))
  262. "\nGuix and Emacs-Guix versions: "
  263. :link ("M-x guix-version"
  264. ,(lambda (_button) (guix-version)))
  265. "\n")
  266. "Text to show with '\\[guix-about]' command.
  267. This is not really a text, it is a list of arguments passed to
  268. `fancy-splash-insert'.")
  269. (defun guix-logo-file ()
  270. "Return the file name of Guix(SD) logo image.
  271. Return nil, if the image cannot be found."
  272. (when guix-image-directory
  273. (expand-file-name (if (guix-guixsd?)
  274. "guixsd-logo.svg"
  275. "guix-logo.svg")
  276. guix-image-directory)))
  277. (defun guix-insert-logo ()
  278. "Insert Guix(SD) logo into the current buffer."
  279. (when (display-images-p)
  280. (let* ((file (guix-logo-file))
  281. (image (and file (create-image file))))
  282. (when image
  283. (let ((width (car (image-size image))))
  284. (when (> (window-width) width)
  285. ;; Center the image in the window.
  286. (insert (propertize
  287. " " 'display
  288. `(space :align-to (+ center (-0.5 . ,image)))))
  289. (insert-image image)
  290. (bui-newline)))))))
  291. (defun guix-about-insert-content ()
  292. "Insert Emacs-Guix 'about' info into the current buffer."
  293. (guix-insert-logo)
  294. (apply #'fancy-splash-insert guix-about-specifications)
  295. (goto-char (point-min))
  296. (forward-line 3))
  297. (defun guix-about-show ()
  298. "Display 'About' buffer with fancy Guix logo if available.
  299. Unlike `guix-about', this command always recreates
  300. `guix-about-buffer-name' buffer."
  301. (interactive)
  302. (guix-help-display-buffer guix-about-buffer-name
  303. #'guix-about-insert-content))
  304. ;;;###autoload
  305. (defun guix-about ()
  306. "Display 'About' buffer with fancy Guix logo if available.
  307. Switch to `guix-about-buffer-name' buffer if it already exists."
  308. (interactive)
  309. (guix-switch-to-buffer-or-funcall
  310. guix-about-buffer-name #'guix-about-show))
  311. (provide 'guix-about)
  312. ;;; guix-about.el ends here