buffer-layers.el 5.1 KB

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