buffer-layers.el 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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.0
  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. (defvar *buffer-layers* nil
  13. "List of all defined buffer layers.")
  14. (defvar *buffer-layers-applied* nil
  15. "List of applied buffer-layers.")
  16. (defvar *buffer-layer-definitions* nil
  17. "List of buffer layer definitions.")
  18. (defun buffer-layer-applied-p (layer)
  19. "Returns true if LAYER is applied."
  20. (member layer *buffer-layers-applied*))
  21. (defun buffer-layer-defined-p (layer)
  22. "Returns true if LAYER is defined."
  23. (member layer *buffer-layers*))
  24. (defun buffer-layer--buffer-list-name (name)
  25. "Generate name to contain buffer layer buffer list based on NAME."
  26. (intern (format "*buffer-layer-%s-buffers*" name)))
  27. (cl-defmacro define-buffer-layer (name &key files run-on-apply run-on-remove buffer-to-select)
  28. "Define a buffer layer named NAME, taking FILES, RUN-ON-APPLY, RUN-ON-REMOVE and BUFFER-TO-SELECT as keyword arguments."
  29. (let ((buffers-list (buffer-layer--buffer-list-name name))
  30. ;; (files-list (cons 'list
  31. ;; (when (not (null files))
  32. ;; (mapcar #'(lambda (name)
  33. ;; (format "%s" name)) files))))
  34. )
  35. `(progn
  36. (add-to-list '*buffer-layers* ',name)
  37. (defvar ,buffers-list nil)
  38. (add-to-list '*buffer-layer-definitions*
  39. '(,name
  40. ,files
  41. ,buffer-to-select
  42. (lambda ()
  43. ,@run-on-apply
  44. nil)
  45. (lambda ()
  46. ,@run-on-remove
  47. nil)))
  48. ;; (defun ,applier ()
  49. ;; ,(format "Apply buffer-layer %s." name)
  50. ;; (interactive)
  51. ;; (mapcar #'(lambda (file)
  52. ;; (add-to-list ',buffers-list (find-file file)))
  53. ;; ,files-list)
  54. ;; ,@run-on-apply
  55. ;; (when (not (null ,buffer-to-select))
  56. ;; (switch-to-buffer ,buffer-to-select))
  57. ;; (add-to-list '*buffer-layers-applied* ',name)
  58. ;; (message "Applied Buffer Layer %s" ',name))
  59. ;; (defun ,remover ()
  60. ;; ,(format "Remove buffer-layer %s." name)
  61. ;; (interactive)
  62. ;; (mapc #'(lambda (buffer)
  63. ;; (when (buffer-live-p buffer)
  64. ;; (with-current-buffer buffer
  65. ;; (save-buffer)
  66. ;; (kill-buffer))))
  67. ;; ,buffers-list)
  68. ;; ,@run-on-remove
  69. ;; (setq ,buffers-list nil)
  70. ;; (setq *buffer-layers-applied* (delq ',name *buffer-layers-applied*))
  71. ;; (message "Removed Buffer Layer %s" ',name))
  72. (setq current-buffer-layer ',name)
  73. ',name)))
  74. (defun load-buffer-layer (name-or-path load-it-p)
  75. "Load a buffer named NAME-OR-PATH, and if a file, apply if LOAD-IT-P is true."
  76. (interactive (list (completing-read "Buffer Layer Name or Path: " (cl-remove-if #'(lambda (layer)
  77. (member layer *buffer-layers-applied*))
  78. *buffer-layers*))
  79. nil))
  80. (if (buffer-layer-defined-p name-or-path)
  81. (let* ((record (assoc name-or-path *buffer-layer-definitions*))
  82. (files-list (nth 1 record))
  83. (selected (nth 2 record))
  84. (on-apply (nth 3 record)))
  85. (mapcar #'(lambda (file)
  86. (add-to-list (buffer-layer--buffer-list-name name-or-path)
  87. (find-file file)))
  88. files-list)
  89. (funcall on-apply)
  90. (when (not (null selected))
  91. (switch-to-buffer selected))
  92. (add-to-list '*buffer-layers-applied* name-or-path)
  93. (message "Applied buffer layer %s." name-or-path))
  94. (progn
  95. (load name-or-path)
  96. (when load-it-p
  97. (load-buffer-layer current-buffer-layer t)))))
  98. (defun unload-buffer-layer (name)
  99. "Unload Buffer Layer named NAME."
  100. (interactive (list (completing-read "Buffer Layer Name: " *buffer-layers-applied*)))
  101. (let ((on-remove (nth 4 (assoc name *buffer-layer-definitions*))))
  102. (mapc #'(lambda (buffer)
  103. (when (buffer-live-p buffer)
  104. (with-current-buffer buffer
  105. (save-buffer)
  106. (kill-buffer))))
  107. (symbol-value (buffer-layer--buffer-list-name name)))
  108. (setq (buffer-layer--buffer-list-name name) nil)
  109. (setq *buffer-layers-applied* (delq name *buffer-layers-applied*))
  110. (funcall on-remove)
  111. (message "Removed Buffer Layer %s." name)))
  112. (defun buffer-layer-list ()
  113. "Produce a list of defined buffer layers."
  114. (interactive)
  115. (with-help-window "*Buffer Layers*"
  116. (when (buffer-live-p "*Buffer Layers*")
  117. (kill-buffer "*Buffer Layers*"))
  118. (with-current-buffer "*Buffer Layers*"
  119. (insert "Defined Buffer Layers:\n\n")
  120. (dolist (layer *buffer-layers*)
  121. (insert (format " - %s%s\n" layer (if (buffer-layer-applied-p layer) " (Applied)"
  122. "")))))))
  123. (defun unload-all-buffer-layers ()
  124. "Unload all loaded buffer layers."
  125. (interactive)
  126. (dolist (buffer-layer *buffer-layers-applied*)
  127. (unload-buffer-layer buffer-layer)))
  128. (defvar buffer-layer-map (make-keymap)
  129. "Keymap for buffer-layer commands.")
  130. (define-key buffer-layer-map (kbd "l") #'load-buffer-layer)
  131. (define-key buffer-layer-map (kbd "L") #'buffer-layer-list)
  132. (define-key buffer-layer-map (kbd "u") #'unload-buffer-layer)
  133. (define-key buffer-layer-map (kbd "U") #'unload-all-buffer-layers)
  134. (define-minor-mode buffer-layer-mode
  135. "A mode for managing layers of buffers."
  136. :lighter " BLM" :global t :variable buffer-layer-mode-p
  137. (if buffer-layer-mode-p
  138. (progn
  139. (define-key ctl-x-map (kbd "L") buffer-layer-map)
  140. (add-hook 'kill-emacs-hook #'unload-all-buffer-layers))
  141. (progn
  142. (define-key ctl-x-map (kbd "L") nil)
  143. (remove-hook 'kill-emacs-hook #'unload-all-buffer-layers))))
  144. (provide 'buffer-layers)
  145. ;;; buffer-layers.el ends here