Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
5.6 KiB

пре 4 година
  1. ;;; cider-popup.el --- Creating and quitting popup buffers -*- lexical-binding: t; -*-
  2. ;; Copyright © 2015-2019 Bozhidar Batsov, Artur Malabarba and CIDER contributors
  3. ;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
  4. ;; This program is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  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. ;; You should have received a copy of the GNU General Public License
  13. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. ;;; Commentary:
  15. ;; Common functionality for dealing with popup buffers.
  16. ;;; Code:
  17. (require 'subr-x)
  18. (require 'cider-compat)
  19. (define-minor-mode cider-popup-buffer-mode
  20. "Mode for CIDER popup buffers"
  21. nil
  22. (" cider-tmp")
  23. '(("q" . cider-popup-buffer-quit-function)))
  24. (defvar-local cider-popup-buffer-quit-function #'cider-popup-buffer-quit
  25. "The function that is used to quit a temporary popup buffer.")
  26. (defun cider-popup-buffer-quit-function (&optional kill-buffer-p)
  27. "Wrapper to invoke the function `cider-popup-buffer-quit-function'.
  28. KILL-BUFFER-P is passed along."
  29. (interactive)
  30. (funcall cider-popup-buffer-quit-function kill-buffer-p))
  31. (defun cider-popup-buffer (name &optional select mode ancillary)
  32. "Create new popup buffer called NAME.
  33. If SELECT is non-nil, select the newly created window.
  34. If major MODE is non-nil, enable it for the popup buffer.
  35. If ANCILLARY is non-nil, the buffer is added to `cider-ancillary-buffers'
  36. and automatically removed when killed."
  37. (thread-first (cider-make-popup-buffer name mode ancillary)
  38. (cider-popup-buffer-display select)))
  39. (defun cider-popup-buffer-display (buffer &optional select)
  40. "Display BUFFER.
  41. If SELECT is non-nil, select the BUFFER."
  42. (let ((window (get-buffer-window buffer 'visible)))
  43. (when window
  44. (with-current-buffer buffer
  45. (set-window-point window (point))))
  46. ;; If the buffer we are popping up is already displayed in the selected
  47. ;; window, the below `inhibit-same-window' logic will cause it to be
  48. ;; displayed twice - so we early out in this case. Note that we must check
  49. ;; `selected-window', as async request handlers are executed in the context
  50. ;; of the current connection buffer (i.e. `current-buffer' is dynamically
  51. ;; bound to that).
  52. (unless (eq window (selected-window))
  53. ;; Non nil `inhibit-same-window' ensures that current window is not covered
  54. ;; Non nil `inhibit-switch-frame' ensures that the other frame is not selected
  55. ;; if that's where the buffer is being shown.
  56. (funcall (if select #'pop-to-buffer #'display-buffer)
  57. buffer `(nil . ((inhibit-same-window . ,pop-up-windows)
  58. (reusable-frames . visible))))))
  59. buffer)
  60. (defun cider-popup-buffer-quit (&optional kill)
  61. "Quit the current (temp) window.
  62. Bury its buffer using `quit-restore-window'.
  63. If prefix argument KILL is non-nil, kill the buffer instead of burying it."
  64. (interactive)
  65. (quit-restore-window (selected-window) (if kill 'kill 'append)))
  66. (defvar-local cider-popup-output-marker nil)
  67. (defvar cider-ancillary-buffers nil
  68. "A list ancillary buffers created by the various CIDER commands.
  69. We track them mostly to be able to clean them up on quit.")
  70. (defun cider-make-popup-buffer (name &optional mode ancillary)
  71. "Create a temporary buffer called NAME using major MODE (if specified).
  72. If ANCILLARY is non-nil, the buffer is added to `cider-ancillary-buffers'
  73. and automatically removed when killed."
  74. (with-current-buffer (get-buffer-create name)
  75. (kill-all-local-variables)
  76. (setq buffer-read-only nil)
  77. (erase-buffer)
  78. (when mode
  79. (funcall mode))
  80. (cider-popup-buffer-mode 1)
  81. (setq cider-popup-output-marker (point-marker))
  82. (setq buffer-read-only t)
  83. (when ancillary
  84. (add-to-list 'cider-ancillary-buffers name)
  85. (add-hook 'kill-buffer-hook
  86. (lambda ()
  87. (setq cider-ancillary-buffers
  88. (remove name cider-ancillary-buffers)))
  89. nil 'local))
  90. (current-buffer)))
  91. (defun cider-emit-into-popup-buffer (buffer value &optional face inhibit-indent)
  92. "Emit into BUFFER the provided VALUE optionally using FACE.
  93. Indent emitted value (usually a sexp) unless INHIBIT-INDENT is specified
  94. and non-nil."
  95. ;; Long string output renders Emacs unresponsive and users might intentionally
  96. ;; kill the frozen popup buffer. Therefore, we don't re-create the buffer and
  97. ;; silently ignore the output.
  98. (when (buffer-live-p buffer)
  99. (with-current-buffer buffer
  100. (let ((inhibit-read-only t)
  101. (buffer-undo-list t)
  102. (moving (= (point) cider-popup-output-marker)))
  103. (save-excursion
  104. (goto-char cider-popup-output-marker)
  105. (let ((value-str (format "%s" value)))
  106. (when face
  107. (if (fboundp 'add-face-text-property)
  108. (add-face-text-property 0 (length value-str) face nil value-str)
  109. (add-text-properties 0 (length value-str) (list 'face face) value-str)))
  110. (insert value-str))
  111. (unless inhibit-indent
  112. (indent-sexp))
  113. (set-marker cider-popup-output-marker (point)))
  114. (when moving (goto-char cider-popup-output-marker))))))
  115. (provide 'cider-popup)
  116. ;;; cider-popup.el ends here