From unknown Wed Jun 18 23:16:03 2025 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Mailer: MIME-tools 5.509 (Entity 5.509) Content-Type: text/plain; charset=utf-8 From: bug#55230 <55230@debbugs.gnu.org> To: bug#55230 <55230@debbugs.gnu.org> Subject: Status: CC Mode 5.35.1 (C++//l); Cache inconsistency Reply-To: bug#55230 <55230@debbugs.gnu.org> Date: Thu, 19 Jun 2025 06:16:03 +0000 retitle 55230 CC Mode 5.35.1 (C++//l); Cache inconsistency reassign 55230 cc-mode submitter 55230 Michael Welsh Duggan severity 55230 normal thanks From debbugs-submit-bounces@debbugs.gnu.org Mon May 02 15:30:17 2022 Received: (at submit) by debbugs.gnu.org; 2 May 2022 19:30:17 +0000 Received: from localhost ([127.0.0.1]:38032 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nlbkP-0005rH-Ej for submit@debbugs.gnu.org; Mon, 02 May 2022 15:30:17 -0400 Received: from lists.gnu.org ([209.51.188.17]:46082) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nlbkN-0005r8-CG for submit@debbugs.gnu.org; Mon, 02 May 2022 15:30:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47556) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nlbkL-0005Hs-UH for bug-gnu-emacs@gnu.org; Mon, 02 May 2022 15:30:15 -0400 Received: from md5i.com ([75.151.244.229]:56196) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nlbkJ-0001Nx-O6 for bug-gnu-emacs@gnu.org; Mon, 02 May 2022 15:30:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=md5i.com; s=dkim; h=Content-Transfer-Encoding:Content-Type:MIME-Version:Message-ID:Date :Subject:To:From:Sender:Reply-To:Cc:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=w82aMRjN+8EPWVLjP8zAtH4ljQf9NNQxTjUJyOltkio=; b=KVQ7IkU5dXzeTCDVrO+ToAzQbI m1qyVMK9D6SgXmAiaSxF4ATX/L9r6xza90YS3XyRp1bXzySak0RtZclQubjVwMvMcet9X+m+0uj+I wnr/+7mfxMX8RjnOMrUyCeP2Y; Received: from abode ([192.168.177.1] helo=miko) by md5i.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1nlbkI-00CIT0-26 for bug-gnu-emacs@gnu.org; Mon, 02 May 2022 15:30:10 -0400 From: Michael Welsh Duggan To: bug-gnu-emacs@gnu.org Subject: CC Mode 5.35.1 (C++//l); Cache inconsistency X-Debbugs-Package: cc-mode Date: Mon, 02 May 2022 15:30:09 -0400 Message-ID: <875ymn4try.fsf@md5i.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Received-SPF: pass client-ip=75.151.244.229; envelope-from=mwd@md5i.com; helo=md5i.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.4 (-) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -2.4 (--) Package: cc-mode >From emacs -Q: C-x C-f /tmp/foo.cpp RET M-x c-toggle-parse-state-debug RET "{} After typing the close brace, I get the following: c-parse-state inconsistency at 3: using cache: (2), from scratch: nil. POI= NT-MIN: 1 Old state: (setq c-state-cache '(2) c-state-cache-good-pos 1 c-state-nonlit-pos-cach= e nil c-state-nonlit-pos-cache-limit 0 c-state-brace-pair-desert nil c-s= tate-point-min 1 c-state-point-min-lit-type nil c-state-point-min-lit-sta= rt nil c-state-min-scan-pos 1 c-state-old-cpp-beg nil c-state-old-cpp-en= d nil c-parse-state-point 3) I have not noticed any indentation errors due to this, but any cache inconsistency might lead to errors down the line, hence this report. Emacs : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, X toolkit, cairo = version 1.16.0) of 2022-04-09 Package: CC Mode 5.35.1 (C++//l) Buffer Style: gnu c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-st= ring-delim gen-comment-delim syntax-properties 1-bit) current state: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D (setq c-basic-offset 2 c-comment-only-line-offset '(0 . 0) c-indent-comment-alist '((anchored-comment column . 0) (end-block space . = 1) (cpp-end-block space . 2)) c-indent-comments-syntactically-p nil c-block-comment-prefix "" c-comment-prefix-regexp '((pike-mode . "//+!?\\|\\**") (awk-mode . "#+") (other . "//+\\|\\**")) c-doc-comment-style '((java-mode . javadoc) (pike-mode . autodoc) (c-mode . gtkdoc) (c++-mode . gtkdoc)) c-cleanup-list '(scope-operator) c-hanging-braces-alist '((substatement-open before after) (arglist-cont-nonempty)) c-hanging-colons-alist nil c-hanging-semi&comma-criteria '(c-semi&comma-inside-parenlist) c-backslash-column 48 c-backslash-max-column 72 c-special-indent-hook '(t c-gnu-impose-minimum) c-label-minimum-indentation 1 c-offsets-alist '((inexpr-class . +) (inexpr-statement . +) (lambda-intro-cont . +) (inlambda . 0) (template-args-cont c-lineup-template-args +) (incomposition . +) (inmodule . +) (innamespace . +) (inextern-lang . +) (composition-close . 0) (module-close . 0) (namespace-close . 0) (extern-lang-close . 0) (composition-open . 0) (module-open . 0) (namespace-open . 0) (extern-lang-open . 0) (objc-method-call-cont c-lineup-ObjC-method-call-colons c-lineup-ObjC-method-call + ) (objc-method-args-cont . c-lineup-ObjC-method-args) (objc-method-intro . [0]) (friend . 0) (cpp-define-intro c-lineup-cpp-define +) (cpp-macro-cont . +) (cpp-macro . [0]) (inclass . +) (stream-op . c-lineup-streamop) (arglist-cont-nonempty c-lineup-gcc-asm-reg c-lineup-arglist ) (arglist-cont c-lineup-gcc-asm-reg 0) (comment-intro c-lineup-knr-region-comment c-lineup-comment ) (catch-clause . 0) (else-clause . 0) (do-while-closure . 0) (access-label . -) (case-label . 0) (substatement . +) (statement-case-intro . +) (statement . 0) (brace-entry-open . 0) (brace-list-entry . 0) (brace-list-close . 0) (block-close . 0) (block-open . 0) (inher-cont . c-lineup-multi-inher) (inher-intro . +) (member-init-cont . c-lineup-multi-inher) (member-init-intro . +) (annotation-var-cont . +) (annotation-top-cont . 0) (topmost-intro . 0) (knr-argdecl . 0) (func-decl-cont . +) (inline-close . 0) (class-close . 0) (class-open . 0) (defun-block-intro . +) (defun-close . 0) (defun-open . 0) (c . c-lineup-C-comments) (string . c-lineup-dont-change) (topmost-intro-cont first c-lineup-topmost-intro-cont c-lineup-gnu-DEFUN-intro-cont ) (brace-list-intro first c-lineup-2nd-brace-entry-in-arglist c-lineup-class-decl-init-+ + ) (brace-list-open . +) (inline-open . 0) (arglist-close . c-lineup-arglist) (arglist-intro . c-lineup-arglist-intro-after-paren) (statement-cont . +) (statement-case-open . +) (label . 0) (substatement-label . 0) (substatement-open . +) (knr-argdecl-intro . 5) (statement-block-intro . +) ) c-buffer-is-cc-mode 'c++-mode c-tab-always-indent t c-syntactic-indentation t c-syntactic-indentation-in-macros t c-ignore-auto-fill '(string cpp code) c-auto-align-backslashes t c-backspace-function 'backward-delete-char-untabify c-delete-function 'delete-char c-electric-pound-behavior nil c-default-style '((java-mode . "java") (awk-mode . "awk") (other . "gnu")) c-enable-xemacs-performance-kludge-p nil c-old-style-variable-behavior nil defun-prompt-regexp nil tab-width 8 comment-column 32 parse-sexp-ignore-comments t parse-sexp-lookup-properties t auto-fill-function nil comment-multi-line t comment-start-skip "\\(?://+\\|/\\*+\\)\\s *" fill-prefix nil fill-column 70 paragraph-start "[ ]*\\(//+\\|\\**\\)[ ]*$\\|^\f" adaptive-fill-mode t adaptive-fill-regexp "[ ]*\\(//+\\|\\**\\)[ ]*\\([ ]*\\([-=E2=80=93!|#%= ;>*=C2=B7=E2=80=A2=E2=80=A3=E2=81=83=E2=97=A6]+[ ]*\\)*\\)" ) =20 --=20 Michael Welsh Duggan (md5i@md5i.com) From debbugs-submit-bounces@debbugs.gnu.org Tue May 03 14:10:46 2022 Received: (at 55230) by debbugs.gnu.org; 3 May 2022 18:10:46 +0000 Received: from localhost ([127.0.0.1]:41018 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nlwz0-00026x-EX for submit@debbugs.gnu.org; Tue, 03 May 2022 14:10:46 -0400 Received: from colin.muc.de ([193.149.48.1]:24588 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1nlwyy-00026g-MU for 55230@debbugs.gnu.org; Tue, 03 May 2022 14:10:45 -0400 Received: (qmail 40029 invoked by uid 3782); 3 May 2022 18:10:38 -0000 Received: from acm.muc.de (p4fe15a81.dip0.t-ipconnect.de [79.225.90.129]) (using STARTTLS) by colin.muc.de (tmda-ofmipd) with ESMTP; Tue, 03 May 2022 20:10:37 +0200 Received: (qmail 7076 invoked by uid 1000); 3 May 2022 18:10:36 -0000 Date: Tue, 3 May 2022 18:10:36 +0000 To: Michael Welsh Duggan Subject: Re: bug#55230: CC Mode 5.35.1 (C++//l); Cache inconsistency Message-ID: References: <875ymn4try.fsf@md5i.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <875ymn4try.fsf@md5i.com> X-Submission-Agent: TMDA/1.3.x (Ph3nix) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 55230 Cc: 55230@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hello, Michael. On Mon, May 02, 2022 at 15:30:09 -0400, Michael Welsh Duggan wrote: > Package: cc-mode > From emacs -Q: > C-x C-f /tmp/foo.cpp RET > M-x c-toggle-parse-state-debug RET > "{} > After typing the close brace, I get the following: > c-parse-state inconsistency at 3: using cache: (2), from scratch: nil. POINT-MIN: 1 > Old state: > (setq c-state-cache '(2) c-state-cache-good-pos 1 c-state-nonlit-pos-cache nil c-state-nonlit-pos-cache-limit 0 c-state-brace-pair-desert nil c-state-point-min 1 c-state-point-min-lit-type nil c-state-point-min-lit-start nil c-state-min-scan-pos 1 c-state-old-cpp-beg nil c-state-old-cpp-end nil c-parse-state-point 3) > I have not noticed any indentation errors due to this, but any cache > inconsistency might lead to errors down the line, hence this report. Many thanks for the bug report. This time it is not the cache mechanism itself which is at fault. Instead, it is the first character ", which since it is unbalanced by another ", has had its syntax is temporarily "commented out" by giving it a syntax-table property of "punctuation". The parse-state cache was generated whilst in this state, but used when it no longer was, hence the inconsistency. There are somewhere between 10 and 20 occurrences of c-parse-state in the source code which will need to be "protected" against this fault. I hope to be able to finish this work in the next two or three days, when I'll get back to you again. > Emacs : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, X toolkit, cairo version 1.16.0) > of 2022-04-09 > Package: CC Mode 5.35.1 (C++//l) > Buffer Style: gnu > c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties 1-bit) [ CC Mode state dump appreciated, but snipped. ] > -- > Michael Welsh Duggan > (md5i@md5i.com) -- Alan Mackenzie (Nuremberg, Germany). From debbugs-submit-bounces@debbugs.gnu.org Tue May 17 05:55:37 2022 Received: (at 55230) by debbugs.gnu.org; 17 May 2022 09:55:37 +0000 Received: from localhost ([127.0.0.1]:55895 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nqtvV-0000eD-8x for submit@debbugs.gnu.org; Tue, 17 May 2022 05:55:37 -0400 Received: from colin.muc.de ([193.149.48.1]:37283 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1nqtvT-0000du-Bd for 55230@debbugs.gnu.org; Tue, 17 May 2022 05:55:36 -0400 Received: (qmail 38843 invoked by uid 3782); 17 May 2022 09:55:28 -0000 Received: from acm.muc.de (p4fe1589c.dip0.t-ipconnect.de [79.225.88.156]) (using STARTTLS) by colin.muc.de (tmda-ofmipd) with ESMTP; Tue, 17 May 2022 11:55:27 +0200 Received: (qmail 3905 invoked by uid 1000); 17 May 2022 09:55:27 -0000 Date: Tue, 17 May 2022 09:55:27 +0000 To: Michael Welsh Duggan Subject: Re: bug#55230: CC Mode 5.35.1 (C++//l); Cache inconsistency Message-ID: References: <875ymn4try.fsf@md5i.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="MYsoMOAPwW+l40Gp" Content-Disposition: inline In-Reply-To: X-Submission-Agent: TMDA/1.3.x (Ph3nix) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Debbugs-Envelope-To: 55230 Cc: 55230@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" --MYsoMOAPwW+l40Gp Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hello again, Michael. On Tue, May 03, 2022 at 18:10:36 +0000, Alan Mackenzie wrote: > On Mon, May 02, 2022 at 15:30:09 -0400, Michael Welsh Duggan wrote: > > Package: cc-mode > > From emacs -Q: > > C-x C-f /tmp/foo.cpp RET > > M-x c-toggle-parse-state-debug RET > > "{} > > After typing the close brace, I get the following: > > c-parse-state inconsistency at 3: using cache: (2), from scratch: nil. POINT-MIN: 1 > > Old state: > > (setq c-state-cache '(2) c-state-cache-good-pos 1 c-state-nonlit-pos-cache nil c-state-nonlit-pos-cache-limit 0 c-state-brace-pair-desert nil c-state-point-min 1 c-state-point-min-lit-type nil c-state-point-min-lit-start nil c-state-min-scan-pos 1 c-state-old-cpp-beg nil c-state-old-cpp-end nil c-parse-state-point 3) > > I have not noticed any indentation errors due to this, but any cache > > inconsistency might lead to errors down the line, hence this report. > Many thanks for the bug report. > This time it is not the cache mechanism itself which is at fault. > Instead, it is the first character ", which since it is unbalanced by > another ", has had its syntax is temporarily "commented out" by giving > it a syntax-table property of "punctuation". The parse-state cache was > generated whilst in this state, but used when it no longer was, hence > the inconsistency. > There are somewhere between 10 and 20 occurrences of c-parse-state in > the source code which will need to be "protected" against this fault. I > hope to be able to finish this work in the next two or three days, when > I'll get back to you again. There were actually 32 such occurrences, and they have generated a rather large patch which I am taking the liberty of just sending to you. The vast bulk of this patch is just putting (c-with-string-fences ....) around these functions, reindenting them. I've attached the patch as a separate file because it is so big. It should apply cleanly to the CC Mode in the Emacs savannah master version. Would you please apply it and try it out a bit, and let me know how well it works. Thanks! > > Emacs : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, X toolkit, cairo version 1.16.0) > > of 2022-04-09 > > Package: CC Mode 5.35.1 (C++//l) > > Buffer Style: gnu > > c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties 1-bit) > > -- > > Michael Welsh Duggan > > (md5i@md5i.com) -- Alan Mackenzie (Nuremberg, Germany). --MYsoMOAPwW+l40Gp Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="diff.20220517.diff" diff --git a/lisp/progmodes/cc-awk.el b/lisp/progmodes/cc-awk.el index 188d5a8a83..45d71a37db 100644 --- a/lisp/progmodes/cc-awk.el +++ b/lisp/progmodes/cc-awk.el @@ -56,6 +56,8 @@ ;; Silence the byte compiler. (cc-bytecomp-defvar c-new-BEG) (cc-bytecomp-defvar c-new-END) +(cc-bytecomp-defun c-restore-string-fences) +(cc-bytecomp-defun c-clear-string-fences) ;; Some functions in cc-engine that are used below. There's a cyclic ;; dependency so it can't be required here. (Perhaps some functions @@ -934,7 +936,7 @@ c-awk-extend-and-syntax-tablify-region ;; It prepares the buffer for font ;; locking, hence must get called before `font-lock-after-change-function'. ;; - ;; This function is the AWK value of `c-before-font-lock-function'. + ;; This function is the AWK value of `c-before-font-lock-functions'. ;; It does hidden buffer changes. (c-save-buffer-state () (setq c-new-END (c-awk-end-of-change-region beg end old-len)) @@ -1109,29 +1111,30 @@ c-awk-beginning-of-defun Note that this function might do hidden buffer changes. See the comment at the start of cc-engine.el for more info." (interactive "p") - (or arg (setq arg 1)) - (save-match-data - (c-save-buffer-state ; ensures the buffer is writable. - nil - (let ((found t)) ; Has the most recent regexp search found b-of-defun? - (if (>= arg 0) - ;; Go back one defun each time round the following loop. (For +ve arg) - (while (and found (> arg 0) (not (eq (point) (point-min)))) - ;; Go back one "candidate" each time round the next loop until one - ;; is genuinely a beginning-of-defun. - (while (and (setq found (search-backward-regexp - "^[^#} \t\n\r]" (point-min) 'stop-at-limit)) - (not (memq (c-awk-get-NL-prop-prev-line) '(?\$ ?\} ?\#))))) - (setq arg (1- arg))) - ;; The same for a -ve arg. - (if (not (eq (point) (point-max))) (forward-char 1)) - (while (and found (< arg 0) (not (eq (point) (point-max)))) ; The same for -ve arg. - (while (and (setq found (search-forward-regexp - "^[^#} \t\n\r]" (point-max) 'stop-at-limit)) - (not (memq (c-awk-get-NL-prop-prev-line) '(?\$ ?\} ?\#))))) - (setq arg (1+ arg))) - (if found (goto-char (match-beginning 0)))) - (eq arg 0))))) + (c-with-string-fences + (or arg (setq arg 1)) + (save-match-data + (c-save-buffer-state ; ensures the buffer is writable. + nil + (let ((found t)) ; Has the most recent regexp search found b-of-defun? + (if (>= arg 0) + ;; Go back one defun each time round the following loop. (For +ve arg) + (while (and found (> arg 0) (not (eq (point) (point-min)))) + ;; Go back one "candidate" each time round the next loop until one + ;; is genuinely a beginning-of-defun. + (while (and (setq found (search-backward-regexp + "^[^#} \t\n\r]" (point-min) 'stop-at-limit)) + (not (memq (c-awk-get-NL-prop-prev-line) '(?\$ ?\} ?\#))))) + (setq arg (1- arg))) + ;; The same for a -ve arg. + (if (not (eq (point) (point-max))) (forward-char 1)) + (while (and found (< arg 0) (not (eq (point) (point-max)))) ; The same for -ve arg. + (while (and (setq found (search-forward-regexp + "^[^#} \t\n\r]" (point-max) 'stop-at-limit)) + (not (memq (c-awk-get-NL-prop-prev-line) '(?\$ ?\} ?\#))))) + (setq arg (1+ arg))) + (if found (goto-char (match-beginning 0)))) + (eq arg 0)))))) (defun c-awk-forward-awk-pattern () ;; Point is at the start of an AWK pattern (which may be null) or function @@ -1187,39 +1190,40 @@ c-awk-end-of-defun Note that this function might do hidden buffer changes. See the comment at the start of cc-engine.el for more info." (interactive "p") - (or arg (setq arg 1)) - (save-match-data - (c-save-buffer-state - nil - (let ((start-point (point)) end-point) - ;; Strategy: (For +ve ARG): If we're not already at a beginning-of-defun, - ;; move backwards to one. - ;; Repeat [(i) move forward to end-of-current-defun (see below); - ;; (ii) If this isn't it, move forward to beginning-of-defun]. - ;; We start counting ARG only when step (i) has passed the original point. - (when (> arg 0) - ;; Try to move back to a beginning-of-defun, if not already at one. - (if (not (c-awk-beginning-of-defun-p)) - (when (not (c-awk-beginning-of-defun 1)) ; No bo-defun before point. - (goto-char start-point) - (c-awk-beginning-of-defun -1))) ; if this fails, we're at EOB, tough! - ;; Now count forward, one defun at a time - (while (and (not (eobp)) - (c-awk-end-of-defun1) - (if (> (point) start-point) (setq arg (1- arg)) t) - (> arg 0) - (c-awk-beginning-of-defun -1)))) - - (when (< arg 0) - (setq end-point start-point) - (while (and (not (bobp)) - (c-awk-beginning-of-defun 1) - (if (< (setq end-point (if (bobp) (point) - (save-excursion (c-awk-end-of-defun1)))) - start-point) - (setq arg (1+ arg)) t) - (< arg 0))) - (goto-char (min start-point end-point))))))) + (c-with-string-fences + (or arg (setq arg 1)) + (save-match-data + (c-save-buffer-state + nil + (let ((start-point (point)) end-point) + ;; Strategy: (For +ve ARG): If we're not already at a beginning-of-defun, + ;; move backwards to one. + ;; Repeat [(i) move forward to end-of-current-defun (see below); + ;; (ii) If this isn't it, move forward to beginning-of-defun]. + ;; We start counting ARG only when step (i) has passed the original point. + (when (> arg 0) + ;; Try to move back to a beginning-of-defun, if not already at one. + (if (not (c-awk-beginning-of-defun-p)) + (when (not (c-awk-beginning-of-defun 1)) ; No bo-defun before point. + (goto-char start-point) + (c-awk-beginning-of-defun -1))) ; if this fails, we're at EOB, tough! + ;; Now count forward, one defun at a time + (while (and (not (eobp)) + (c-awk-end-of-defun1) + (if (> (point) start-point) (setq arg (1- arg)) t) + (> arg 0) + (c-awk-beginning-of-defun -1)))) + + (when (< arg 0) + (setq end-point start-point) + (while (and (not (bobp)) + (c-awk-beginning-of-defun 1) + (if (< (setq end-point (if (bobp) (point) + (save-excursion (c-awk-end-of-defun1)))) + start-point) + (setq arg (1+ arg)) t) + (< arg 0))) + (goto-char (min start-point end-point)))))))) (cc-provide 'cc-awk) ; Changed from 'awk-mode, ACM 2002/5/21 diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index f1f61f7e08..62e1ee8f58 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -45,6 +45,8 @@ (cc-require 'cc-engine) ;; Silence the compiler. +(cc-bytecomp-defun c-restore-string-fences) +(cc-bytecomp-defun c-clear-string-fences) (cc-bytecomp-defvar filladapt-mode) ; c-fill-paragraph contains a kludge ; which looks at this. (cc-bytecomp-defun electric-pair-post-self-insert-function) @@ -210,35 +212,36 @@ c-show-syntactic-information "Show syntactic information for current line. With universal argument, inserts the analysis as a comment on that line." (interactive "P") - (let* ((c-parsing-error nil) - (syntax (if (boundp 'c-syntactic-context) - ;; Use `c-syntactic-context' in the same way as - ;; `c-indent-line', to be consistent. - c-syntactic-context - (c-save-buffer-state nil - (c-guess-basic-syntax))))) - (if (not (consp arg)) - (let (elem pos ols) - (message "Syntactic analysis: %s" syntax) - (unwind-protect - (progn - (while syntax - (setq elem (pop syntax)) - (when (setq pos (c-langelem-pos elem)) - (push (c-put-overlay pos (1+ pos) - 'face 'highlight) - ols)) - (when (setq pos (c-langelem-2nd-pos elem)) - (push (c-put-overlay pos (1+ pos) - 'face 'secondary-selection) - ols))) - (sit-for 10)) - (while ols - (c-delete-overlay (pop ols))))) - (indent-for-comment) - (insert-and-inherit (format "%s" syntax)) - )) - (c-keep-region-active)) + (c-with-string-fences + (let* ((c-parsing-error nil) + (syntax (if (boundp 'c-syntactic-context) + ;; Use `c-syntactic-context' in the same way as + ;; `c-indent-line', to be consistent. + c-syntactic-context + (c-save-buffer-state nil + (c-guess-basic-syntax))))) + (if (not (consp arg)) + (let (elem pos ols) + (message "Syntactic analysis: %s" syntax) + (unwind-protect + (progn + (while syntax + (setq elem (pop syntax)) + (when (setq pos (c-langelem-pos elem)) + (push (c-put-overlay pos (1+ pos) + 'face 'highlight) + ols)) + (when (setq pos (c-langelem-2nd-pos elem)) + (push (c-put-overlay pos (1+ pos) + 'face 'secondary-selection) + ols))) + (sit-for 10)) + (while ols + (c-delete-overlay (pop ols))))) + (indent-for-comment) + (insert-and-inherit (format "%s" syntax)) + )) + (c-keep-region-active))) (defun c-syntactic-information-on-region (from to) "Insert a comment with the syntactic analysis on every line in the region." @@ -414,23 +417,25 @@ c-electric-backspace inside a literal then the function in the variable `c-backspace-function' is called." (interactive "*P") - (if (c-save-buffer-state () - (or (not c-hungry-delete-key) - arg - (c-in-literal))) - (funcall c-backspace-function (prefix-numeric-value arg)) - (c-hungry-delete-backwards))) + (c-with-string-fences + (if (c-save-buffer-state () + (or (not c-hungry-delete-key) + arg + (c-in-literal))) + (funcall c-backspace-function (prefix-numeric-value arg)) + (c-hungry-delete-backwards)))) (defun c-hungry-delete-backwards () "Delete the preceding character or all preceding whitespace back to the previous non-whitespace character. See also \\[c-hungry-delete-forward]." (interactive) - (let ((here (point))) - (c-skip-ws-backward) - (if (/= (point) here) - (delete-region (point) here) - (funcall c-backspace-function 1)))) + (c-with-string-fences + (let ((here (point))) + (c-skip-ws-backward) + (if (/= (point) here) + (delete-region (point) here) + (funcall c-backspace-function 1))))) (defalias 'c-hungry-backspace 'c-hungry-delete-backwards) @@ -442,23 +447,26 @@ c-electric-delete-forward inside a literal then the function in the variable `c-delete-function' is called." (interactive "*P") - (if (c-save-buffer-state () - (or (not c-hungry-delete-key) - arg - (c-in-literal))) - (funcall c-delete-function (prefix-numeric-value arg)) - (c-hungry-delete-forward))) + (c-with-string-fences + (if + (c-save-buffer-state () + (or (not c-hungry-delete-key) + arg + (c-in-literal))) + (funcall c-delete-function (prefix-numeric-value arg)) + (c-hungry-delete-forward)))) (defun c-hungry-delete-forward () "Delete the following character or all following whitespace up to the next non-whitespace character. See also \\[c-hungry-delete-backwards]." (interactive) - (let ((here (point))) - (c-skip-ws-forward) - (if (/= (point) here) - (delete-region (point) here) - (funcall c-delete-function 1)))) + (c-with-string-fences + (let ((here (point))) + (c-skip-ws-forward) + (if (/= (point) here) + (delete-region (point) here) + (funcall c-delete-function 1))))) ;; This function is only used in XEmacs. (defun c-electric-delete (arg) @@ -530,31 +538,32 @@ c-electric-pound `c-electric-pound-behavior'. If a numeric ARG is supplied, or if point is inside a literal or a macro, nothing special happens." (interactive "*P") - (if (c-save-buffer-state () - (or arg - (not c-electric-flag) - (not (memq 'alignleft c-electric-pound-behavior)) - (save-excursion - (skip-chars-backward " \t") - (not (bolp))) - (save-excursion - (and (= (forward-line -1) 0) - (progn (end-of-line) - (eq (char-before) ?\\)))) - (c-in-literal))) - ;; do nothing special - (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))) - (beginning-of-line) - (delete-horizontal-space) - (insert (c-last-command-char)) - (and (not bolp) - (goto-char (- (point-max) pos))) - )) - (c--call-post-self-insert-hook-more-safely)) + (c-with-string-fences + (if (c-save-buffer-state () + (or arg + (not c-electric-flag) + (not (memq 'alignleft c-electric-pound-behavior)) + (save-excursion + (skip-chars-backward " \t") + (not (bolp))) + (save-excursion + (and (= (forward-line -1) 0) + (progn (end-of-line) + (eq (char-before) ?\\)))) + (c-in-literal))) + ;; do nothing special + (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))) + (beginning-of-line) + (delete-horizontal-space) + (insert (c-last-command-char)) + (and (not bolp) + (goto-char (- (point-max) pos))) + )) + (c--call-post-self-insert-hook-more-safely))) (defun c-point-syntax () ;; Return the syntactic context of the construct at point. (This is NOT @@ -882,60 +891,61 @@ c-electric-brace settings of `c-cleanup-list' are done." (interactive "*P") - (let (safepos literal - ;; 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 - (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)) - literal (c-in-literal safepos))) - - ;; Insert the brace. Note that expand-abbrev might reindent - ;; the line here if there's a preceding "else" or something. - (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)) - 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-} + (c-with-string-fences + (let (safepos literal + ;; 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 + (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)) + literal (c-in-literal safepos))) + + ;; Insert the brace. Note that expand-abbrev might reindent + ;; the line here if there's a preceding "else" or something. + (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)) + 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) + (c-do-brace-electrics 'assume 'ignore)) + (c-indent-line)))) + + ;; blink the paren + (and (eq (c-last-command-char) ?\}) + (not executing-kbd-macro) + old-blink-paren (save-excursion - (forward-char) - (c-do-brace-electrics 'assume 'ignore)) - (c-indent-line)))) - - ;; blink the paren - (and (eq (c-last-command-char) ?\}) - (not executing-kbd-macro) - old-blink-paren - (save-excursion - (c-save-buffer-state nil - (c-backward-syntactic-ws safepos)) - (funcall old-blink-paren))) - (c--call-post-self-insert-hook-more-safely))) + (c-save-buffer-state nil + (c-backward-syntactic-ws safepos)) + (funcall old-blink-paren))) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-slash (arg) "Insert a slash character. @@ -956,39 +966,40 @@ c-electric-slash `c-syntactic-indentation' is nil or `c-electric-flag' is nil, indentation is inhibited." (interactive "*P") - (let ((literal (c-save-buffer-state () (c-in-literal))) - indentp - ;; shut this up - (c-echo-syntactic-information-p nil)) + (c-with-string-fences + (let ((literal (c-save-buffer-state () (c-in-literal))) + indentp + ;; shut this up + (c-echo-syntactic-information-p nil)) - ;; comment-close-slash cleanup? This DOESN'T need `c-electric-flag' or - ;; `c-syntactic-indentation' set. - (when (and (not arg) - (eq literal 'c) - (memq 'comment-close-slash c-cleanup-list) - (eq (c-last-command-char) ?/) - (looking-at (concat "[ \t]*\\(" - (regexp-quote comment-end) "\\)?$")) - ; (eq c-block-comment-ender "*/") ; C-style comments ALWAYS end in */ - (save-excursion - (save-restriction - (narrow-to-region (point-min) (point)) - (back-to-indentation) - (looking-at (concat c-current-comment-prefix "[ \t]*$"))))) - (delete-region (progn (forward-line 0) (point)) - (progn (end-of-line) (point))) - (insert-char ?* 1)) ; the / comes later. ; Do I need a t (retain sticky properties) here? - - (setq indentp (and (not arg) - c-syntactic-indentation - c-electric-flag - (eq (c-last-command-char) ?/) - (eq (char-before) (if literal ?* ?/)))) - (let (post-self-insert-hook) ; Disable random functionality. - (self-insert-command (prefix-numeric-value arg))) - (if indentp - (indent-according-to-mode)) - (c--call-post-self-insert-hook-more-safely))) + ;; comment-close-slash cleanup? This DOESN'T need `c-electric-flag' or + ;; `c-syntactic-indentation' set. + (when (and (not arg) + (eq literal 'c) + (memq 'comment-close-slash c-cleanup-list) + (eq (c-last-command-char) ?/) + (looking-at (concat "[ \t]*\\(" + (regexp-quote comment-end) "\\)?$")) + ; (eq c-block-comment-ender "*/") ; C-style comments ALWAYS end in */ + (save-excursion + (save-restriction + (narrow-to-region (point-min) (point)) + (back-to-indentation) + (looking-at (concat c-current-comment-prefix "[ \t]*$"))))) + (delete-region (progn (forward-line 0) (point)) + (progn (end-of-line) (point))) + (insert-char ?* 1)) ; the / comes later. ; Do I need a t (retain sticky properties) here? + + (setq indentp (and (not arg) + c-syntactic-indentation + c-electric-flag + (eq (c-last-command-char) ?/) + (eq (char-before) (if literal ?* ?/)))) + (let (post-self-insert-hook) ; Disable random functionality. + (self-insert-command (prefix-numeric-value arg))) + (if indentp + (indent-according-to-mode)) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-star (arg) "Insert a star character. @@ -999,27 +1010,27 @@ c-electric-star this indentation is inhibited." (interactive "*P") - (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 () - (and c-syntactic-indentation - c-electric-flag - (not arg) - (eq (c-in-literal) 'c) - (eq (char-before) ?*) - (save-excursion - (forward-char -1) - (skip-chars-backward "*") - (if (eq (char-before) ?/) - (forward-char -1)) - (skip-chars-backward " \t") - (bolp)))) - (let (c-echo-syntactic-information-p) ; shut this up - (indent-according-to-mode)) - ) - (c--call-post-self-insert-hook-more-safely)) + (c-with-string-fences + (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 () + (and c-syntactic-indentation + c-electric-flag + (not arg) + (eq (c-in-literal) 'c) + (eq (char-before) ?*) + (save-excursion + (forward-char -1) + (skip-chars-backward "*") + (if (eq (char-before) ?/) + (forward-char -1)) + (skip-chars-backward " \t") + (bolp)))) + (let (c-echo-syntactic-information-p) ; shut this up + (indent-according-to-mode))) + (c--call-post-self-insert-hook-more-safely))) (defun c-electric-semi&comma (arg) "Insert a comma or semicolon. @@ -1039,60 +1050,61 @@ c-electric-semi&comma semicolon following a defun might be cleaned up, depending on the settings of `c-cleanup-list'." (interactive "*P") - (let* (lim literal c-syntactic-context - (here (point)) - ;; shut this up - (c-echo-syntactic-information-p nil)) - - (c-save-buffer-state () - (setq lim (c-most-enclosing-brace (c-parse-state)) - literal (c-in-literal lim))) - - (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. - (if (or (not c-auto-newline) - (not (looking-at "[ \t]*\\\\?$"))) - (if c-syntactic-indentation - (c-indent-line)) - ;; clean ups: list-close-comma or defun-close-semi - (let ((pos (- (point-max) (point)))) - (if (c-save-buffer-state () - (and (or (and - (eq (c-last-command-char) ?,) - (memq 'list-close-comma c-cleanup-list)) - (and - (eq (c-last-command-char) ?\;) - (memq 'defun-close-semi c-cleanup-list))) - (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 lim)))) - (delete-region (point) here)) - (goto-char (- (point-max) pos))) - ;; reindent line - (when c-syntactic-indentation - (setq c-syntactic-context (c-guess-basic-syntax)) - (c-indent-line c-syntactic-context)) - ;; check to see if a newline should be added - (let ((criteria c-hanging-semi&comma-criteria) - answer add-newline-p) - (while criteria - (setq answer (funcall (car criteria))) - ;; only nil value means continue checking - (if (not answer) - (setq criteria (cdr criteria)) - (setq criteria nil) - ;; only 'stop specifically says do not add a newline - (setq add-newline-p (not (eq answer 'stop))) - )) - (if add-newline-p - (c-newline-and-indent))))) - (c--call-post-self-insert-hook-more-safely))) + (c-with-string-fences + (let* (lim literal c-syntactic-context + (here (point)) + ;; shut this up + (c-echo-syntactic-information-p nil)) + + (c-save-buffer-state () + (setq lim (c-most-enclosing-brace (c-parse-state)) + literal (c-in-literal lim))) + + (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. + (if (or (not c-auto-newline) + (not (looking-at "[ \t]*\\\\?$"))) + (if c-syntactic-indentation + (c-indent-line)) + ;; clean ups: list-close-comma or defun-close-semi + (let ((pos (- (point-max) (point)))) + (if (c-save-buffer-state () + (and (or (and + (eq (c-last-command-char) ?,) + (memq 'list-close-comma c-cleanup-list)) + (and + (eq (c-last-command-char) ?\;) + (memq 'defun-close-semi c-cleanup-list))) + (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 lim)))) + (delete-region (point) here)) + (goto-char (- (point-max) pos))) + ;; reindent line + (when c-syntactic-indentation + (setq c-syntactic-context (c-guess-basic-syntax)) + (c-indent-line c-syntactic-context)) + ;; check to see if a newline should be added + (let ((criteria c-hanging-semi&comma-criteria) + answer add-newline-p) + (while criteria + (setq answer (funcall (car criteria))) + ;; only nil value means continue checking + (if (not answer) + (setq criteria (cdr criteria)) + (setq criteria nil) + ;; only 'stop specifically says do not add a newline + (setq add-newline-p (not (eq answer 'stop))) + )) + (if add-newline-p + (c-newline-and-indent))))) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-colon (arg) "Insert a colon. @@ -1113,89 +1125,90 @@ c-electric-colon `c-cleanup-list'." (interactive "*P") - (let* ((bod (c-point 'bod)) - (literal (c-save-buffer-state () (c-in-literal bod))) - newlines is-scope-op - ;; shut this up - (c-echo-syntactic-information-p nil)) - (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. - (if (not (looking-at "[ \t]*\\\\?$")) - (if c-syntactic-indentation - (indent-according-to-mode)) - - ;; scope-operator clean-up? - (let ((pos (- (point-max) (point))) - (here (point))) - (if (c-save-buffer-state () ; Why do we need this? [ACM, 2003-03-12] - (and c-auto-newline - (memq 'scope-operator c-cleanup-list) - (eq (char-before) ?:) - (progn - (forward-char -1) - (c-skip-ws-backward) - (eq (char-before) ?:)) - (not (c-in-literal)) - (not (eq (char-after (- (point) 2)) ?:)))) - (progn - (delete-region (point) (1- here)) - (setq is-scope-op t))) - (goto-char (- (point-max) pos))) - - ;; indent the current line if it's done syntactically. - (if c-syntactic-indentation - ;; Cannot use the same syntax analysis as we find below, - ;; since that's made with c-syntactic-indentation-in-macros - ;; always set to t. - (indent-according-to-mode)) - - ;; Calculate where, if anywhere, we want newlines. - (c-save-buffer-state - ((c-syntactic-indentation-in-macros t) - (c-auto-newline-analysis t) - ;; Turn on syntactic macro analysis to help with auto newlines - ;; only. - (syntax (c-guess-basic-syntax)) - (elem syntax)) - ;; Translate substatement-label to label for this operation. - (while elem - (if (eq (car (car elem)) 'substatement-label) - (setcar (car elem) 'label)) - (setq elem (cdr elem))) - ;; some language elements can only be determined by checking - ;; the following line. Let's first look for ones that can be - ;; found when looking on the line with the colon - (setq newlines - (and c-auto-newline - (or (c-lookup-lists '(case-label label access-label) - syntax c-hanging-colons-alist) - (c-lookup-lists '(member-init-intro inher-intro) - (progn - (insert ?\n) - (unwind-protect - (c-guess-basic-syntax) - (delete-char -1))) - c-hanging-colons-alist))))) - ;; does a newline go before the colon? Watch out for already - ;; non-hung colons. However, we don't unhang them because that - ;; would be a cleanup (and anti-social). - (if (and (memq 'before newlines) - (not is-scope-op) - (save-excursion - (skip-chars-backward ": \t") - (not (bolp)))) - (let ((pos (- (point-max) (point)))) - (forward-char -1) - (c-newline-and-indent) - (goto-char (- (point-max) pos)))) - ;; does a newline go after the colon? - (if (and (memq 'after (cdr-safe newlines)) - (not is-scope-op)) - (c-newline-and-indent)))) - (c--call-post-self-insert-hook-more-safely))) + (c-with-string-fences + (let* ((bod (c-point 'bod)) + (literal (c-save-buffer-state () (c-in-literal bod))) + newlines is-scope-op + ;; shut this up + (c-echo-syntactic-information-p nil)) + (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. + (if (not (looking-at "[ \t]*\\\\?$")) + (if c-syntactic-indentation + (indent-according-to-mode)) + + ;; scope-operator clean-up? + (let ((pos (- (point-max) (point))) + (here (point))) + (if (c-save-buffer-state () ; Why do we need this? [ACM, 2003-03-12] + (and c-auto-newline + (memq 'scope-operator c-cleanup-list) + (eq (char-before) ?:) + (progn + (forward-char -1) + (c-skip-ws-backward) + (eq (char-before) ?:)) + (not (c-in-literal)) + (not (eq (char-after (- (point) 2)) ?:)))) + (progn + (delete-region (point) (1- here)) + (setq is-scope-op t))) + (goto-char (- (point-max) pos))) + + ;; indent the current line if it's done syntactically. + (if c-syntactic-indentation + ;; Cannot use the same syntax analysis as we find below, + ;; since that's made with c-syntactic-indentation-in-macros + ;; always set to t. + (indent-according-to-mode)) + + ;; Calculate where, if anywhere, we want newlines. + (c-save-buffer-state + ((c-syntactic-indentation-in-macros t) + (c-auto-newline-analysis t) + ;; Turn on syntactic macro analysis to help with auto newlines + ;; only. + (syntax (c-guess-basic-syntax)) + (elem syntax)) + ;; Translate substatement-label to label for this operation. + (while elem + (if (eq (car (car elem)) 'substatement-label) + (setcar (car elem) 'label)) + (setq elem (cdr elem))) + ;; some language elements can only be determined by checking + ;; the following line. Let's first look for ones that can be + ;; found when looking on the line with the colon + (setq newlines + (and c-auto-newline + (or (c-lookup-lists '(case-label label access-label) + syntax c-hanging-colons-alist) + (c-lookup-lists '(member-init-intro inher-intro) + (progn + (insert ?\n) + (unwind-protect + (c-guess-basic-syntax) + (delete-char -1))) + c-hanging-colons-alist))))) + ;; does a newline go before the colon? Watch out for already + ;; non-hung colons. However, we don't unhang them because that + ;; would be a cleanup (and anti-social). + (if (and (memq 'before newlines) + (not is-scope-op) + (save-excursion + (skip-chars-backward ": \t") + (not (bolp)))) + (let ((pos (- (point-max) (point)))) + (forward-char -1) + (c-newline-and-indent) + (goto-char (- (point-max) pos)))) + ;; does a newline go after the colon? + (if (and (memq 'after (cdr-safe newlines)) + (not is-scope-op)) + (c-newline-and-indent)))) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-lt-gt (arg) "Insert a \"<\" or \">\" character. @@ -1209,84 +1222,85 @@ c-electric-lt-gt numeric argument is supplied, or the point is inside a literal." (interactive "*P") - (let ((literal (c-save-buffer-state () (c-in-literal))) - template-delim include-delim - (c-echo-syntactic-information-p nil) - final-pos found-delim case-fold-search) + (c-with-string-fences + (let ((literal (c-save-buffer-state () (c-in-literal))) + template-delim include-delim + (c-echo-syntactic-information-p nil) + final-pos found-delim case-fold-search) - (let (post-self-insert-hook) ; Disable random functionality. - (self-insert-command (prefix-numeric-value arg))) - (setq final-pos (point)) + (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 ;;;; property on the new < or > and its mate (if any) when they are template ;;;; parens. This is now done in an after-change function. - (when (and (not arg) (not literal)) - ;; Have we got a delimiter on a #include directive? - (beginning-of-line) - (setq include-delim - (and - (looking-at c-cpp-include-key) - (if (eq (c-last-command-char) ?<) - (eq (match-end 0) (1- final-pos)) - (goto-char (1- final-pos)) - (skip-chars-backward "^<>" (c-point 'bol)) - (eq (char-before) ?<)))) - (goto-char final-pos) - - ;; Indent the line if appropriate. - (when (and c-electric-flag c-syntactic-indentation c-recognize-<>-arglists) - (setq found-delim + (when (and (not arg) (not literal)) + ;; Have we got a delimiter on a #include directive? + (beginning-of-line) + (setq include-delim + (and + (looking-at c-cpp-include-key) (if (eq (c-last-command-char) ?<) - ;; If a <, basically see if it's got "template" before it ..... - (or (and (progn - (backward-char) - (= (point) - (progn (c-beginning-of-current-token) (point)))) - (progn - (c-backward-token-2) - (looking-at c-opt-<>-sexp-key)) - (setq template-delim t)) - ;; ..... or is a C++ << operator. - (and (c-major-mode-is 'c++-mode) - (progn - (goto-char (1- final-pos)) - (c-beginning-of-current-token) - (looking-at "<<")) - (>= (match-end 0) final-pos))) - - ;; It's a >. Either a template/generic terminator ... - (or (and (c-get-char-property (1- final-pos) 'syntax-table) - (setq template-delim t)) - ;; or a C++ >> operator. - (and (c-major-mode-is 'c++-mode) - (progn - (goto-char (1- final-pos)) - (c-beginning-of-current-token) - (looking-at ">>")) - (>= (match-end 0) final-pos))))) - (goto-char final-pos) - - (when found-delim - (indent-according-to-mode))) - - ;; On the off chance that < and > are configured as pairs in - ;; electric-pair-mode. - (when (and (boundp 'electric-pair-mode) electric-pair-mode - (or template-delim include-delim)) - (let (post-self-insert-hook) - (electric-pair-post-self-insert-function)))) - - (when found-delim - (when (and (eq (char-before) ?>) - (not executing-kbd-macro) - blink-paren-function) - ;; From now (2016-01-01), the syntax-table text properties on < and > - ;; are applied in an after-change function, not during redisplay. Hence - ;; we no longer need to call (sit-for 0) for blink paren to work. - (funcall blink-paren-function)))) - (c--call-post-self-insert-hook-more-safely)) + (eq (match-end 0) (1- final-pos)) + (goto-char (1- final-pos)) + (skip-chars-backward "^<>" (c-point 'bol)) + (eq (char-before) ?<)))) + (goto-char final-pos) + + ;; Indent the line if appropriate. + (when (and c-electric-flag c-syntactic-indentation c-recognize-<>-arglists) + (setq found-delim + (if (eq (c-last-command-char) ?<) + ;; If a <, basically see if it's got "template" before it ..... + (or (and (progn + (backward-char) + (= (point) + (progn (c-beginning-of-current-token) (point)))) + (progn + (c-backward-token-2) + (looking-at c-opt-<>-sexp-key)) + (setq template-delim t)) + ;; ..... or is a C++ << operator. + (and (c-major-mode-is 'c++-mode) + (progn + (goto-char (1- final-pos)) + (c-beginning-of-current-token) + (looking-at "<<")) + (>= (match-end 0) final-pos))) + + ;; It's a >. Either a template/generic terminator ... + (or (and (c-get-char-property (1- final-pos) 'syntax-table) + (setq template-delim t)) + ;; or a C++ >> operator. + (and (c-major-mode-is 'c++-mode) + (progn + (goto-char (1- final-pos)) + (c-beginning-of-current-token) + (looking-at ">>")) + (>= (match-end 0) final-pos))))) + (goto-char final-pos) + + (when found-delim + (indent-according-to-mode))) + + ;; On the off chance that < and > are configured as pairs in + ;; electric-pair-mode. + (when (and (boundp 'electric-pair-mode) electric-pair-mode + (or template-delim include-delim)) + (let (post-self-insert-hook) + (electric-pair-post-self-insert-function)))) + + (when found-delim + (when (and (eq (char-before) ?>) + (not executing-kbd-macro) + blink-paren-function) + ;; From now (2016-01-01), the syntax-table text properties on < and > + ;; are applied in an after-change function, not during redisplay. Hence + ;; we no longer need to call (sit-for 0) for blink paren to work. + (funcall blink-paren-function)))) + (c--call-post-self-insert-hook-more-safely))) (defun c-electric-paren (arg) "Insert a parenthesis. @@ -1301,112 +1315,113 @@ c-electric-paren Also, if `c-electric-flag' and `c-auto-newline' are both non-nil, some newline cleanups are done if appropriate; see the variable `c-cleanup-list'." (interactive "*P") - (let ((literal (c-save-buffer-state () (c-in-literal))) - ;; shut this up - (c-echo-syntactic-information-p nil) - case-fold-search) - (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 - ;; be most disruptive. We'll blink it ourselves - ;; afterwards. - (old-blink-paren blink-paren-function) - blink-paren-function) - (if (and c-syntactic-indentation c-electric-flag) - (indent-according-to-mode)) - - ;; If we're at EOL, check for new-line clean-ups. - (when (and c-electric-flag c-auto-newline - (looking-at "[ \t]*\\\\?$")) - - ;; clean up brace-elseif-brace - (when - (and (memq 'brace-elseif-brace c-cleanup-list) - (eq (c-last-command-char) ?\() - (re-search-backward - (concat "}" - "\\([ \t\n]\\|\\\\\n\\)*" - "else" - "\\([ \t\n]\\|\\\\\n\\)+" - "if" - "\\([ \t\n]\\|\\\\\n\\)*" - "(" - "\\=") - nil t) - (not (c-save-buffer-state () (c-in-literal)))) - (delete-region (match-beginning 0) (match-end 0)) - (insert-and-inherit "} else if (")) - - ;; clean up brace-catch-brace - (when - (and (memq 'brace-catch-brace c-cleanup-list) - (eq (c-last-command-char) ?\() - (re-search-backward - (concat "}" - "\\([ \t\n]\\|\\\\\n\\)*" - "catch" - "\\([ \t\n]\\|\\\\\n\\)*" - "(" - "\\=") - nil t) - (not (c-save-buffer-state () (c-in-literal)))) - (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. - (let (beg (end (1- (point)))) - (cond - - ;; space-before-funcall clean-up? - ((and (memq 'space-before-funcall c-cleanup-list) - (eq (c-last-command-char) ?\() - (save-excursion - (backward-char) - (skip-chars-backward " \t") - (setq beg (point)) - (and (c-save-buffer-state () (c-on-identifier)) - ;; Don't add a space into #define FOO().... - (not (and (c-beginning-of-macro) - (c-forward-over-cpp-define-id) - (eq (point) beg)))))) - (save-excursion - (delete-region beg end) - (goto-char beg) - (insert ?\ ))) - - ;; compact-empty-funcall clean-up? - ((c-save-buffer-state () - (and (memq 'compact-empty-funcall c-cleanup-list) - (eq (c-last-command-char) ?\)) - (save-excursion - (c-safe (backward-char 2)) - (when (looking-at "()") - (setq end (point)) - (skip-chars-backward " \t") - (setq beg (point)) - (c-on-identifier))))) - (delete-region beg end)))) - (and (eq last-input-event ?\)) - (not executing-kbd-macro) - old-blink-paren - (funcall old-blink-paren))) - - ;; Apply `electric-pair-mode' stuff inside a string or comment. - (when (and (boundp 'electric-pair-mode) electric-pair-mode) - (let (post-self-insert-hook) - (electric-pair-post-self-insert-function)))) - (c--call-post-self-insert-hook-more-safely))) + (c-with-string-fences + (let ((literal (c-save-buffer-state () (c-in-literal))) + ;; shut this up + (c-echo-syntactic-information-p nil) + case-fold-search) + (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 + ;; be most disruptive. We'll blink it ourselves + ;; afterwards. + (old-blink-paren blink-paren-function) + blink-paren-function) + (if (and c-syntactic-indentation c-electric-flag) + (indent-according-to-mode)) + + ;; If we're at EOL, check for new-line clean-ups. + (when (and c-electric-flag c-auto-newline + (looking-at "[ \t]*\\\\?$")) + + ;; clean up brace-elseif-brace + (when + (and (memq 'brace-elseif-brace c-cleanup-list) + (eq (c-last-command-char) ?\() + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "else" + "\\([ \t\n]\\|\\\\\n\\)+" + "if" + "\\([ \t\n]\\|\\\\\n\\)*" + "(" + "\\=") + nil t) + (not (c-save-buffer-state () (c-in-literal)))) + (delete-region (match-beginning 0) (match-end 0)) + (insert-and-inherit "} else if (")) + + ;; clean up brace-catch-brace + (when + (and (memq 'brace-catch-brace c-cleanup-list) + (eq (c-last-command-char) ?\() + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "catch" + "\\([ \t\n]\\|\\\\\n\\)*" + "(" + "\\=") + nil t) + (not (c-save-buffer-state () (c-in-literal)))) + (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. + (let (beg (end (1- (point)))) + (cond + + ;; space-before-funcall clean-up? + ((and (memq 'space-before-funcall c-cleanup-list) + (eq (c-last-command-char) ?\() + (save-excursion + (backward-char) + (skip-chars-backward " \t") + (setq beg (point)) + (and (c-save-buffer-state () (c-on-identifier)) + ;; Don't add a space into #define FOO().... + (not (and (c-beginning-of-macro) + (c-forward-over-cpp-define-id) + (eq (point) beg)))))) + (save-excursion + (delete-region beg end) + (goto-char beg) + (insert ?\ ))) + + ;; compact-empty-funcall clean-up? + ((c-save-buffer-state () + (and (memq 'compact-empty-funcall c-cleanup-list) + (eq (c-last-command-char) ?\)) + (save-excursion + (c-safe (backward-char 2)) + (when (looking-at "()") + (setq end (point)) + (skip-chars-backward " \t") + (setq beg (point)) + (c-on-identifier))))) + (delete-region beg end)))) + (and (eq last-input-event ?\)) + (not executing-kbd-macro) + old-blink-paren + (funcall old-blink-paren))) + + ;; Apply `electric-pair-mode' stuff inside a string or comment. + (when (and (boundp 'electric-pair-mode) electric-pair-mode) + (let (post-self-insert-hook) + (electric-pair-post-self-insert-function)))) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-continued-statement () "Reindent the current line if appropriate. @@ -1868,70 +1883,71 @@ c-beginning-of-defun (c-region-is-active-p) (push-mark)) - (c-save-buffer-state - (beginning-of-defun-function - end-of-defun-function - (paren-state (c-parse-state)) - (orig-point-min (point-min)) (orig-point-max (point-max)) - lim ; Position of { which has been widened to. - where pos case-fold-search) - - (save-restriction - (if (eq c-defun-tactic 'go-outward) - (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace. - paren-state orig-point-min orig-point-max))) - - ;; Move back out of any macro/comment/string we happen to be in. - (c-beginning-of-macro) - (setq pos (c-literal-start)) - (if pos (goto-char pos)) - - (setq where (c-where-wrt-brace-construct)) - - (if (< arg 0) - ;; Move forward to the closing brace of a function. - (progn - (if (memq where '(at-function-end outwith-function)) - (setq arg (1+ arg))) - (if (< arg 0) - (c-while-widening-to-decl-block - (< (setq arg (- (c-forward-to-nth-EOF-\;-or-} (- arg) where))) 0))) - (prog1 - ;; Move forward to the next opening brace.... - (when (and (= arg 0) - (progn - (c-while-widening-to-decl-block - (not (c-syntactic-re-search-forward "{" nil 'eob))) - (eq (char-before) ?{))) - (backward-char) - ;; ... and backward to the function header. - (c-beginning-of-decl-1) - t) - (c-keep-region-active))) - - ;; Move backward to the opening brace of a function, making successively - ;; larger portions of the buffer visible as necessary. - (when (> arg 0) - (c-while-widening-to-decl-block - (> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0))) - - (when (eq arg 0) - ;; Go backward to this function's header. - (c-beginning-of-decl-1) - - (setq pos (point)) - ;; We're now there, modulo comments and whitespace. - ;; Try to be line oriented; position point at the closest - ;; preceding boi that isn't inside a comment, but if we hit - ;; the previous declaration then we use the current point - ;; instead. - (while (and (/= (point) (c-point 'boi)) - (c-backward-single-comment))) - (if (/= (point) (c-point 'boi)) - (goto-char pos))) - - (c-keep-region-active) - (= arg 0))))) + (c-with-string-fences + (c-save-buffer-state + (beginning-of-defun-function + end-of-defun-function + (paren-state (c-parse-state)) + (orig-point-min (point-min)) (orig-point-max (point-max)) + lim ; Position of { which has been widened to. + where pos case-fold-search) + + (save-restriction + (if (eq c-defun-tactic 'go-outward) + (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace. + paren-state orig-point-min orig-point-max))) + + ;; Move back out of any macro/comment/string we happen to be in. + (c-beginning-of-macro) + (setq pos (c-literal-start)) + (if pos (goto-char pos)) + + (setq where (c-where-wrt-brace-construct)) + + (if (< arg 0) + ;; Move forward to the closing brace of a function. + (progn + (if (memq where '(at-function-end outwith-function)) + (setq arg (1+ arg))) + (if (< arg 0) + (c-while-widening-to-decl-block + (< (setq arg (- (c-forward-to-nth-EOF-\;-or-} (- arg) where))) 0))) + (prog1 + ;; Move forward to the next opening brace.... + (when (and (= arg 0) + (progn + (c-while-widening-to-decl-block + (not (c-syntactic-re-search-forward "{" nil 'eob))) + (eq (char-before) ?{))) + (backward-char) + ;; ... and backward to the function header. + (c-beginning-of-decl-1) + t) + (c-keep-region-active))) + + ;; Move backward to the opening brace of a function, making successively + ;; larger portions of the buffer visible as necessary. + (when (> arg 0) + (c-while-widening-to-decl-block + (> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0))) + + (when (eq arg 0) + ;; Go backward to this function's header. + (c-beginning-of-decl-1) + + (setq pos (point)) + ;; We're now there, modulo comments and whitespace. + ;; Try to be line oriented; position point at the closest + ;; preceding boi that isn't inside a comment, but if we hit + ;; the previous declaration then we use the current point + ;; instead. + (while (and (/= (point) (c-point 'boi)) + (c-backward-single-comment))) + (if (/= (point) (c-point 'boi)) + (goto-char pos))) + + (c-keep-region-active) + (= arg 0)))))) (defun c-forward-to-nth-EOF-\;-or-} (n where) ;; Skip to the closing brace or semicolon of the Nth function after point. @@ -1998,65 +2014,66 @@ c-end-of-defun (c-region-is-active-p) (push-mark)) - (c-save-buffer-state - (beginning-of-defun-function - end-of-defun-function - (paren-state (c-parse-state)) - (orig-point-min (point-min)) (orig-point-max (point-max)) - lim - where pos case-fold-search) - - (save-restriction - (if (eq c-defun-tactic 'go-outward) - (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace - paren-state orig-point-min orig-point-max))) + (c-with-string-fences + (c-save-buffer-state + (beginning-of-defun-function + end-of-defun-function + (paren-state (c-parse-state)) + (orig-point-min (point-min)) (orig-point-max (point-max)) + lim + where pos case-fold-search) + + (save-restriction + (if (eq c-defun-tactic 'go-outward) + (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace + paren-state orig-point-min orig-point-max))) + + ;; Move back out of any macro/comment/string we happen to be in. + (c-beginning-of-macro) + (setq pos (c-literal-start)) + (if pos (goto-char pos)) + + (setq where (c-where-wrt-brace-construct)) + + (if (< arg 0) + ;; Move backwards to the } of a function + (progn + (if (memq where '(at-header outwith-function)) + (setq arg (1+ arg))) + (if (< arg 0) + (c-while-widening-to-decl-block + (< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0))) + (if (= arg 0) + (c-while-widening-to-decl-block + (progn (c-syntactic-skip-backward "^}") + (not (eq (char-before) ?})))))) + + ;; Move forward to the } of a function + (if (> arg 0) + (c-while-widening-to-decl-block + (> (setq arg (c-forward-to-nth-EOF-\;-or-} arg where)) 0)))) + + ;; Do we need to move forward from the brace to the semicolon? + (when (eq arg 0) + (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc. + (c-syntactic-re-search-forward ";")) - ;; Move back out of any macro/comment/string we happen to be in. - (c-beginning-of-macro) - (setq pos (c-literal-start)) - (if pos (goto-char pos)) + (setq pos (point)) + ;; We're there now, modulo comments and whitespace. + ;; Try to be line oriented; position point after the next + ;; newline that isn't inside a comment, but if we hit the + ;; next declaration then we use the current point instead. + (while (and (not (bolp)) + (not (looking-at "\\s *$")) + (c-forward-single-comment))) + (cond ((bolp)) + ((looking-at "\\s *$") + (forward-line 1)) + (t + (goto-char pos)))) - (setq where (c-where-wrt-brace-construct)) - - (if (< arg 0) - ;; Move backwards to the } of a function - (progn - (if (memq where '(at-header outwith-function)) - (setq arg (1+ arg))) - (if (< arg 0) - (c-while-widening-to-decl-block - (< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0))) - (if (= arg 0) - (c-while-widening-to-decl-block - (progn (c-syntactic-skip-backward "^}") - (not (eq (char-before) ?})))))) - - ;; Move forward to the } of a function - (if (> arg 0) - (c-while-widening-to-decl-block - (> (setq arg (c-forward-to-nth-EOF-\;-or-} arg where)) 0)))) - - ;; Do we need to move forward from the brace to the semicolon? - (when (eq arg 0) - (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc. - (c-syntactic-re-search-forward ";")) - - (setq pos (point)) - ;; We're there now, modulo comments and whitespace. - ;; Try to be line oriented; position point after the next - ;; newline that isn't inside a comment, but if we hit the - ;; next declaration then we use the current point instead. - (while (and (not (bolp)) - (not (looking-at "\\s *$")) - (c-forward-single-comment))) - (cond ((bolp)) - ((looking-at "\\s *$") - (forward-line 1)) - (t - (goto-char pos)))) - - (c-keep-region-active) - (= arg 0)))) + (c-keep-region-active) + (= arg 0))))) (defun c-defun-name-1 () "Return name of current defun, at current narrowing, or nil if there isn't one. @@ -2342,18 +2359,19 @@ c-display-defun-name "Display the name of the current CC mode defun and the position in it. With a prefix arg, push the name onto the kill ring too." (interactive "P") - (save-restriction - (widen) - (c-save-buffer-state ((name-and-limits (c-defun-name-and-limits nil)) - (name (car name-and-limits)) - (limits (cdr name-and-limits)) - (point-bol (c-point 'bol))) - (when name - (message "%s. Line %s/%s." name - (1+ (count-lines (car limits) (max point-bol (car limits)))) - (count-lines (car limits) (cdr limits))) - (if arg (kill-new name)) - (sit-for 3 t))))) + (c-with-string-fences + (save-restriction + (widen) + (c-save-buffer-state ((name-and-limits (c-defun-name-and-limits nil)) + (name (car name-and-limits)) + (limits (cdr name-and-limits)) + (point-bol (c-point 'bol))) + (when name + (message "%s. Line %s/%s." name + (1+ (count-lines (car limits) (max point-bol (car limits)))) + (count-lines (car limits) (cdr limits))) + (if arg (kill-new name)) + (sit-for 3 t)))))) (put 'c-display-defun-name 'isearch-scroll t) (defun c-mark-function () @@ -2369,34 +2387,35 @@ c-mark-function function does not require the declaration to contain a brace block." (interactive) - (let (decl-limits case-fold-search) - (c-save-buffer-state nil - ;; We try to be line oriented, unless there are several - ;; declarations on the same line. - (if (looking-at c-syntactic-eol) - (c-backward-token-2 1 nil (c-point 'bol))) - (setq decl-limits (c-declaration-limits t))) - - (if (not decl-limits) - (error "Cannot find any declaration") - (let* ((extend-region-p - (and (eq this-command 'c-mark-function) - (eq last-command 'c-mark-function))) - (push-mark-p (and (eq this-command 'c-mark-function) - (not extend-region-p) - (not (c-region-is-active-p))))) - (if push-mark-p (push-mark)) - (if extend-region-p - (progn - (exchange-point-and-mark) - (setq decl-limits (c-declaration-limits t)) - (when (not decl-limits) - (exchange-point-and-mark) - (error "Cannot find any declaration")) - (goto-char (cdr decl-limits)) - (exchange-point-and-mark)) - (goto-char (car decl-limits)) - (push-mark (cdr decl-limits) nil t)))))) + (c-with-string-fences + (let (decl-limits case-fold-search) + (c-save-buffer-state nil + ;; We try to be line oriented, unless there are several + ;; declarations on the same line. + (if (looking-at c-syntactic-eol) + (c-backward-token-2 1 nil (c-point 'bol))) + (setq decl-limits (c-declaration-limits t))) + + (if (not decl-limits) + (error "Cannot find any declaration") + (let* ((extend-region-p + (and (eq this-command 'c-mark-function) + (eq last-command 'c-mark-function))) + (push-mark-p (and (eq this-command 'c-mark-function) + (not extend-region-p) + (not (c-region-is-active-p))))) + (if push-mark-p (push-mark)) + (if extend-region-p + (progn + (exchange-point-and-mark) + (setq decl-limits (c-declaration-limits t)) + (when (not decl-limits) + (exchange-point-and-mark) + (error "Cannot find any declaration")) + (goto-char (cdr decl-limits)) + (exchange-point-and-mark)) + (goto-char (car decl-limits)) + (push-mark (cdr decl-limits) nil t))))))) (defun c-cpp-define-name () "Return the name of the current CPP macro, or NIL if we're not in one." @@ -3033,85 +3052,86 @@ c-beginning-of-statement nil t)) (if (< count 0) (c-end-of-statement (- count) lim sentence-flag) - (c-save-buffer-state - ((count (or count 1)) - last ; start point for going back ONE chunk. Updated each chunk movement. - (macro-fence - (save-excursion (and (not (bobp)) (c-beginning-of-macro) (point)))) - res ; result from sub-function call - not-bos ; "not beginning-of-statement" - (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL - - ;; Go back one statement at each iteration of the following loop. - (while (and (/= count 0) - (or (not lim) (> (point) lim))) - ;; Go back one "chunk" each time round the following loop, stopping - ;; when we reach a statement boundary, etc. - (setq last (point)) - (while - (cond ; Each arm of this cond returns NIL on reaching a desired - ; statement boundary, non-NIL otherwise. - ((bobp) - (setq count 0) - nil) - - (range ; point is within or approaching a literal. - (cond - ;; Single line string or sentence-flag is null => skip the - ;; entire literal. - ((or (null sentence-flag) - (c-one-line-string-p range)) - (goto-char (car range)) - (setq range (c-ascertain-preceding-literal)) - ;; N.B. The following is essentially testing for an AWK regexp - ;; at BOS: - ;; Was the previous non-ws thing an end of statement? - (save-excursion - (if macro-fence - (c-backward-comments) - (c-backward-syntactic-ws)) - (not (or (bobp) (c-after-statement-terminator-p))))) - - ;; Comment inside a statement or a multi-line string. - (t (when (setq res ; returns non-nil when we go out of the literal - (if (eq (c-literal-type range) 'string) - (c-beginning-of-sentence-in-string range) - (c-beginning-of-sentence-in-comment range))) - (setq range (c-ascertain-preceding-literal))) - res))) - - ;; Non-literal code. - (t (setq res (c-back-over-illiterals macro-fence)) - (setq not-bos ; "not reached beginning-of-statement". - (or (= (point) last) - (memq (char-after) '(?\) ?\})) - (and - (car res) - ;; We're at a tentative BOS. The next form goes - ;; back over WS looking for an end of previous - ;; statement. - (not (save-excursion - (if macro-fence - (c-backward-comments) - (c-backward-syntactic-ws)) - (or (bobp) (c-after-statement-terminator-p))))))) - ;; Are we about to move backwards into or out of a - ;; preprocessor command? If so, locate its beginning. - (when (eq (cdr res) 'macro-boundary) - (save-excursion - (beginning-of-line) - (setq macro-fence - (and (not (bobp)) - (progn (c-skip-ws-backward) (c-beginning-of-macro)) - (point))))) - ;; Are we about to move backwards into a literal? - (when (memq (cdr res) '(macro-boundary literal)) - (setq range (c-ascertain-preceding-literal))) - not-bos)) - (setq last (point))) - - (if (/= count 0) (setq count (1- count)))) - (c-keep-region-active)))) + (c-with-string-fences + (c-save-buffer-state + ((count (or count 1)) + last ; start point for going back ONE chunk. Updated each chunk movement. + (macro-fence + (save-excursion (and (not (bobp)) (c-beginning-of-macro) (point)))) + res ; result from sub-function call + not-bos ; "not beginning-of-statement" + (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL + + ;; Go back one statement at each iteration of the following loop. + (while (and (/= count 0) + (or (not lim) (> (point) lim))) + ;; Go back one "chunk" each time round the following loop, stopping + ;; when we reach a statement boundary, etc. + (setq last (point)) + (while + (cond ; Each arm of this cond returns NIL on reaching a desired + ; statement boundary, non-NIL otherwise. + ((bobp) + (setq count 0) + nil) + + (range ; point is within or approaching a literal. + (cond + ;; Single line string or sentence-flag is null => skip the + ;; entire literal. + ((or (null sentence-flag) + (c-one-line-string-p range)) + (goto-char (car range)) + (setq range (c-ascertain-preceding-literal)) + ;; N.B. The following is essentially testing for an AWK regexp + ;; at BOS: + ;; Was the previous non-ws thing an end of statement? + (save-excursion + (if macro-fence + (c-backward-comments) + (c-backward-syntactic-ws)) + (not (or (bobp) (c-after-statement-terminator-p))))) + + ;; Comment inside a statement or a multi-line string. + (t (when (setq res ; returns non-nil when we go out of the literal + (if (eq (c-literal-type range) 'string) + (c-beginning-of-sentence-in-string range) + (c-beginning-of-sentence-in-comment range))) + (setq range (c-ascertain-preceding-literal))) + res))) + + ;; Non-literal code. + (t (setq res (c-back-over-illiterals macro-fence)) + (setq not-bos ; "not reached beginning-of-statement". + (or (= (point) last) + (memq (char-after) '(?\) ?\})) + (and + (car res) + ;; We're at a tentative BOS. The next form goes + ;; back over WS looking for an end of previous + ;; statement. + (not (save-excursion + (if macro-fence + (c-backward-comments) + (c-backward-syntactic-ws)) + (or (bobp) (c-after-statement-terminator-p))))))) + ;; Are we about to move backwards into or out of a + ;; preprocessor command? If so, locate its beginning. + (when (eq (cdr res) 'macro-boundary) + (save-excursion + (beginning-of-line) + (setq macro-fence + (and (not (bobp)) + (progn (c-skip-ws-backward) (c-beginning-of-macro)) + (point))))) + ;; Are we about to move backwards into a literal? + (when (memq (cdr res) '(macro-boundary literal)) + (setq range (c-ascertain-preceding-literal))) + not-bos)) + (setq last (point))) + + (if (/= count 0) (setq count (1- count)))) + (c-keep-region-active))))) (defun c-end-of-statement (&optional count lim sentence-flag) "Go to the end of the innermost C statement. @@ -3129,78 +3149,79 @@ c-end-of-statement (setq count (or count 1)) (if (< count 0) (c-beginning-of-statement (- count) lim sentence-flag) - (c-save-buffer-state - (here ; start point for going forward ONE statement. Updated each statement. - (macro-fence - (save-excursion - (and (not (eobp)) (c-beginning-of-macro) - (progn (c-end-of-macro) (point))))) - res - (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL - - ;; Go back/forward one statement at each iteration of the following loop. - (while (and (/= count 0) - (or (not lim) (< (point) lim))) - (setq here (point)) ; ONLY HERE is HERE updated - - ;; Go forward one "chunk" each time round the following loop, stopping - ;; when we reach a statement boundary, etc. - (while - (cond ; Each arm of this cond returns NIL on reaching a desired - ; statement boundary, non-NIL otherwise. - ((eobp) - (setq count 0) - nil) - - (range ; point is within a literal. - (cond - ;; sentence-flag is null => skip the entire literal. - ;; or a Single line string. - ((or (null sentence-flag) - (c-one-line-string-p range)) - (goto-char (cdr range)) - (setq range (c-ascertain-following-literal)) - ;; Is there a virtual semicolon here (e.g. for AWK)? - (not (c-at-vsemi-p))) - - ;; Comment or multi-line string. - (t (when (setq res ; gets non-nil when we go out of the literal - (if (eq (c-literal-type range) 'string) - (c-end-of-sentence-in-string range) - (c-end-of-sentence-in-comment range))) - (setq range (c-ascertain-following-literal))) - ;; If we've just come forward out of a literal, check for - ;; vsemi. (N.B. AWK can't have a vsemi after a comment, but - ;; some other language may do in the future) - (and res - (not (c-at-vsemi-p)))))) - - ;; Non-literal code. - (t (setq res (c-forward-over-illiterals macro-fence - (> (point) here))) - ;; Are we about to move forward into or out of a - ;; preprocessor command? - (when (eq (cdr res) 'macro-boundary) - (setq macro-fence - (save-excursion - (if macro-fence - (progn - (end-of-line) - (and (not (eobp)) - (progn (c-skip-ws-forward) - (c-beginning-of-macro)) - (progn (c-end-of-macro) - (point)))) - (and (not (eobp)) - (c-beginning-of-macro) - (progn (c-end-of-macro) (point))))))) - ;; Are we about to move forward into a literal? - (when (memq (cdr res) '(macro-boundary literal)) - (setq range (c-ascertain-following-literal))) - (car res)))) - - (if (/= count 0) (setq count (1- count)))) - (c-keep-region-active)))) + (c-with-string-fences + (c-save-buffer-state + (here ; start point for going forward ONE statement. Updated each statement. + (macro-fence + (save-excursion + (and (not (eobp)) (c-beginning-of-macro) + (progn (c-end-of-macro) (point))))) + res + (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL + + ;; Go back/forward one statement at each iteration of the following loop. + (while (and (/= count 0) + (or (not lim) (< (point) lim))) + (setq here (point)) ; ONLY HERE is HERE updated + + ;; Go forward one "chunk" each time round the following loop, stopping + ;; when we reach a statement boundary, etc. + (while + (cond ; Each arm of this cond returns NIL on reaching a desired + ; statement boundary, non-NIL otherwise. + ((eobp) + (setq count 0) + nil) + + (range ; point is within a literal. + (cond + ;; sentence-flag is null => skip the entire literal. + ;; or a Single line string. + ((or (null sentence-flag) + (c-one-line-string-p range)) + (goto-char (cdr range)) + (setq range (c-ascertain-following-literal)) + ;; Is there a virtual semicolon here (e.g. for AWK)? + (not (c-at-vsemi-p))) + + ;; Comment or multi-line string. + (t (when (setq res ; gets non-nil when we go out of the literal + (if (eq (c-literal-type range) 'string) + (c-end-of-sentence-in-string range) + (c-end-of-sentence-in-comment range))) + (setq range (c-ascertain-following-literal))) + ;; If we've just come forward out of a literal, check for + ;; vsemi. (N.B. AWK can't have a vsemi after a comment, but + ;; some other language may do in the future) + (and res + (not (c-at-vsemi-p)))))) + + ;; Non-literal code. + (t (setq res (c-forward-over-illiterals macro-fence + (> (point) here))) + ;; Are we about to move forward into or out of a + ;; preprocessor command? + (when (eq (cdr res) 'macro-boundary) + (setq macro-fence + (save-excursion + (if macro-fence + (progn + (end-of-line) + (and (not (eobp)) + (progn (c-skip-ws-forward) + (c-beginning-of-macro)) + (progn (c-end-of-macro) + (point)))) + (and (not (eobp)) + (c-beginning-of-macro) + (progn (c-end-of-macro) (point))))))) + ;; Are we about to move forward into a literal? + (when (memq (cdr res) '(macro-boundary literal)) + (setq range (c-ascertain-following-literal))) + (car res)))) + + (if (/= count 0) (setq count (1- count)))) + (c-keep-region-active))))) ;; set up electric character functions to work with pending-del, @@ -3539,122 +3560,125 @@ c-indent-command depending on the variable `indent-tabs-mode'." (interactive "P") - (let ((indent-function - (if c-syntactic-indentation - (symbol-function 'indent-according-to-mode) - (lambda () - (let ((c-macro-start c-macro-start) - (steps (if (equal arg '(4)) - -1 - (prefix-numeric-value arg)))) - (c-shift-line-indentation (* steps c-basic-offset)) - (when (and c-auto-align-backslashes - (save-excursion - (end-of-line) - (eq (char-before) ?\\)) - (c-query-and-set-macro-start)) - ;; Realign the line continuation backslash if inside a macro. - (c-backslash-region (point) (point) nil t))) - )))) - (if (and c-syntactic-indentation arg) - ;; If c-syntactic-indentation and got arg, always indent this - ;; line as C and shift remaining lines of expression the same - ;; amount. - (let ((shift-amt (save-excursion - (back-to-indentation) - (current-column))) - beg end) - (c-indent-line) - (setq shift-amt (- (save-excursion - (back-to-indentation) - (current-column)) - shift-amt)) - (save-excursion - (if (eq c-tab-always-indent t) - (beginning-of-line)) ; FIXME!!! What is this here for? ACM 2005/10/31 - (setq beg (point)) - (c-forward-sexp 1) - (setq end (point)) - (goto-char beg) - (forward-line 1) - (setq beg (point))) - (if (> end beg) - (indent-code-rigidly beg end shift-amt "#"))) - ;; Else use c-tab-always-indent to determine behavior. - (cond - ;; CASE 1: indent when at column zero or in line's indentation, - ;; otherwise insert a tab - ((not c-tab-always-indent) - (if (save-excursion - (skip-chars-backward " \t") - (not (bolp))) - (funcall c-insert-tab-function) - (funcall indent-function))) - ;; CASE 2: just indent the line - ((eq c-tab-always-indent t) - (funcall indent-function)) - ;; CASE 3: if in a literal, insert a tab, but always indent the - ;; line - (t - (if (c-save-buffer-state () (c-in-literal)) - (funcall c-insert-tab-function)) - (funcall indent-function) - ))))) + (c-with-string-fences + (let ((indent-function + (if c-syntactic-indentation + (symbol-function 'indent-according-to-mode) + (lambda () + (let ((c-macro-start c-macro-start) + (steps (if (equal arg '(4)) + -1 + (prefix-numeric-value arg)))) + (c-shift-line-indentation (* steps c-basic-offset)) + (when (and c-auto-align-backslashes + (save-excursion + (end-of-line) + (eq (char-before) ?\\)) + (c-query-and-set-macro-start)) + ;; Realign the line continuation backslash if inside a macro. + (c-backslash-region (point) (point) nil t))) + )))) + (if (and c-syntactic-indentation arg) + ;; If c-syntactic-indentation and got arg, always indent this + ;; line as C and shift remaining lines of expression the same + ;; amount. + (let ((shift-amt (save-excursion + (back-to-indentation) + (current-column))) + beg end) + (c-indent-line) + (setq shift-amt (- (save-excursion + (back-to-indentation) + (current-column)) + shift-amt)) + (save-excursion + (if (eq c-tab-always-indent t) + (beginning-of-line)) ; FIXME!!! What is this here for? ACM 2005/10/31 + (setq beg (point)) + (c-forward-sexp 1) + (setq end (point)) + (goto-char beg) + (forward-line 1) + (setq beg (point))) + (if (> end beg) + (indent-code-rigidly beg end shift-amt "#"))) + ;; Else use c-tab-always-indent to determine behavior. + (cond + ;; CASE 1: indent when at column zero or in line's indentation, + ;; otherwise insert a tab + ((not c-tab-always-indent) + (if (save-excursion + (skip-chars-backward " \t") + (not (bolp))) + (funcall c-insert-tab-function) + (funcall indent-function))) + ;; CASE 2: just indent the line + ((eq c-tab-always-indent t) + (funcall indent-function)) + ;; CASE 3: if in a literal, insert a tab, but always indent the + ;; line + (t + (if (c-save-buffer-state () (c-in-literal)) + (funcall c-insert-tab-function)) + (funcall indent-function) + )))))) (defun c-indent-exp (&optional shutup-p) "Indent each line in the balanced expression following point syntactically. If optional SHUTUP-P is non-nil, no errors are signaled if no balanced expression is found." (interactive "*P") - (let ((here (point-marker)) - end) - (set-marker-insertion-type here t) - (unwind-protect - (let ((start (save-restriction - ;; Find the closest following open paren that - ;; ends on another line. - (narrow-to-region (point-min) (c-point 'eol)) - (let (beg (end (point))) - (while (and (setq beg (c-down-list-forward end)) - (setq end (c-up-list-forward beg)))) - (and beg - (eq (char-syntax (char-before beg)) ?\() - (1- beg)))))) - ;; sanity check - (if (not start) - (unless shutup-p - (error "Cannot find start of balanced expression to indent")) - (goto-char start) - (setq end (c-safe (scan-sexps (point) 1))) - (if (not end) - (unless shutup-p - (error "Cannot find end of balanced expression to indent")) - (forward-line) - (if (< (point) end) - (c-indent-region (point) end))))) - (goto-char here) - (set-marker here nil)))) + (c-with-string-fences + (let ((here (point-marker)) + end) + (set-marker-insertion-type here t) + (unwind-protect + (let ((start (save-restriction + ;; Find the closest following open paren that + ;; ends on another line. + (narrow-to-region (point-min) (c-point 'eol)) + (let (beg (end (point))) + (while (and (setq beg (c-down-list-forward end)) + (setq end (c-up-list-forward beg)))) + (and beg + (eq (char-syntax (char-before beg)) ?\() + (1- beg)))))) + ;; sanity check + (if (not start) + (unless shutup-p + (error "Cannot find start of balanced expression to indent")) + (goto-char start) + (setq end (c-safe (scan-sexps (point) 1))) + (if (not end) + (unless shutup-p + (error "Cannot find end of balanced expression to indent")) + (forward-line) + (if (< (point) end) + (c-indent-region (point) end))))) + (goto-char here) + (set-marker here nil))))) (defun c-indent-defun () "Indent the current top-level declaration or macro syntactically. In the macro case this also has the effect of realigning any line continuation backslashes, unless `c-auto-align-backslashes' is nil." (interactive "*") - (let ((here (point-marker)) decl-limits case-fold-search) - (unwind-protect - (progn - (c-save-buffer-state nil - ;; We try to be line oriented, unless there are several - ;; declarations on the same line. - (if (looking-at c-syntactic-eol) - (c-backward-token-2 1 nil (c-point 'bol)) - (c-forward-token-2 0 nil (c-point 'eol))) - (setq decl-limits (c-declaration-limits nil))) - (if decl-limits - (c-indent-region (car decl-limits) - (cdr decl-limits)))) - (goto-char here) - (set-marker here nil)))) + (c-with-string-fences + (let ((here (point-marker)) decl-limits case-fold-search) + (unwind-protect + (progn + (c-save-buffer-state nil + ;; We try to be line oriented, unless there are several + ;; declarations on the same line. + (if (looking-at c-syntactic-eol) + (c-backward-token-2 1 nil (c-point 'bol)) + (c-forward-token-2 0 nil (c-point 'eol))) + (setq decl-limits (c-declaration-limits nil))) + (if decl-limits + (c-indent-region (car decl-limits) + (cdr decl-limits)))) + (goto-char here) + (set-marker here nil))))) (defun c-indent-region (start end &optional quiet) "Indent syntactically lines whose first char is between START and END inclusive. @@ -3734,9 +3758,10 @@ c-indent-line-or-region Otherwise reindent just the current line." (interactive (list current-prefix-arg (c-region-is-active-p))) - (if region - (c-indent-region (region-beginning) (region-end)) - (c-indent-command arg))) + (c-with-string-fences + (if region + (c-indent-region (region-beginning) (region-end)) + (c-indent-command arg)))) ;; for progress reporting (defvar c-progress-info nil) @@ -4823,15 +4848,16 @@ c-fill-paragraph Optional prefix ARG means justify paragraph as well." (interactive "*P") - (let ((fill-paragraph-function - ;; Avoid infinite recursion. - (if (not (eq fill-paragraph-function 'c-fill-paragraph)) - fill-paragraph-function))) - (c-mask-paragraph t nil 'fill-paragraph arg)) - ;; Always return t. This has the effect that if filling isn't done - ;; above, it isn't done at all, and it's therefore effectively - ;; disabled in normal code. - t) + (c-with-string-fences + (let ((fill-paragraph-function + ;; Avoid infinite recursion. + (if (not (eq fill-paragraph-function 'c-fill-paragraph)) + fill-paragraph-function))) + (c-mask-paragraph t nil 'fill-paragraph arg)) + ;; Always return t. This has the effect that if filling isn't done + ;; above, it isn't done at all, and it's therefore effectively + ;; disabled in normal code. + t)) (defun c-do-auto-fill () ;; Do automatic filling if not inside a context where it should be @@ -4863,165 +4889,166 @@ c-indent-new-comment-line ;; used from auto-fill itself, that's normally disabled to avoid ;; unnecessary recursion. (interactive) - (let ((fill-prefix fill-prefix) - (do-line-break - (lambda () - (delete-horizontal-space) - (if soft - (insert-and-inherit ?\n) - (newline (if allow-auto-fill nil 1))))) - ;; Already know the literal type and limits when called from - ;; c-context-line-break. - (c-lit-limits c-lit-limits) - (c-lit-type c-lit-type) - (c-macro-start c-macro-start)) - - (c-save-buffer-state () - (when (not (eq c-auto-fill-prefix t)) - ;; Called from do-auto-fill. - (unless c-lit-limits - (setq c-lit-limits (c-literal-limits nil nil t))) - (unless c-lit-type - (setq c-lit-type (c-literal-type c-lit-limits))) - (if (memq (cond ((c-query-and-set-macro-start) 'cpp) - ((null c-lit-type) 'code) - (t c-lit-type)) - c-ignore-auto-fill) - (setq fill-prefix t) ; Used as flag in the cond. - (if (and (null c-auto-fill-prefix) - (eq c-lit-type 'c) - (<= (c-point 'bol) (car c-lit-limits))) - ;; The adaptive fill function has generated a prefix, but - ;; we're on the first line in a block comment so it'll be - ;; wrong. Ignore it to guess a better one below. - (setq fill-prefix nil) - (when (and (eq c-lit-type 'c++) - (not (string-match (concat "\\`[ \t]*" - c-line-comment-starter) - (or fill-prefix "")))) - ;; Kludge: If the function that adapted the fill prefix - ;; doesn't produce the required comment starter for line - ;; comments, then we ignore it. - (setq fill-prefix nil))) - ))) - - (cond ((eq fill-prefix t) - ;; A call from do-auto-fill which should be ignored. - ) - (fill-prefix - ;; A fill-prefix overrides anything. - (funcall do-line-break) - (insert-and-inherit fill-prefix)) - ((c-save-buffer-state () - (unless c-lit-limits - (setq c-lit-limits (c-literal-limits))) - (unless c-lit-type - (setq c-lit-type (c-literal-type c-lit-limits))) - (memq c-lit-type '(c c++))) - ;; Some sort of comment. - (if (or comment-multi-line - (save-excursion - (goto-char (car c-lit-limits)) - (end-of-line) - (< (point) (cdr c-lit-limits)))) - ;; Inside a comment that should be continued. - (let ((fill (c-save-buffer-state nil - (c-guess-fill-prefix - (setq c-lit-limits - (c-collect-line-comments c-lit-limits)) - c-lit-type))) - (pos (point)) - (comment-text-end - (or (and (eq c-lit-type 'c) - (save-excursion - (goto-char (- (cdr c-lit-limits) 2)) - (if (looking-at "\\*/") (point)))) - (cdr c-lit-limits)))) - ;; Skip forward past the fill prefix in case - ;; we're standing in it. - ;; - ;; FIXME: This doesn't work well in cases like - ;; - ;; /* Bla bla bla bla bla - ;; bla bla - ;; - ;; If point is on the 'B' then the line will be - ;; broken after "Bla b". - ;; - ;; If we have an empty comment, /* */, the next - ;; lot of code pushes point to the */. We fix - ;; this by never allowing point to end up to the - ;; right of where it started. - (while (and (< (current-column) (cdr fill)) - (not (eolp))) - (forward-char 1)) - (if (and (> (point) comment-text-end) - (> (c-point 'bol) (car c-lit-limits))) - (progn - ;; The skip takes us out of the (block) - ;; comment; insert the fill prefix at bol - ;; instead and keep the position. - (setq pos (copy-marker pos t)) - (beginning-of-line) - (insert-and-inherit (car fill)) - (if soft (insert-and-inherit ?\n) (newline 1)) - (goto-char pos) - (set-marker pos nil)) - ;; Don't break in the middle of a comment starter - ;; or ender. - (cond ((> (point) comment-text-end) - (goto-char comment-text-end)) - ((< (point) (+ (car c-lit-limits) 2)) - (goto-char (+ (car c-lit-limits) 2)))) - (funcall do-line-break) - (insert-and-inherit (car fill)) - (if (and (looking-at c-block-comment-ender-regexp) - (memq (char-before) '(?\ ?\t))) - (backward-char)))) ; can this hit the - ; middle of a TAB? - ;; Inside a comment that should be broken. - (let ((comment-start comment-start) - (comment-end comment-end) - col) - (if (eq c-lit-type 'c) - (unless (string-match "[ \t]*/\\*" comment-start) - (setq comment-start "/* " comment-end " */")) - (unless (string-match "[ \t]*//" comment-start) - (setq comment-start "// " comment-end ""))) - (setq col (save-excursion - (back-to-indentation) - (current-column))) - (funcall do-line-break) - (when (and comment-end (not (equal comment-end ""))) - (forward-char -1) - (insert-and-inherit comment-end) - (forward-char 1)) - ;; c-comment-indent may look at the current - ;; indentation, so let's start out with the same - ;; indentation as the previous one. - (indent-to col) - (insert-and-inherit comment-start) - (indent-for-comment)))) - ((c-query-and-set-macro-start) - ;; In a macro. - (unless (looking-at "[ \t]*\\\\$") - ;; Do not clobber the alignment of the line continuation - ;; slash; c-backslash-region might look at it. - (delete-horizontal-space)) - ;; Got an asymmetry here: In normal code this command - ;; doesn't indent the next line syntactically, and otoh a - ;; normal syntactically indenting newline doesn't continue - ;; the macro. - (c-newline-and-indent (if allow-auto-fill nil 1))) - (t - ;; Somewhere else in the code. - (let ((col (save-excursion + (c-with-string-fences + (let ((fill-prefix fill-prefix) + (do-line-break + (lambda () + (delete-horizontal-space) + (if soft + (insert-and-inherit ?\n) + (newline (if allow-auto-fill nil 1))))) + ;; Already know the literal type and limits when called from + ;; c-context-line-break. + (c-lit-limits c-lit-limits) + (c-lit-type c-lit-type) + (c-macro-start c-macro-start)) + + (c-save-buffer-state () + (when (not (eq c-auto-fill-prefix t)) + ;; Called from do-auto-fill. + (unless c-lit-limits + (setq c-lit-limits (c-literal-limits nil nil t))) + (unless c-lit-type + (setq c-lit-type (c-literal-type c-lit-limits))) + (if (memq (cond ((c-query-and-set-macro-start) 'cpp) + ((null c-lit-type) 'code) + (t c-lit-type)) + c-ignore-auto-fill) + (setq fill-prefix t) ; Used as flag in the cond. + (if (and (null c-auto-fill-prefix) + (eq c-lit-type 'c) + (<= (c-point 'bol) (car c-lit-limits))) + ;; The adaptive fill function has generated a prefix, but + ;; we're on the first line in a block comment so it'll be + ;; wrong. Ignore it to guess a better one below. + (setq fill-prefix nil) + (when (and (eq c-lit-type 'c++) + (not (string-match (concat "\\`[ \t]*" + c-line-comment-starter) + (or fill-prefix "")))) + ;; Kludge: If the function that adapted the fill prefix + ;; doesn't produce the required comment starter for line + ;; comments, then we ignore it. + (setq fill-prefix nil))) + ))) + + (cond ((eq fill-prefix t) + ;; A call from do-auto-fill which should be ignored. + ) + (fill-prefix + ;; A fill-prefix overrides anything. + (funcall do-line-break) + (insert-and-inherit fill-prefix)) + ((c-save-buffer-state () + (unless c-lit-limits + (setq c-lit-limits (c-literal-limits))) + (unless c-lit-type + (setq c-lit-type (c-literal-type c-lit-limits))) + (memq c-lit-type '(c c++))) + ;; Some sort of comment. + (if (or comment-multi-line + (save-excursion + (goto-char (car c-lit-limits)) + (end-of-line) + (< (point) (cdr c-lit-limits)))) + ;; Inside a comment that should be continued. + (let ((fill (c-save-buffer-state nil + (c-guess-fill-prefix + (setq c-lit-limits + (c-collect-line-comments c-lit-limits)) + c-lit-type))) + (pos (point)) + (comment-text-end + (or (and (eq c-lit-type 'c) + (save-excursion + (goto-char (- (cdr c-lit-limits) 2)) + (if (looking-at "\\*/") (point)))) + (cdr c-lit-limits)))) + ;; Skip forward past the fill prefix in case + ;; we're standing in it. + ;; + ;; FIXME: This doesn't work well in cases like + ;; + ;; /* Bla bla bla bla bla + ;; bla bla + ;; + ;; If point is on the 'B' then the line will be + ;; broken after "Bla b". + ;; + ;; If we have an empty comment, /* */, the next + ;; lot of code pushes point to the */. We fix + ;; this by never allowing point to end up to the + ;; right of where it started. + (while (and (< (current-column) (cdr fill)) + (not (eolp))) + (forward-char 1)) + (if (and (> (point) comment-text-end) + (> (c-point 'bol) (car c-lit-limits))) + (progn + ;; The skip takes us out of the (block) + ;; comment; insert the fill prefix at bol + ;; instead and keep the position. + (setq pos (copy-marker pos t)) (beginning-of-line) - (while (and (looking-at "[ \t]*\\\\?$") - (= (forward-line -1) 0))) - (current-indentation)))) - (funcall do-line-break) - (indent-to col)))))) + (insert-and-inherit (car fill)) + (if soft (insert-and-inherit ?\n) (newline 1)) + (goto-char pos) + (set-marker pos nil)) + ;; Don't break in the middle of a comment starter + ;; or ender. + (cond ((> (point) comment-text-end) + (goto-char comment-text-end)) + ((< (point) (+ (car c-lit-limits) 2)) + (goto-char (+ (car c-lit-limits) 2)))) + (funcall do-line-break) + (insert-and-inherit (car fill)) + (if (and (looking-at c-block-comment-ender-regexp) + (memq (char-before) '(?\ ?\t))) + (backward-char)))) ; can this hit the + ; middle of a TAB? + ;; Inside a comment that should be broken. + (let ((comment-start comment-start) + (comment-end comment-end) + col) + (if (eq c-lit-type 'c) + (unless (string-match "[ \t]*/\\*" comment-start) + (setq comment-start "/* " comment-end " */")) + (unless (string-match "[ \t]*//" comment-start) + (setq comment-start "// " comment-end ""))) + (setq col (save-excursion + (back-to-indentation) + (current-column))) + (funcall do-line-break) + (when (and comment-end (not (equal comment-end ""))) + (forward-char -1) + (insert-and-inherit comment-end) + (forward-char 1)) + ;; c-comment-indent may look at the current + ;; indentation, so let's start out with the same + ;; indentation as the previous one. + (indent-to col) + (insert-and-inherit comment-start) + (indent-for-comment)))) + ((c-query-and-set-macro-start) + ;; In a macro. + (unless (looking-at "[ \t]*\\\\$") + ;; Do not clobber the alignment of the line continuation + ;; slash; c-backslash-region might look at it. + (delete-horizontal-space)) + ;; Got an asymmetry here: In normal code this command + ;; doesn't indent the next line syntactically, and otoh a + ;; normal syntactically indenting newline doesn't continue + ;; the macro. + (c-newline-and-indent (if allow-auto-fill nil 1))) + (t + ;; Somewhere else in the code. + (let ((col (save-excursion + (beginning-of-line) + (while (and (looking-at "[ \t]*\\\\?$") + (= (forward-line -1) 0))) + (current-indentation)))) + (funcall do-line-break) + (indent-to col))))))) (defalias 'c-comment-line-break-function 'c-indent-new-comment-line) (make-obsolete 'c-comment-line-break-function 'c-indent-new-comment-line "21.1") @@ -5048,58 +5075,59 @@ c-context-line-break inside a preprocessor directive." (interactive "*") - (let* (c-lit-limits c-lit-type - (c-macro-start c-macro-start) - case-fold-search) - - (c-save-buffer-state () - (setq c-lit-limits (c-literal-limits nil nil t) - c-lit-type (c-literal-type c-lit-limits)) - (when (eq c-lit-type 'c++) - (setq c-lit-limits (c-collect-line-comments c-lit-limits))) - (c-query-and-set-macro-start)) - - (cond - ((or (eq c-lit-type 'c) - (and (eq c-lit-type 'c++) ; C++ comment, but not at the very end of it. - (< (save-excursion - (skip-chars-forward " \t") - (point)) - (1- (cdr c-lit-limits)))) - (and (numberp c-macro-start) ; Macro, but not at the very end of + (c-with-string-fences + (let* (c-lit-limits c-lit-type + (c-macro-start c-macro-start) + case-fold-search) + + (c-save-buffer-state () + (setq c-lit-limits (c-literal-limits nil nil t) + c-lit-type (c-literal-type c-lit-limits)) + (when (eq c-lit-type 'c++) + (setq c-lit-limits (c-collect-line-comments c-lit-limits))) + (c-query-and-set-macro-start)) + + (cond + ((or (eq c-lit-type 'c) + (and (eq c-lit-type 'c++) ; C++ comment, but not at the very end of it. + (< (save-excursion + (skip-chars-forward " \t") + (point)) + (1- (cdr c-lit-limits)))) + (and (numberp c-macro-start) ; Macro, but not at the very end of ; it, not in a string, and not in the ; cpp keyword. - (not (eq c-lit-type 'string)) - (or (not (looking-at "\\s *$")) - (eq (char-before) ?\\)) - (<= (save-excursion - (goto-char c-macro-start) - (if (looking-at c-opt-cpp-start) - (goto-char (match-end 0))) - (point)) - (point)))) - (let ((comment-multi-line t) - (fill-prefix nil)) - (c-indent-new-comment-line nil t))) - - ((eq c-lit-type 'string) - (if (and (numberp c-macro-start) - (not (eq (char-before) ?\\))) - (insert ?\\)) - (newline)) - - (t (delete-horizontal-space) - (newline) - ;; c-indent-line may look at the current indentation, so let's - ;; start out with the same indentation as the previous line. - (let ((col (save-excursion - (backward-char) - (forward-line 0) - (while (and (looking-at "[ \t]*\\\\?$") - (= (forward-line -1) 0))) - (current-indentation)))) - (indent-to col)) - (indent-according-to-mode))))) + (not (eq c-lit-type 'string)) + (or (not (looking-at "\\s *$")) + (eq (char-before) ?\\)) + (<= (save-excursion + (goto-char c-macro-start) + (if (looking-at c-opt-cpp-start) + (goto-char (match-end 0))) + (point)) + (point)))) + (let ((comment-multi-line t) + (fill-prefix nil)) + (c-indent-new-comment-line nil t))) + + ((eq c-lit-type 'string) + (if (and (numberp c-macro-start) + (not (eq (char-before) ?\\))) + (insert ?\\)) + (newline)) + + (t (delete-horizontal-space) + (newline) + ;; c-indent-line may look at the current indentation, so let's + ;; start out with the same indentation as the previous line. + (let ((col (save-excursion + (backward-char) + (forward-line 0) + (while (and (looking-at "[ \t]*\\\\?$") + (= (forward-line -1) 0))) + (current-indentation)))) + (indent-to col)) + (indent-according-to-mode)))))) (defun c-context-open-line () "Insert a line break suitable to the context and leave point before it. diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index a127024355..b7f2ecd5b7 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -1562,6 +1562,28 @@ c-put-char-properties-on-char (c-put-char-property (point) ,property ,value) (forward-char))))) + +;; Miscellaneous macro(s) +(defvar c-string-fences-set-flag nil) +;; Non-nil when we have set string fences with `c-restore-string-fences'. +(defmacro c-with-string-fences (&rest forms) + ;; Restore the string fences, evaluate FORMS, then remove them again. It + ;; should only be used at the top level of "boundary" functions in CC Mode, + ;; i.e. those called from outside CC Mode which directly or indirectly need + ;; unbalanced string markers to have their string-fence syntax-table text + ;; properties. This includes all calls to `c-parse-state'. It is not + ;; intended that this macro be invoked recursively; however the + ;; `c-string-fences-set-flag' mechanism should ensure consistency, should + ;; this ever happen. + `(unwind-protect + (progn + (unless c-string-fences-set-flag + (c-restore-string-fences)) + (let ((c-string-fences-set-flag t)) + ,@forms)) + (unless c-string-fences-set-flag + (c-clear-string-fences)))) + ;; Macros to put overlays (Emacs) or extents (XEmacs) on buffer text. ;; For our purposes, these are characterized by being possible to diff --git a/lisp/progmodes/cc-guess.el b/lisp/progmodes/cc-guess.el index ea5dd48986..584db86539 100644 --- a/lisp/progmodes/cc-guess.el +++ b/lisp/progmodes/cc-guess.el @@ -76,6 +76,8 @@ (cc-require 'cc-engine) (cc-require 'cc-styles) +(cc-bytecomp-defun c-restore-string-fences) +(cc-bytecomp-defun c-clear-string-fences) (defcustom c-guess-offset-threshold 10 @@ -225,11 +227,12 @@ c-guess-region-no-install Note that the larger the region to guess in, the slower the guessing. So you can limit the region with `c-guess-region-max'." (interactive "r\nP") - (let ((accumulator (when accumulate c-guess-accumulator))) - (setq c-guess-accumulator (c-guess-examine start end accumulator)) - (let ((pair (c-guess-guess c-guess-accumulator))) - (setq c-guess-guessed-basic-offset (car pair) - c-guess-guessed-offsets-alist (cdr pair))))) + (c-with-string-fences + (let ((accumulator (when accumulate c-guess-accumulator))) + (setq c-guess-accumulator (c-guess-examine start end accumulator)) + (let ((pair (c-guess-guess c-guess-accumulator))) + (setq c-guess-guessed-basic-offset (car pair) + c-guess-guessed-offsets-alist (cdr pair)))))) (defun c-guess-examine (start end accumulator) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 957a0b8a7c..f8e3b4d95b 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -997,7 +997,8 @@ c-called-from-text-property-change-p ;; `c-before/after-change', frame 3 is the primitive invoking the change ;; hook. (memq (cadr (backtrace-frame 3)) - '(put-text-property remove-list-of-text-properties))) + '(put-text-property remove-text-properties + remove-list-of-text-properties))) (defun c-depropertize-CPP (beg end) ;; Remove the punctuation syntax-table text property from the CPP parts of @@ -2016,120 +2017,116 @@ c-before-change ;; or a comment - "wrongly" removing a symbol from `c-found-types' ;; isn't critical. (unless (c-called-from-text-property-change-p) - (save-restriction - (widen) - ;; Clear the list of found types if we make a change at the start of the - ;; buffer, to make it easier to get rid of misspelled types and - ;; variables that have gotten recognized as types in malformed code. - (when (eq beg (point-min)) - (c-clear-found-types)) - (if c-just-done-before-change - ;; We have two consecutive calls to `before-change-functions' - ;; without an intervening `after-change-functions'. An example of - ;; this is bug #38691. To protect CC Mode, assume that the entire - ;; buffer has changed. - (setq beg (point-min) - end (point-max) - c-just-done-before-change 'whole-buffer) - (setq c-just-done-before-change t)) - ;; (c-new-BEG c-new-END) will be the region to fontify. - (setq c-new-BEG beg c-new-END end) - (setq c-maybe-stale-found-type nil) - ;; A workaround for syntax-ppss's failure to notice syntax-table text - ;; property changes. - (when (fboundp 'syntax-ppss) - (setq c-syntax-table-hwm most-positive-fixnum)) - (save-match-data - (widen) - (unwind-protect - (progn - (c-restore-string-fences) - (save-excursion - ;; Are we inserting/deleting stuff in the middle of an - ;; identifier? - (c-unfind-enclosing-token beg) - (c-unfind-enclosing-token end) - ;; Are we coalescing two tokens together, e.g. "fo o" - ;; -> "foo"? - (when (< beg end) - (c-unfind-coalesced-tokens beg end)) - (c-invalidate-sws-region-before beg end) - ;; Are we (potentially) disrupting the syntactic - ;; context which makes a type a type? E.g. by - ;; inserting stuff after "foo" in "foo bar;", or - ;; before "foo" in "typedef foo *bar;"? - ;; - ;; We search for appropriate c-type properties "near" - ;; the change. First, find an appropriate boundary - ;; for this property search. - (let (lim lim-2 - type type-pos - marked-id term-pos - (end1 - (or (and (eq (get-text-property end 'face) - 'font-lock-comment-face) - (previous-single-property-change end 'face)) - end))) - (when (>= end1 beg) ; Don't hassle about changes entirely in + (c-with-string-fences + (save-restriction + (widen) + ;; Clear the list of found types if we make a change at the start of the + ;; buffer, to make it easier to get rid of misspelled types and + ;; variables that have gotten recognized as types in malformed code. + (when (eq beg (point-min)) + (c-clear-found-types)) + (if c-just-done-before-change + ;; We have two consecutive calls to `before-change-functions' + ;; without an intervening `after-change-functions'. An example of + ;; this is bug #38691. To protect CC Mode, assume that the entire + ;; buffer has changed. + (setq beg (point-min) + end (point-max) + c-just-done-before-change 'whole-buffer) + (setq c-just-done-before-change t)) + ;; (c-new-BEG c-new-END) will be the region to fontify. + (setq c-new-BEG beg c-new-END end) + (setq c-maybe-stale-found-type nil) + ;; A workaround for syntax-ppss's failure to notice syntax-table text + ;; property changes. + (when (fboundp 'syntax-ppss) + (setq c-syntax-table-hwm most-positive-fixnum)) + (save-match-data + (save-excursion + ;; Are we inserting/deleting stuff in the middle of an + ;; identifier? + (c-unfind-enclosing-token beg) + (c-unfind-enclosing-token end) + ;; Are we coalescing two tokens together, e.g. "fo o" + ;; -> "foo"? + (when (< beg end) + (c-unfind-coalesced-tokens beg end)) + (c-invalidate-sws-region-before beg end) + ;; Are we (potentially) disrupting the syntactic + ;; context which makes a type a type? E.g. by + ;; inserting stuff after "foo" in "foo bar;", or + ;; before "foo" in "typedef foo *bar;"? + ;; + ;; We search for appropriate c-type properties "near" + ;; the change. First, find an appropriate boundary + ;; for this property search. + (let (lim lim-2 + type type-pos + marked-id term-pos + (end1 + (or (and (eq (get-text-property end 'face) + 'font-lock-comment-face) + (previous-single-property-change end 'face)) + end))) + (when (>= end1 beg) ; Don't hassle about changes entirely in ; comments. - ;; Find a limit for the search for a `c-type' property - ;; Point is currently undefined. A `goto-char' somewhere is needed. (2020-12-06). - (setq lim-2 (c-determine-limit 1000 (point) ; that is wrong. FIXME!!! (2020-12-06) - )) - (while - (and (/= (skip-chars-backward "^;{}" lim-2) 0) - (> (point) (point-min)) - (memq (c-get-char-property (1- (point)) 'face) - '(font-lock-comment-face font-lock-string-face)))) - (setq lim (max (point-min) (1- (point)))) - - ;; Look for the latest `c-type' property before end1 - (when (and (> end1 (point-min)) - (setq type-pos - (if (get-text-property (1- end1) 'c-type) - end1 - (previous-single-property-change end1 'c-type - nil lim)))) - (setq type (get-text-property (max (1- type-pos) lim) 'c-type)) - - (when (memq type '(c-decl-id-start c-decl-type-start)) - ;; Get the identifier, if any, that the property is on. - (goto-char (1- type-pos)) - (setq marked-id - (when (looking-at "\\(\\sw\\|\\s_\\)") - (c-beginning-of-current-token) - (buffer-substring-no-properties (point) type-pos))) - - (goto-char end1) - (setq lim-2 (c-determine-+ve-limit 1000)) - (skip-chars-forward "^;{}" lim-2) ; FIXME!!! loop for + ;; Find a limit for the search for a `c-type' property + ;; Point is currently undefined. A `goto-char' somewhere is needed. (2020-12-06). + (setq lim-2 (c-determine-limit 1000 (point) ; that is wrong. FIXME!!! (2020-12-06) + )) + (while + (and (/= (skip-chars-backward "^;{}" lim-2) 0) + (> (point) (point-min)) + (memq (c-get-char-property (1- (point)) 'face) + '(font-lock-comment-face font-lock-string-face)))) + (setq lim (max (point-min) (1- (point)))) + + ;; Look for the latest `c-type' property before end1 + (when (and (> end1 (point-min)) + (setq type-pos + (if (get-text-property (1- end1) 'c-type) + end1 + (previous-single-property-change end1 'c-type + nil lim)))) + (setq type (get-text-property (max (1- type-pos) lim) 'c-type)) + + (when (memq type '(c-decl-id-start c-decl-type-start)) + ;; Get the identifier, if any, that the property is on. + (goto-char (1- type-pos)) + (setq marked-id + (when (looking-at "\\(\\sw\\|\\s_\\)") + (c-beginning-of-current-token) + (buffer-substring-no-properties (point) type-pos))) + + (goto-char end1) + (setq lim-2 (c-determine-+ve-limit 1000)) + (skip-chars-forward "^;{}" lim-2) ; FIXME!!! loop for ; comment, maybe - (setq lim (point)) - (setq term-pos - (or (c-next-single-property-change end 'c-type nil lim) lim)) - (setq c-maybe-stale-found-type - (list type marked-id - type-pos term-pos - (buffer-substring-no-properties type-pos - term-pos) - (buffer-substring-no-properties beg end))))))) - - (if c-get-state-before-change-functions - (mapc (lambda (fn) - (funcall fn beg end)) - c-get-state-before-change-functions)) - - (c-laomib-invalidate-cache beg end))) - (c-clear-string-fences)))) - (c-truncate-lit-pos-cache beg) - ;; The following must be done here rather than in `c-after-change' - ;; because newly inserted parens would foul up the invalidation - ;; algorithm. - (c-invalidate-state-cache beg) - ;; The following must happen after the previous, which likely alters - ;; the macro cache. - (when c-opt-cpp-symbol - (c-invalidate-macro-cache beg end)))) + (setq lim (point)) + (setq term-pos + (or (c-next-single-property-change end 'c-type nil lim) lim)) + (setq c-maybe-stale-found-type + (list type marked-id + type-pos term-pos + (buffer-substring-no-properties type-pos + term-pos) + (buffer-substring-no-properties beg end))))))) + + (if c-get-state-before-change-functions + (mapc (lambda (fn) + (funcall fn beg end)) + c-get-state-before-change-functions)) + + (c-laomib-invalidate-cache beg end)))) + (c-truncate-lit-pos-cache beg) + ;; The following must be done here rather than in `c-after-change' + ;; because newly inserted parens would foul up the invalidation + ;; algorithm. + (c-invalidate-state-cache beg) + ;; The following must happen after the previous, which likely alters + ;; the macro cache. + (when c-opt-cpp-symbol + (c-invalidate-macro-cache beg end))))) (defvar c-in-after-change-fontification nil) (make-variable-buffer-local 'c-in-after-change-fontification) @@ -2181,51 +2178,48 @@ c-after-change (save-restriction (save-match-data ; c-recognize-<>-arglists changes match-data (widen) - (unwind-protect - (progn - (c-restore-string-fences) - (when (> end (point-max)) - ;; Some emacsen might return positions past the end. This - ;; has been observed in Emacs 20.7 when rereading a buffer - ;; changed on disk (haven't been able to minimize it, but - ;; Emacs 21.3 appears to work). - (setq end (point-max)) - (when (> beg end) - (setq beg end))) - - ;; C-y is capable of spuriously converting category - ;; properties c--as-paren-syntax and - ;; c-cpp-delimiter into hard syntax-table properties. - ;; Remove these when it happens. - (when (eval-when-compile (memq 'category-properties c-emacs-features)) - (c-save-buffer-state () - (c-clear-char-property-with-value beg end 'syntax-table - c-<-as-paren-syntax) - (c-clear-char-property-with-value beg end 'syntax-table - c->-as-paren-syntax) - (c-clear-char-property-with-value beg end 'syntax-table nil))) - - (c-update-new-id end) - (c-trim-found-types beg end old-len) ; maybe we don't - ; need all of these. - (c-invalidate-sws-region-after beg end old-len) - ;; (c-invalidate-state-cache beg) ; moved to - ;; `c-before-change'. - (c-invalidate-find-decl-cache beg) - - (when c-recognize-<>-arglists - (c-after-change-check-<>-operators beg end)) - - (setq c-in-after-change-fontification t) - (save-excursion - (mapc (lambda (fn) - (funcall fn beg end old-len)) - c-before-font-lock-functions))) - (c-clear-string-fences)))))) + (c-with-string-fences + (when (> end (point-max)) + ;; Some emacsen might return positions past the end. This + ;; has been observed in Emacs 20.7 when rereading a buffer + ;; changed on disk (haven't been able to minimize it, but + ;; Emacs 21.3 appears to work). + (setq end (point-max)) + (when (> beg end) + (setq beg end))) + + ;; C-y is capable of spuriously converting category + ;; properties c--as-paren-syntax and + ;; c-cpp-delimiter into hard syntax-table properties. + ;; Remove these when it happens. + (when (eval-when-compile (memq 'category-properties c-emacs-features)) + (c-save-buffer-state () + (c-clear-char-property-with-value beg end 'syntax-table + c-<-as-paren-syntax) + (c-clear-char-property-with-value beg end 'syntax-table + c->-as-paren-syntax) + (c-clear-char-property-with-value beg end 'syntax-table nil))) + + (c-update-new-id end) + (c-trim-found-types beg end old-len) ; maybe we don't + ; need all of these. + (c-invalidate-sws-region-after beg end old-len) + ;; (c-invalidate-state-cache beg) ; moved to + ;; `c-before-change'. + (c-invalidate-find-decl-cache beg) + + (when c-recognize-<>-arglists + (c-after-change-check-<>-operators beg end)) + + (setq c-in-after-change-fontification t) + (save-excursion + (mapc (lambda (fn) + (funcall fn beg end old-len)) + c-before-font-lock-functions))))) ;; A workaround for syntax-ppss's failure to notice syntax-table text ;; property changes. (when (fboundp 'syntax-ppss) - (syntax-ppss-flush-cache c-syntax-table-hwm))) + (syntax-ppss-flush-cache c-syntax-table-hwm))))) (defun c-doc-fl-decl-start (pos) ;; If the line containing POS is in a doc comment continued line (as defined @@ -2457,46 +2451,42 @@ c-font-lock-fontify-region (widen) (let (new-beg new-end new-region case-fold-search) (c-save-buffer-state nil - ;; Temporarily reapply the string fence syntax-table properties. - (unwind-protect - (progn - (c-restore-string-fences) - (if (and c-in-after-change-fontification - (< beg c-new-END) (> end c-new-BEG)) - ;; Region and the latest after-change fontification region overlap. - ;; Determine the upper and lower bounds of our adjusted region - ;; separately. - (progn - (if (<= beg c-new-BEG) - (setq c-in-after-change-fontification nil)) - (setq new-beg - (if (and (>= beg (c-point 'bol c-new-BEG)) - (<= beg c-new-BEG)) - ;; Either jit-lock has accepted `c-new-BEG', or has - ;; (probably) extended the change region spuriously - ;; to BOL, which position likely has a - ;; syntactically different position. To ensure - ;; correct fontification, we start at `c-new-BEG', - ;; assuming any characters to the left of - ;; `c-new-BEG' on the line do not require - ;; fontification. - c-new-BEG - (setq new-region (c-before-context-fl-expand-region beg end) - new-end (cdr new-region)) - (car new-region))) - (setq new-end - (if (and (>= end (c-point 'bol c-new-END)) - (<= end c-new-END)) - c-new-END - (or new-end - (cdr (c-before-context-fl-expand-region beg end)))))) - ;; Context (etc.) fontification. - (setq new-region (c-before-context-fl-expand-region beg end) - new-beg (car new-region) new-end (cdr new-region))) - ;; Finally invoke font lock's functionality. - (funcall (default-value 'font-lock-fontify-region-function) - new-beg new-end verbose)) - (c-clear-string-fences)))))) + (c-with-string-fences + (if (and c-in-after-change-fontification + (< beg c-new-END) (> end c-new-BEG)) + ;; Region and the latest after-change fontification region overlap. + ;; Determine the upper and lower bounds of our adjusted region + ;; separately. + (progn + (if (<= beg c-new-BEG) + (setq c-in-after-change-fontification nil)) + (setq new-beg + (if (and (>= beg (c-point 'bol c-new-BEG)) + (<= beg c-new-BEG)) + ;; Either jit-lock has accepted `c-new-BEG', or has + ;; (probably) extended the change region spuriously + ;; to BOL, which position likely has a + ;; syntactically different position. To ensure + ;; correct fontification, we start at `c-new-BEG', + ;; assuming any characters to the left of + ;; `c-new-BEG' on the line do not require + ;; fontification. + c-new-BEG + (setq new-region (c-before-context-fl-expand-region beg end) + new-end (cdr new-region)) + (car new-region))) + (setq new-end + (if (and (>= end (c-point 'bol c-new-END)) + (<= end c-new-END)) + c-new-END + (or new-end + (cdr (c-before-context-fl-expand-region beg end)))))) + ;; Context (etc.) fontification. + (setq new-region (c-before-context-fl-expand-region beg end) + new-beg (car new-region) new-end (cdr new-region))) + ;; Finally invoke font lock's functionality. + (funcall (default-value 'font-lock-fontify-region-function) + new-beg new-end verbose)))))) (defun c-after-font-lock-init () ;; Put on `font-lock-mode-hook'. This function ensures our after-change --MYsoMOAPwW+l40Gp-- From debbugs-submit-bounces@debbugs.gnu.org Thu May 19 00:24:29 2022 Received: (at 55230) by debbugs.gnu.org; 19 May 2022 04:24:29 +0000 Received: from localhost ([127.0.0.1]:34119 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nrXi8-0007Aq-NQ for submit@debbugs.gnu.org; Thu, 19 May 2022 00:24:29 -0400 Received: from md5i.com ([75.151.244.229]:36028) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nrXi6-0007Ac-FR for 55230@debbugs.gnu.org; Thu, 19 May 2022 00:24:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=md5i.com; s=dkim; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date:References: Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=iYJ7MfPt0OZqlBJC9vGpvzCZC6jd2+Bj08EEYGeez2M=; b=TdADmbi8FezBj1U+WjUIl8cgPm qiYsbdOMmkEvzgfsTzAeObuRM9ks+FUXarLUocybNLGb0jREKDOp+pyibf0Dt9zTsa7LRN6wsScXV OSb/L6LdWSXlHcUliiSpcG3VB; Received: from abode ([192.168.177.1] helo=miko) by md5i.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1nrXhz-00Dgap-9w; Thu, 19 May 2022 00:24:19 -0400 From: Michael Welsh Duggan To: Alan Mackenzie Subject: Re: bug#55230: CC Mode 5.35.1 (C++//l); Cache inconsistency References: <875ymn4try.fsf@md5i.com> Date: Thu, 19 May 2022 00:24:18 -0400 In-Reply-To: (Alan Mackenzie's message of "Tue, 17 May 2022 09:55:27 +0000") Message-ID: <874k1mywst.fsf@md5i.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 55230 Cc: Michael Welsh Duggan , 55230@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Alan Mackenzie writes: > Hello again, Michael. > > On Tue, May 03, 2022 at 18:10:36 +0000, Alan Mackenzie wrote: >> On Mon, May 02, 2022 at 15:30:09 -0400, Michael Welsh Duggan wrote: >> > Package: cc-mode > >> > From emacs -Q: > >> > C-x C-f /tmp/foo.cpp RET >> > M-x c-toggle-parse-state-debug RET >> > "{} > >> > After typing the close brace, I get the following: >> > c-parse-state inconsistency at 3: using cache: (2), from scratch: >> > nil. POINT-MIN: 1 >> > Old state: >> > (setq c-state-cache '(2) c-state-cache-good-pos 1 >> > c-state-nonlit-pos-cache nil c-state-nonlit-pos-cache-limit 0 >> > c-state-brace-pair-desert nil c-state-point-min 1 >> > c-state-point-min-lit-type nil c-state-point-min-lit-start nil >> > c-state-min-scan-pos 1 c-state-old-cpp-beg nil c-state-old-cpp-end >> > nil c-parse-state-point 3) > >> > I have not noticed any indentation errors due to this, but any cache >> > inconsistency might lead to errors down the line, hence this report. > >> Many thanks for the bug report. > >> This time it is not the cache mechanism itself which is at fault. >> Instead, it is the first character ", which since it is unbalanced by >> another ", has had its syntax is temporarily "commented out" by giving >> it a syntax-table property of "punctuation". The parse-state cache was >> generated whilst in this state, but used when it no longer was, hence >> the inconsistency. > >> There are somewhere between 10 and 20 occurrences of c-parse-state in >> the source code which will need to be "protected" against this fault. I >> hope to be able to finish this work in the next two or three days, when >> I'll get back to you again. > > There were actually 32 such occurrences, and they have generated a rather > large patch which I am taking the liberty of just sending to you. The > vast bulk of this patch is just putting (c-with-string-fences ....) > around these functions, reindenting them. > > I've attached the patch as a separate file because it is so big. It > should apply cleanly to the CC Mode in the Emacs savannah master version. > Would you please apply it and try it out a bit, and let me know how well > it works. Thanks! Unfortunately, it has some major problems. If you follow the original recipe, after the first brace is input cc-mode errors out with "Marker does not point anywhere". Backtrace follows: Debugger entered--Lisp error: (error "Marker does not point anywhere") c-restore-string-fences() c-electric-brace(nil) funcall-interactively(c-electric-brace nil) command-execute(c-electric-brace) >> > Emacs : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, X toolkit, cairo version 1.16.0) >> > of 2022-04-09 >> > Package: CC Mode 5.35.1 (C++//l) >> > Buffer Style: gnu >> > c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties 1-bit) > >> > -- >> > Michael Welsh Duggan >> > (md5i@md5i.com) -- Michael Welsh Duggan (md5i@md5i.com) From debbugs-submit-bounces@debbugs.gnu.org Sat May 21 06:03:21 2022 Received: (at 55230) by debbugs.gnu.org; 21 May 2022 10:03:21 +0000 Received: from localhost ([127.0.0.1]:40721 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nsLxB-0001yU-1a for submit@debbugs.gnu.org; Sat, 21 May 2022 06:03:21 -0400 Received: from colin.muc.de ([193.149.48.1]:49236 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1nsLx8-0001yE-U3 for 55230@debbugs.gnu.org; Sat, 21 May 2022 06:03:19 -0400 Received: (qmail 15467 invoked by uid 3782); 21 May 2022 10:03:12 -0000 Received: from acm.muc.de (p4fe152d8.dip0.t-ipconnect.de [79.225.82.216]) (using STARTTLS) by colin.muc.de (tmda-ofmipd) with ESMTP; Sat, 21 May 2022 12:03:11 +0200 Received: (qmail 3892 invoked by uid 1000); 21 May 2022 10:03:10 -0000 Date: Sat, 21 May 2022 10:03:10 +0000 To: Michael Welsh Duggan Subject: Re: bug#55230: CC Mode 5.35.1 (C++//l); Cache inconsistency Message-ID: References: <875ymn4try.fsf@md5i.com> <874k1mywst.fsf@md5i.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="uNfu+MDeOpTjK3rm" Content-Disposition: inline In-Reply-To: <874k1mywst.fsf@md5i.com> X-Submission-Agent: TMDA/1.3.x (Ph3nix) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Debbugs-Envelope-To: 55230 Cc: 55230@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" --uNfu+MDeOpTjK3rm Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hello, Michael. On Thu, May 19, 2022 at 00:24:18 -0400, Michael Welsh Duggan wrote: > Unfortunately, it [the patch] has some major problems. If you follow > the original recipe, after the first brace is input cc-mode errors out > with "Marker does not point anywhere". Backtrace follows: > Debugger entered--Lisp error: (error "Marker does not point anywhere") > c-restore-string-fences() > c-electric-brace(nil) > funcall-interactively(c-electric-brace nil) > command-execute(c-electric-brace) Apologies for that. I had failed to test the scenario from a freshly started Emacs. The problem was setting and clearing text properties without masking before-change-functions and after-change-functions. This allowed a recursive call to these text property functions which fouled things up. This is now corrected. Please undo the previous faulty patch and apply the one in this post instead. I think it should have fixed the bug. Thanks! I look forward to hearing from you again. > >> > Emacs : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, X toolkit, cairo version 1.16.0) > >> > of 2022-04-09 > >> > Package: CC Mode 5.35.1 (C++//l) > >> > Buffer Style: gnu > >> > c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties 1-bit) > -- > Michael Welsh Duggan > (md5i@md5i.com) -- Alan Mackenzie (Nuremberg, Germany). --uNfu+MDeOpTjK3rm Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="diff.20220520.diff" diff --git a/lisp/progmodes/cc-awk.el b/lisp/progmodes/cc-awk.el index 188d5a8a83..9ea1557391 100644 --- a/lisp/progmodes/cc-awk.el +++ b/lisp/progmodes/cc-awk.el @@ -56,6 +56,8 @@ ;; Silence the byte compiler. (cc-bytecomp-defvar c-new-BEG) (cc-bytecomp-defvar c-new-END) +(cc-bytecomp-defun c-restore-string-fences) +(cc-bytecomp-defun c-clear-string-fences) ;; Some functions in cc-engine that are used below. There's a cyclic ;; dependency so it can't be required here. (Perhaps some functions @@ -934,7 +936,7 @@ c-awk-extend-and-syntax-tablify-region ;; It prepares the buffer for font ;; locking, hence must get called before `font-lock-after-change-function'. ;; - ;; This function is the AWK value of `c-before-font-lock-function'. + ;; This function is the AWK value of `c-before-font-lock-functions'. ;; It does hidden buffer changes. (c-save-buffer-state () (setq c-new-END (c-awk-end-of-change-region beg end old-len)) @@ -1109,29 +1111,30 @@ c-awk-beginning-of-defun Note that this function might do hidden buffer changes. See the comment at the start of cc-engine.el for more info." (interactive "p") - (or arg (setq arg 1)) - (save-match-data - (c-save-buffer-state ; ensures the buffer is writable. - nil - (let ((found t)) ; Has the most recent regexp search found b-of-defun? - (if (>= arg 0) - ;; Go back one defun each time round the following loop. (For +ve arg) - (while (and found (> arg 0) (not (eq (point) (point-min)))) - ;; Go back one "candidate" each time round the next loop until one - ;; is genuinely a beginning-of-defun. - (while (and (setq found (search-backward-regexp - "^[^#} \t\n\r]" (point-min) 'stop-at-limit)) - (not (memq (c-awk-get-NL-prop-prev-line) '(?\$ ?\} ?\#))))) - (setq arg (1- arg))) - ;; The same for a -ve arg. - (if (not (eq (point) (point-max))) (forward-char 1)) - (while (and found (< arg 0) (not (eq (point) (point-max)))) ; The same for -ve arg. - (while (and (setq found (search-forward-regexp - "^[^#} \t\n\r]" (point-max) 'stop-at-limit)) - (not (memq (c-awk-get-NL-prop-prev-line) '(?\$ ?\} ?\#))))) - (setq arg (1+ arg))) - (if found (goto-char (match-beginning 0)))) - (eq arg 0))))) + (c-with-string-fences + (or arg (setq arg 1)) + (save-match-data + (c-save-buffer-state ; ensures the buffer is writable. + nil + (let ((found t)) ; Has the most recent regexp search found b-of-defun? + (if (>= arg 0) + ;; Go back one defun each time round the following loop. (For +ve arg) + (while (and found (> arg 0) (not (eq (point) (point-min)))) + ;; Go back one "candidate" each time round the next loop until one + ;; is genuinely a beginning-of-defun. + (while (and (setq found (search-backward-regexp + "^[^#} \t\n\r]" (point-min) 'stop-at-limit)) + (not (memq (c-awk-get-NL-prop-prev-line) '(?\$ ?\} ?\#))))) + (setq arg (1- arg))) + ;; The same for a -ve arg. + (if (not (eq (point) (point-max))) (forward-char 1)) + (while (and found (< arg 0) (not (eq (point) (point-max)))) ; The same for -ve arg. + (while (and (setq found (search-forward-regexp + "^[^#} \t\n\r]" (point-max) 'stop-at-limit)) + (not (memq (c-awk-get-NL-prop-prev-line) '(?\$ ?\} ?\#))))) + (setq arg (1+ arg))) + (if found (goto-char (match-beginning 0)))) + (eq arg 0)))))) (defun c-awk-forward-awk-pattern () ;; Point is at the start of an AWK pattern (which may be null) or function @@ -1187,39 +1190,40 @@ c-awk-end-of-defun Note that this function might do hidden buffer changes. See the comment at the start of cc-engine.el for more info." (interactive "p") - (or arg (setq arg 1)) - (save-match-data - (c-save-buffer-state - nil - (let ((start-point (point)) end-point) - ;; Strategy: (For +ve ARG): If we're not already at a beginning-of-defun, - ;; move backwards to one. - ;; Repeat [(i) move forward to end-of-current-defun (see below); - ;; (ii) If this isn't it, move forward to beginning-of-defun]. - ;; We start counting ARG only when step (i) has passed the original point. - (when (> arg 0) - ;; Try to move back to a beginning-of-defun, if not already at one. - (if (not (c-awk-beginning-of-defun-p)) - (when (not (c-awk-beginning-of-defun 1)) ; No bo-defun before point. - (goto-char start-point) - (c-awk-beginning-of-defun -1))) ; if this fails, we're at EOB, tough! - ;; Now count forward, one defun at a time - (while (and (not (eobp)) - (c-awk-end-of-defun1) - (if (> (point) start-point) (setq arg (1- arg)) t) - (> arg 0) - (c-awk-beginning-of-defun -1)))) - - (when (< arg 0) - (setq end-point start-point) - (while (and (not (bobp)) - (c-awk-beginning-of-defun 1) - (if (< (setq end-point (if (bobp) (point) - (save-excursion (c-awk-end-of-defun1)))) - start-point) - (setq arg (1+ arg)) t) - (< arg 0))) - (goto-char (min start-point end-point))))))) + (c-with-string-fences + (or arg (setq arg 1)) + (save-match-data + (c-save-buffer-state + nil + (let ((start-point (point)) end-point) + ;; Strategy: (For +ve ARG): If we're not already at a beginning-of-defun, + ;; move backwards to one. + ;; Repeat [(i) move forward to end-of-current-defun (see below); + ;; (ii) If this isn't it, move forward to beginning-of-defun]. + ;; We start counting ARG only when step (i) has passed the original point. + (when (> arg 0) + ;; Try to move back to a beginning-of-defun, if not already at one. + (if (not (c-awk-beginning-of-defun-p)) + (when (not (c-awk-beginning-of-defun 1)) ; No bo-defun before point. + (goto-char start-point) + (c-awk-beginning-of-defun -1))) ; if this fails, we're at EOB, tough! + ;; Now count forward, one defun at a time + (while (and (not (eobp)) + (c-awk-end-of-defun1) + (if (> (point) start-point) (setq arg (1- arg)) t) + (> arg 0) + (c-awk-beginning-of-defun -1)))) + + (when (< arg 0) + (setq end-point start-point) + (while (and (not (bobp)) + (c-awk-beginning-of-defun 1) + (if (< (setq end-point (if (bobp) (point) + (save-excursion (c-awk-end-of-defun1)))) + start-point) + (setq arg (1+ arg)) t) + (< arg 0))) + (goto-char (min start-point end-point)))))))) (cc-provide 'cc-awk) ; Changed from 'awk-mode, ACM 2002/5/21 diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index f1f61f7e08..e3f2bd152b 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -49,6 +49,8 @@ ; which looks at this. (cc-bytecomp-defun electric-pair-post-self-insert-function) (cc-bytecomp-defvar c-indent-to-body-directives) +(cc-bytecomp-defun c-restore-string-fences) +(cc-bytecomp-defun c-clear-string-fences) (defvar c-syntactic-context) ;; Indentation / Display syntax functions @@ -210,35 +212,36 @@ c-show-syntactic-information "Show syntactic information for current line. With universal argument, inserts the analysis as a comment on that line." (interactive "P") - (let* ((c-parsing-error nil) - (syntax (if (boundp 'c-syntactic-context) - ;; Use `c-syntactic-context' in the same way as - ;; `c-indent-line', to be consistent. - c-syntactic-context - (c-save-buffer-state nil - (c-guess-basic-syntax))))) - (if (not (consp arg)) - (let (elem pos ols) - (message "Syntactic analysis: %s" syntax) - (unwind-protect - (progn - (while syntax - (setq elem (pop syntax)) - (when (setq pos (c-langelem-pos elem)) - (push (c-put-overlay pos (1+ pos) - 'face 'highlight) - ols)) - (when (setq pos (c-langelem-2nd-pos elem)) - (push (c-put-overlay pos (1+ pos) - 'face 'secondary-selection) - ols))) - (sit-for 10)) - (while ols - (c-delete-overlay (pop ols))))) - (indent-for-comment) - (insert-and-inherit (format "%s" syntax)) - )) - (c-keep-region-active)) + (c-with-string-fences + (let* ((c-parsing-error nil) + (syntax (if (boundp 'c-syntactic-context) + ;; Use `c-syntactic-context' in the same way as + ;; `c-indent-line', to be consistent. + c-syntactic-context + (c-save-buffer-state nil + (c-guess-basic-syntax))))) + (if (not (consp arg)) + (let (elem pos ols) + (message "Syntactic analysis: %s" syntax) + (unwind-protect + (progn + (while syntax + (setq elem (pop syntax)) + (when (setq pos (c-langelem-pos elem)) + (push (c-put-overlay pos (1+ pos) + 'face 'highlight) + ols)) + (when (setq pos (c-langelem-2nd-pos elem)) + (push (c-put-overlay pos (1+ pos) + 'face 'secondary-selection) + ols))) + (sit-for 10)) + (while ols + (c-delete-overlay (pop ols))))) + (indent-for-comment) + (insert-and-inherit (format "%s" syntax)) + )) + (c-keep-region-active))) (defun c-syntactic-information-on-region (from to) "Insert a comment with the syntactic analysis on every line in the region." @@ -414,23 +417,25 @@ c-electric-backspace inside a literal then the function in the variable `c-backspace-function' is called." (interactive "*P") - (if (c-save-buffer-state () - (or (not c-hungry-delete-key) - arg - (c-in-literal))) - (funcall c-backspace-function (prefix-numeric-value arg)) - (c-hungry-delete-backwards))) + (c-with-string-fences + (if (c-save-buffer-state () + (or (not c-hungry-delete-key) + arg + (c-in-literal))) + (funcall c-backspace-function (prefix-numeric-value arg)) + (c-hungry-delete-backwards)))) (defun c-hungry-delete-backwards () "Delete the preceding character or all preceding whitespace back to the previous non-whitespace character. See also \\[c-hungry-delete-forward]." (interactive) - (let ((here (point))) - (c-skip-ws-backward) - (if (/= (point) here) - (delete-region (point) here) - (funcall c-backspace-function 1)))) + (c-with-string-fences + (let ((here (point))) + (c-skip-ws-backward) + (if (/= (point) here) + (delete-region (point) here) + (funcall c-backspace-function 1))))) (defalias 'c-hungry-backspace 'c-hungry-delete-backwards) @@ -442,23 +447,26 @@ c-electric-delete-forward inside a literal then the function in the variable `c-delete-function' is called." (interactive "*P") - (if (c-save-buffer-state () - (or (not c-hungry-delete-key) - arg - (c-in-literal))) - (funcall c-delete-function (prefix-numeric-value arg)) - (c-hungry-delete-forward))) + (c-with-string-fences + (if + (c-save-buffer-state () + (or (not c-hungry-delete-key) + arg + (c-in-literal))) + (funcall c-delete-function (prefix-numeric-value arg)) + (c-hungry-delete-forward)))) (defun c-hungry-delete-forward () "Delete the following character or all following whitespace up to the next non-whitespace character. See also \\[c-hungry-delete-backwards]." (interactive) - (let ((here (point))) - (c-skip-ws-forward) - (if (/= (point) here) - (delete-region (point) here) - (funcall c-delete-function 1)))) + (c-with-string-fences + (let ((here (point))) + (c-skip-ws-forward) + (if (/= (point) here) + (delete-region (point) here) + (funcall c-delete-function 1))))) ;; This function is only used in XEmacs. (defun c-electric-delete (arg) @@ -530,31 +538,32 @@ c-electric-pound `c-electric-pound-behavior'. If a numeric ARG is supplied, or if point is inside a literal or a macro, nothing special happens." (interactive "*P") - (if (c-save-buffer-state () - (or arg - (not c-electric-flag) - (not (memq 'alignleft c-electric-pound-behavior)) - (save-excursion - (skip-chars-backward " \t") - (not (bolp))) - (save-excursion - (and (= (forward-line -1) 0) - (progn (end-of-line) - (eq (char-before) ?\\)))) - (c-in-literal))) - ;; do nothing special - (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))) - (beginning-of-line) - (delete-horizontal-space) - (insert (c-last-command-char)) - (and (not bolp) - (goto-char (- (point-max) pos))) - )) - (c--call-post-self-insert-hook-more-safely)) + (c-with-string-fences + (if (c-save-buffer-state () + (or arg + (not c-electric-flag) + (not (memq 'alignleft c-electric-pound-behavior)) + (save-excursion + (skip-chars-backward " \t") + (not (bolp))) + (save-excursion + (and (= (forward-line -1) 0) + (progn (end-of-line) + (eq (char-before) ?\\)))) + (c-in-literal))) + ;; do nothing special + (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))) + (beginning-of-line) + (delete-horizontal-space) + (insert (c-last-command-char)) + (and (not bolp) + (goto-char (- (point-max) pos))) + )) + (c--call-post-self-insert-hook-more-safely))) (defun c-point-syntax () ;; Return the syntactic context of the construct at point. (This is NOT @@ -882,60 +891,61 @@ c-electric-brace settings of `c-cleanup-list' are done." (interactive "*P") - (let (safepos literal - ;; 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 - (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)) - literal (c-in-literal safepos))) - - ;; Insert the brace. Note that expand-abbrev might reindent - ;; the line here if there's a preceding "else" or something. - (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)) - 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-} + (c-with-string-fences + (let (safepos literal + ;; 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 + (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)) + literal (c-in-literal safepos))) + + ;; Insert the brace. Note that expand-abbrev might reindent + ;; the line here if there's a preceding "else" or something. + (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)) + 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) + (c-do-brace-electrics 'assume 'ignore)) + (c-indent-line)))) + + ;; blink the paren + (and (eq (c-last-command-char) ?\}) + (not executing-kbd-macro) + old-blink-paren (save-excursion - (forward-char) - (c-do-brace-electrics 'assume 'ignore)) - (c-indent-line)))) - - ;; blink the paren - (and (eq (c-last-command-char) ?\}) - (not executing-kbd-macro) - old-blink-paren - (save-excursion - (c-save-buffer-state nil - (c-backward-syntactic-ws safepos)) - (funcall old-blink-paren))) - (c--call-post-self-insert-hook-more-safely))) + (c-save-buffer-state nil + (c-backward-syntactic-ws safepos)) + (funcall old-blink-paren))) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-slash (arg) "Insert a slash character. @@ -956,39 +966,40 @@ c-electric-slash `c-syntactic-indentation' is nil or `c-electric-flag' is nil, indentation is inhibited." (interactive "*P") - (let ((literal (c-save-buffer-state () (c-in-literal))) - indentp - ;; shut this up - (c-echo-syntactic-information-p nil)) + (c-with-string-fences + (let ((literal (c-save-buffer-state () (c-in-literal))) + indentp + ;; shut this up + (c-echo-syntactic-information-p nil)) - ;; comment-close-slash cleanup? This DOESN'T need `c-electric-flag' or - ;; `c-syntactic-indentation' set. - (when (and (not arg) - (eq literal 'c) - (memq 'comment-close-slash c-cleanup-list) - (eq (c-last-command-char) ?/) - (looking-at (concat "[ \t]*\\(" - (regexp-quote comment-end) "\\)?$")) - ; (eq c-block-comment-ender "*/") ; C-style comments ALWAYS end in */ - (save-excursion - (save-restriction - (narrow-to-region (point-min) (point)) - (back-to-indentation) - (looking-at (concat c-current-comment-prefix "[ \t]*$"))))) - (delete-region (progn (forward-line 0) (point)) - (progn (end-of-line) (point))) - (insert-char ?* 1)) ; the / comes later. ; Do I need a t (retain sticky properties) here? - - (setq indentp (and (not arg) - c-syntactic-indentation - c-electric-flag - (eq (c-last-command-char) ?/) - (eq (char-before) (if literal ?* ?/)))) - (let (post-self-insert-hook) ; Disable random functionality. - (self-insert-command (prefix-numeric-value arg))) - (if indentp - (indent-according-to-mode)) - (c--call-post-self-insert-hook-more-safely))) + ;; comment-close-slash cleanup? This DOESN'T need `c-electric-flag' or + ;; `c-syntactic-indentation' set. + (when (and (not arg) + (eq literal 'c) + (memq 'comment-close-slash c-cleanup-list) + (eq (c-last-command-char) ?/) + (looking-at (concat "[ \t]*\\(" + (regexp-quote comment-end) "\\)?$")) + ; (eq c-block-comment-ender "*/") ; C-style comments ALWAYS end in */ + (save-excursion + (save-restriction + (narrow-to-region (point-min) (point)) + (back-to-indentation) + (looking-at (concat c-current-comment-prefix "[ \t]*$"))))) + (delete-region (progn (forward-line 0) (point)) + (progn (end-of-line) (point))) + (insert-char ?* 1)) ; the / comes later. ; Do I need a t (retain sticky properties) here? + + (setq indentp (and (not arg) + c-syntactic-indentation + c-electric-flag + (eq (c-last-command-char) ?/) + (eq (char-before) (if literal ?* ?/)))) + (let (post-self-insert-hook) ; Disable random functionality. + (self-insert-command (prefix-numeric-value arg))) + (if indentp + (indent-according-to-mode)) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-star (arg) "Insert a star character. @@ -999,27 +1010,27 @@ c-electric-star this indentation is inhibited." (interactive "*P") - (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 () - (and c-syntactic-indentation - c-electric-flag - (not arg) - (eq (c-in-literal) 'c) - (eq (char-before) ?*) - (save-excursion - (forward-char -1) - (skip-chars-backward "*") - (if (eq (char-before) ?/) - (forward-char -1)) - (skip-chars-backward " \t") - (bolp)))) - (let (c-echo-syntactic-information-p) ; shut this up - (indent-according-to-mode)) - ) - (c--call-post-self-insert-hook-more-safely)) + (c-with-string-fences + (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 () + (and c-syntactic-indentation + c-electric-flag + (not arg) + (eq (c-in-literal) 'c) + (eq (char-before) ?*) + (save-excursion + (forward-char -1) + (skip-chars-backward "*") + (if (eq (char-before) ?/) + (forward-char -1)) + (skip-chars-backward " \t") + (bolp)))) + (let (c-echo-syntactic-information-p) ; shut this up + (indent-according-to-mode))) + (c--call-post-self-insert-hook-more-safely))) (defun c-electric-semi&comma (arg) "Insert a comma or semicolon. @@ -1039,60 +1050,61 @@ c-electric-semi&comma semicolon following a defun might be cleaned up, depending on the settings of `c-cleanup-list'." (interactive "*P") - (let* (lim literal c-syntactic-context - (here (point)) - ;; shut this up - (c-echo-syntactic-information-p nil)) - - (c-save-buffer-state () - (setq lim (c-most-enclosing-brace (c-parse-state)) - literal (c-in-literal lim))) - - (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. - (if (or (not c-auto-newline) - (not (looking-at "[ \t]*\\\\?$"))) - (if c-syntactic-indentation - (c-indent-line)) - ;; clean ups: list-close-comma or defun-close-semi - (let ((pos (- (point-max) (point)))) - (if (c-save-buffer-state () - (and (or (and - (eq (c-last-command-char) ?,) - (memq 'list-close-comma c-cleanup-list)) - (and - (eq (c-last-command-char) ?\;) - (memq 'defun-close-semi c-cleanup-list))) - (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 lim)))) - (delete-region (point) here)) - (goto-char (- (point-max) pos))) - ;; reindent line - (when c-syntactic-indentation - (setq c-syntactic-context (c-guess-basic-syntax)) - (c-indent-line c-syntactic-context)) - ;; check to see if a newline should be added - (let ((criteria c-hanging-semi&comma-criteria) - answer add-newline-p) - (while criteria - (setq answer (funcall (car criteria))) - ;; only nil value means continue checking - (if (not answer) - (setq criteria (cdr criteria)) - (setq criteria nil) - ;; only 'stop specifically says do not add a newline - (setq add-newline-p (not (eq answer 'stop))) - )) - (if add-newline-p - (c-newline-and-indent))))) - (c--call-post-self-insert-hook-more-safely))) + (c-with-string-fences + (let* (lim literal c-syntactic-context + (here (point)) + ;; shut this up + (c-echo-syntactic-information-p nil)) + + (c-save-buffer-state () + (setq lim (c-most-enclosing-brace (c-parse-state)) + literal (c-in-literal lim))) + + (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. + (if (or (not c-auto-newline) + (not (looking-at "[ \t]*\\\\?$"))) + (if c-syntactic-indentation + (c-indent-line)) + ;; clean ups: list-close-comma or defun-close-semi + (let ((pos (- (point-max) (point)))) + (if (c-save-buffer-state () + (and (or (and + (eq (c-last-command-char) ?,) + (memq 'list-close-comma c-cleanup-list)) + (and + (eq (c-last-command-char) ?\;) + (memq 'defun-close-semi c-cleanup-list))) + (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 lim)))) + (delete-region (point) here)) + (goto-char (- (point-max) pos))) + ;; reindent line + (when c-syntactic-indentation + (setq c-syntactic-context (c-guess-basic-syntax)) + (c-indent-line c-syntactic-context)) + ;; check to see if a newline should be added + (let ((criteria c-hanging-semi&comma-criteria) + answer add-newline-p) + (while criteria + (setq answer (funcall (car criteria))) + ;; only nil value means continue checking + (if (not answer) + (setq criteria (cdr criteria)) + (setq criteria nil) + ;; only 'stop specifically says do not add a newline + (setq add-newline-p (not (eq answer 'stop))) + )) + (if add-newline-p + (c-newline-and-indent))))) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-colon (arg) "Insert a colon. @@ -1113,89 +1125,90 @@ c-electric-colon `c-cleanup-list'." (interactive "*P") - (let* ((bod (c-point 'bod)) - (literal (c-save-buffer-state () (c-in-literal bod))) - newlines is-scope-op - ;; shut this up - (c-echo-syntactic-information-p nil)) - (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. - (if (not (looking-at "[ \t]*\\\\?$")) - (if c-syntactic-indentation - (indent-according-to-mode)) - - ;; scope-operator clean-up? - (let ((pos (- (point-max) (point))) - (here (point))) - (if (c-save-buffer-state () ; Why do we need this? [ACM, 2003-03-12] - (and c-auto-newline - (memq 'scope-operator c-cleanup-list) - (eq (char-before) ?:) - (progn - (forward-char -1) - (c-skip-ws-backward) - (eq (char-before) ?:)) - (not (c-in-literal)) - (not (eq (char-after (- (point) 2)) ?:)))) - (progn - (delete-region (point) (1- here)) - (setq is-scope-op t))) - (goto-char (- (point-max) pos))) - - ;; indent the current line if it's done syntactically. - (if c-syntactic-indentation - ;; Cannot use the same syntax analysis as we find below, - ;; since that's made with c-syntactic-indentation-in-macros - ;; always set to t. - (indent-according-to-mode)) - - ;; Calculate where, if anywhere, we want newlines. - (c-save-buffer-state - ((c-syntactic-indentation-in-macros t) - (c-auto-newline-analysis t) - ;; Turn on syntactic macro analysis to help with auto newlines - ;; only. - (syntax (c-guess-basic-syntax)) - (elem syntax)) - ;; Translate substatement-label to label for this operation. - (while elem - (if (eq (car (car elem)) 'substatement-label) - (setcar (car elem) 'label)) - (setq elem (cdr elem))) - ;; some language elements can only be determined by checking - ;; the following line. Let's first look for ones that can be - ;; found when looking on the line with the colon - (setq newlines - (and c-auto-newline - (or (c-lookup-lists '(case-label label access-label) - syntax c-hanging-colons-alist) - (c-lookup-lists '(member-init-intro inher-intro) - (progn - (insert ?\n) - (unwind-protect - (c-guess-basic-syntax) - (delete-char -1))) - c-hanging-colons-alist))))) - ;; does a newline go before the colon? Watch out for already - ;; non-hung colons. However, we don't unhang them because that - ;; would be a cleanup (and anti-social). - (if (and (memq 'before newlines) - (not is-scope-op) - (save-excursion - (skip-chars-backward ": \t") - (not (bolp)))) - (let ((pos (- (point-max) (point)))) - (forward-char -1) - (c-newline-and-indent) - (goto-char (- (point-max) pos)))) - ;; does a newline go after the colon? - (if (and (memq 'after (cdr-safe newlines)) - (not is-scope-op)) - (c-newline-and-indent)))) - (c--call-post-self-insert-hook-more-safely))) + (c-with-string-fences + (let* ((bod (c-point 'bod)) + (literal (c-save-buffer-state () (c-in-literal bod))) + newlines is-scope-op + ;; shut this up + (c-echo-syntactic-information-p nil)) + (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. + (if (not (looking-at "[ \t]*\\\\?$")) + (if c-syntactic-indentation + (indent-according-to-mode)) + + ;; scope-operator clean-up? + (let ((pos (- (point-max) (point))) + (here (point))) + (if (c-save-buffer-state () ; Why do we need this? [ACM, 2003-03-12] + (and c-auto-newline + (memq 'scope-operator c-cleanup-list) + (eq (char-before) ?:) + (progn + (forward-char -1) + (c-skip-ws-backward) + (eq (char-before) ?:)) + (not (c-in-literal)) + (not (eq (char-after (- (point) 2)) ?:)))) + (progn + (delete-region (point) (1- here)) + (setq is-scope-op t))) + (goto-char (- (point-max) pos))) + + ;; indent the current line if it's done syntactically. + (if c-syntactic-indentation + ;; Cannot use the same syntax analysis as we find below, + ;; since that's made with c-syntactic-indentation-in-macros + ;; always set to t. + (indent-according-to-mode)) + + ;; Calculate where, if anywhere, we want newlines. + (c-save-buffer-state + ((c-syntactic-indentation-in-macros t) + (c-auto-newline-analysis t) + ;; Turn on syntactic macro analysis to help with auto newlines + ;; only. + (syntax (c-guess-basic-syntax)) + (elem syntax)) + ;; Translate substatement-label to label for this operation. + (while elem + (if (eq (car (car elem)) 'substatement-label) + (setcar (car elem) 'label)) + (setq elem (cdr elem))) + ;; some language elements can only be determined by checking + ;; the following line. Let's first look for ones that can be + ;; found when looking on the line with the colon + (setq newlines + (and c-auto-newline + (or (c-lookup-lists '(case-label label access-label) + syntax c-hanging-colons-alist) + (c-lookup-lists '(member-init-intro inher-intro) + (progn + (insert ?\n) + (unwind-protect + (c-guess-basic-syntax) + (delete-char -1))) + c-hanging-colons-alist))))) + ;; does a newline go before the colon? Watch out for already + ;; non-hung colons. However, we don't unhang them because that + ;; would be a cleanup (and anti-social). + (if (and (memq 'before newlines) + (not is-scope-op) + (save-excursion + (skip-chars-backward ": \t") + (not (bolp)))) + (let ((pos (- (point-max) (point)))) + (forward-char -1) + (c-newline-and-indent) + (goto-char (- (point-max) pos)))) + ;; does a newline go after the colon? + (if (and (memq 'after (cdr-safe newlines)) + (not is-scope-op)) + (c-newline-and-indent)))) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-lt-gt (arg) "Insert a \"<\" or \">\" character. @@ -1209,84 +1222,85 @@ c-electric-lt-gt numeric argument is supplied, or the point is inside a literal." (interactive "*P") - (let ((literal (c-save-buffer-state () (c-in-literal))) - template-delim include-delim - (c-echo-syntactic-information-p nil) - final-pos found-delim case-fold-search) + (c-with-string-fences + (let ((literal (c-save-buffer-state () (c-in-literal))) + template-delim include-delim + (c-echo-syntactic-information-p nil) + final-pos found-delim case-fold-search) - (let (post-self-insert-hook) ; Disable random functionality. - (self-insert-command (prefix-numeric-value arg))) - (setq final-pos (point)) + (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 ;;;; property on the new < or > and its mate (if any) when they are template ;;;; parens. This is now done in an after-change function. - (when (and (not arg) (not literal)) - ;; Have we got a delimiter on a #include directive? - (beginning-of-line) - (setq include-delim - (and - (looking-at c-cpp-include-key) - (if (eq (c-last-command-char) ?<) - (eq (match-end 0) (1- final-pos)) - (goto-char (1- final-pos)) - (skip-chars-backward "^<>" (c-point 'bol)) - (eq (char-before) ?<)))) - (goto-char final-pos) - - ;; Indent the line if appropriate. - (when (and c-electric-flag c-syntactic-indentation c-recognize-<>-arglists) - (setq found-delim + (when (and (not arg) (not literal)) + ;; Have we got a delimiter on a #include directive? + (beginning-of-line) + (setq include-delim + (and + (looking-at c-cpp-include-key) (if (eq (c-last-command-char) ?<) - ;; If a <, basically see if it's got "template" before it ..... - (or (and (progn - (backward-char) - (= (point) - (progn (c-beginning-of-current-token) (point)))) - (progn - (c-backward-token-2) - (looking-at c-opt-<>-sexp-key)) - (setq template-delim t)) - ;; ..... or is a C++ << operator. - (and (c-major-mode-is 'c++-mode) - (progn - (goto-char (1- final-pos)) - (c-beginning-of-current-token) - (looking-at "<<")) - (>= (match-end 0) final-pos))) - - ;; It's a >. Either a template/generic terminator ... - (or (and (c-get-char-property (1- final-pos) 'syntax-table) - (setq template-delim t)) - ;; or a C++ >> operator. - (and (c-major-mode-is 'c++-mode) - (progn - (goto-char (1- final-pos)) - (c-beginning-of-current-token) - (looking-at ">>")) - (>= (match-end 0) final-pos))))) - (goto-char final-pos) - - (when found-delim - (indent-according-to-mode))) - - ;; On the off chance that < and > are configured as pairs in - ;; electric-pair-mode. - (when (and (boundp 'electric-pair-mode) electric-pair-mode - (or template-delim include-delim)) - (let (post-self-insert-hook) - (electric-pair-post-self-insert-function)))) - - (when found-delim - (when (and (eq (char-before) ?>) - (not executing-kbd-macro) - blink-paren-function) - ;; From now (2016-01-01), the syntax-table text properties on < and > - ;; are applied in an after-change function, not during redisplay. Hence - ;; we no longer need to call (sit-for 0) for blink paren to work. - (funcall blink-paren-function)))) - (c--call-post-self-insert-hook-more-safely)) + (eq (match-end 0) (1- final-pos)) + (goto-char (1- final-pos)) + (skip-chars-backward "^<>" (c-point 'bol)) + (eq (char-before) ?<)))) + (goto-char final-pos) + + ;; Indent the line if appropriate. + (when (and c-electric-flag c-syntactic-indentation c-recognize-<>-arglists) + (setq found-delim + (if (eq (c-last-command-char) ?<) + ;; If a <, basically see if it's got "template" before it ..... + (or (and (progn + (backward-char) + (= (point) + (progn (c-beginning-of-current-token) (point)))) + (progn + (c-backward-token-2) + (looking-at c-opt-<>-sexp-key)) + (setq template-delim t)) + ;; ..... or is a C++ << operator. + (and (c-major-mode-is 'c++-mode) + (progn + (goto-char (1- final-pos)) + (c-beginning-of-current-token) + (looking-at "<<")) + (>= (match-end 0) final-pos))) + + ;; It's a >. Either a template/generic terminator ... + (or (and (c-get-char-property (1- final-pos) 'syntax-table) + (setq template-delim t)) + ;; or a C++ >> operator. + (and (c-major-mode-is 'c++-mode) + (progn + (goto-char (1- final-pos)) + (c-beginning-of-current-token) + (looking-at ">>")) + (>= (match-end 0) final-pos))))) + (goto-char final-pos) + + (when found-delim + (indent-according-to-mode))) + + ;; On the off chance that < and > are configured as pairs in + ;; electric-pair-mode. + (when (and (boundp 'electric-pair-mode) electric-pair-mode + (or template-delim include-delim)) + (let (post-self-insert-hook) + (electric-pair-post-self-insert-function)))) + + (when found-delim + (when (and (eq (char-before) ?>) + (not executing-kbd-macro) + blink-paren-function) + ;; From now (2016-01-01), the syntax-table text properties on < and > + ;; are applied in an after-change function, not during redisplay. Hence + ;; we no longer need to call (sit-for 0) for blink paren to work. + (funcall blink-paren-function)))) + (c--call-post-self-insert-hook-more-safely))) (defun c-electric-paren (arg) "Insert a parenthesis. @@ -1301,112 +1315,113 @@ c-electric-paren Also, if `c-electric-flag' and `c-auto-newline' are both non-nil, some newline cleanups are done if appropriate; see the variable `c-cleanup-list'." (interactive "*P") - (let ((literal (c-save-buffer-state () (c-in-literal))) - ;; shut this up - (c-echo-syntactic-information-p nil) - case-fold-search) - (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 - ;; be most disruptive. We'll blink it ourselves - ;; afterwards. - (old-blink-paren blink-paren-function) - blink-paren-function) - (if (and c-syntactic-indentation c-electric-flag) - (indent-according-to-mode)) - - ;; If we're at EOL, check for new-line clean-ups. - (when (and c-electric-flag c-auto-newline - (looking-at "[ \t]*\\\\?$")) - - ;; clean up brace-elseif-brace - (when - (and (memq 'brace-elseif-brace c-cleanup-list) - (eq (c-last-command-char) ?\() - (re-search-backward - (concat "}" - "\\([ \t\n]\\|\\\\\n\\)*" - "else" - "\\([ \t\n]\\|\\\\\n\\)+" - "if" - "\\([ \t\n]\\|\\\\\n\\)*" - "(" - "\\=") - nil t) - (not (c-save-buffer-state () (c-in-literal)))) - (delete-region (match-beginning 0) (match-end 0)) - (insert-and-inherit "} else if (")) - - ;; clean up brace-catch-brace - (when - (and (memq 'brace-catch-brace c-cleanup-list) - (eq (c-last-command-char) ?\() - (re-search-backward - (concat "}" - "\\([ \t\n]\\|\\\\\n\\)*" - "catch" - "\\([ \t\n]\\|\\\\\n\\)*" - "(" - "\\=") - nil t) - (not (c-save-buffer-state () (c-in-literal)))) - (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. - (let (beg (end (1- (point)))) - (cond - - ;; space-before-funcall clean-up? - ((and (memq 'space-before-funcall c-cleanup-list) - (eq (c-last-command-char) ?\() - (save-excursion - (backward-char) - (skip-chars-backward " \t") - (setq beg (point)) - (and (c-save-buffer-state () (c-on-identifier)) - ;; Don't add a space into #define FOO().... - (not (and (c-beginning-of-macro) - (c-forward-over-cpp-define-id) - (eq (point) beg)))))) - (save-excursion - (delete-region beg end) - (goto-char beg) - (insert ?\ ))) - - ;; compact-empty-funcall clean-up? - ((c-save-buffer-state () - (and (memq 'compact-empty-funcall c-cleanup-list) - (eq (c-last-command-char) ?\)) - (save-excursion - (c-safe (backward-char 2)) - (when (looking-at "()") - (setq end (point)) - (skip-chars-backward " \t") - (setq beg (point)) - (c-on-identifier))))) - (delete-region beg end)))) - (and (eq last-input-event ?\)) - (not executing-kbd-macro) - old-blink-paren - (funcall old-blink-paren))) - - ;; Apply `electric-pair-mode' stuff inside a string or comment. - (when (and (boundp 'electric-pair-mode) electric-pair-mode) - (let (post-self-insert-hook) - (electric-pair-post-self-insert-function)))) - (c--call-post-self-insert-hook-more-safely))) + (c-with-string-fences + (let ((literal (c-save-buffer-state () (c-in-literal))) + ;; shut this up + (c-echo-syntactic-information-p nil) + case-fold-search) + (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 + ;; be most disruptive. We'll blink it ourselves + ;; afterwards. + (old-blink-paren blink-paren-function) + blink-paren-function) + (if (and c-syntactic-indentation c-electric-flag) + (indent-according-to-mode)) + + ;; If we're at EOL, check for new-line clean-ups. + (when (and c-electric-flag c-auto-newline + (looking-at "[ \t]*\\\\?$")) + + ;; clean up brace-elseif-brace + (when + (and (memq 'brace-elseif-brace c-cleanup-list) + (eq (c-last-command-char) ?\() + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "else" + "\\([ \t\n]\\|\\\\\n\\)+" + "if" + "\\([ \t\n]\\|\\\\\n\\)*" + "(" + "\\=") + nil t) + (not (c-save-buffer-state () (c-in-literal)))) + (delete-region (match-beginning 0) (match-end 0)) + (insert-and-inherit "} else if (")) + + ;; clean up brace-catch-brace + (when + (and (memq 'brace-catch-brace c-cleanup-list) + (eq (c-last-command-char) ?\() + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "catch" + "\\([ \t\n]\\|\\\\\n\\)*" + "(" + "\\=") + nil t) + (not (c-save-buffer-state () (c-in-literal)))) + (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. + (let (beg (end (1- (point)))) + (cond + + ;; space-before-funcall clean-up? + ((and (memq 'space-before-funcall c-cleanup-list) + (eq (c-last-command-char) ?\() + (save-excursion + (backward-char) + (skip-chars-backward " \t") + (setq beg (point)) + (and (c-save-buffer-state () (c-on-identifier)) + ;; Don't add a space into #define FOO().... + (not (and (c-beginning-of-macro) + (c-forward-over-cpp-define-id) + (eq (point) beg)))))) + (save-excursion + (delete-region beg end) + (goto-char beg) + (insert ?\ ))) + + ;; compact-empty-funcall clean-up? + ((c-save-buffer-state () + (and (memq 'compact-empty-funcall c-cleanup-list) + (eq (c-last-command-char) ?\)) + (save-excursion + (c-safe (backward-char 2)) + (when (looking-at "()") + (setq end (point)) + (skip-chars-backward " \t") + (setq beg (point)) + (c-on-identifier))))) + (delete-region beg end)))) + (and (eq last-input-event ?\)) + (not executing-kbd-macro) + old-blink-paren + (funcall old-blink-paren))) + + ;; Apply `electric-pair-mode' stuff inside a string or comment. + (when (and (boundp 'electric-pair-mode) electric-pair-mode) + (let (post-self-insert-hook) + (electric-pair-post-self-insert-function)))) + (c--call-post-self-insert-hook-more-safely)))) (defun c-electric-continued-statement () "Reindent the current line if appropriate. @@ -1868,70 +1883,71 @@ c-beginning-of-defun (c-region-is-active-p) (push-mark)) - (c-save-buffer-state - (beginning-of-defun-function - end-of-defun-function - (paren-state (c-parse-state)) - (orig-point-min (point-min)) (orig-point-max (point-max)) - lim ; Position of { which has been widened to. - where pos case-fold-search) - - (save-restriction - (if (eq c-defun-tactic 'go-outward) - (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace. - paren-state orig-point-min orig-point-max))) - - ;; Move back out of any macro/comment/string we happen to be in. - (c-beginning-of-macro) - (setq pos (c-literal-start)) - (if pos (goto-char pos)) - - (setq where (c-where-wrt-brace-construct)) - - (if (< arg 0) - ;; Move forward to the closing brace of a function. - (progn - (if (memq where '(at-function-end outwith-function)) - (setq arg (1+ arg))) - (if (< arg 0) - (c-while-widening-to-decl-block - (< (setq arg (- (c-forward-to-nth-EOF-\;-or-} (- arg) where))) 0))) - (prog1 - ;; Move forward to the next opening brace.... - (when (and (= arg 0) - (progn - (c-while-widening-to-decl-block - (not (c-syntactic-re-search-forward "{" nil 'eob))) - (eq (char-before) ?{))) - (backward-char) - ;; ... and backward to the function header. - (c-beginning-of-decl-1) - t) - (c-keep-region-active))) - - ;; Move backward to the opening brace of a function, making successively - ;; larger portions of the buffer visible as necessary. - (when (> arg 0) - (c-while-widening-to-decl-block - (> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0))) - - (when (eq arg 0) - ;; Go backward to this function's header. - (c-beginning-of-decl-1) - - (setq pos (point)) - ;; We're now there, modulo comments and whitespace. - ;; Try to be line oriented; position point at the closest - ;; preceding boi that isn't inside a comment, but if we hit - ;; the previous declaration then we use the current point - ;; instead. - (while (and (/= (point) (c-point 'boi)) - (c-backward-single-comment))) - (if (/= (point) (c-point 'boi)) - (goto-char pos))) - - (c-keep-region-active) - (= arg 0))))) + (c-with-string-fences + (c-save-buffer-state + (beginning-of-defun-function + end-of-defun-function + (paren-state (c-parse-state)) + (orig-point-min (point-min)) (orig-point-max (point-max)) + lim ; Position of { which has been widened to. + where pos case-fold-search) + + (save-restriction + (if (eq c-defun-tactic 'go-outward) + (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace. + paren-state orig-point-min orig-point-max))) + + ;; Move back out of any macro/comment/string we happen to be in. + (c-beginning-of-macro) + (setq pos (c-literal-start)) + (if pos (goto-char pos)) + + (setq where (c-where-wrt-brace-construct)) + + (if (< arg 0) + ;; Move forward to the closing brace of a function. + (progn + (if (memq where '(at-function-end outwith-function)) + (setq arg (1+ arg))) + (if (< arg 0) + (c-while-widening-to-decl-block + (< (setq arg (- (c-forward-to-nth-EOF-\;-or-} (- arg) where))) 0))) + (prog1 + ;; Move forward to the next opening brace.... + (when (and (= arg 0) + (progn + (c-while-widening-to-decl-block + (not (c-syntactic-re-search-forward "{" nil 'eob))) + (eq (char-before) ?{))) + (backward-char) + ;; ... and backward to the function header. + (c-beginning-of-decl-1) + t) + (c-keep-region-active))) + + ;; Move backward to the opening brace of a function, making successively + ;; larger portions of the buffer visible as necessary. + (when (> arg 0) + (c-while-widening-to-decl-block + (> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0))) + + (when (eq arg 0) + ;; Go backward to this function's header. + (c-beginning-of-decl-1) + + (setq pos (point)) + ;; We're now there, modulo comments and whitespace. + ;; Try to be line oriented; position point at the closest + ;; preceding boi that isn't inside a comment, but if we hit + ;; the previous declaration then we use the current point + ;; instead. + (while (and (/= (point) (c-point 'boi)) + (c-backward-single-comment))) + (if (/= (point) (c-point 'boi)) + (goto-char pos))) + + (c-keep-region-active) + (= arg 0)))))) (defun c-forward-to-nth-EOF-\;-or-} (n where) ;; Skip to the closing brace or semicolon of the Nth function after point. @@ -1998,65 +2014,66 @@ c-end-of-defun (c-region-is-active-p) (push-mark)) - (c-save-buffer-state - (beginning-of-defun-function - end-of-defun-function - (paren-state (c-parse-state)) - (orig-point-min (point-min)) (orig-point-max (point-max)) - lim - where pos case-fold-search) - - (save-restriction - (if (eq c-defun-tactic 'go-outward) - (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace - paren-state orig-point-min orig-point-max))) - - ;; Move back out of any macro/comment/string we happen to be in. - (c-beginning-of-macro) - (setq pos (c-literal-start)) - (if pos (goto-char pos)) + (c-with-string-fences + (c-save-buffer-state + (beginning-of-defun-function + end-of-defun-function + (paren-state (c-parse-state)) + (orig-point-min (point-min)) (orig-point-max (point-max)) + lim + where pos case-fold-search) + + (save-restriction + (if (eq c-defun-tactic 'go-outward) + (setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace + paren-state orig-point-min orig-point-max))) + + ;; Move back out of any macro/comment/string we happen to be in. + (c-beginning-of-macro) + (setq pos (c-literal-start)) + (if pos (goto-char pos)) + + (setq where (c-where-wrt-brace-construct)) + + (if (< arg 0) + ;; Move backwards to the } of a function + (progn + (if (memq where '(at-header outwith-function)) + (setq arg (1+ arg))) + (if (< arg 0) + (c-while-widening-to-decl-block + (< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0))) + (if (= arg 0) + (c-while-widening-to-decl-block + (progn (c-syntactic-skip-backward "^}") + (not (eq (char-before) ?})))))) + + ;; Move forward to the } of a function + (if (> arg 0) + (c-while-widening-to-decl-block + (> (setq arg (c-forward-to-nth-EOF-\;-or-} arg where)) 0)))) + + ;; Do we need to move forward from the brace to the semicolon? + (when (eq arg 0) + (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc. + (c-syntactic-re-search-forward ";")) - (setq where (c-where-wrt-brace-construct)) + (setq pos (point)) + ;; We're there now, modulo comments and whitespace. + ;; Try to be line oriented; position point after the next + ;; newline that isn't inside a comment, but if we hit the + ;; next declaration then we use the current point instead. + (while (and (not (bolp)) + (not (looking-at "\\s *$")) + (c-forward-single-comment))) + (cond ((bolp)) + ((looking-at "\\s *$") + (forward-line 1)) + (t + (goto-char pos)))) - (if (< arg 0) - ;; Move backwards to the } of a function - (progn - (if (memq where '(at-header outwith-function)) - (setq arg (1+ arg))) - (if (< arg 0) - (c-while-widening-to-decl-block - (< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0))) - (if (= arg 0) - (c-while-widening-to-decl-block - (progn (c-syntactic-skip-backward "^}") - (not (eq (char-before) ?})))))) - - ;; Move forward to the } of a function - (if (> arg 0) - (c-while-widening-to-decl-block - (> (setq arg (c-forward-to-nth-EOF-\;-or-} arg where)) 0)))) - - ;; Do we need to move forward from the brace to the semicolon? - (when (eq arg 0) - (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc. - (c-syntactic-re-search-forward ";")) - - (setq pos (point)) - ;; We're there now, modulo comments and whitespace. - ;; Try to be line oriented; position point after the next - ;; newline that isn't inside a comment, but if we hit the - ;; next declaration then we use the current point instead. - (while (and (not (bolp)) - (not (looking-at "\\s *$")) - (c-forward-single-comment))) - (cond ((bolp)) - ((looking-at "\\s *$") - (forward-line 1)) - (t - (goto-char pos)))) - - (c-keep-region-active) - (= arg 0)))) + (c-keep-region-active) + (= arg 0))))) (defun c-defun-name-1 () "Return name of current defun, at current narrowing, or nil if there isn't one. @@ -2342,18 +2359,19 @@ c-display-defun-name "Display the name of the current CC mode defun and the position in it. With a prefix arg, push the name onto the kill ring too." (interactive "P") - (save-restriction - (widen) - (c-save-buffer-state ((name-and-limits (c-defun-name-and-limits nil)) - (name (car name-and-limits)) - (limits (cdr name-and-limits)) - (point-bol (c-point 'bol))) - (when name - (message "%s. Line %s/%s." name - (1+ (count-lines (car limits) (max point-bol (car limits)))) - (count-lines (car limits) (cdr limits))) - (if arg (kill-new name)) - (sit-for 3 t))))) + (c-with-string-fences + (save-restriction + (widen) + (c-save-buffer-state ((name-and-limits (c-defun-name-and-limits nil)) + (name (car name-and-limits)) + (limits (cdr name-and-limits)) + (point-bol (c-point 'bol))) + (when name + (message "%s. Line %s/%s." name + (1+ (count-lines (car limits) (max point-bol (car limits)))) + (count-lines (car limits) (cdr limits))) + (if arg (kill-new name)) + (sit-for 3 t)))))) (put 'c-display-defun-name 'isearch-scroll t) (defun c-mark-function () @@ -2369,34 +2387,35 @@ c-mark-function function does not require the declaration to contain a brace block." (interactive) - (let (decl-limits case-fold-search) - (c-save-buffer-state nil - ;; We try to be line oriented, unless there are several - ;; declarations on the same line. - (if (looking-at c-syntactic-eol) - (c-backward-token-2 1 nil (c-point 'bol))) - (setq decl-limits (c-declaration-limits t))) - - (if (not decl-limits) - (error "Cannot find any declaration") - (let* ((extend-region-p - (and (eq this-command 'c-mark-function) - (eq last-command 'c-mark-function))) - (push-mark-p (and (eq this-command 'c-mark-function) - (not extend-region-p) - (not (c-region-is-active-p))))) - (if push-mark-p (push-mark)) - (if extend-region-p - (progn - (exchange-point-and-mark) - (setq decl-limits (c-declaration-limits t)) - (when (not decl-limits) - (exchange-point-and-mark) - (error "Cannot find any declaration")) - (goto-char (cdr decl-limits)) - (exchange-point-and-mark)) - (goto-char (car decl-limits)) - (push-mark (cdr decl-limits) nil t)))))) + (c-with-string-fences + (let (decl-limits case-fold-search) + (c-save-buffer-state nil + ;; We try to be line oriented, unless there are several + ;; declarations on the same line. + (if (looking-at c-syntactic-eol) + (c-backward-token-2 1 nil (c-point 'bol))) + (setq decl-limits (c-declaration-limits t))) + + (if (not decl-limits) + (error "Cannot find any declaration") + (let* ((extend-region-p + (and (eq this-command 'c-mark-function) + (eq last-command 'c-mark-function))) + (push-mark-p (and (eq this-command 'c-mark-function) + (not extend-region-p) + (not (c-region-is-active-p))))) + (if push-mark-p (push-mark)) + (if extend-region-p + (progn + (exchange-point-and-mark) + (setq decl-limits (c-declaration-limits t)) + (when (not decl-limits) + (exchange-point-and-mark) + (error "Cannot find any declaration")) + (goto-char (cdr decl-limits)) + (exchange-point-and-mark)) + (goto-char (car decl-limits)) + (push-mark (cdr decl-limits) nil t))))))) (defun c-cpp-define-name () "Return the name of the current CPP macro, or NIL if we're not in one." @@ -3033,85 +3052,86 @@ c-beginning-of-statement nil t)) (if (< count 0) (c-end-of-statement (- count) lim sentence-flag) - (c-save-buffer-state - ((count (or count 1)) - last ; start point for going back ONE chunk. Updated each chunk movement. - (macro-fence - (save-excursion (and (not (bobp)) (c-beginning-of-macro) (point)))) - res ; result from sub-function call - not-bos ; "not beginning-of-statement" - (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL - - ;; Go back one statement at each iteration of the following loop. - (while (and (/= count 0) - (or (not lim) (> (point) lim))) - ;; Go back one "chunk" each time round the following loop, stopping - ;; when we reach a statement boundary, etc. - (setq last (point)) - (while - (cond ; Each arm of this cond returns NIL on reaching a desired - ; statement boundary, non-NIL otherwise. - ((bobp) - (setq count 0) - nil) - - (range ; point is within or approaching a literal. - (cond - ;; Single line string or sentence-flag is null => skip the - ;; entire literal. - ((or (null sentence-flag) - (c-one-line-string-p range)) - (goto-char (car range)) - (setq range (c-ascertain-preceding-literal)) - ;; N.B. The following is essentially testing for an AWK regexp - ;; at BOS: - ;; Was the previous non-ws thing an end of statement? - (save-excursion - (if macro-fence - (c-backward-comments) - (c-backward-syntactic-ws)) - (not (or (bobp) (c-after-statement-terminator-p))))) - - ;; Comment inside a statement or a multi-line string. - (t (when (setq res ; returns non-nil when we go out of the literal - (if (eq (c-literal-type range) 'string) - (c-beginning-of-sentence-in-string range) - (c-beginning-of-sentence-in-comment range))) - (setq range (c-ascertain-preceding-literal))) - res))) - - ;; Non-literal code. - (t (setq res (c-back-over-illiterals macro-fence)) - (setq not-bos ; "not reached beginning-of-statement". - (or (= (point) last) - (memq (char-after) '(?\) ?\})) - (and - (car res) - ;; We're at a tentative BOS. The next form goes - ;; back over WS looking for an end of previous - ;; statement. - (not (save-excursion - (if macro-fence - (c-backward-comments) - (c-backward-syntactic-ws)) - (or (bobp) (c-after-statement-terminator-p))))))) - ;; Are we about to move backwards into or out of a - ;; preprocessor command? If so, locate its beginning. - (when (eq (cdr res) 'macro-boundary) - (save-excursion - (beginning-of-line) - (setq macro-fence - (and (not (bobp)) - (progn (c-skip-ws-backward) (c-beginning-of-macro)) - (point))))) - ;; Are we about to move backwards into a literal? - (when (memq (cdr res) '(macro-boundary literal)) - (setq range (c-ascertain-preceding-literal))) - not-bos)) - (setq last (point))) - - (if (/= count 0) (setq count (1- count)))) - (c-keep-region-active)))) + (c-with-string-fences + (c-save-buffer-state + ((count (or count 1)) + last ; start point for going back ONE chunk. Updated each chunk movement. + (macro-fence + (save-excursion (and (not (bobp)) (c-beginning-of-macro) (point)))) + res ; result from sub-function call + not-bos ; "not beginning-of-statement" + (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL + + ;; Go back one statement at each iteration of the following loop. + (while (and (/= count 0) + (or (not lim) (> (point) lim))) + ;; Go back one "chunk" each time round the following loop, stopping + ;; when we reach a statement boundary, etc. + (setq last (point)) + (while + (cond ; Each arm of this cond returns NIL on reaching a desired + ; statement boundary, non-NIL otherwise. + ((bobp) + (setq count 0) + nil) + + (range ; point is within or approaching a literal. + (cond + ;; Single line string or sentence-flag is null => skip the + ;; entire literal. + ((or (null sentence-flag) + (c-one-line-string-p range)) + (goto-char (car range)) + (setq range (c-ascertain-preceding-literal)) + ;; N.B. The following is essentially testing for an AWK regexp + ;; at BOS: + ;; Was the previous non-ws thing an end of statement? + (save-excursion + (if macro-fence + (c-backward-comments) + (c-backward-syntactic-ws)) + (not (or (bobp) (c-after-statement-terminator-p))))) + + ;; Comment inside a statement or a multi-line string. + (t (when (setq res ; returns non-nil when we go out of the literal + (if (eq (c-literal-type range) 'string) + (c-beginning-of-sentence-in-string range) + (c-beginning-of-sentence-in-comment range))) + (setq range (c-ascertain-preceding-literal))) + res))) + + ;; Non-literal code. + (t (setq res (c-back-over-illiterals macro-fence)) + (setq not-bos ; "not reached beginning-of-statement". + (or (= (point) last) + (memq (char-after) '(?\) ?\})) + (and + (car res) + ;; We're at a tentative BOS. The next form goes + ;; back over WS looking for an end of previous + ;; statement. + (not (save-excursion + (if macro-fence + (c-backward-comments) + (c-backward-syntactic-ws)) + (or (bobp) (c-after-statement-terminator-p))))))) + ;; Are we about to move backwards into or out of a + ;; preprocessor command? If so, locate its beginning. + (when (eq (cdr res) 'macro-boundary) + (save-excursion + (beginning-of-line) + (setq macro-fence + (and (not (bobp)) + (progn (c-skip-ws-backward) (c-beginning-of-macro)) + (point))))) + ;; Are we about to move backwards into a literal? + (when (memq (cdr res) '(macro-boundary literal)) + (setq range (c-ascertain-preceding-literal))) + not-bos)) + (setq last (point))) + + (if (/= count 0) (setq count (1- count)))) + (c-keep-region-active))))) (defun c-end-of-statement (&optional count lim sentence-flag) "Go to the end of the innermost C statement. @@ -3129,78 +3149,79 @@ c-end-of-statement (setq count (or count 1)) (if (< count 0) (c-beginning-of-statement (- count) lim sentence-flag) - (c-save-buffer-state - (here ; start point for going forward ONE statement. Updated each statement. - (macro-fence - (save-excursion - (and (not (eobp)) (c-beginning-of-macro) - (progn (c-end-of-macro) (point))))) - res - (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL - - ;; Go back/forward one statement at each iteration of the following loop. - (while (and (/= count 0) - (or (not lim) (< (point) lim))) - (setq here (point)) ; ONLY HERE is HERE updated - - ;; Go forward one "chunk" each time round the following loop, stopping - ;; when we reach a statement boundary, etc. - (while - (cond ; Each arm of this cond returns NIL on reaching a desired - ; statement boundary, non-NIL otherwise. - ((eobp) - (setq count 0) - nil) + (c-with-string-fences + (c-save-buffer-state + (here ; start point for going forward ONE statement. Updated each statement. + (macro-fence + (save-excursion + (and (not (eobp)) (c-beginning-of-macro) + (progn (c-end-of-macro) (point))))) + res + (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL + + ;; Go back/forward one statement at each iteration of the following loop. + (while (and (/= count 0) + (or (not lim) (< (point) lim))) + (setq here (point)) ; ONLY HERE is HERE updated + + ;; Go forward one "chunk" each time round the following loop, stopping + ;; when we reach a statement boundary, etc. + (while + (cond ; Each arm of this cond returns NIL on reaching a desired + ; statement boundary, non-NIL otherwise. + ((eobp) + (setq count 0) + nil) + + (range ; point is within a literal. + (cond + ;; sentence-flag is null => skip the entire literal. + ;; or a Single line string. + ((or (null sentence-flag) + (c-one-line-string-p range)) + (goto-char (cdr range)) + (setq range (c-ascertain-following-literal)) + ;; Is there a virtual semicolon here (e.g. for AWK)? + (not (c-at-vsemi-p))) + + ;; Comment or multi-line string. + (t (when (setq res ; gets non-nil when we go out of the literal + (if (eq (c-literal-type range) 'string) + (c-end-of-sentence-in-string range) + (c-end-of-sentence-in-comment range))) + (setq range (c-ascertain-following-literal))) + ;; If we've just come forward out of a literal, check for + ;; vsemi. (N.B. AWK can't have a vsemi after a comment, but + ;; some other language may do in the future) + (and res + (not (c-at-vsemi-p)))))) + + ;; Non-literal code. + (t (setq res (c-forward-over-illiterals macro-fence + (> (point) here))) + ;; Are we about to move forward into or out of a + ;; preprocessor command? + (when (eq (cdr res) 'macro-boundary) + (setq macro-fence + (save-excursion + (if macro-fence + (progn + (end-of-line) + (and (not (eobp)) + (progn (c-skip-ws-forward) + (c-beginning-of-macro)) + (progn (c-end-of-macro) + (point)))) + (and (not (eobp)) + (c-beginning-of-macro) + (progn (c-end-of-macro) (point))))))) + ;; Are we about to move forward into a literal? + (when (memq (cdr res) '(macro-boundary literal)) + (setq range (c-ascertain-following-literal))) + (car res)))) - (range ; point is within a literal. - (cond - ;; sentence-flag is null => skip the entire literal. - ;; or a Single line string. - ((or (null sentence-flag) - (c-one-line-string-p range)) - (goto-char (cdr range)) - (setq range (c-ascertain-following-literal)) - ;; Is there a virtual semicolon here (e.g. for AWK)? - (not (c-at-vsemi-p))) - - ;; Comment or multi-line string. - (t (when (setq res ; gets non-nil when we go out of the literal - (if (eq (c-literal-type range) 'string) - (c-end-of-sentence-in-string range) - (c-end-of-sentence-in-comment range))) - (setq range (c-ascertain-following-literal))) - ;; If we've just come forward out of a literal, check for - ;; vsemi. (N.B. AWK can't have a vsemi after a comment, but - ;; some other language may do in the future) - (and res - (not (c-at-vsemi-p)))))) - - ;; Non-literal code. - (t (setq res (c-forward-over-illiterals macro-fence - (> (point) here))) - ;; Are we about to move forward into or out of a - ;; preprocessor command? - (when (eq (cdr res) 'macro-boundary) - (setq macro-fence - (save-excursion - (if macro-fence - (progn - (end-of-line) - (and (not (eobp)) - (progn (c-skip-ws-forward) - (c-beginning-of-macro)) - (progn (c-end-of-macro) - (point)))) - (and (not (eobp)) - (c-beginning-of-macro) - (progn (c-end-of-macro) (point))))))) - ;; Are we about to move forward into a literal? - (when (memq (cdr res) '(macro-boundary literal)) - (setq range (c-ascertain-following-literal))) - (car res)))) - - (if (/= count 0) (setq count (1- count)))) - (c-keep-region-active)))) + (if (/= count 0) (setq count (1- count)))) + (c-keep-region-active))))) ;; set up electric character functions to work with pending-del, @@ -3539,122 +3560,125 @@ c-indent-command depending on the variable `indent-tabs-mode'." (interactive "P") - (let ((indent-function - (if c-syntactic-indentation - (symbol-function 'indent-according-to-mode) - (lambda () - (let ((c-macro-start c-macro-start) - (steps (if (equal arg '(4)) - -1 - (prefix-numeric-value arg)))) - (c-shift-line-indentation (* steps c-basic-offset)) - (when (and c-auto-align-backslashes - (save-excursion - (end-of-line) - (eq (char-before) ?\\)) - (c-query-and-set-macro-start)) - ;; Realign the line continuation backslash if inside a macro. - (c-backslash-region (point) (point) nil t))) - )))) - (if (and c-syntactic-indentation arg) - ;; If c-syntactic-indentation and got arg, always indent this - ;; line as C and shift remaining lines of expression the same - ;; amount. - (let ((shift-amt (save-excursion - (back-to-indentation) - (current-column))) - beg end) - (c-indent-line) - (setq shift-amt (- (save-excursion - (back-to-indentation) - (current-column)) - shift-amt)) - (save-excursion - (if (eq c-tab-always-indent t) - (beginning-of-line)) ; FIXME!!! What is this here for? ACM 2005/10/31 - (setq beg (point)) - (c-forward-sexp 1) - (setq end (point)) - (goto-char beg) - (forward-line 1) - (setq beg (point))) - (if (> end beg) - (indent-code-rigidly beg end shift-amt "#"))) - ;; Else use c-tab-always-indent to determine behavior. - (cond - ;; CASE 1: indent when at column zero or in line's indentation, - ;; otherwise insert a tab - ((not c-tab-always-indent) - (if (save-excursion - (skip-chars-backward " \t") - (not (bolp))) - (funcall c-insert-tab-function) - (funcall indent-function))) - ;; CASE 2: just indent the line - ((eq c-tab-always-indent t) - (funcall indent-function)) - ;; CASE 3: if in a literal, insert a tab, but always indent the - ;; line - (t - (if (c-save-buffer-state () (c-in-literal)) - (funcall c-insert-tab-function)) - (funcall indent-function) - ))))) + (c-with-string-fences + (let ((indent-function + (if c-syntactic-indentation + (symbol-function 'indent-according-to-mode) + (lambda () + (let ((c-macro-start c-macro-start) + (steps (if (equal arg '(4)) + -1 + (prefix-numeric-value arg)))) + (c-shift-line-indentation (* steps c-basic-offset)) + (when (and c-auto-align-backslashes + (save-excursion + (end-of-line) + (eq (char-before) ?\\)) + (c-query-and-set-macro-start)) + ;; Realign the line continuation backslash if inside a macro. + (c-backslash-region (point) (point) nil t))) + )))) + (if (and c-syntactic-indentation arg) + ;; If c-syntactic-indentation and got arg, always indent this + ;; line as C and shift remaining lines of expression the same + ;; amount. + (let ((shift-amt (save-excursion + (back-to-indentation) + (current-column))) + beg end) + (c-indent-line) + (setq shift-amt (- (save-excursion + (back-to-indentation) + (current-column)) + shift-amt)) + (save-excursion + (if (eq c-tab-always-indent t) + (beginning-of-line)) ; FIXME!!! What is this here for? ACM 2005/10/31 + (setq beg (point)) + (c-forward-sexp 1) + (setq end (point)) + (goto-char beg) + (forward-line 1) + (setq beg (point))) + (if (> end beg) + (indent-code-rigidly beg end shift-amt "#"))) + ;; Else use c-tab-always-indent to determine behavior. + (cond + ;; CASE 1: indent when at column zero or in line's indentation, + ;; otherwise insert a tab + ((not c-tab-always-indent) + (if (save-excursion + (skip-chars-backward " \t") + (not (bolp))) + (funcall c-insert-tab-function) + (funcall indent-function))) + ;; CASE 2: just indent the line + ((eq c-tab-always-indent t) + (funcall indent-function)) + ;; CASE 3: if in a literal, insert a tab, but always indent the + ;; line + (t + (if (c-save-buffer-state () (c-in-literal)) + (funcall c-insert-tab-function)) + (funcall indent-function) + )))))) (defun c-indent-exp (&optional shutup-p) "Indent each line in the balanced expression following point syntactically. If optional SHUTUP-P is non-nil, no errors are signaled if no balanced expression is found." (interactive "*P") - (let ((here (point-marker)) - end) - (set-marker-insertion-type here t) - (unwind-protect - (let ((start (save-restriction - ;; Find the closest following open paren that - ;; ends on another line. - (narrow-to-region (point-min) (c-point 'eol)) - (let (beg (end (point))) - (while (and (setq beg (c-down-list-forward end)) - (setq end (c-up-list-forward beg)))) - (and beg - (eq (char-syntax (char-before beg)) ?\() - (1- beg)))))) - ;; sanity check - (if (not start) - (unless shutup-p - (error "Cannot find start of balanced expression to indent")) - (goto-char start) - (setq end (c-safe (scan-sexps (point) 1))) - (if (not end) - (unless shutup-p - (error "Cannot find end of balanced expression to indent")) - (forward-line) - (if (< (point) end) - (c-indent-region (point) end))))) - (goto-char here) - (set-marker here nil)))) + (c-with-string-fences + (let ((here (point-marker)) + end) + (set-marker-insertion-type here t) + (unwind-protect + (let ((start (save-restriction + ;; Find the closest following open paren that + ;; ends on another line. + (narrow-to-region (point-min) (c-point 'eol)) + (let (beg (end (point))) + (while (and (setq beg (c-down-list-forward end)) + (setq end (c-up-list-forward beg)))) + (and beg + (eq (char-syntax (char-before beg)) ?\() + (1- beg)))))) + ;; sanity check + (if (not start) + (unless shutup-p + (error "Cannot find start of balanced expression to indent")) + (goto-char start) + (setq end (c-safe (scan-sexps (point) 1))) + (if (not end) + (unless shutup-p + (error "Cannot find end of balanced expression to indent")) + (forward-line) + (if (< (point) end) + (c-indent-region (point) end))))) + (goto-char here) + (set-marker here nil))))) (defun c-indent-defun () "Indent the current top-level declaration or macro syntactically. In the macro case this also has the effect of realigning any line continuation backslashes, unless `c-auto-align-backslashes' is nil." (interactive "*") - (let ((here (point-marker)) decl-limits case-fold-search) - (unwind-protect - (progn - (c-save-buffer-state nil - ;; We try to be line oriented, unless there are several - ;; declarations on the same line. - (if (looking-at c-syntactic-eol) - (c-backward-token-2 1 nil (c-point 'bol)) - (c-forward-token-2 0 nil (c-point 'eol))) - (setq decl-limits (c-declaration-limits nil))) - (if decl-limits - (c-indent-region (car decl-limits) - (cdr decl-limits)))) - (goto-char here) - (set-marker here nil)))) + (c-with-string-fences + (let ((here (point-marker)) decl-limits case-fold-search) + (unwind-protect + (progn + (c-save-buffer-state nil + ;; We try to be line oriented, unless there are several + ;; declarations on the same line. + (if (looking-at c-syntactic-eol) + (c-backward-token-2 1 nil (c-point 'bol)) + (c-forward-token-2 0 nil (c-point 'eol))) + (setq decl-limits (c-declaration-limits nil))) + (if decl-limits + (c-indent-region (car decl-limits) + (cdr decl-limits)))) + (goto-char here) + (set-marker here nil))))) (defun c-indent-region (start end &optional quiet) "Indent syntactically lines whose first char is between START and END inclusive. @@ -3734,9 +3758,10 @@ c-indent-line-or-region Otherwise reindent just the current line." (interactive (list current-prefix-arg (c-region-is-active-p))) - (if region - (c-indent-region (region-beginning) (region-end)) - (c-indent-command arg))) + (c-with-string-fences + (if region + (c-indent-region (region-beginning) (region-end)) + (c-indent-command arg)))) ;; for progress reporting (defvar c-progress-info nil) @@ -4823,15 +4848,16 @@ c-fill-paragraph Optional prefix ARG means justify paragraph as well." (interactive "*P") - (let ((fill-paragraph-function - ;; Avoid infinite recursion. - (if (not (eq fill-paragraph-function 'c-fill-paragraph)) - fill-paragraph-function))) - (c-mask-paragraph t nil 'fill-paragraph arg)) - ;; Always return t. This has the effect that if filling isn't done - ;; above, it isn't done at all, and it's therefore effectively - ;; disabled in normal code. - t) + (c-with-string-fences + (let ((fill-paragraph-function + ;; Avoid infinite recursion. + (if (not (eq fill-paragraph-function 'c-fill-paragraph)) + fill-paragraph-function))) + (c-mask-paragraph t nil 'fill-paragraph arg)) + ;; Always return t. This has the effect that if filling isn't done + ;; above, it isn't done at all, and it's therefore effectively + ;; disabled in normal code. + t)) (defun c-do-auto-fill () ;; Do automatic filling if not inside a context where it should be @@ -4863,165 +4889,166 @@ c-indent-new-comment-line ;; used from auto-fill itself, that's normally disabled to avoid ;; unnecessary recursion. (interactive) - (let ((fill-prefix fill-prefix) - (do-line-break - (lambda () - (delete-horizontal-space) - (if soft - (insert-and-inherit ?\n) - (newline (if allow-auto-fill nil 1))))) - ;; Already know the literal type and limits when called from - ;; c-context-line-break. - (c-lit-limits c-lit-limits) - (c-lit-type c-lit-type) - (c-macro-start c-macro-start)) - - (c-save-buffer-state () - (when (not (eq c-auto-fill-prefix t)) - ;; Called from do-auto-fill. - (unless c-lit-limits - (setq c-lit-limits (c-literal-limits nil nil t))) - (unless c-lit-type - (setq c-lit-type (c-literal-type c-lit-limits))) - (if (memq (cond ((c-query-and-set-macro-start) 'cpp) - ((null c-lit-type) 'code) - (t c-lit-type)) - c-ignore-auto-fill) - (setq fill-prefix t) ; Used as flag in the cond. - (if (and (null c-auto-fill-prefix) - (eq c-lit-type 'c) - (<= (c-point 'bol) (car c-lit-limits))) - ;; The adaptive fill function has generated a prefix, but - ;; we're on the first line in a block comment so it'll be - ;; wrong. Ignore it to guess a better one below. - (setq fill-prefix nil) - (when (and (eq c-lit-type 'c++) - (not (string-match (concat "\\`[ \t]*" - c-line-comment-starter) - (or fill-prefix "")))) - ;; Kludge: If the function that adapted the fill prefix - ;; doesn't produce the required comment starter for line - ;; comments, then we ignore it. - (setq fill-prefix nil))) - ))) - - (cond ((eq fill-prefix t) - ;; A call from do-auto-fill which should be ignored. - ) - (fill-prefix - ;; A fill-prefix overrides anything. - (funcall do-line-break) - (insert-and-inherit fill-prefix)) - ((c-save-buffer-state () - (unless c-lit-limits - (setq c-lit-limits (c-literal-limits))) - (unless c-lit-type - (setq c-lit-type (c-literal-type c-lit-limits))) - (memq c-lit-type '(c c++))) - ;; Some sort of comment. - (if (or comment-multi-line - (save-excursion - (goto-char (car c-lit-limits)) - (end-of-line) - (< (point) (cdr c-lit-limits)))) - ;; Inside a comment that should be continued. - (let ((fill (c-save-buffer-state nil - (c-guess-fill-prefix - (setq c-lit-limits - (c-collect-line-comments c-lit-limits)) - c-lit-type))) - (pos (point)) - (comment-text-end - (or (and (eq c-lit-type 'c) - (save-excursion - (goto-char (- (cdr c-lit-limits) 2)) - (if (looking-at "\\*/") (point)))) - (cdr c-lit-limits)))) - ;; Skip forward past the fill prefix in case - ;; we're standing in it. - ;; - ;; FIXME: This doesn't work well in cases like - ;; - ;; /* Bla bla bla bla bla - ;; bla bla - ;; - ;; If point is on the 'B' then the line will be - ;; broken after "Bla b". - ;; - ;; If we have an empty comment, /* */, the next - ;; lot of code pushes point to the */. We fix - ;; this by never allowing point to end up to the - ;; right of where it started. - (while (and (< (current-column) (cdr fill)) - (not (eolp))) - (forward-char 1)) - (if (and (> (point) comment-text-end) - (> (c-point 'bol) (car c-lit-limits))) - (progn - ;; The skip takes us out of the (block) - ;; comment; insert the fill prefix at bol - ;; instead and keep the position. - (setq pos (copy-marker pos t)) - (beginning-of-line) - (insert-and-inherit (car fill)) - (if soft (insert-and-inherit ?\n) (newline 1)) - (goto-char pos) - (set-marker pos nil)) - ;; Don't break in the middle of a comment starter - ;; or ender. - (cond ((> (point) comment-text-end) - (goto-char comment-text-end)) - ((< (point) (+ (car c-lit-limits) 2)) - (goto-char (+ (car c-lit-limits) 2)))) - (funcall do-line-break) - (insert-and-inherit (car fill)) - (if (and (looking-at c-block-comment-ender-regexp) - (memq (char-before) '(?\ ?\t))) - (backward-char)))) ; can this hit the - ; middle of a TAB? - ;; Inside a comment that should be broken. - (let ((comment-start comment-start) - (comment-end comment-end) - col) - (if (eq c-lit-type 'c) - (unless (string-match "[ \t]*/\\*" comment-start) - (setq comment-start "/* " comment-end " */")) - (unless (string-match "[ \t]*//" comment-start) - (setq comment-start "// " comment-end ""))) - (setq col (save-excursion - (back-to-indentation) - (current-column))) - (funcall do-line-break) - (when (and comment-end (not (equal comment-end ""))) - (forward-char -1) - (insert-and-inherit comment-end) - (forward-char 1)) - ;; c-comment-indent may look at the current - ;; indentation, so let's start out with the same - ;; indentation as the previous one. - (indent-to col) - (insert-and-inherit comment-start) - (indent-for-comment)))) - ((c-query-and-set-macro-start) - ;; In a macro. - (unless (looking-at "[ \t]*\\\\$") - ;; Do not clobber the alignment of the line continuation - ;; slash; c-backslash-region might look at it. - (delete-horizontal-space)) - ;; Got an asymmetry here: In normal code this command - ;; doesn't indent the next line syntactically, and otoh a - ;; normal syntactically indenting newline doesn't continue - ;; the macro. - (c-newline-and-indent (if allow-auto-fill nil 1))) - (t - ;; Somewhere else in the code. - (let ((col (save-excursion + (c-with-string-fences + (let ((fill-prefix fill-prefix) + (do-line-break + (lambda () + (delete-horizontal-space) + (if soft + (insert-and-inherit ?\n) + (newline (if allow-auto-fill nil 1))))) + ;; Already know the literal type and limits when called from + ;; c-context-line-break. + (c-lit-limits c-lit-limits) + (c-lit-type c-lit-type) + (c-macro-start c-macro-start)) + + (c-save-buffer-state () + (when (not (eq c-auto-fill-prefix t)) + ;; Called from do-auto-fill. + (unless c-lit-limits + (setq c-lit-limits (c-literal-limits nil nil t))) + (unless c-lit-type + (setq c-lit-type (c-literal-type c-lit-limits))) + (if (memq (cond ((c-query-and-set-macro-start) 'cpp) + ((null c-lit-type) 'code) + (t c-lit-type)) + c-ignore-auto-fill) + (setq fill-prefix t) ; Used as flag in the cond. + (if (and (null c-auto-fill-prefix) + (eq c-lit-type 'c) + (<= (c-point 'bol) (car c-lit-limits))) + ;; The adaptive fill function has generated a prefix, but + ;; we're on the first line in a block comment so it'll be + ;; wrong. Ignore it to guess a better one below. + (setq fill-prefix nil) + (when (and (eq c-lit-type 'c++) + (not (string-match (concat "\\`[ \t]*" + c-line-comment-starter) + (or fill-prefix "")))) + ;; Kludge: If the function that adapted the fill prefix + ;; doesn't produce the required comment starter for line + ;; comments, then we ignore it. + (setq fill-prefix nil))) + ))) + + (cond ((eq fill-prefix t) + ;; A call from do-auto-fill which should be ignored. + ) + (fill-prefix + ;; A fill-prefix overrides anything. + (funcall do-line-break) + (insert-and-inherit fill-prefix)) + ((c-save-buffer-state () + (unless c-lit-limits + (setq c-lit-limits (c-literal-limits))) + (unless c-lit-type + (setq c-lit-type (c-literal-type c-lit-limits))) + (memq c-lit-type '(c c++))) + ;; Some sort of comment. + (if (or comment-multi-line + (save-excursion + (goto-char (car c-lit-limits)) + (end-of-line) + (< (point) (cdr c-lit-limits)))) + ;; Inside a comment that should be continued. + (let ((fill (c-save-buffer-state nil + (c-guess-fill-prefix + (setq c-lit-limits + (c-collect-line-comments c-lit-limits)) + c-lit-type))) + (pos (point)) + (comment-text-end + (or (and (eq c-lit-type 'c) + (save-excursion + (goto-char (- (cdr c-lit-limits) 2)) + (if (looking-at "\\*/") (point)))) + (cdr c-lit-limits)))) + ;; Skip forward past the fill prefix in case + ;; we're standing in it. + ;; + ;; FIXME: This doesn't work well in cases like + ;; + ;; /* Bla bla bla bla bla + ;; bla bla + ;; + ;; If point is on the 'B' then the line will be + ;; broken after "Bla b". + ;; + ;; If we have an empty comment, /* */, the next + ;; lot of code pushes point to the */. We fix + ;; this by never allowing point to end up to the + ;; right of where it started. + (while (and (< (current-column) (cdr fill)) + (not (eolp))) + (forward-char 1)) + (if (and (> (point) comment-text-end) + (> (c-point 'bol) (car c-lit-limits))) + (progn + ;; The skip takes us out of the (block) + ;; comment; insert the fill prefix at bol + ;; instead and keep the position. + (setq pos (copy-marker pos t)) (beginning-of-line) - (while (and (looking-at "[ \t]*\\\\?$") - (= (forward-line -1) 0))) - (current-indentation)))) - (funcall do-line-break) - (indent-to col)))))) + (insert-and-inherit (car fill)) + (if soft (insert-and-inherit ?\n) (newline 1)) + (goto-char pos) + (set-marker pos nil)) + ;; Don't break in the middle of a comment starter + ;; or ender. + (cond ((> (point) comment-text-end) + (goto-char comment-text-end)) + ((< (point) (+ (car c-lit-limits) 2)) + (goto-char (+ (car c-lit-limits) 2)))) + (funcall do-line-break) + (insert-and-inherit (car fill)) + (if (and (looking-at c-block-comment-ender-regexp) + (memq (char-before) '(?\ ?\t))) + (backward-char)))) ; can this hit the + ; middle of a TAB? + ;; Inside a comment that should be broken. + (let ((comment-start comment-start) + (comment-end comment-end) + col) + (if (eq c-lit-type 'c) + (unless (string-match "[ \t]*/\\*" comment-start) + (setq comment-start "/* " comment-end " */")) + (unless (string-match "[ \t]*//" comment-start) + (setq comment-start "// " comment-end ""))) + (setq col (save-excursion + (back-to-indentation) + (current-column))) + (funcall do-line-break) + (when (and comment-end (not (equal comment-end ""))) + (forward-char -1) + (insert-and-inherit comment-end) + (forward-char 1)) + ;; c-comment-indent may look at the current + ;; indentation, so let's start out with the same + ;; indentation as the previous one. + (indent-to col) + (insert-and-inherit comment-start) + (indent-for-comment)))) + ((c-query-and-set-macro-start) + ;; In a macro. + (unless (looking-at "[ \t]*\\\\$") + ;; Do not clobber the alignment of the line continuation + ;; slash; c-backslash-region might look at it. + (delete-horizontal-space)) + ;; Got an asymmetry here: In normal code this command + ;; doesn't indent the next line syntactically, and otoh a + ;; normal syntactically indenting newline doesn't continue + ;; the macro. + (c-newline-and-indent (if allow-auto-fill nil 1))) + (t + ;; Somewhere else in the code. + (let ((col (save-excursion + (beginning-of-line) + (while (and (looking-at "[ \t]*\\\\?$") + (= (forward-line -1) 0))) + (current-indentation)))) + (funcall do-line-break) + (indent-to col))))))) (defalias 'c-comment-line-break-function 'c-indent-new-comment-line) (make-obsolete 'c-comment-line-break-function 'c-indent-new-comment-line "21.1") @@ -5048,58 +5075,59 @@ c-context-line-break inside a preprocessor directive." (interactive "*") - (let* (c-lit-limits c-lit-type - (c-macro-start c-macro-start) - case-fold-search) - - (c-save-buffer-state () - (setq c-lit-limits (c-literal-limits nil nil t) - c-lit-type (c-literal-type c-lit-limits)) - (when (eq c-lit-type 'c++) - (setq c-lit-limits (c-collect-line-comments c-lit-limits))) - (c-query-and-set-macro-start)) - - (cond - ((or (eq c-lit-type 'c) - (and (eq c-lit-type 'c++) ; C++ comment, but not at the very end of it. - (< (save-excursion - (skip-chars-forward " \t") - (point)) - (1- (cdr c-lit-limits)))) - (and (numberp c-macro-start) ; Macro, but not at the very end of + (c-with-string-fences + (let* (c-lit-limits c-lit-type + (c-macro-start c-macro-start) + case-fold-search) + + (c-save-buffer-state () + (setq c-lit-limits (c-literal-limits nil nil t) + c-lit-type (c-literal-type c-lit-limits)) + (when (eq c-lit-type 'c++) + (setq c-lit-limits (c-collect-line-comments c-lit-limits))) + (c-query-and-set-macro-start)) + + (cond + ((or (eq c-lit-type 'c) + (and (eq c-lit-type 'c++) ; C++ comment, but not at the very end of it. + (< (save-excursion + (skip-chars-forward " \t") + (point)) + (1- (cdr c-lit-limits)))) + (and (numberp c-macro-start) ; Macro, but not at the very end of ; it, not in a string, and not in the ; cpp keyword. - (not (eq c-lit-type 'string)) - (or (not (looking-at "\\s *$")) - (eq (char-before) ?\\)) - (<= (save-excursion - (goto-char c-macro-start) - (if (looking-at c-opt-cpp-start) - (goto-char (match-end 0))) - (point)) - (point)))) - (let ((comment-multi-line t) - (fill-prefix nil)) - (c-indent-new-comment-line nil t))) - - ((eq c-lit-type 'string) - (if (and (numberp c-macro-start) - (not (eq (char-before) ?\\))) - (insert ?\\)) - (newline)) - - (t (delete-horizontal-space) - (newline) - ;; c-indent-line may look at the current indentation, so let's - ;; start out with the same indentation as the previous line. - (let ((col (save-excursion - (backward-char) - (forward-line 0) - (while (and (looking-at "[ \t]*\\\\?$") - (= (forward-line -1) 0))) - (current-indentation)))) - (indent-to col)) - (indent-according-to-mode))))) + (not (eq c-lit-type 'string)) + (or (not (looking-at "\\s *$")) + (eq (char-before) ?\\)) + (<= (save-excursion + (goto-char c-macro-start) + (if (looking-at c-opt-cpp-start) + (goto-char (match-end 0))) + (point)) + (point)))) + (let ((comment-multi-line t) + (fill-prefix nil)) + (c-indent-new-comment-line nil t))) + + ((eq c-lit-type 'string) + (if (and (numberp c-macro-start) + (not (eq (char-before) ?\\))) + (insert ?\\)) + (newline)) + + (t (delete-horizontal-space) + (newline) + ;; c-indent-line may look at the current indentation, so let's + ;; start out with the same indentation as the previous line. + (let ((col (save-excursion + (backward-char) + (forward-line 0) + (while (and (looking-at "[ \t]*\\\\?$") + (= (forward-line -1) 0))) + (current-indentation)))) + (indent-to col)) + (indent-according-to-mode)))))) (defun c-context-open-line () "Insert a line break suitable to the context and leave point before it. diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index a127024355..54bedb4d9c 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -1562,6 +1562,27 @@ c-put-char-properties-on-char (c-put-char-property (point) ,property ,value) (forward-char))))) + +;; Miscellaneous macro(s) +(defvar c-string-fences-set-flag nil) +;; Non-nil when we have set string fences with `c-restore-string-fences'. +(defmacro c-with-string-fences (&rest forms) + ;; Restore the string fences, evaluate FORMS, then remove them again. It + ;; should only be used at the top level of "boundary" functions in CC Mode, + ;; i.e. those called from outside CC Mode which directly or indirectly need + ;; unbalanced string markers to have their string-fence syntax-table text + ;; properties. This includes all calls to `c-parse-state'. This macro will + ;; be invoked recursively; however the `c-string-fences-set-flag' mechanism + ;; should ensure consistency, when this happens. + `(unwind-protect + (progn + (unless c-string-fences-set-flag + (c-restore-string-fences)) + (let ((c-string-fences-set-flag t)) + ,@forms)) + (unless c-string-fences-set-flag + (c-clear-string-fences)))) + ;; Macros to put overlays (Emacs) or extents (XEmacs) on buffer text. ;; For our purposes, these are characterized by being possible to diff --git a/lisp/progmodes/cc-guess.el b/lisp/progmodes/cc-guess.el index ea5dd48986..584db86539 100644 --- a/lisp/progmodes/cc-guess.el +++ b/lisp/progmodes/cc-guess.el @@ -76,6 +76,8 @@ (cc-require 'cc-engine) (cc-require 'cc-styles) +(cc-bytecomp-defun c-restore-string-fences) +(cc-bytecomp-defun c-clear-string-fences) (defcustom c-guess-offset-threshold 10 @@ -225,11 +227,12 @@ c-guess-region-no-install Note that the larger the region to guess in, the slower the guessing. So you can limit the region with `c-guess-region-max'." (interactive "r\nP") - (let ((accumulator (when accumulate c-guess-accumulator))) - (setq c-guess-accumulator (c-guess-examine start end accumulator)) - (let ((pair (c-guess-guess c-guess-accumulator))) - (setq c-guess-guessed-basic-offset (car pair) - c-guess-guessed-offsets-alist (cdr pair))))) + (c-with-string-fences + (let ((accumulator (when accumulate c-guess-accumulator))) + (setq c-guess-accumulator (c-guess-examine start end accumulator)) + (let ((pair (c-guess-guess c-guess-accumulator))) + (setq c-guess-guessed-basic-offset (car pair) + c-guess-guessed-offsets-alist (cdr pair)))))) (defun c-guess-examine (start end accumulator) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 957a0b8a7c..d65c87e847 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -997,7 +997,8 @@ c-called-from-text-property-change-p ;; `c-before/after-change', frame 3 is the primitive invoking the change ;; hook. (memq (cadr (backtrace-frame 3)) - '(put-text-property remove-list-of-text-properties))) + '(put-text-property remove-text-properties + remove-list-of-text-properties))) (defun c-depropertize-CPP (beg end) ;; Remove the punctuation syntax-table text property from the CPP parts of @@ -1319,7 +1320,8 @@ c-clear-string-fences ;; balanced by another " is left with a '(1) syntax-table property. (when (and c-min-syn-tab-mkr c-max-syn-tab-mkr) - (let (s pos) + (c-save-buffer-state (s pos) ; Prevent text property stuff causing change + ; function invocation. (setq pos c-min-syn-tab-mkr) (while (and @@ -1342,7 +1344,8 @@ c-clear-string-fences (c-search-backward-char-property-with-value-on-char 'c-fl-syn-tab '(15) ?\" (max (- (point) 500) (point-min)))) - (not (equal (c-get-char-property (point) 'syntax-table) '(1)))) + (not (equal (c-get-char-property (point) 'syntax-table) + '(1)))) (setq pos (1+ pos)))) (while (< pos c-max-syn-tab-mkr) (setq pos @@ -1372,7 +1375,9 @@ c-restore-string-fences ;; Restore any syntax-table text properties which are "mirrored" by ;; c-fl-syn-tab text properties. (when (and c-min-syn-tab-mkr c-max-syn-tab-mkr) - (let ((pos c-min-syn-tab-mkr)) + (c-save-buffer-state ; Prevent text property stuff causing change function + ; invocation. + ((pos c-min-syn-tab-mkr)) (while (and (< pos c-max-syn-tab-mkr) @@ -2016,120 +2021,116 @@ c-before-change ;; or a comment - "wrongly" removing a symbol from `c-found-types' ;; isn't critical. (unless (c-called-from-text-property-change-p) - (save-restriction - (widen) - ;; Clear the list of found types if we make a change at the start of the - ;; buffer, to make it easier to get rid of misspelled types and - ;; variables that have gotten recognized as types in malformed code. - (when (eq beg (point-min)) - (c-clear-found-types)) - (if c-just-done-before-change - ;; We have two consecutive calls to `before-change-functions' - ;; without an intervening `after-change-functions'. An example of - ;; this is bug #38691. To protect CC Mode, assume that the entire - ;; buffer has changed. - (setq beg (point-min) - end (point-max) - c-just-done-before-change 'whole-buffer) - (setq c-just-done-before-change t)) - ;; (c-new-BEG c-new-END) will be the region to fontify. - (setq c-new-BEG beg c-new-END end) - (setq c-maybe-stale-found-type nil) - ;; A workaround for syntax-ppss's failure to notice syntax-table text - ;; property changes. - (when (fboundp 'syntax-ppss) - (setq c-syntax-table-hwm most-positive-fixnum)) - (save-match-data - (widen) - (unwind-protect - (progn - (c-restore-string-fences) - (save-excursion - ;; Are we inserting/deleting stuff in the middle of an - ;; identifier? - (c-unfind-enclosing-token beg) - (c-unfind-enclosing-token end) - ;; Are we coalescing two tokens together, e.g. "fo o" - ;; -> "foo"? - (when (< beg end) - (c-unfind-coalesced-tokens beg end)) - (c-invalidate-sws-region-before beg end) - ;; Are we (potentially) disrupting the syntactic - ;; context which makes a type a type? E.g. by - ;; inserting stuff after "foo" in "foo bar;", or - ;; before "foo" in "typedef foo *bar;"? - ;; - ;; We search for appropriate c-type properties "near" - ;; the change. First, find an appropriate boundary - ;; for this property search. - (let (lim lim-2 - type type-pos - marked-id term-pos - (end1 - (or (and (eq (get-text-property end 'face) - 'font-lock-comment-face) - (previous-single-property-change end 'face)) - end))) - (when (>= end1 beg) ; Don't hassle about changes entirely in + (c-with-string-fences + (save-restriction + (widen) + ;; Clear the list of found types if we make a change at the start of the + ;; buffer, to make it easier to get rid of misspelled types and + ;; variables that have gotten recognized as types in malformed code. + (when (eq beg (point-min)) + (c-clear-found-types)) + (if c-just-done-before-change + ;; We have two consecutive calls to `before-change-functions' + ;; without an intervening `after-change-functions'. An example of + ;; this is bug #38691. To protect CC Mode, assume that the entire + ;; buffer has changed. + (setq beg (point-min) + end (point-max) + c-just-done-before-change 'whole-buffer) + (setq c-just-done-before-change t)) + ;; (c-new-BEG c-new-END) will be the region to fontify. + (setq c-new-BEG beg c-new-END end) + (setq c-maybe-stale-found-type nil) + ;; A workaround for syntax-ppss's failure to notice syntax-table text + ;; property changes. + (when (fboundp 'syntax-ppss) + (setq c-syntax-table-hwm most-positive-fixnum)) + (save-match-data + (save-excursion + ;; Are we inserting/deleting stuff in the middle of an + ;; identifier? + (c-unfind-enclosing-token beg) + (c-unfind-enclosing-token end) + ;; Are we coalescing two tokens together, e.g. "fo o" + ;; -> "foo"? + (when (< beg end) + (c-unfind-coalesced-tokens beg end)) + (c-invalidate-sws-region-before beg end) + ;; Are we (potentially) disrupting the syntactic + ;; context which makes a type a type? E.g. by + ;; inserting stuff after "foo" in "foo bar;", or + ;; before "foo" in "typedef foo *bar;"? + ;; + ;; We search for appropriate c-type properties "near" + ;; the change. First, find an appropriate boundary + ;; for this property search. + (let (lim lim-2 + type type-pos + marked-id term-pos + (end1 + (or (and (eq (get-text-property end 'face) + 'font-lock-comment-face) + (previous-single-property-change end 'face)) + end))) + (when (>= end1 beg) ; Don't hassle about changes entirely in ; comments. - ;; Find a limit for the search for a `c-type' property - ;; Point is currently undefined. A `goto-char' somewhere is needed. (2020-12-06). - (setq lim-2 (c-determine-limit 1000 (point) ; that is wrong. FIXME!!! (2020-12-06) - )) - (while - (and (/= (skip-chars-backward "^;{}" lim-2) 0) - (> (point) (point-min)) - (memq (c-get-char-property (1- (point)) 'face) - '(font-lock-comment-face font-lock-string-face)))) - (setq lim (max (point-min) (1- (point)))) - - ;; Look for the latest `c-type' property before end1 - (when (and (> end1 (point-min)) - (setq type-pos - (if (get-text-property (1- end1) 'c-type) - end1 - (previous-single-property-change end1 'c-type - nil lim)))) - (setq type (get-text-property (max (1- type-pos) lim) 'c-type)) - - (when (memq type '(c-decl-id-start c-decl-type-start)) - ;; Get the identifier, if any, that the property is on. - (goto-char (1- type-pos)) - (setq marked-id - (when (looking-at "\\(\\sw\\|\\s_\\)") - (c-beginning-of-current-token) - (buffer-substring-no-properties (point) type-pos))) - - (goto-char end1) - (setq lim-2 (c-determine-+ve-limit 1000)) - (skip-chars-forward "^;{}" lim-2) ; FIXME!!! loop for + ;; Find a limit for the search for a `c-type' property + ;; Point is currently undefined. A `goto-char' somewhere is needed. (2020-12-06). + (setq lim-2 (c-determine-limit 1000 (point) ; that is wrong. FIXME!!! (2020-12-06) + )) + (while + (and (/= (skip-chars-backward "^;{}" lim-2) 0) + (> (point) (point-min)) + (memq (c-get-char-property (1- (point)) 'face) + '(font-lock-comment-face font-lock-string-face)))) + (setq lim (max (point-min) (1- (point)))) + + ;; Look for the latest `c-type' property before end1 + (when (and (> end1 (point-min)) + (setq type-pos + (if (get-text-property (1- end1) 'c-type) + end1 + (previous-single-property-change end1 'c-type + nil lim)))) + (setq type (get-text-property (max (1- type-pos) lim) 'c-type)) + + (when (memq type '(c-decl-id-start c-decl-type-start)) + ;; Get the identifier, if any, that the property is on. + (goto-char (1- type-pos)) + (setq marked-id + (when (looking-at "\\(\\sw\\|\\s_\\)") + (c-beginning-of-current-token) + (buffer-substring-no-properties (point) type-pos))) + + (goto-char end1) + (setq lim-2 (c-determine-+ve-limit 1000)) + (skip-chars-forward "^;{}" lim-2) ; FIXME!!! loop for ; comment, maybe - (setq lim (point)) - (setq term-pos - (or (c-next-single-property-change end 'c-type nil lim) lim)) - (setq c-maybe-stale-found-type - (list type marked-id - type-pos term-pos - (buffer-substring-no-properties type-pos - term-pos) - (buffer-substring-no-properties beg end))))))) - - (if c-get-state-before-change-functions - (mapc (lambda (fn) - (funcall fn beg end)) - c-get-state-before-change-functions)) - - (c-laomib-invalidate-cache beg end))) - (c-clear-string-fences)))) - (c-truncate-lit-pos-cache beg) - ;; The following must be done here rather than in `c-after-change' - ;; because newly inserted parens would foul up the invalidation - ;; algorithm. - (c-invalidate-state-cache beg) - ;; The following must happen after the previous, which likely alters - ;; the macro cache. - (when c-opt-cpp-symbol - (c-invalidate-macro-cache beg end)))) + (setq lim (point)) + (setq term-pos + (or (c-next-single-property-change end 'c-type nil lim) lim)) + (setq c-maybe-stale-found-type + (list type marked-id + type-pos term-pos + (buffer-substring-no-properties type-pos + term-pos) + (buffer-substring-no-properties beg end))))))) + + (if c-get-state-before-change-functions + (mapc (lambda (fn) + (funcall fn beg end)) + c-get-state-before-change-functions)) + + (c-laomib-invalidate-cache beg end)))) + (c-truncate-lit-pos-cache beg) + ;; The following must be done here rather than in `c-after-change' + ;; because newly inserted parens would foul up the invalidation + ;; algorithm. + (c-invalidate-state-cache beg) + ;; The following must happen after the previous, which likely alters + ;; the macro cache. + (when c-opt-cpp-symbol + (c-invalidate-macro-cache beg end))))) (defvar c-in-after-change-fontification nil) (make-variable-buffer-local 'c-in-after-change-fontification) @@ -2457,46 +2458,42 @@ c-font-lock-fontify-region (widen) (let (new-beg new-end new-region case-fold-search) (c-save-buffer-state nil - ;; Temporarily reapply the string fence syntax-table properties. - (unwind-protect - (progn - (c-restore-string-fences) - (if (and c-in-after-change-fontification - (< beg c-new-END) (> end c-new-BEG)) - ;; Region and the latest after-change fontification region overlap. - ;; Determine the upper and lower bounds of our adjusted region - ;; separately. - (progn - (if (<= beg c-new-BEG) - (setq c-in-after-change-fontification nil)) - (setq new-beg - (if (and (>= beg (c-point 'bol c-new-BEG)) - (<= beg c-new-BEG)) - ;; Either jit-lock has accepted `c-new-BEG', or has - ;; (probably) extended the change region spuriously - ;; to BOL, which position likely has a - ;; syntactically different position. To ensure - ;; correct fontification, we start at `c-new-BEG', - ;; assuming any characters to the left of - ;; `c-new-BEG' on the line do not require - ;; fontification. - c-new-BEG - (setq new-region (c-before-context-fl-expand-region beg end) - new-end (cdr new-region)) - (car new-region))) - (setq new-end - (if (and (>= end (c-point 'bol c-new-END)) - (<= end c-new-END)) - c-new-END - (or new-end - (cdr (c-before-context-fl-expand-region beg end)))))) - ;; Context (etc.) fontification. - (setq new-region (c-before-context-fl-expand-region beg end) - new-beg (car new-region) new-end (cdr new-region))) - ;; Finally invoke font lock's functionality. - (funcall (default-value 'font-lock-fontify-region-function) - new-beg new-end verbose)) - (c-clear-string-fences)))))) + (c-with-string-fences + (if (and c-in-after-change-fontification + (< beg c-new-END) (> end c-new-BEG)) + ;; Region and the latest after-change fontification region overlap. + ;; Determine the upper and lower bounds of our adjusted region + ;; separately. + (progn + (if (<= beg c-new-BEG) + (setq c-in-after-change-fontification nil)) + (setq new-beg + (if (and (>= beg (c-point 'bol c-new-BEG)) + (<= beg c-new-BEG)) + ;; Either jit-lock has accepted `c-new-BEG', or has + ;; (probably) extended the change region spuriously + ;; to BOL, which position likely has a + ;; syntactically different position. To ensure + ;; correct fontification, we start at `c-new-BEG', + ;; assuming any characters to the left of + ;; `c-new-BEG' on the line do not require + ;; fontification. + c-new-BEG + (setq new-region (c-before-context-fl-expand-region beg end) + new-end (cdr new-region)) + (car new-region))) + (setq new-end + (if (and (>= end (c-point 'bol c-new-END)) + (<= end c-new-END)) + c-new-END + (or new-end + (cdr (c-before-context-fl-expand-region beg end)))))) + ;; Context (etc.) fontification. + (setq new-region (c-before-context-fl-expand-region beg end) + new-beg (car new-region) new-end (cdr new-region))) + ;; Finally invoke font lock's functionality. + (funcall (default-value 'font-lock-fontify-region-function) + new-beg new-end verbose)))))) (defun c-after-font-lock-init () ;; Put on `font-lock-mode-hook'. This function ensures our after-change --uNfu+MDeOpTjK3rm-- From debbugs-submit-bounces@debbugs.gnu.org Sun May 22 09:34:03 2022 Received: (at 55230) by debbugs.gnu.org; 22 May 2022 13:34:03 +0000 Received: from localhost ([127.0.0.1]:43988 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nslid-0006XE-Ay for submit@debbugs.gnu.org; Sun, 22 May 2022 09:34:03 -0400 Received: from md5i.com ([75.151.244.229]:36030) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nslia-0006Wb-Tk for 55230@debbugs.gnu.org; Sun, 22 May 2022 09:34:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=md5i.com; s=dkim; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date:References: Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=tRtrEuR6ACZ8mEYs3MJzrxMdqn+iTiS29+lCqN78Qk8=; b=xubtbG3WbcwN4USKz4h2ROaQAo fJKLgt2CMvrJ3hnx0O61+snv2AyUtyOeGdiT448JmuxBV2PMdGktkz8edByzM8XOBkHOlbStkLWy0 czegnwQJyFOqVkCJPOxM5OyIg; Received: from abode ([192.168.177.1] helo=miko) by md5i.com with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1nsliU-00DtzO-5m; Sun, 22 May 2022 09:33:54 -0400 From: Michael Welsh Duggan To: Alan Mackenzie Subject: Re: bug#55230: CC Mode 5.35.1 (C++//l); Cache inconsistency References: <875ymn4try.fsf@md5i.com> <874k1mywst.fsf@md5i.com> Date: Sun, 22 May 2022 09:33:53 -0400 In-Reply-To: (Alan Mackenzie's message of "Sat, 21 May 2022 10:03:10 +0000") Message-ID: <87h75hu1xa.fsf@md5i.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 55230 Cc: Michael Welsh Duggan , 55230@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Alan Mackenzie writes: > On Thu, May 19, 2022 at 00:24:18 -0400, Michael Welsh Duggan wrote: > >> Unfortunately, it [the patch] has some major problems. If you follow >> the original recipe, after the first brace is input cc-mode errors out >> with "Marker does not point anywhere". Backtrace follows: > >> Debugger entered--Lisp error: (error "Marker does not point anywhere") >> c-restore-string-fences() >> c-electric-brace(nil) >> funcall-interactively(c-electric-brace nil) >> command-execute(c-electric-brace) > > Apologies for that. I had failed to test the scenario from a freshly > started Emacs. The problem was setting and clearing text properties > without masking before-change-functions and after-change-functions. > This allowed a recursive call to these text property functions which > fouled things up. > > This is now corrected. Please undo the previous faulty patch and apply > the one in this post instead. I think it should have fixed the bug. > Thanks! I look forward to hearing from you again. That seems to have done the trick. Thank you! >> >> > Emacs : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, X >> >> > toolkit, cairo version 1.16.0) >> >> > of 2022-04-09 >> >> > Package: CC Mode 5.35.1 (C++//l) >> >> > Buffer Style: gnu >> >> > c-emacs-features: (pps-extended-state col-0-paren >> >> > posix-char-classes gen-string-delim gen-comment-delim >> >> > syntax-properties 1-bit) -- Michael Welsh Duggan (md5i@md5i.com) From debbugs-submit-bounces@debbugs.gnu.org Sun May 22 13:12:25 2022 Received: (at 55230-done) by debbugs.gnu.org; 22 May 2022 17:12:26 +0000 Received: from localhost ([127.0.0.1]:46247 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nsp7x-000272-MX for submit@debbugs.gnu.org; Sun, 22 May 2022 13:12:25 -0400 Received: from colin.muc.de ([193.149.48.1]:39843 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1nsp7v-00026p-71 for 55230-done@debbugs.gnu.org; Sun, 22 May 2022 13:12:25 -0400 Received: (qmail 87402 invoked by uid 3782); 22 May 2022 17:12:16 -0000 Received: from acm.muc.de (p4fe15ce5.dip0.t-ipconnect.de [79.225.92.229]) (using STARTTLS) by colin.muc.de (tmda-ofmipd) with ESMTP; Sun, 22 May 2022 19:12:16 +0200 Received: (qmail 29044 invoked by uid 1000); 22 May 2022 17:12:11 -0000 Date: Sun, 22 May 2022 17:12:11 +0000 To: Michael Welsh Duggan Subject: Re: bug#55230: CC Mode 5.35.1 (C++//l); Cache inconsistency Message-ID: References: <875ymn4try.fsf@md5i.com> <874k1mywst.fsf@md5i.com> <87h75hu1xa.fsf@md5i.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <87h75hu1xa.fsf@md5i.com> X-Submission-Agent: TMDA/1.3.x (Ph3nix) From: Alan Mackenzie X-Primary-Address: acm@muc.de X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 55230-done Cc: acm@muc.de, 55230-done@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hello, Michael. On Sun, May 22, 2022 at 09:33:53 -0400, Michael Welsh Duggan wrote: > Alan Mackenzie writes: > > On Thu, May 19, 2022 at 00:24:18 -0400, Michael Welsh Duggan wrote: > >> Unfortunately, it [the patch] has some major problems. If you follow > >> the original recipe, after the first brace is input cc-mode errors out > >> with "Marker does not point anywhere". Backtrace follows: > >> Debugger entered--Lisp error: (error "Marker does not point anywhere") > >> c-restore-string-fences() > >> c-electric-brace(nil) > >> funcall-interactively(c-electric-brace nil) > >> command-execute(c-electric-brace) > > Apologies for that. I had failed to test the scenario from a freshly > > started Emacs. The problem was setting and clearing text properties > > without masking before-change-functions and after-change-functions. > > This allowed a recursive call to these text property functions which > > fouled things up. > > This is now corrected. Please undo the previous faulty patch and apply > > the one in this post instead. I think it should have fixed the bug. > > Thanks! I look forward to hearing from you again. > That seems to have done the trick. Thank you! Thank you for the testing! I have now committed the patch, and I am closing the bug with this post. > >> >> > Emacs : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, X > >> >> > toolkit, cairo version 1.16.0) > >> >> > of 2022-04-09 > >> >> > Package: CC Mode 5.35.1 (C++//l) > >> >> > Buffer Style: gnu > >> >> > c-emacs-features: (pps-extended-state col-0-paren > >> >> > posix-char-classes gen-string-delim gen-comment-delim > >> >> > syntax-properties 1-bit) > -- > Michael Welsh Duggan > (md5i@md5i.com) -- Alan Mackenzie (Nuremberg, Germany). From unknown Wed Jun 18 23:16:03 2025 Received: (at fakecontrol) by fakecontrolmessage; To: internal_control@debbugs.gnu.org From: Debbugs Internal Request Subject: Internal Control Message-Id: bug archived. Date: Mon, 20 Jun 2022 11:24:04 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator