diff options
author | Alan Mackenzie <acm@muc.de> | 2019-01-15 15:54:02 +0000 |
---|---|---|
committer | Alan Mackenzie <acm@muc.de> | 2019-01-15 15:54:02 +0000 |
commit | 223e7b87872d4a010ae1c9a6f09a9c15aee46692 (patch) | |
tree | 609573333dd10bdce35efc2cfff7ca7b4ea643df /lisp/progmodes/cc-cmds.el | |
parent | 9530108fbc8bbf1ad5c1debe4b4f21da1238325b (diff) | |
download | emacs-223e7b87872d4a010ae1c9a6f09a9c15aee46692.tar.gz |
Make CC Mode and electric-pair-mode work together. This fixes bug #33794
* lisp/progmodes/cc-cmds.el (c-electric-pound, c-electric-slash)
(c-electric-star, c-electric-semi&comma, c-electric-colon, c-electric-lt-gt):
Bind post-self-insert-hook to nil around calls to self-insert-command to
protect against arbitrary functionality confusing CC Mode.
(c-do-brace-electrics): New function, extracted from c-electric-brace and
enhanced.
(c-electric-brace): Bind post-self-insert-hook to nil around the call to
self-insert-command. When electric-pair-mode is configured, call
electric-pair-post-self-insert-function. Handle any deletion done by this
function. Call c-do-brace-electrics for the inserted brace, and perhaps for a
brace inserted by electric-pair-self-insert-function.
(c-electric-paren): Bind post-self-insert-hook to nil around the call to
self-insert-command. When electric-pair-mode is configured, call
electric-pair-post-self-insert-function.
Diffstat (limited to 'lisp/progmodes/cc-cmds.el')
-rw-r--r-- | lisp/progmodes/cc-cmds.el | 312 |
1 files changed, 183 insertions, 129 deletions
diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index a07527e4b8b..78677fefadb 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -47,6 +47,7 @@ ;; Silence the compiler. (cc-bytecomp-defvar filladapt-mode) ; c-fill-paragraph contains a kludge ; which looks at this. +(cc-bytecomp-defun electric-pair-post-self-insert-function) ;; Indentation / Display syntax functions (defvar c-fix-backslashes t) @@ -503,7 +504,8 @@ inside a literal or a macro, nothing special happens." (eq (char-before) ?\\)))) (c-in-literal))) ;; do nothing special - (self-insert-command (prefix-numeric-value arg)) + (let (post-self-insert-hook) ; Disable random functionality. + (self-insert-command (prefix-numeric-value arg))) ;; place the pound character at the left edge (let ((pos (- (point-max) (point))) (bolp (bolp))) @@ -694,6 +696,134 @@ inside a literal or a macro, nothing special happens." t)))) (goto-char (- (point-max) pos)))))) +(defun c-do-brace-electrics (before after) + ;; Point is just after a brace. Indent the various lines, add any required + ;; auto newlines, and apply pertinent clean ups. It is assumed that the + ;; caller has checked that point is at EOL if need be, and that the brace is + ;; not in a comment or string, and suchlike. + ;; + ;; BEFORE and AFTER qualify the newlines required before and after the + ;; brace as follows: + ;; If + ;; o - nil: insert a newline or not according to `c-hanging-braces-alist'. + ;; o - 'ignore: don't insert a newline. + ;; o - 'assume: insert a newline. + ;; + ;; The return value has no significance. + (let (;; shut this up too + (c-echo-syntactic-information-p nil) + newlines + ln-syntax br-syntax syntax) ; Syntactic context of the original line, + ; of the brace itself, of the line the + ; brace ends up on. + (c-save-buffer-state ((c-syntactic-indentation-in-macros t) + (c-auto-newline-analysis t)) + (setq ln-syntax (c-guess-basic-syntax))) + (if c-syntactic-indentation + (c-indent-line ln-syntax)) + + (when c-auto-newline + (backward-char) + (setq br-syntax (c-point-syntax) + newlines (c-brace-newlines br-syntax)) + + ;; Insert the BEFORE newline, if wanted, and reindent the newline. + (if (or (and (null before) (memq 'before newlines) + (> (current-column) (current-indentation))) + (eq before 'assume)) + (if c-syntactic-indentation + ;; Only a plain newline for now - it's indented + ;; after the cleanups when the line has its final + ;; appearance. + (newline) + (c-newline-and-indent))) + (forward-char) + + ;; `syntax' is the syntactic context of the line which ends up + ;; with the brace on it. + (setq syntax (if (memq 'before newlines) br-syntax ln-syntax)) + + ;; Do all appropriate clean ups + (let ((here (point)) + (pos (- (point-max) (point))) + mbeg mend + ) + + ;; `}': clean up empty defun braces + (when (c-save-buffer-state () + (and (memq 'empty-defun-braces c-cleanup-list) + (eq (c-last-command-char) ?\}) + (c-intersect-lists '(defun-close class-close inline-close) + syntax) + (progn + (forward-char -1) + (c-skip-ws-backward) + (eq (char-before) ?\{)) + ;; make sure matching open brace isn't in a comment + (not (c-in-literal)))) + (delete-region (point) (1- here)) + (setq here (- (point-max) pos))) + (goto-char here) + + ;; `}': compact to a one-liner defun? + (save-match-data + (when + (and (eq (c-last-command-char) ?\}) + (memq 'one-liner-defun c-cleanup-list) + (c-intersect-lists '(defun-close) syntax) + (c-try-one-liner)) + (setq here (- (point-max) pos)))) + + ;; `{': clean up brace-else-brace and brace-elseif-brace + (when (eq (c-last-command-char) ?\{) + (cond + ((and (memq 'brace-else-brace c-cleanup-list) + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "else" + "\\([ \t\n]\\|\\\\\n\\)*" + "{" + "\\=") + nil t)) + (delete-region (match-beginning 0) (match-end 0)) + (insert-and-inherit "} else {")) + ((and (memq 'brace-elseif-brace c-cleanup-list) + (progn + (goto-char (1- here)) + (setq mend (point)) + (c-skip-ws-backward) + (setq mbeg (point)) + (eq (char-before) ?\))) + (zerop (c-save-buffer-state nil (c-backward-token-2 1 t))) + (eq (char-after) ?\() + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "else" + "\\([ \t\n]\\|\\\\\n\\)+" + "if" + "\\([ \t\n]\\|\\\\\n\\)*" + "\\=") + nil t)) + (delete-region mbeg mend) + (goto-char mbeg) + (insert ?\ )))) + + (goto-char (- (point-max) pos)) + + ;; Indent the line after the cleanups since it might + ;; very well indent differently due to them, e.g. if + ;; c-indent-one-line-block is used together with the + ;; one-liner-defun cleanup. + (when c-syntactic-indentation + (c-indent-line))) + + ;; does a newline go after the brace? + (if (or (and (null after) (memq 'after newlines)) + (eq after 'assume)) + (c-newline-and-indent))))) + (defun c-electric-brace (arg) "Insert a brace. @@ -716,7 +846,10 @@ settings of `c-cleanup-list' are done." ;; We want to inhibit blinking the paren since this would be ;; most disruptive. We'll blink it ourselves later on. (old-blink-paren blink-paren-function) - blink-paren-function case-fold-search) + blink-paren-function case-fold-search + (at-eol (looking-at "[ \t]*\\\\?$")) + (active-region (and (fboundp 'use-region-p) (use-region-p))) + got-pair-} electric-pair-deletion) (c-save-buffer-state () (setq safepos (c-safe-position (point) (c-parse-state)) @@ -724,128 +857,36 @@ settings of `c-cleanup-list' are done." ;; Insert the brace. Note that expand-abbrev might reindent ;; the line here if there's a preceding "else" or something. - (self-insert-command (prefix-numeric-value arg)) - - (when (and c-electric-flag (not literal) (not arg)) - (if (not (looking-at "[ \t]*\\\\?$")) - (if c-syntactic-indentation - (indent-according-to-mode)) - - (let ( ;; shut this up too - (c-echo-syntactic-information-p nil) - newlines - ln-syntax br-syntax syntax) ; Syntactic context of the original line, - ; of the brace itself, of the line the brace ends up on. - (c-save-buffer-state ((c-syntactic-indentation-in-macros t) - (c-auto-newline-analysis t)) - (setq ln-syntax (c-guess-basic-syntax))) - (if c-syntactic-indentation - (c-indent-line ln-syntax)) - - (when c-auto-newline - (backward-char) - (setq br-syntax (c-point-syntax) - newlines (c-brace-newlines br-syntax)) - - ;; Insert the BEFORE newline, if wanted, and reindent the newline. - (if (and (memq 'before newlines) - (> (current-column) (current-indentation))) - (if c-syntactic-indentation - ;; Only a plain newline for now - it's indented - ;; after the cleanups when the line has its final - ;; appearance. - (newline) - (c-newline-and-indent))) + (let (post-self-insert-hook) ; the only way to get defined functionality + ; from `self-insert-command'. + (self-insert-command (prefix-numeric-value arg))) + + ;; Emulate `electric-pair-mode'. + (when (and (boundp 'electric-pair-mode) + electric-pair-mode) + (let ((size (buffer-size)) + (c-in-electric-pair-functionality t) + post-self-insert-hook) + (electric-pair-post-self-insert-function) + (setq got-pair-} (and at-eol + (eq (c-last-command-char) ?{) + (eq (char-after) ?})) + electric-pair-deletion (< (buffer-size) size)))) + + ;; Perform any required CC Mode electric actions. + (cond + ((or literal arg (not c-electric-flag) active-region)) + ((not at-eol) + (c-indent-line)) + (electric-pair-deletion + (c-indent-line) + (c-do-brace-electrics 'ignore nil)) + (t (c-do-brace-electrics nil nil) + (when got-pair-} + (save-excursion (forward-char) - - ;; `syntax' is the syntactic context of the line which ends up - ;; with the brace on it. - (setq syntax (if (memq 'before newlines) br-syntax ln-syntax)) - - ;; Do all appropriate clean ups - (let ((here (point)) - (pos (- (point-max) (point))) - mbeg mend - ) - - ;; `}': clean up empty defun braces - (when (c-save-buffer-state () - (and (memq 'empty-defun-braces c-cleanup-list) - (eq (c-last-command-char) ?\}) - (c-intersect-lists '(defun-close class-close inline-close) - syntax) - (progn - (forward-char -1) - (c-skip-ws-backward) - (eq (char-before) ?\{)) - ;; make sure matching open brace isn't in a comment - (not (c-in-literal)))) - (delete-region (point) (1- here)) - (setq here (- (point-max) pos))) - (goto-char here) - - ;; `}': compact to a one-liner defun? - (save-match-data - (when - (and (eq (c-last-command-char) ?\}) - (memq 'one-liner-defun c-cleanup-list) - (c-intersect-lists '(defun-close) syntax) - (c-try-one-liner)) - (setq here (- (point-max) pos)))) - - ;; `{': clean up brace-else-brace and brace-elseif-brace - (when (eq (c-last-command-char) ?\{) - (cond - ((and (memq 'brace-else-brace c-cleanup-list) - (re-search-backward - (concat "}" - "\\([ \t\n]\\|\\\\\n\\)*" - "else" - "\\([ \t\n]\\|\\\\\n\\)*" - "{" - "\\=") - nil t)) - (delete-region (match-beginning 0) (match-end 0)) - (insert-and-inherit "} else {")) - ((and (memq 'brace-elseif-brace c-cleanup-list) - (progn - (goto-char (1- here)) - (setq mend (point)) - (c-skip-ws-backward) - (setq mbeg (point)) - (eq (char-before) ?\))) - (zerop (c-save-buffer-state nil (c-backward-token-2 1 t))) - (eq (char-after) ?\() - ; (progn - ; (setq tmp (point)) - (re-search-backward - (concat "}" - "\\([ \t\n]\\|\\\\\n\\)*" - "else" - "\\([ \t\n]\\|\\\\\n\\)+" - "if" - "\\([ \t\n]\\|\\\\\n\\)*" - "\\=") - nil t);) - ;(eq (match-end 0) tmp); - ) - (delete-region mbeg mend) - (goto-char mbeg) - (insert ?\ )))) - - (goto-char (- (point-max) pos)) - - ;; Indent the line after the cleanups since it might - ;; very well indent differently due to them, e.g. if - ;; c-indent-one-line-block is used together with the - ;; one-liner-defun cleanup. - (when c-syntactic-indentation - (c-indent-line))) - - ;; does a newline go after the brace? - (if (memq 'after newlines) - (c-newline-and-indent)) - )))) + (c-do-brace-electrics 'assume 'ignore)) + (c-indent-line)))) ;; blink the paren (and (eq (c-last-command-char) ?\}) @@ -903,7 +944,8 @@ is inhibited." c-electric-flag (eq (c-last-command-char) ?/) (eq (char-before) (if literal ?* ?/)))) - (self-insert-command (prefix-numeric-value arg)) + (let (post-self-insert-hook) ; Disable random functionality. + (self-insert-command (prefix-numeric-value arg))) (if indentp (indent-according-to-mode)))) @@ -916,7 +958,8 @@ supplied, point is inside a literal, or `c-syntactic-indentation' is nil, this indentation is inhibited." (interactive "*P") - (self-insert-command (prefix-numeric-value arg)) + (let (post-self-insert-hook) ; Disable random functionality. + (self-insert-command (prefix-numeric-value arg))) ;; if we are in a literal, or if arg is given do not reindent the ;; current line, unless this star introduces a comment-only line. (if (c-save-buffer-state () @@ -963,7 +1006,8 @@ settings of `c-cleanup-list'." (setq lim (c-most-enclosing-brace (c-parse-state)) literal (c-in-literal lim))) - (self-insert-command (prefix-numeric-value arg)) + (let (post-self-insert-hook) ; Disable random functionality. + (self-insert-command (prefix-numeric-value arg))) (if (and c-electric-flag (not literal) (not arg)) ;; do all cleanups and newline insertions if c-auto-newline is on. @@ -1032,7 +1076,8 @@ reindented unless `c-syntactic-indentation' is nil. newlines is-scope-op ;; shut this up (c-echo-syntactic-information-p nil)) - (self-insert-command (prefix-numeric-value arg)) + (let (post-self-insert-hook) ; Disable random functionality. + (self-insert-command (prefix-numeric-value arg))) ;; Any electric action? (if (and c-electric-flag (not literal) (not arg)) ;; Unless we're at EOL, only re-indentation happens. @@ -1125,7 +1170,8 @@ numeric argument is supplied, or the point is inside a literal." (let ((c-echo-syntactic-information-p nil) final-pos found-delim case-fold-search) - (self-insert-command (prefix-numeric-value arg)) + (let (post-self-insert-hook) ; Disable random functionality. + (self-insert-command (prefix-numeric-value arg))) (setq final-pos (point)) ;;;; 2010-01-31: There used to be code here to put a syntax-table text @@ -1190,7 +1236,9 @@ newline cleanups are done if appropriate; see the variable `c-cleanup-list'." ;; shut this up (c-echo-syntactic-information-p nil) case-fold-search) - (self-insert-command (prefix-numeric-value arg)) + (let (post-self-insert-hook) ; The only way to get defined functionality + ; from `self-insert-command'. + (self-insert-command (prefix-numeric-value arg))) (if (and (not arg) (not literal)) (let* ( ;; We want to inhibit blinking the paren since this will @@ -1239,6 +1287,12 @@ newline cleanups are done if appropriate; see the variable `c-cleanup-list'." (delete-region (match-beginning 0) (match-end 0)) (insert-and-inherit "} catch ("))) + ;; Apply `electric-pair-mode' stuff. + (when (and (boundp 'electric-pair-mode) + electric-pair-mode) + (let (post-self-insert-hook) + (electric-pair-post-self-insert-function))) + ;; Check for clean-ups at function calls. These two DON'T need ;; `c-electric-flag' or `c-syntactic-indentation' set. ;; Point is currently just after the inserted paren. |