guix-ui-profile.el 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. ;;; guix-ui-profile.el --- Interface for displaying profiles -*- lexical-binding: t -*-
  2. ;; Copyright © 2016 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 a 'list' interface for displaying Guix profiles
  18. ;; with `guix-profiles' command.
  19. ;;
  20. ;; `guix-profiles' variable controls what profiles are displayed.
  21. ;;; Code:
  22. (require 'dash)
  23. (require 'bui)
  24. (require 'guix nil t)
  25. (require 'guix-profiles)
  26. (require 'guix-utils)
  27. (guix-define-groups profile)
  28. (defcustom guix-profiles
  29. (-filter #'file-exists-p
  30. (list guix-user-profile
  31. guix-system-profile))
  32. "List of profiles displayed by '\\[guix-profiles]' command."
  33. :type '(repeat file)
  34. :group 'guix-profile)
  35. (defun guix-profile->entry (profile)
  36. "Return 'guix-profile' entry by PROFILE file-name."
  37. `((id . ,profile)
  38. (profile . ,profile)
  39. (current . ,(guix-current-profile? profile))
  40. (number-of-packages . ,(guix-profile-number-of-packages
  41. profile))
  42. (number-of-generations . ,(guix-profile-number-of-generations
  43. profile))))
  44. (defun guix-profile-get-entries ()
  45. "Return 'guix-profile' entries."
  46. (mapcar #'guix-profile->entry guix-profiles))
  47. ;;; Profile 'list'
  48. (bui-define-interface guix-profile list
  49. :mode-name "Profile-List"
  50. :buffer-name "*Guix Profiles*"
  51. :get-entries-function 'guix-profile-get-entries
  52. :format '((current guix-profile-list-get-current 10 t)
  53. (profile bui-list-get-file-name 40 t)
  54. (number-of-packages nil 11 bui-list-sort-numerically-2
  55. :right-align t)
  56. (number-of-generations nil 14 bui-list-sort-numerically-3
  57. :right-align t))
  58. :titles '((number-of-packages . "Packages")
  59. (number-of-generations . "Generations"))
  60. :sort-key '(profile))
  61. (let ((map guix-profile-list-mode-map))
  62. (define-key map [remap self-insert-command] 'guix-profile-list-hint)
  63. (define-key map (kbd "P") 'guix-profile-list-show-packages)
  64. (define-key map (kbd "G") 'guix-profile-list-show-generations)
  65. (define-key map (kbd "M") 'guix-profile-list-apply-manifest)
  66. (define-key map (kbd "c") 'guix-profile-list-set-current)
  67. ;; Unbind "i" and "RET" as "Profile Info" interface is not defined.
  68. (define-key map (kbd "i") nil)
  69. (define-key map (kbd "RET") 'guix-profile-list-hint))
  70. (defun guix-profile-list-hint ()
  71. "Display a message with useful key bindings."
  72. (interactive)
  73. (message (substitute-command-keys "Hint:
  74. Press '\\[guix-profile-list-show-packages]' to display packages.
  75. Press '\\[guix-profile-list-show-generations]' to display generations.")))
  76. (defun guix-profile-list-current-profile ()
  77. "Return file name of the current profile."
  78. ;; (bui-entry-value (bui-list-current-entry) 'profile)
  79. ;; Just get the ID, as currently ID is the profile file name.
  80. (bui-list-current-id))
  81. (declare-function guix-installed-packages "guix-ui-package" t)
  82. (declare-function guix-generations "guix-ui-generation" t)
  83. (declare-function guix-system-generations "guix-ui-system-generation" t)
  84. (declare-function guix-apply-manifest "guix-misc" t)
  85. (defun guix-profile-list-show-packages ()
  86. "Display packages installed in the current profile."
  87. (interactive)
  88. (guix-installed-packages (guix-package-profile
  89. (guix-profile-list-current-profile))))
  90. (defun guix-profile-list-show-generations ()
  91. "Display generations of the current profile."
  92. (interactive)
  93. (let ((profile (guix-profile-list-current-profile)))
  94. (if (guix-system-profile? profile)
  95. (guix-system-generations)
  96. (guix-generations (guix-generation-profile profile)))))
  97. (defun guix-profile-list-apply-manifest (file)
  98. "Apply manifest from FILE to the current profile."
  99. (interactive
  100. (list (read-file-name "File with manifest: ")))
  101. (guix-apply-manifest (guix-package-profile
  102. (guix-profile-list-current-profile))
  103. file (current-buffer)))
  104. (defun guix-profile-list-get-current (value &optional _)
  105. "Return string from VALUE showing whether this profile is current."
  106. (if value "(current)" ""))
  107. (defun guix-profile-list-set-current ()
  108. "Set `guix-current-profile' to the profile on the current line."
  109. (interactive)
  110. (guix-set-current-profile (guix-profile-list-current-profile))
  111. ;; Now updating "Current" column is needed. It can be done simply by
  112. ;; reverting the buffer, but it should be more effective to reset
  113. ;; 'current' parameter for all entries and to redisplay the buffer
  114. ;; instead.
  115. (let* ((current-id (bui-list-current-id))
  116. (new-entries (mapcar
  117. (lambda (entry)
  118. (let ((id (bui-entry-id entry)))
  119. (cons `(current . ,(equal id current-id))
  120. (--remove-first (eq (car it) 'current)
  121. entry))))
  122. (bui-current-entries))))
  123. (setf (bui-item-entries bui-item)
  124. new-entries))
  125. (bui-redisplay))
  126. ;;; Interactive commands
  127. ;;;###autoload
  128. (defun guix-profiles ()
  129. "Display Guix profiles.
  130. Modify `guix-profiles' variable to add more profiles."
  131. (interactive)
  132. (bui-list-get-display-entries 'guix-profile))
  133. (provide 'guix-ui-profile)
  134. ;;; guix-ui-profile.el ends here