emacs-lock.el 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. ;;; emacs-lock.el --- protect buffers against killing or exiting -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2011-2012 Free Software Foundation, Inc.
  3. ;; Author: Juanma Barranquero <lekktu@gmail.com>
  4. ;; Inspired by emacs-lock.el by Tom Wurgler <twurgler@goodyear.com>
  5. ;; Maintainer: FSF
  6. ;; Keywords: extensions, processes
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; This package defines a minor mode Emacs Lock to mark a buffer as
  20. ;; protected against accidental killing, or exiting Emacs, or both.
  21. ;; Buffers associated with inferior modes, like shell or telnet, can
  22. ;; be treated specially, by auto-unlocking them if their interior
  23. ;; processes are dead.
  24. ;;; Code:
  25. (defgroup emacs-lock nil
  26. "Emacs-Lock mode."
  27. :version "24.1"
  28. :group 'convenience)
  29. (defcustom emacs-lock-default-locking-mode 'all
  30. "Default locking mode of Emacs-Locked buffers.
  31. Its value is used as the default for `emacs-lock-mode' (which
  32. see) the first time that Emacs Lock mode is turned on in a buffer
  33. without passing an explicit locking mode.
  34. Possible values are:
  35. exit -- Emacs cannot exit while the buffer is locked
  36. kill -- the buffer cannot be killed, but Emacs can exit as usual
  37. all -- the buffer is locked against both actions
  38. nil -- the buffer is not locked"
  39. :type '(choice
  40. (const :tag "Do not allow Emacs to exit" exit)
  41. (const :tag "Do not allow killing the buffer" kill)
  42. (const :tag "Do not allow killing the buffer or exiting Emacs" all)
  43. (const :tag "Do not lock the buffer" nil))
  44. :group 'emacs-lock
  45. :version "24.1")
  46. ;; Note: as auto-unlocking can lead to data loss, it would be better
  47. ;; to default to nil; but the value below is for compatibility with
  48. ;; the old emacs-lock.el.
  49. (defcustom emacs-lock-unlockable-modes '((shell-mode . all)
  50. (telnet-mode . all))
  51. "Alist of auto-unlockable modes.
  52. Each element is a pair (MAJOR-MODE . ACTION), where ACTION is
  53. one of `kill', `exit' or `all'. Buffers with matching major
  54. modes are auto-unlocked for the specific action if their
  55. inferior processes are not alive. If this variable is t, all
  56. buffers associated to inferior processes are auto-unlockable
  57. for both actions (NOT RECOMMENDED)."
  58. :type '(choice
  59. (const :tag "All buffers with inferior processes" t)
  60. (repeat :tag "Selected modes"
  61. (cons :tag "Set auto-unlock for"
  62. (symbol :tag "Major mode")
  63. (radio
  64. (const :tag "Allow exiting" exit)
  65. (const :tag "Allow killing" kill)
  66. (const :tag "Allow both" all)))))
  67. :group 'emacs-lock
  68. :version "24.1")
  69. (defvar emacs-lock-mode nil
  70. "If non-nil, the current buffer is locked.
  71. It can be one of the following values:
  72. exit -- Emacs cannot exit while the buffer is locked
  73. kill -- the buffer cannot be killed, but Emacs can exit as usual
  74. all -- the buffer is locked against both actions
  75. nil -- the buffer is not locked")
  76. (make-variable-buffer-local 'emacs-lock-mode)
  77. (put 'emacs-lock-mode 'permanent-local t)
  78. (defvar emacs-lock--old-mode nil
  79. "Most recent locking mode set on the buffer.
  80. Internal use only.")
  81. (make-variable-buffer-local 'emacs-lock--old-mode)
  82. (put 'emacs-lock--old-mode 'permanent-local t)
  83. (defvar emacs-lock--try-unlocking nil
  84. "Non-nil if current buffer should be checked for auto-unlocking.
  85. Internal use only.")
  86. (make-variable-buffer-local 'emacs-lock--try-unlocking)
  87. (put 'emacs-lock--try-unlocking 'permanent-local t)
  88. (defun emacs-lock-live-process-p (buffer-or-name)
  89. "Return t if BUFFER-OR-NAME is associated with a live process."
  90. (let ((proc (get-buffer-process buffer-or-name)))
  91. (and proc (process-live-p proc))))
  92. (defun emacs-lock--can-auto-unlock (action)
  93. "Return t if the current buffer can auto-unlock for ACTION.
  94. ACTION must be one of `kill' or `exit'.
  95. See `emacs-lock-unlockable-modes'."
  96. (and emacs-lock--try-unlocking
  97. (not (emacs-lock-live-process-p (current-buffer)))
  98. (or (eq emacs-lock-unlockable-modes t)
  99. (let ((unlock (cdr (assq major-mode emacs-lock-unlockable-modes))))
  100. (or (eq unlock 'all) (eq unlock action))))))
  101. (defun emacs-lock--exit-locked-buffer ()
  102. "Return the name of the first exit-locked buffer found."
  103. (save-current-buffer
  104. (catch :found
  105. (dolist (buffer (buffer-list))
  106. (set-buffer buffer)
  107. (unless (or (emacs-lock--can-auto-unlock 'exit)
  108. (memq emacs-lock-mode '(nil kill)))
  109. (throw :found (buffer-name))))
  110. nil)))
  111. (defun emacs-lock--kill-emacs-hook ()
  112. "Signal an error if any buffer is exit-locked.
  113. Used from `kill-emacs-hook' (which see)."
  114. (let ((buffer-name (emacs-lock--exit-locked-buffer)))
  115. (when buffer-name
  116. (error "Emacs cannot exit because buffer %S is locked" buffer-name))))
  117. (defun emacs-lock--kill-emacs-query-functions ()
  118. "Display a message if any buffer is exit-locked.
  119. Return a value appropriate for `kill-emacs-query-functions' (which see)."
  120. (let ((locked (emacs-lock--exit-locked-buffer)))
  121. (or (not locked)
  122. (progn
  123. (message "Emacs cannot exit because buffer %S is locked" locked)
  124. nil))))
  125. (defun emacs-lock--kill-buffer-query-functions ()
  126. "Display a message if the current buffer is kill-locked.
  127. Return a value appropriate for `kill-buffer-query-functions' (which see)."
  128. (or (emacs-lock--can-auto-unlock 'kill)
  129. (memq emacs-lock-mode '(nil exit))
  130. (progn
  131. (message "Buffer %S is locked and cannot be killed" (buffer-name))
  132. nil)))
  133. (defun emacs-lock--set-mode (mode arg)
  134. "Setter function for `emacs-lock-mode'."
  135. (setq emacs-lock-mode
  136. (cond ((memq arg '(all exit kill))
  137. ;; explicit locking mode arg, use it
  138. arg)
  139. ((and (eq arg current-prefix-arg) (consp current-prefix-arg))
  140. ;; called with C-u M-x emacs-lock-mode, so ask the user
  141. (intern (completing-read "Locking mode: "
  142. '("all" "exit" "kill")
  143. nil t nil nil
  144. (symbol-name
  145. emacs-lock-default-locking-mode))))
  146. ((eq mode t)
  147. ;; turn on, so use previous setting, or customized default
  148. (or emacs-lock--old-mode emacs-lock-default-locking-mode))
  149. (t
  150. ;; anything else (turn off)
  151. mode))))
  152. ;;;###autoload
  153. (define-minor-mode emacs-lock-mode
  154. "Toggle Emacs Lock mode in the current buffer.
  155. If called with a plain prefix argument, ask for the locking mode
  156. to be used. With any other prefix ARG, turn mode on if ARG is
  157. positive, off otherwise. If called from Lisp, enable the mode if
  158. ARG is omitted or nil.
  159. Initially, if the user does not pass an explicit locking mode, it
  160. defaults to `emacs-lock-default-locking-mode' (which see);
  161. afterwards, the locking mode most recently set on the buffer is
  162. used instead.
  163. When called from Elisp code, ARG can be any locking mode:
  164. exit -- Emacs cannot exit while the buffer is locked
  165. kill -- the buffer cannot be killed, but Emacs can exit as usual
  166. all -- the buffer is locked against both actions
  167. Other values are interpreted as usual."
  168. :init-value nil
  169. :lighter (""
  170. (emacs-lock--try-unlocking " locked:" " Locked:")
  171. (:eval (symbol-name emacs-lock-mode)))
  172. :group 'emacs-lock
  173. :variable (emacs-lock-mode .
  174. (lambda (mode)
  175. (emacs-lock--set-mode mode arg)))
  176. (when emacs-lock-mode
  177. (setq emacs-lock--old-mode emacs-lock-mode)
  178. (setq emacs-lock--try-unlocking
  179. (and (if (eq emacs-lock-unlockable-modes t)
  180. (emacs-lock-live-process-p (current-buffer))
  181. (assq major-mode emacs-lock-unlockable-modes))
  182. t))))
  183. (unless noninteractive
  184. (add-hook 'kill-buffer-query-functions 'emacs-lock--kill-buffer-query-functions)
  185. ;; We set a hook in both kill-emacs-hook and kill-emacs-query-functions because
  186. ;; we really want to use k-e-q-f to stop as soon as possible, but don't want to
  187. ;; be caught by surprise if someone calls `kill-emacs' instead.
  188. (add-hook 'kill-emacs-hook 'emacs-lock--kill-emacs-hook)
  189. (add-hook 'kill-emacs-query-functions 'emacs-lock--kill-emacs-query-functions))
  190. (defun emacs-lock-unload-function ()
  191. "Unload the Emacs Lock library."
  192. (catch :continue
  193. (dolist (buffer (buffer-list))
  194. (set-buffer buffer)
  195. (when emacs-lock-mode
  196. (if (y-or-n-p (format "Buffer %S is locked, unlock it? " (buffer-name)))
  197. (emacs-lock-mode -1)
  198. (message "Unloading of feature `emacs-lock' aborted.")
  199. (throw :continue t))))
  200. ;; continue standard unloading
  201. nil))
  202. ;;; Compatibility
  203. (define-obsolete-variable-alias 'emacs-lock-from-exiting 'emacs-lock-mode "24.1")
  204. (defun toggle-emacs-lock ()
  205. "Toggle `emacs-lock-from-exiting' for the current buffer."
  206. (interactive)
  207. (call-interactively 'emacs-lock-mode))
  208. (make-obsolete 'toggle-emacs-lock 'emacs-lock-mode "24.1")
  209. (provide 'emacs-lock)
  210. ;;; emacs-lock.el ends here