buffers.el 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. ;;; buffers.el --- List of buffers and buffer info
  2. ;; Copyright © 2016–2017, 2021 Alex Kost <alezost@gmail.com>
  3. ;; This program is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;;
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;;
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;; This is an example of using BUI (Buffer User Interface) library.
  17. ;;
  18. ;; It shows how to use bui to display a list of buffers à la
  19. ;; `list-buffers' or `ibuffer'.
  20. ;;
  21. ;; To try it, load this file (for example, with "M-x load-file"), and
  22. ;; run "M-x buffers" command. There you can mark several buffers (with
  23. ;; "m") and press "i" to display the info buffer; press "f f" to enable
  24. ;; filters, etc. Press "h" to look at the "hint" (available keys).
  25. ;;; Code:
  26. (require 'bui)
  27. (require 'help-mode) ; for `help-function' button
  28. (bui-define-groups buffers
  29. :parent-group tools
  30. :parent-faces-group faces
  31. :group-doc "Settings for '\\[buffers]' command."
  32. :faces-group-doc "Faces for '\\[buffers]' command.")
  33. (defun buffers-get-buffers (&optional search-type &rest search-values)
  34. (or search-type (setq search-type 'all))
  35. (cl-case search-type
  36. (all (buffer-list))
  37. (id search-values)
  38. (t (error "Unknown search type: %S" search-type))))
  39. (defun buffers-buffer-file-name ()
  40. (or buffer-file-name
  41. (and (boundp 'dired-directory)
  42. (if (stringp dired-directory)
  43. dired-directory
  44. (car dired-directory)))))
  45. (defun buffers-visited-file-modtime ()
  46. (let ((time (visited-file-modtime)))
  47. (cl-case time
  48. ((-1 0) nil)
  49. (t time))))
  50. (defun buffers-buffer->entry (buffer)
  51. (with-current-buffer buffer
  52. `((id . ,buffer)
  53. (name . ,(buffer-name))
  54. (mode . ,major-mode)
  55. (size . ,(buffer-size))
  56. (mod-time . ,(buffers-visited-file-modtime))
  57. (file-name . ,(buffers-buffer-file-name)))))
  58. (defun buffers-get-entries (&rest args)
  59. (mapcar #'buffers-buffer->entry
  60. (apply #'buffers-get-buffers args)))
  61. (bui-define-entry-type buffers
  62. :titles '((mod-time . "Modification Time"))
  63. :get-entries-function #'buffers-get-entries
  64. :filter-predicates
  65. (append bui-filter-predicates
  66. '(buffers-buffer-ephemeral?
  67. buffers-buffer-non-ephemeral?
  68. buffers-buffer-visiting-file?
  69. buffers-buffer-not-visiting-file?)))
  70. (defun buffers-describe-mode-function (button)
  71. (describe-function (intern (button-label button))))
  72. ;;; Filter predicates
  73. (defun buffers-buffer-ephemeral? (entry)
  74. "Return non-nil, if ENTRY's buffer name starts with a space."
  75. (string= " " (substring (bui-entry-value entry 'name) 0 1)))
  76. (defun buffers-buffer-non-ephemeral? (entry)
  77. "Return non-nil, if ENTRY's buffer name does not start with a space."
  78. (not (buffers-buffer-ephemeral? entry)))
  79. (defun buffers-buffer-visiting-file? (entry)
  80. "Return non-nil, if ENTRY's buffer visits a file."
  81. (bui-entry-non-void-value entry 'file-name))
  82. (defun buffers-buffer-not-visiting-file? (entry)
  83. "Return non-nil, if ENTRY's buffer does not visit a file."
  84. (not (buffers-buffer-visiting-file? entry)))
  85. ;;; 'Info' interface
  86. (bui-define-interface buffers info
  87. :format '((name format buffers-info-insert-name)
  88. (mode format (simple buffers-mode-function))
  89. (size format (format))
  90. nil
  91. (file-name nil (simple bui-file))
  92. (mod-time format (time))))
  93. (define-button-type 'buffers-mode-function
  94. :supertype 'help-function
  95. 'action 'buffers-describe-mode-function)
  96. (defun buffers-info-insert-name (name entry)
  97. (bui-info-insert-value-simple (bui-entry-value entry 'name)
  98. 'mode-line-buffer-id)
  99. (bui-insert-indent)
  100. (bui-insert-action-button
  101. "Switch"
  102. (lambda (btn)
  103. (pop-to-buffer (button-get btn 'buffer)))
  104. "Switch to this buffer"
  105. 'buffer (bui-entry-id entry)))
  106. ;;; 'List' interface
  107. (bui-define-interface buffers list
  108. :buffer-name "*Buffers*"
  109. :describe-function #'buffers-list-describe
  110. :titles '((mod-time . "Mod. Time"))
  111. :format '((name nil 30 t)
  112. (mode buffers-list-get-mode 25 t)
  113. (size nil 8 bui-list-sort-numerically-2 :right-align t)
  114. ;; (mod-time bui-list-get-time 20 t)
  115. (file-name bui-list-get-file-name 30 t))
  116. :hint 'buffers-list-hint
  117. :sort-key '(name))
  118. (let ((map buffers-list-mode-map))
  119. (define-key map (kbd "RET") 'buffers-list-switch-to-buffer)
  120. (define-key map (kbd "k") 'buffers-list-kill-buffers))
  121. (defvar buffers-list-default-hint
  122. '(("\\[buffers-list-switch-to-buffer]") " switch to buffer;\n"
  123. ("\\[buffers-list-kill-buffers]") " kill buffer(s);\n"))
  124. (defun buffers-list-hint ()
  125. "Return a hint string to display in the echo area."
  126. (bui-format-hints
  127. buffers-list-default-hint
  128. (bui-default-hint)))
  129. (defun buffers-list-get-mode (mode &optional _)
  130. "Return MODE button specification for `tabulated-list-entries'.
  131. MODE may be nil."
  132. (list (symbol-name mode)
  133. :supertype 'help-function
  134. 'action 'buffers-describe-mode-function))
  135. (defun buffers-list-describe (&rest buffers)
  136. "Display 'info' buffer for BUFFERS."
  137. (bui-get-display-entries 'buffers 'info (cons 'id buffers)))
  138. (defun buffers-list-switch-to-buffer ()
  139. (interactive)
  140. (pop-to-buffer (bui-list-current-id)))
  141. (defun buffers-list-kill-buffers ()
  142. "Kill marked buffers (or the current buffer)."
  143. (interactive)
  144. (dolist (buffer (or (bui-list-get-marked-id-list)
  145. (list (bui-list-current-id))))
  146. (kill-buffer buffer))
  147. (revert-buffer nil t))
  148. ;;; Interactive commands
  149. ;;;###autoload
  150. (defun buffers ()
  151. "Display a list of buffers."
  152. (interactive)
  153. (bui-list-get-display-entries 'buffers))
  154. (provide 'buffers)
  155. ;;; buffers.el ends here