buffer-layers.el 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. ;; This is Buffer Layers, a simple, layer-based buffer management system.
  11. ;;
  12. ;; It works by defining buffer layers using a fairly simple macro. The following would be put in a file called `org.layer`
  13. ;;
  14. ;; ```elisp
  15. ;; ;; -*- emacs-lisp -*-
  16. ;; (define-buffer-layer org
  17. ;; :files ("~/org/"
  18. ;; "~/org/main.org")
  19. ;; :buffer-to-select "main.org"
  20. ;; :run-on-apply ((my/find-current-notes-file)))
  21. ;; ```
  22. ;;
  23. ;; It can be loaded with `(load-buffer-layer "/path/to/org.layer" nil)`. If the final `nil` is changed to `t`, it will load and apply the layer.
  24. ;;
  25. ;; Buffer Layer Definitions take the following arguments:
  26. ;;
  27. ;; - `:files`: A list. This is the list of files that are loaded when the buffer layer is applied.
  28. ;; - `:buffer-to-select`: The buffer to select after files are loaded, and the given forms to run on application are executed.
  29. ;; - `:run-on-apply`: This is a list of forms to be executed in between finding files and selecting the given buffer.
  30. ;; - `:run-on-remove`: This is a list of forms to be executed after killing the buffers that have been loaded.
  31. ;;
  32. ;; To manipulate buffer layers, execute `buffer-layer-mode`, and then you can use the following keybindings:
  33. ;;
  34. ;; - `C-x L l`: Load a buffer layer, if defined, otherwise, load from the given file.
  35. ;; - `C-x L u`: Unload a loaded buffer layer.
  36. ;; - `C-x L U`: Unload all loaded buffer layers.
  37. ;; - `C-x L L`: List defined buffer layers, noting if they've been applied.
  38. ;;
  39. ;; The following are the user-facing functions:
  40. ;;
  41. ;; - `define-buffer-layer`
  42. ;; - `buffer-layer-load-buffer-layer`, also known as `load-buffer-layer`
  43. ;; - `buffer-layers-unload-buffer-layer`
  44. ;; - `buffer-layers-list`
  45. ;; - `buffer-layers-unload-all-buffer-layers`
  46. ;; - `buffer-layers-mode`
  47. ;;
  48. ;; On enabling `buffer-layer-mode`, the map is placed onto `C-x L`, and `buffer-layers-unload-all-buffer-layers` is added to the `kill-emacs-hook`, and on disabling the mode, they are removed.
  49. ;;; Code:
  50. (require 'cl-lib)
  51. (cl-defstruct buffer-layer
  52. name
  53. files
  54. select
  55. on-apply
  56. on-apply-source
  57. on-remove
  58. on-remove-source)
  59. (defvar *buffer-layers* nil
  60. "List of all defined buffer layers.")
  61. (defvar *buffer-layers-applied* nil
  62. "List of applied buffer-layers.")
  63. (defvar *buffer-layer-definitions* nil
  64. "List of all buffer layer definitions.")
  65. (defvar *buffer-layer-buffers* nil
  66. "List of buffers in loaded buffer layers.")
  67. (defvar *buffer-layer-file* "~/.emacs.d/buffer-layer-definitions.el"
  68. "The file to store buffer layer definitions in.")
  69. (defun buffer-layers-applied-p (layer)
  70. "Returns true if LAYER is applied."
  71. (member layer *buffer-layers-applied*))
  72. (defun buffer-layer--get-buffer-layer-definition (layer-name)
  73. (first (cl-remove-if-not (lambda (layer)
  74. (eq layer-name (buffer-layer-name layer))) *buffer-layer-definitions*)))
  75. (defun buffer-layer--generate-buffers-list (layer-name)
  76. (intern (format "*buffer-layer-%s--buffers*" layer-name)))
  77. (cl-defmacro define-buffer-layer (name &key files select on-apply on-remove)
  78. "Define a buffer layer named NAME, taking FILES, RUN-ON-APPLY, RUN-ON-REMOVE and BUFFER-TO-SELECT as keyword arguments."
  79. `(progn
  80. (cl-pushnew ',name *buffer-layers*)
  81. (cl-pushnew (make-buffer-layer :name ',name
  82. :files ',files
  83. :select ,select
  84. :on-apply-source ',on-apply
  85. :on-remove-source ',on-remove
  86. :on-apply (lambda () ,@on-apply)
  87. :on-remove (lambda () ,@on-remove))
  88. *buffer-layer-definitions*
  89. :key #'buffer-layer-name)
  90. (defvar ,(buffer-layer--generate-buffers-list name))
  91. ',name))
  92. (defun buffer-layers-load-layer (name)
  93. (interactive (list (completing-read "Layer Name: "
  94. (cl-remove-if #'(lambda (layer) (member layer *buffer-layers-applied*)) *buffer-layers*)
  95. nil t)))
  96. (let ((layer-definition (buffer-layer--get-buffer-layer-definition name)))
  97. ;; (if (not (buffer-layer-p layer-definition))
  98. ;; (error "Layer Undefined: %s" name))
  99. (let ((files (buffer-layer-files layer-definition))
  100. (select (buffer-layer-select layer-definition))
  101. (on-apply (buffer-layer-on-apply layer-definition))
  102. (buffers-list (buffer-layer--generate-buffers-list name)))
  103. (mapc (lambda (file)
  104. (add-to-list buffers-list (find-file file)))
  105. files)
  106. (funcall on-apply)
  107. (when (stringp select)
  108. (switch-to-buffer select))
  109. (add-to-list '*buffer-layers-applied* name)
  110. (message "Applied buffer layer %s." name))))
  111. (defalias 'load-buffer-layer 'buffer-layers-load-layer)
  112. (defun buffer-layers-unload-buffer-layer (name)
  113. "Unload Buffer Layer named NAME."
  114. (interactive (list (completing-read "Buffer Layer Name: " *buffer-layers-applied*)))
  115. (funcall (buffer-layers--remover-name name)))
  116. (defun buffer-layers-list ()
  117. "Produce a list of defined buffer layers."
  118. (interactive)
  119. (when (buffer-live-p "*Buffer Layers*")
  120. (kill-buffer "*Buffer Layers*"))
  121. (with-help-window "*Buffer Layers*"
  122. (with-current-buffer "*Buffer Layers*"
  123. (insert "Defined Buffer Layers:\n\n")
  124. (dolist (layer *buffer-layers*)
  125. (if (not (buffer-layers-applied-p layer))
  126. (insert (format " - %s\n" layer))
  127. (insert (format " - %s (Applied)\n" layer)))
  128. (dolist (buffer (symbol-value (buffer-layers--buffers-list-name layer)))
  129. (if (null (get-buffer-window-list buffer nil t))
  130. (insert (format " - %s\n" (buffer-name buffer)))
  131. (insert (format " - %s (visible)\n" (buffer-name buffer)))))))))
  132. (defun buffer-layers-unload-all-buffer-layers ()
  133. "Unload all loaded buffer layers."
  134. (interactive)
  135. (dolist (buffer-layer *buffer-layers-applied*)
  136. (buffer-layers-unload-buffer-layer buffer-layer)))
  137. (defun buffer-layers-create-layer (name)
  138. "Create a new layer."
  139. (interactive "SNew Layer Name: "))
  140. (defun buffer-layers-add-file-to-layer (name file)
  141. "Add a file to the layer."
  142. (interactive (list
  143. (completing-read "Layer: " *buffer-layers* nil t)
  144. (read-file-name "File Name: "))))
  145. (defun buffer-layers-add-buffer-to-layer (name buffer)
  146. "Add a buffer to the given layer."
  147. (interactive (list
  148. (completing-read "Layer: " *buffer-layers* nil t)
  149. (read-buffer "Buffer: " (current-buffer)))))
  150. (defun buffer-layers-edit-load-actions (layer)
  151. "Edit the actions to be preformed on buffer layer load."
  152. (interactive (list (completing-read "Layer: " *buffer-layers* nil t))))
  153. (defun buffer-layers-edit-remove-actions (layer)
  154. "Edit the actions to be preformed on buffer layer removal."
  155. (interactive (list (completing-read "Layer: " *buffer-layers* nil t))))
  156. (defun buffer-layers-set-buffer-to-select (layer)
  157. "Set the buffer to automatically select."
  158. (interactive (list (completing-read "Layer: " *buffer-layers* nil t))))
  159. (defun buffer-layers-save ()
  160. "Save defined buffer layers."
  161. (interactive)
  162. (insert (format "%S\n\n" (let ((name (buffer-layer-name the-layer))
  163. (files (buffer-layer-files the-layer))
  164. (select (buffer-layer-select the-layer))
  165. (on-apply (buffer-layer-on-apply-source the-layer))
  166. (on-remove (buffer-layer-on-remove-source the-layer)))
  167. `(define-buffer-layer* ,name
  168. :files ,files
  169. :select ,select
  170. :on-apply ,on-apply
  171. :on-remove ,on-remove)))))
  172. (defvar buffer-layers-map (make-keymap)
  173. "Keymap for buffer-layer commands.")
  174. (define-key buffer-layers-map (kbd "l") #'buffer-layers-load-buffer-layer)
  175. (define-key buffer-layers-map (kbd "L") #'buffer-layers-list)
  176. (define-key buffer-layers-map (kbd "u") #'buffer-layers-unload-buffer-layer)
  177. (define-key buffer-layers-map (kbd "U") #'buffer-layers-unload-all-buffer-layers)
  178. (define-key buffer-layers-map (kbd "c") #'buffer-layers-create-layer)
  179. (define-key buffer-layers-map (kbd "f") #'buffer-layers-add-file-to-layer)
  180. (define-key buffer-layers-map (kbd "b") #'buffer-layers-add-buffer-to-layer)
  181. (define-key buffer-layers-map (kbd "a") #'buffer-layers-edit-load-actions)
  182. (define-key buffer-layers-map (kbd "r") #'buffer-layers-edit-remove-actions)
  183. (define-key buffer-layers-map (kbd "s") #'buffer-layers-set-buffer-to-select)
  184. (define-key buffer-layers-map (kbd "C-s") #'buffer-layers-save)
  185. (define-minor-mode buffer-layers-mode
  186. "A mode for managing layers of buffers."
  187. :lighter " BLM" :global t :variable buffer-layers-mode-p
  188. (if buffer-layers-mode-p
  189. (progn
  190. (define-key ctl-x-map (kbd "L") buffer-layers-map)
  191. (add-hook 'kill-emacs-hook #'buffer-layers-unload-all-buffer-layers))
  192. (progn
  193. (define-key ctl-x-map (kbd "L") nil)
  194. (remove-hook 'kill-emacs-hook #'buffer-layers-unload-all-buffer-layers))))
  195. (provide 'buffer-layers)
  196. ;;; buffer-layers.el ends here