summaryrefslogtreecommitdiff
path: root/lisp/electric.el
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2015-05-28 00:46:59 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2015-05-28 00:54:06 -0700
commit73512b8cff21a5d92ca72b6cfa34a9210d5a5441 (patch)
treeca007c5cb2d83a984d2991b62a81c908e25596df /lisp/electric.el
parent4643f6c21a88d27cfb8a3410494bfd7909a98462 (diff)
downloademacs-73512b8cff21a5d92ca72b6cfa34a9210d5a5441.tar.gz
New minor mode Electric Quote
This lets you easily insert quotes ‘like this’ by typing quotes `like this', and similarly you can easily insert quotes “like this” by typing quotes ``like this'' (Bug#20545). * doc/emacs/basic.texi (Inserting Text): * doc/emacs/modes.texi (Minor Modes): * etc/NEWS: Document it. * doc/emacs/text.texi (Quotation Marks): New section. * lisp/electric.el (electric-quote-comment) (electric-quote-string, electric-quote-paragraph): New custom vars. (electric--insertable-p) (electric-quote-post-self-insert-function): New functions. (electric-quote-mode, electric-quote-local-mode): New minor modes. * lisp/progmodes/elisp-mode.el (emacs-lisp-mode): Add curved single quotes to electric-pair-text-pairs. Set electric-quote-string in this buffer.
Diffstat (limited to 'lisp/electric.el')
-rw-r--r--lisp/electric.el108
1 files changed, 108 insertions, 0 deletions
diff --git a/lisp/electric.el b/lisp/electric.el
index dd7767fd5eb..88b28352ac0 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -413,6 +413,114 @@ The variable `electric-layout-rules' says when and how to insert newlines."
(remove-hook 'post-self-insert-hook
#'electric-layout-post-self-insert-function))))
+;;; Electric quoting.
+
+(defcustom electric-quote-comment t
+ "Non-nil means to use electric quoting in program comments."
+ :type 'boolean :safe 'booleanp :group 'electricity)
+
+(defcustom electric-quote-string nil
+ "Non-nil means to use electric quoting in program strings."
+ :type 'boolean :safe 'booleanp :group 'electricity)
+
+(defcustom electric-quote-paragraph t
+ "Non-nil means to use electric quoting in text paragraphs."
+ :type 'boolean :safe 'booleanp :group 'electricity)
+
+(defun electric--insertable-p (string)
+ (not (unencodable-char-position nil nil buffer-file-coding-system
+ nil string)))
+
+(defun electric-quote-post-self-insert-function ()
+ "Function that ‘electric-quote-mode’ adds to ‘post-self-insert-hook’.
+This requotes when a quoting key is typed."
+ (when (and electric-quote-mode
+ (memq last-command-event '(?\' ?\`)))
+ (let ((start
+ (if comment-start
+ (when (or electric-quote-comment electric-quote-string)
+ (let ((syntax (syntax-ppss)))
+ (and (or (and electric-quote-comment (nth 4 syntax))
+ (and electric-quote-string (nth 3 syntax)))
+ (nth 8 syntax))))
+ (and electric-quote-paragraph
+ (derived-mode-p 'text-mode)
+ (or (eq last-command-event ?\`)
+ (save-excursion (backward-paragraph) (point)))))))
+ (when start
+ (save-excursion
+ (if (eq last-command-event ?\`)
+ (cond ((and (electric--insertable-p "“")
+ (re-search-backward "[`‘]`" (- (point) 2) t))
+ (replace-match "“")
+ (when (and electric-pair-mode
+ (eq (cdr-safe
+ (assq ?‘ electric-pair-text-pairs))
+ (char-after)))
+ (delete-char 1))
+ (setq last-command-event ?“))
+ ((and (electric--insertable-p "‘")
+ (search-backward "`" (1- (point)) t))
+ (replace-match "‘")
+ (setq last-command-event ?‘)))
+ (let ((pos (point)))
+ (if (memq (char-before (1- (point))) '(?\' ?’))
+ (when (and (search-backward "“" start t)
+ (eq pos (re-search-forward
+ "“\\(\\([^‘”]\\|‘[^‘’”]*’\\)*\\)['’]'"
+ pos t)))
+ (replace-match "“\\1”")
+ (setq last-command-event ?”))
+ (when (and (search-backward "‘" start t)
+ (eq pos (re-search-forward
+ "‘\\([^’]*\\)'" pos t)))
+ (replace-match "‘\\1’")
+ (setq last-command-event ?’))))))))))
+
+(put 'electric-quote-post-self-insert-function 'priority 10)
+
+;;;###autoload
+(define-minor-mode electric-quote-mode
+ "Toggle on-the-fly requoting (Electric Quote mode).
+With a prefix argument ARG, enable Electric Quote mode if
+ARG is positive, and disable it otherwise. If called from Lisp,
+enable the mode if ARG is omitted or nil.
+
+When enabled, this replaces \\=`foo bar' with ‘foo bar’ and replaces
+\\=`\\=`foo bar'' with “foo bar” as you type. This occurs only in
+comments, strings, and text paragraphs, and these are selectively
+controlled with ‘electric-quote-comment’,
+‘electric-quote-string’, and ‘electric-quote-paragraph’.
+
+This is a global minor mode. To toggle the mode in a single buffer,
+use ‘electric-quote-local-mode’."
+ :global t :group 'electricity
+ :initialize 'custom-initialize-delay
+ :init-value nil
+ (if (not electric-quote-mode)
+ (unless (catch 'found
+ (dolist (buf (buffer-list))
+ (with-current-buffer buf
+ (if electric-quote-mode (throw 'found t)))))
+ (remove-hook 'post-self-insert-hook
+ #'electric-quote-post-self-insert-function))
+ (add-hook 'post-self-insert-hook
+ #'electric-quote-post-self-insert-function)
+ (electric--sort-post-self-insertion-hook)))
+
+;;;###autoload
+(define-minor-mode electric-quote-local-mode
+ "Toggle ‘electric-quote-mode’ only in this buffer."
+ :variable (buffer-local-value 'electric-quote-mode (current-buffer))
+ (cond
+ ((eq electric-quote-mode (default-value 'electric-quote-mode))
+ (kill-local-variable 'electric-quote-mode))
+ ((not (default-value 'electric-quote-mode))
+ ;; Locally enabled, but globally disabled.
+ (electric-quote-mode 1) ; Setup the hooks.
+ (setq-default electric-quote-mode nil) ; But keep it globally disabled.
+ )))
+
(provide 'electric)
;;; electric.el ends here