buffer-layers.el 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. ;;; buffer-layers.el --- Layered Buffers for Buffer Management
  2. ;; Copyright (C) 2016 Samuel Flint
  3. ;; Author: Samuel W. Flint <swflint@flintfam.org>
  4. ;; Version: 1.7
  5. ;; Package-Requires: ((cl-lib "0.5"))
  6. ;; Keywords: buffer-management
  7. ;; URL: http://github.com/swflint/buffer-layers
  8. ;;; Commentary:
  9. ;;
  10. ;;; Code:
  11. (require 'cl-lib)
  12. (cl-defstruct buffer-layer
  13. name
  14. files
  15. select
  16. on-apply
  17. on-apply-source
  18. on-remove
  19. on-remove-source)
  20. (defvar *buffer-layers* nil
  21. "List of all defined buffer layers.")
  22. (defvar *buffer-layers-applied* nil
  23. "List of applied buffer-layers.")
  24. (defvar *buffer-layer-definitions* nil
  25. "List of all buffer layer definitions.")
  26. (defvar *buffer-layer-buffers* nil
  27. "List of buffers in loaded buffer layers.")
  28. (defvar *buffer-layer-file* "~/.emacs.d/buffer-layer-definitions.el"
  29. "The file to store buffer layer definitions in.")
  30. (defun buffer-layers-applied-p (layer)
  31. "Returns true if LAYER is applied."
  32. (member layer *buffer-layers-applied*))
  33. (defun buffer-layer--get-buffer-layer-definition (layer-name)
  34. (car (cl-remove-if-not (lambda (layer)
  35. (eq layer-name (buffer-layer-name layer))) *buffer-layer-definitions*)))
  36. (defun buffer-layer--generate-buffers-list (layer-name)
  37. (intern (format "*buffer-layer-%s--buffers*" layer-name)))
  38. (cl-defmacro define-buffer-layer (name &key files select on-apply on-remove)
  39. "Define a buffer layer named NAME, taking FILES, RUN-ON-APPLY, RUN-ON-REMOVE and BUFFER-TO-SELECT as keyword arguments."
  40. `(progn
  41. (cl-pushnew ',name *buffer-layers*)
  42. (cl-pushnew (make-buffer-layer :name ',name
  43. :files ',files
  44. :select ,select
  45. :on-apply-source ',on-apply
  46. :on-remove-source ',on-remove
  47. :on-apply (lambda () ,@on-apply)
  48. :on-remove (lambda () ,@on-remove))
  49. *buffer-layer-definitions*
  50. :key #'buffer-layer-name)
  51. (defvar ,(buffer-layer--generate-buffers-list name) nil)
  52. ',name))
  53. (defun buffer-layers-load-layer (name)
  54. (interactive (list (intern (completing-read "Layer Name: "
  55. (cl-remove-if #'(lambda (layer) (member layer *buffer-layers-applied*)) *buffer-layers*)
  56. nil t))))
  57. (let ((layer-definition (buffer-layer--get-buffer-layer-definition name)))
  58. (if (not (buffer-layer-p layer-definition))
  59. (error "Layer Undefined: %s" name)
  60. (let ((files (buffer-layer-files layer-definition))
  61. (select (buffer-layer-select layer-definition))
  62. (on-apply (buffer-layer-on-apply layer-definition))
  63. (buffers-list (buffer-layer--generate-buffers-list name)))
  64. (setf (symbol-value buffers-list) (mapcar #'find-file files))
  65. (funcall on-apply)
  66. (when (stringp select)
  67. (switch-to-buffer select))
  68. (add-to-list '*buffer-layers-applied* name)
  69. (message "Applied buffer layer %s." name)))))
  70. (defalias 'load-buffer-layer 'buffer-layers-load-layer)
  71. (defun buffer-layers-unload-buffer-layer (name)
  72. "Unload Buffer Layer named NAME."
  73. (interactive (list (intern (completing-read "Buffer Layer Name: " *buffer-layers-applied*))))
  74. (let ((layer-definition (buffer-layer--get-buffer-layer-definition name)))
  75. (if (not (buffer-layer-p layer-definition))
  76. (error "Layer Undefined: %s" name)
  77. (let ((buffers-list (buffer-layer--generate-buffers-list name))
  78. (on-remove (buffer-layer-on-remove layer-definition)))
  79. (mapc (lambda (buffer)
  80. (with-current-buffer buffer
  81. (save-buffer)
  82. (kill-buffer buffer)))
  83. (symbol-value buffers-list))
  84. (funcall on-remove)
  85. (setf (symbol-value buffers-list) nil)
  86. (setq *buffer-layers-applied* (delq name *buffer-layers-applied*))
  87. (message "Removed Buffer Layer: %s" name)))))
  88. (defun buffer-layers-list ()
  89. "Produce a list of defined buffer layers."
  90. (interactive)
  91. (when (buffer-live-p "*Buffer Layers*")
  92. (kill-buffer "*Buffer Layers*"))
  93. (with-help-window "*Buffer Layers*"
  94. (with-current-buffer "*Buffer Layers*"
  95. (insert "Defined Buffer Layers:\n\n")
  96. (dolist (layer *buffer-layers*)
  97. (if (not (buffer-layers-applied-p layer))
  98. (insert (format " - %s\n" layer))
  99. (insert (format " - %s (Applied)\n" layer)))
  100. (dolist (buffer (symbol-value (buffer-layer--generate-buffers-list layer)))
  101. (if (null (get-buffer-window-list buffer nil t))
  102. (insert (format " - %s\n" (buffer-name buffer)))
  103. (insert (format " - %s (visible)\n" (buffer-name buffer)))))))))
  104. (defun buffer-layers-unload-all-buffer-layers ()
  105. "Unload all loaded buffer layers."
  106. (interactive)
  107. (dolist (buffer-layer *buffer-layers-applied*)
  108. (buffer-layers-unload-buffer-layer buffer-layer)))
  109. (defun buffer-layers-create-layer (name)
  110. "Create a new layer."
  111. (interactive "SNew Layer Name: "))
  112. (defun buffer-layers-add-file-to-layer (name file)
  113. "Add a file to the layer."
  114. (interactive (list
  115. (completing-read "Layer: " *buffer-layers* nil t)
  116. (read-file-name "File Name: "))))
  117. (defun buffer-layers-add-buffer-to-layer (name buffer)
  118. "Add a buffer to the given layer."
  119. (interactive (list
  120. (completing-read "Layer: " *buffer-layers* nil t)
  121. (read-buffer "Buffer: " (current-buffer)))))
  122. (defun buffer-layers-edit-load-actions (layer)
  123. "Edit the actions to be preformed on buffer layer load."
  124. (interactive (list (completing-read "Layer: " *buffer-layers* nil t))))
  125. (defun buffer-layers-edit-remove-actions (layer)
  126. "Edit the actions to be preformed on buffer layer removal."
  127. (interactive (list (completing-read "Layer: " *buffer-layers* nil t))))
  128. (defun buffer-layers-set-buffer-to-select (layer)
  129. "Set the buffer to automatically select."
  130. (interactive (list (completing-read "Layer: " *buffer-layers* nil t))))
  131. (defun buffer-layers-save ()
  132. "Save defined buffer layers."
  133. (interactive)
  134. (insert (format "%S\n\n" (let ((name (buffer-layer-name the-layer))
  135. (files (buffer-layer-files the-layer))
  136. (select (buffer-layer-select the-layer))
  137. (on-apply (buffer-layer-on-apply-source the-layer))
  138. (on-remove (buffer-layer-on-remove-source the-layer)))
  139. `(define-buffer-layer* ,name
  140. :files ,files
  141. :select ,select
  142. :on-apply ,on-apply
  143. :on-remove ,on-remove)))))
  144. (defvar buffer-layers-map (make-keymap)
  145. "Keymap for buffer-layer commands.")
  146. (define-key buffer-layers-map (kbd "l") #'buffer-layers-load-buffer-layer)
  147. (define-key buffer-layers-map (kbd "L") #'buffer-layers-list)
  148. (define-key buffer-layers-map (kbd "u") #'buffer-layers-unload-buffer-layer)
  149. (define-key buffer-layers-map (kbd "U") #'buffer-layers-unload-all-buffer-layers)
  150. (define-key buffer-layers-map (kbd "c") #'buffer-layers-create-layer)
  151. (define-key buffer-layers-map (kbd "f") #'buffer-layers-add-file-to-layer)
  152. (define-key buffer-layers-map (kbd "b") #'buffer-layers-add-buffer-to-layer)
  153. (define-key buffer-layers-map (kbd "a") #'buffer-layers-edit-load-actions)
  154. (define-key buffer-layers-map (kbd "r") #'buffer-layers-edit-remove-actions)
  155. (define-key buffer-layers-map (kbd "s") #'buffer-layers-set-buffer-to-select)
  156. (define-key buffer-layers-map (kbd "C-s") #'buffer-layers-save)
  157. (define-minor-mode buffer-layers-mode
  158. "A mode for managing layers of buffers."
  159. :lighter " BLM" :global t :variable buffer-layers-mode-p
  160. (if buffer-layers-mode-p
  161. (progn
  162. (define-key ctl-x-map (kbd "L") buffer-layers-map)
  163. (add-hook 'kill-emacs-hook #'buffer-layers-unload-all-buffer-layers))
  164. (progn
  165. (define-key ctl-x-map (kbd "L") nil)
  166. (remove-hook 'kill-emacs-hook #'buffer-layers-unload-all-buffer-layers))))
  167. (provide 'buffer-layers)
  168. ;;; buffer-layers.el ends here