Mercurial > emacs
changeset 44728:7a3ac6c387fe
CC Mode update to version 5.29. This is for testing; it's not a released
version.
author | Martin Stjernholm <mast@lysator.liu.se> |
---|---|
date | Mon, 22 Apr 2002 00:35:36 +0000 |
parents | 3936c522b4d3 |
children | fa72416139fb |
files | lisp/ChangeLog lisp/progmodes/cc-align.el lisp/progmodes/cc-bytecomp.el lisp/progmodes/cc-cmds.el lisp/progmodes/cc-compat.el lisp/progmodes/cc-defs.el lisp/progmodes/cc-engine.el lisp/progmodes/cc-langs.el lisp/progmodes/cc-menus.el lisp/progmodes/cc-mode.el lisp/progmodes/cc-styles.el lisp/progmodes/cc-vars.el |
diffstat | 12 files changed, 6547 insertions(+), 3216 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/ChangeLog Mon Apr 22 00:35:36 2002 +0000 @@ -1,3 +1,893 @@ +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el: (c-define-abbrev-table): New function to + pass the SYSTEM-FLAG to `define-abbrev' in a way that works in + emacsen that doesn't support it. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el, progmodes/cc-engine.el, + progmodes/cc-styles.el, progmodes/cc-vars.el + (c-guess-basic-syntax, c-lineup-topmost-intro-cont): Find + correct anchor for statement-cont in top level constructs. + Analyze variable initializations in top level constructs as + topmost-intro-cont instead of statement-cont. That is an + incompatible change but it gives better consistency. The new + lineup function c-lineup-topmost-intro-cont' compensates for + it and is now put on topmost-intro-cont by default. + + * progmodes/cc-align.el, progmodes/cc-engine.el, + progmodes/cc-langs.el (c-lineup-argcont): Lineup function + contributed by Kevin Ryde. + + (c-in-gcc-asm-p): Function to recognize asm statements. + Contributed by Kevin Ryde. + + (c-opt-asm-stmt-key): New language variable to recognize the + beginning of asm statements. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-guess-basic-syntax): Detect + variable declarations after class and struct declarations + correctly. Fixed limit error when finding the anchor for + template-args-cont and topmost-intro-cont. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-beginning-of-defun, + c-declaration-limits): Find the "line oriented" declaration + start too, just like the "line oriented" end is found. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-vars.el (c-offsets-alist): A more sane default + for `inexpr-statement'. This is not compatible, though. I + think the benefit of a good default style outweights that in + this case. Besides, `inexpr-statement' is not very common. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-electric-delete-forward): Fixed + silly bug that caused it to delete backwards in hungry delete + mode. (It's amazing that this bug hasn't been reported.) + + * progmodes/cc-cmds.el (c-declaration-limits, c-mark-function): + Extracted the code to get the declaration limits from + `c-mark-function' to a new `c-declaration-limits'. + + (c-indent-defun): Use the same method to get the limits of the + declaration or macro as `c-mark-function'. + + * progmodes/cc-engine.el (c-beginning-of-decl-1): Handle brace + list initializers correctly (but costly; it ought to be + integrated into `c-beginning-of-statement-1'). + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el, progmodes/cc-engine.el + (c-beginning-of-defun, c-end-of-defun, c-mark-function): + Rewritten to detect the declaration limits better. Now + handles K&R argdecls, class definitions followed by variables + etc. + + (c-in-knr-argdecl): Broke out the K&R argdecl test in + `c-beginning-of-decl-1' to this new function. + + (c-end-of-statement-1, c-end-of-decl-1): Replaced + `c-end-of-statement-1' with `c-end-of-decl-1', which correctly + handles declarations that continue after the block. + + * progmodes/cc-engine.el (c-syntactic-re-search-forward): + Added an option to restrict matching to the top level of the + current paren sexp. + + * progmodes/cc-langs.el (c-opt-block-decls-with-vars-key): New + regexp to recognize declarations that continue after the + block. + + (c-syntactic-eol): New regexp to match a "syntactic" eol. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-guess-basic-syntax): Fixed a bug + that often caused the backward limit to be lost at the top + level. This improves performance a bit. + + * progmodes/cc-engine.el (c-syntactic-re-search-forward): New + function that works like `re-search-forward' but only returns + matches in syntactically significant text. + + * progmodes/cc-engine.el: Fixed a faster and more accurate way + to recognize K&R argdecls. + + (c-beginning-of-decl-1): New function that put point at the + beginning of the declaration. It handles K&R argdecl blocks. + + (c-guess-basic-syntax): Replaced the `knr-argdecl' recognition + code with one that doesn't depend on the current indentation. + The anchor position for `knr-argdecl' has also changed, but in + a way that is unlikely to cause compatibility problems. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el, progmodes/cc-engine.el + (c-forward-comment): `forward-comment' in XEmacs skips over + line continuations in the backward direction. Correct for + that. Also made this a defun since it has grown too large now + to be a defsubst. + + * progmodes/cc-langs.el: More convenient and decentralized + setup of the language specific variables. The regexp-opt + mangling is also done at compile time now. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-indent-line-or-region): Call + `c-indent-line' directly instead of through + `indent-according-to-mode' so that this function always + indents syntactically. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Fixed a bug + where a class beginning with a nested class could cause an + infinite loop (the state outside the narrowed out class is + never used now). + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el, progmodes/cc-cmds.el, + progmodes/cc-engine.el, progmodes/cc-vars.el: Fixes so that + the context sensitive analysis inside macros is restricted to + the bodies of #define's; other things, like #if expressions, + never have anything in common with their surroundings. The + old `cpp-macro-cont' syntax is now used in situations where + the syntactic analysis isn't applicable, and a new syntactic + element `cpp-define-intro' is used to add indentation in + #define bodies. + + (c-lineup-cpp-define): New name for `c-lineup-macro-cont' to + better reflect its use. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Ignore line + continuation backslashes in the detection of + `arglist-cont-nonempty'. + + * progmodes/cc-align.el: Use the vector form in the return + value in all cases where lineup functions return absolute + columns. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-add-stmt-syntax, + c-guess-basic-syntax): Anchor `brace-list-intro' and + `bracec-list-close' better for brace lists nested inside + expressions. + + * progmodes/cc-engine.el, progmodes/cc-langs.el, + progmodes/cc-mode.el, progmodes/cc-styles.el: Cleaned up the + various language specific variables and their initialization. + The keyword regexps are now lists that are combined with + regexp-opt. Some variables have changed names to fit better + with the naming convention. + + * progmodes/cc-defs.el, progmodes/cc-vars.el + (c-buffer-is-cc-mode): The value is the mode symbol of the + original CC Mode mode. + + (c-major-mode-is): Compare against the buffer local variable + `c-buffer-is-cc-mode', which is faster than using + `derived-mode-class'. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-forward-syntactic-ws, + c-backward-syntactic-ws, c-forward-token-1, + c-backward-token-1, c-in-literal, c-literal-limits, + c-collect-line-comments, c-literal-type, c-on-identifier, + c-guess-basic-syntax): These functions are now considered part + of the "CC Mode API" and may be used by other code. That's + signified by making their documentation into docstrings. + + (c-whack-state, c-hack-state, c-skip-case-statement-forward): + Removed these internal functions since they aren't used. + + (c-forward-to-cpp-expression): Classified this function as + internal. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-langs.el (c-ObjC-class-key, c-Java-class-key): + Simplified these regexps; the class keywords they contain + ought to be enough to avoid false matches, so checking for + following identifiers etc is just unnecessary (and might also + fail for oddly formatted code). + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el, progmodes/cc-cmds.el + (c-forward-comment-lc): New function that behaves like + `c-forward-comment', with the exception that line + continuations are treated as whitespace. + + (c-beginning-of-statement): Use `c-forward-comment-lc', to + work correctly in macros and other places where line + continuations should be treated as whitespace. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Analyze a + normal label in a switch block as a case label, to get + consistent lineup with the case labels. + + * progmodes/cc-engine.el (c-backward-syntactic-ws): Fixed bug + in skipping over a macro that ends with an empty line. + + * progmodes/cc-styles.el: Require cc-align since styles added + with `c-add-style' often contains references to functions + defined there, and so the `c-valid-offset' check might + otherwise complain on them. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el, progmodes/cc-mode.texi, + progmodes/cc-vars.el: Added two new lineup functions: + + (c-lineup-knr-region-comment): A new lineup function to get + (what most people think is) better indentation of comments in + the "K&R region" between the function header and its body. + + (c-lineup-gcc-asm-reg): New lineup function for better + indentation inside gcc asm blocks. Contributed by Kevin Ryde. + + (c-offsets-alist): Use `c-lineup-gcc-asm-reg' and + `c-lineup-knr-region-comment' in the default offset + configuration, since these two functions have little impact + outside their intended use, and they generally do the right + thing when they kick in. + + * progmodes/cc-engine.el (c-guess-continued-construct, + c-guess-basic-syntax): Handle nested functions in all + languages, not just Pike. In C and C++ there's a gcc + extension for this, and it also gives better treatment of + macros that are followed by blocks. + + * progmodes/cc-langs.el (c-symbol-key): Made this variable + mode specific, to handle Pike special symbols like `== better. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el, progmodes/cc-engine.el, + progmodes/cc-vars.el (c-report-syntactic-errors): A new + variable to control the syntactic error messages. It defaults + to off; since CC Mode ignores most syntactic errors it might + as well ignore them all for the sake of consistency. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-looking-at-inexpr-block): + Optimization. Can give a noticeable speedup if there's a + large preceding function or class body. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el, progmodes/cc-cmds.el: Use more + efficient and correct insertion functions in many places. + Always inherit text properties correctly if the text is + permanent. Also do it for speed in temporary insertions, + since I figure it's less work to continue the surrounding text + properties than to break them. + + * progmodes/cc-styles.el (c-read-offset): Unbind SPC in the + completion to make it easier to enter lists. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-beginning-of-defun): Fixed bug where + c-state-cache was clobbered. + + * progmodes/cc-cmds.el, progmodes/cc-engine.el + (c-calculate-state): Moved from cc-cmds.el to cc-engine.el due + to dependency. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-parse-state): Ignore unbalanced + open parens in macros (if point isn't in the same one). + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-context-open-line): New function + that is the `open-line' equivalent to `c-context-line-break'. + + * progmodes/cc-mode.el (c-mode-base-map): Compatibility fix + for Emacs 21 since `indent-new-comment-line' has been changed + to `comment-indent-new-line' there. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el, progmodes/cc-langs.el + (c-stmt-delim-chars, c-stmt-delim-chars-with-comma): New + variables containing the character sets used to recognize + statement/declaration boundaries. These variables might help + to support languages like javascript and awk, where newlines + sometimes delimits statements. + + (c-crosses-statement-barrier-p): Use `c-stmt-delim-chars' as + the set of statement delimiting characters, to allow it to be + changed dynamically and per-mode. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-looking-at-bos, + c-looking-at-inexpr-block, c-add-stmt-syntax, + c-guess-basic-syntax): Treat blocks directly inside function + calls like "bare" statements inside function calls, and not + like in-expression statements. This to make indentation of + such blocks consistent with other statements inside macro + calls. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Made + arglist-cont anchor correctly in arglists that contain + statements. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Fixed + consistent anchoring of defun-block-intro in defuns in code + blocks (can only occur in Pike). + + * progmodes/cc-engine.el (c-looking-at-inexpr-block, + c-looking-at-inexpr-block-backward): Changed the arguments to + require containing sexps and paren state, for better + efficiency. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el, progmodes/cc-engine.el, + progmodes/cc-vars.el: Improved anchoring of statement and + handling of labels in front of substatements. + + (c-guess-continued-construct, c-guess-basic-syntax): Improved + and unified anchoring at statements. Statements beginning + with comments or labels are now avoided, by going out of + blocks and containing statements if necessary. This nesting + handling also fixes the case when there's a statement after a + block open brace. Added the syntactic symbol + `substatement-label'. + + (c-electric-colon): Map the new `substatement-label' to + `label' when consulting `c-hanging-colons-alist'. + + (c-offsets-alist): Added substatement-label. Updated the + comments for the new anchoring positions at statements. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Use more sane + anchor points for knr-argdecl-intro and access-label. They + used to refer to some point on the same line, a bug which was + neutralized by a kludge in `c-get-syntactic-indentation' which + ignored such anchor points. + + (c-get-syntactic-indentation): Removed the kludge that was + necessary due to buggy anchor points. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Do not check + the absence of a comma before arglist-close (case 7A) in any + language, since there's nothing better to do that case anyway. + Added special case to make in-expression statements be + recognized as normal arglist-cont if we're directly in a macro + arglist, for consistency with other "bare" statements. + + * progmodes/cc-engine.el (c-looking-at-bos): Added optional + limit arg for backward searches. + + * progmodes/cc-engine.el (c-looking-at-inexpr-block): Anchor + gcc in-expression statements at the surrounding open + parenthesis. Treat a class body as an in-expression class if + it's used in an object clone expression in Pike. + + * progmodes/cc-engine.el (c-get-offset, + c-get-syntactic-indentation): Allow several anchor positions + in the list of syntactic symbols. Only the first is used as + the base for the offset calculation. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-indent-defun): Indent the current + macro if inside one at the top level. Do not throw an error + if used at the top level outside a macro. + + * progmodes/cc-cmds.el (c-backslash-region): Do tab width + alignment only if the backslashes can't be aligned with + surrounding backslashes. + + * progmodes/cc-engine.el (c-end-of-macro): New function. + + * progmodes/cc-engine.el (c-least-enclosing-brace): Rewritten + to not be destructive. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-context-line-break): Only do a macro + line break when point is inside the content of it; if it's in + the cpp keyword a normal line break is done. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Do not add + cpp-macro-cont inside the argument list to a #define. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el (c-forward-comment): Implemented a + kludge to avoid the problem most forward-comment incarnations + have with `\' together with comment parsing. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-check-state-cache): Fixed bug + which could cause the state returned by `c-parse-state' to + lack a closed paren element. That in turn could result in + very long searches, since it's common that they start from the + last preceding close brace. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-statement-1): Do not + treat else-if as a single continuation, since that'd make it + hard to get the right anchor point when there's a line break + between the two keywords. This change causes else-clause to + be anchored on the closest preceding else-if and not always on + the starting if, but that doesn't affect the indentation for + any reasonably sane style. Also introduced a noerror flag. + + (c-beginning-of-closest-statement): Removed; + c-beginning-of-statement-1 now avoids the problem this one + solved. + + * progmodes/cc-engine.el (c-guess-continued-construct, + c-guess-basic-syntax): Better and more uniform anchor points + for 'statement-cont and 'substatement. The effect is + noticeable mostly when there's a label on the same line as the + beginning of the statement, or when there are more stuff + before the start of the statement. + + * progmodes/cc-engine.el (c-looking-at-inexpr-block): Added + flag to disable looking at the type of the surrounding paren + since that confuses c-beginning-of-statement-1 and a couple of + other places. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Avoid + stepping to the previous statement in case 18. Improvements + in recognition of statement blocks on the top level. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-statement-1, + c-crosses-statement-barrier-p): Rewritten to get a well + defined and documented behavior. This fixes some tricky cases + in recognition of do-while constructs. + + (c-backward-to-start-of-do, c-backward-to-start-of-if): + Removed; use c-beginning-of-statement-1 instead. + + (c-guess-continued-construct, c-guess-basic-syntax): Various + fixes to not depend on the bugs previously in + c-beginning-of-statement-1. Cleanups in cases 18 and 17 to + use the new behavior of c-beginning-of-statement-1 better. + Fixed recognition of catch blocks inside macros. + + * progmodes/cc-engine.el (c-backward-syntactic-ws): Fixed bug + in skipping over a macro. + + * progmodes/cc-langs.el (c-label-kwds): New variable to + contain the appropriate c-*-label-kwds value. + + * progmodes/cc-vars.el (defcustom-c-stylevar): Fixed value + evaluation bug that caused the widget for + c-block-comment-prefix to bug out. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-guess-basic-syntax): Improved + recognition of statements: They are now recognized in contexts + where they normally can't occur, e.g. on the top level or in + function call arguments. This is mainly useful to recognize + statements in macros at the top level, and in arguments to + macros. The cases has been moved around quite a bit, and case + 10 has been copied to case 18. (The cases has not been + renumbered because of this.) + + (c-guess-continued-construct): New function which has the + rules which are common between cases 10 and 18. + + * progmodes/cc-engine.el (c-beginning-of-statement-1, + c-backward-to-start-of-do, c-backward-to-start-of-if): Fixes + so that they really obey the passed limits. + + (c-safe-position): Return nil if the state doesn't contain a + suitable position. + + (c-guess-basic-syntax): Fixes some too short limits in calls + to c-beginning-of-statement-1. Some fixes for top level + analysis in ObjC mode. + + * progmodes/cc-engine.el (c-beginning-of-statement-1): Fixed + bug in do-while statements where the body is not a block. + + * progmodes/cc-styles.el (c-set-style): Reset + c-special-indent-hook to its global value if in override mode. + Fixes problem where functions on that hook remained after + style switch. + + * progmodes/cc-engine.el (c-evaluate-offset, c-get-offset): + Use c-benign-error to report the c-strict-syntax-p error. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el, progmodes/cc-defs.el, + progmodes/cc-cmds.el, progmodes/cc-engine.el, cc-vars.el: + Several fixes to treat macros as code and not literals and to + handle line continuations transparently. + + (c-skip-ws-forward, c-skip-ws-backward): New macros to skip + through whitespace and line continuations, but not comments + and macros. + + (c-in-literal): No longer recognizes macros as literals by + default. An extra flag argument is required to do that. + + (c-macro-start, c-query-macro-start, + c-query-and-set-macro-start): Added a cache for the macro + start position. + + (c-forward-syntactic-ws, c-backward-syntactic-ws): Fixes for + more speed when limits are given. Workaround for bad behavior + in forward-comment in some emacsen when it hits a buffer limit + with a large repeat count. + + (c-lineup-macro-cont): Improved behavior when + c-syntactic-indentation-in-macros is nil. + + (c-syntactic-indentation-in-macros, c-backslash-max-column, + c-auto-align-backslashes): New customization variables to + control macro handling. + + * progmodes/cc-menus.el (cc-imenu-c++-generic-expression): + Fixes to handle line continuations. + + * progmodes/cc-defs.el, progmodes/cc-styles.el + (c-get-style-variables, c-set-offset): Report style errors + with message and ding instead of error signal. This to avoid + interrupted mode init if there's some style problem. + + (c-benign-error): New macro to report errors that doesn't need + to interrupt the operation. + + * progmodes/cc-defs.el (c-point): Added eonl and eopl + positions. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-electric-brace, c-indent-region): + Removed most of the c-state-cache fiddling, since the global + state cache now handles this. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Fixed bug + when there's an open paren at the very first char of the + visible buffer region. + + * progmodes/cc-engine.el (c-parse-state, c-check-state-cache): + Cache the state globally and invalidate it below every buffer + change with the new after change function + `c-check-state-cache'. This gives a considerable performance + boost when editing large functions or classes. + + * progmodes/cc-engine.el (c-whack-state-after): Slight + optimization. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el, progmodes/cc-langs.el, + progmodes/cc-align.el: Improvements to syntactic analysis + inside macros: + + (c-block-stmt-1-kwds, c-block-stmt-2-kwds): New variables used + by `c-guess-basic-syntax'. + + (c-parse-state): Fixed bug with braces inside macros when + using cached state info. + + (c-forward-to-cpp-expression): New function to aid in + syntactic analysis inside macros. + + (c-beginning-of-statement-1, c-backward-syntactic-ws): Fixes + to work better inside macros. + + (c-forward-syntactic-ws): Whitespace between the # and the + command should be allowed in preprocessor directives. + + (c-lineup-macro-cont): New lineup function to get context + sensitive indentation inside macros. + + (c-offsets-alist): Made `c-lineup-macro-cont' the default for + cpp-macro-cont. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-statement-1, + c-forward-syntactic-ws): Fixes to handle continued lines. + + (c-backward-to-start-of-if, c-guess-basic-syntax): Do + syntactic analysis inside macros. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-indent-region): Did a speedup made + possible by the more flexible state cache. + + * progmodes/cc-engine.el (c-parse-state, c-whack-state-before, + c-whack-state-after, c-hack-state, + c-narrow-out-enclosing-class, c-guess-basic-syntax): Improved + the state cache system. It now can use partial info from an + old cached state to calculate a new one at a different + position. Removed some kludges to avoid the state cache. The + new functions `c-whack-state-before' and `c-whack-state-after' + replace the now obsolete `c-whack-state'. + + * progmodes/cc-engine.el (c-beginning-of-statement-1): + Optimized backing through a macro. This can speed things up + quite a bit when there are long macros before point. + + (c-beginning-of-macro): Do not ignore the limit. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-electric-continued-statement): Fixed + a bug where the keyword wasn't reindented correctly if + followed by another keyword or identifier. + + * progmodes/cc-engine.el (c-parse-state): Ignore closed brace + pairs that are in macros. Fixes some cases where e.g. the + second of two "do { } while (0)" macros after each other + indented differently. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-macro, + c-forward-syntactic-ws): Recognize "#!" as a preprocessor + directive when it begins a line, to allow for script + interpreter lines like "#!/usr/bin/pike" at the beginning of + the file. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-looking-at-inexpr-block): + Recognize brace blocks inside a parenthesis expression as + inexpr-statement. Useful when writing statements as macro + arguments. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-fill-paragraph, c-do-auto-fill, + c-mask-comment): Broke out the comment masking code from + `c-fill-paragraph' to a new function `c-mask-comment', to be + able to do the same thing in `c-do-auto-fill'. This should + make auto-fill-mode behave better. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-electric-brace, c-electric-paren): + Check `executing-macro' to avoid blinking parens when macros + are executed. + + * progmodes/cc-mode.el, progmodes/cc-styles.el + (c-setup-filladapt): Moved from cc-mode.el to cc-styles.el for + consistency with `c-setup-paragraph-variables' (which was + placed there due to the dependency from `c-set-style'). + + * progmodes/cc-styles.el, progmodes/cc-vars.el: Fixed bug with + incomplete initialization from the style variable fallbacks if + there already is a style called "user" defined when CC Mode + starts up for the first time. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el, progmodes/cc-vars.el + (c-comment-indent, c-indent-comment-alist): Added new variable + `c-indent-comment-alist' to allow better control over + `c-comment-indent'. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-C-comments): Try to match + both `comment-start-skip' and the comment prefix on the + current line with the comment starter, so that we line up + comments which matches `c-comment-prefix-regexp' on the first + line (after the `/') without the need to make + `comment-start-skip' match whatever `c-comment-prefix-regexp' + matches. + + * progmodes/cc-mode.el, progmodes/cc-styles.el (c-common-init, + c-set-style-1, c-setup-paragraph-variables): Moved the + variable initialization based on `c-comment-prefix-regexp' to + a new function `c-setup-paragraph-variables', which is now + used both at mode init and when a style that sets + `c-comment-prefix-regexp' is activated. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-member-init-list): + Better handling of C++ template args to avoid confusion with + `<' and `>' used as operators in member init expressions. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-most-enclosing-brace, + c-least-enclosing-brace): Added optional second arg to limit + the search to before a certain point. + + * progmodes/cc-engine.el (c-guess-basic-syntax): Fixed bug + which could cause incorrect analysis if a cached state is used + (usually only happens when an electric key reindents a line). + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-defs.el (c-forward-comment): More idiosyncrasy + insulation. This time for XEmacs 21. + + * progmodes/cc-engine.el, progmodes/cc-langs.el: Improved + handling of inheritance lists: + + (c-beginning-of-inheritance-list): Rewritten to use a more + syntactically correct method that doesn't get confused by + badly placed linebreaks and comments. + + (c-guess-basic-syntax): Several fixes to the handling of + inheritance lists in combination with templates. 'inher-intro + is now anchored on the start of the class declaration and not + the indentation of the current line. Switched places on cases + 5D.3 and 5D.4 and made them use more syntactically correct + methods. + + (c-inher-key): Removed since the code in + `c-guess-basic-syntax' now uses token-based search. + + * progmodes/cc-cmds.el, progmodes/cc-mode.el (c-mode-menu): + Added a submenu to access some toggles. + + (c-toggle-syntactic-indentation): New function to toggle the + variable `c-syntactic-indentation'. + + * progmodes/cc-styles.el (c-set-style): Improved the error + message for incorrect offsets a bit. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-indent-exp): Don't require that the + sexp follows point immediately, instead find the closest + following open paren that ends on another line. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-cascaded-calls): New + indentation function. + + * progmodes/cc-engine.el (c-beginning-of-macro): Bugfix for + directives with whitespace between the '#' and the name. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-forward-syntactic-ws, + c-backward-syntactic-ws): Handle line continuations as + whitespace. Don't move past a macro if that'd take us past + the limit. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-engine.el (c-beginning-of-macro, + c-forward-syntactic-ws): Multiline strings begin with `#"' in + Pike, and that shouldn't be confused with a preprocessor + directive. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el: Extended the kludge to interoperate + with the delsel and pending-del packages wrt to the new + function `c-electric-delete-forward'. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-indent-exp): Keep the indentation of + the block itself, i.e. only indent the contents in it. + + * progmodes/cc-styles.el (c-set-style): Use the default + argument to completing-read instead of initial-contents, if + the function is recent enough to support it. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el (c-mode-help-address): Removed + bug-gnu-emacs@gnu.org from the receiver list for bug reports. + I've almost never seen a bug reported this way that should go + to that list, but it's rather common that the reports concern + the combination CC Mode and XEmacs instead. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-electric-paren): Fixed bug when both + brace-elseif-brace and brace-catch-brace are active and + there's a "else if"-block before the catch block. + + * progmodes/cc-menus.el (cc-imenu-c++-generic-expression): + Detect function headers that span lines. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-electric-brace, + c-electric-semi&comma, c-electric-colon, c-electric-paren): + Check for last on line only for doing the auto-newline-mode + stuff, not for the reindentation. + + * progmodes/cc-cmds.el (c-electric-brace): Fixed bugs in the + handling of c-syntactic-indentation: When it's nil, indent the + new lines but don't reindent the current one. Reindent the + line only when the inserted brace comes first on it, instead + of last. + + * progmodes/cc-cmds.el (c-electric-brace, + c-electric-semi&comma): Fixed two places where + c-syntactic-indentation wasn't heeded. + + * progmodes/cc-cmds.el (c-electric-pound): Don't be electric + inside a macro. + + * progmodes/cc-engine.el (c-backward-to-start-of-if): Try a + little harder to find a fallback position when an orphan else + is found. Fixed case where an else following a do-while + statement could be associated with an if inside the do-while. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-guess-fill-prefix): Tuned the dwim + for the fallback to add a single space after the comment + prefix. + + * progmodes/cc-cmds.el (c-indent-new-comment-line): Somewhat + better behavior in some special cases, especially for + single-line comments. Avoid breaking up a comment starter or + ender. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-outline-level): Applied patch from + the Emacs sources to make this work in invisible text. + + * progmodes/cc-langs.el (c-switch-label-key): Fixed regexp to + not be confused by a later ':' on the same line as the label. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el, progmodes/cc-mode.el + (c-electric-delete, c-electric-delete-forward): Split + `c-electric-delete' into two functions where + `c-electric-delete-forward' always deletes forward and + `c-electric-delete' only contains the code necessary for + XEmacs to choose between backward and forward deletion. + `c-electric-delete-forward' is now bound to C-d to get the + electric behavior on that key too. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-cmds.el (c-fill-paragraph): Fixed bogus direct + use of c-comment-prefix-regexp, which caused an error when + it's a list. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-mode.el, progmodes/cc-vars.el (c-common-init, + c-default-style): Removed the hardcoded switch to "java" style + in Java mode. It's instead taken care of by the default value + for c-default-style. + +2002-04-22 Martin Stjernholm <bug-cc-mode@gnu.org> + + * progmodes/cc-align.el (c-lineup-math): Fix bug where lineup + was triggered by equal signs in string literals. + 2002-04-21 Kim F. Storm <storm@cua.dk> * subr.el (insert-buffer-substring-no-properties): New function.
--- a/lisp/progmodes/cc-align.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-align.el Mon Apr 22 00:35:36 2002 +0000 @@ -25,7 +25,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. @@ -49,47 +49,107 @@ ;; Standard indentation line-ups +(defun c-lineup-topmost-intro-cont (langelem) + "Line up declaration continuation lines zero or one indentation step. +For lines in the \"header\" of a definition, zero is used. For other +lines, `c-basic-offset' is added to the indentation. E.g: + +int +neg (int i) <- c-lineup-topmost-intro-cont +{ + return -i; +} + +struct +larch <- c-lineup-topmost-intro-cont +{ + double height; +} + the_larch, <- c-lineup-topmost-intro-cont + another_larch; <- c-lineup-topmost-intro-cont +<--> c-basic-offset + +struct larch +the_larch, <- c-lineup-topmost-intro-cont + another_larch; <- c-lineup-topmost-intro-cont + +\(This function is mainly provided to mimic the behavior of CC Mode +5.28 and earlier where this case wasn't handled consistently so that +these lines could be analyzed as either topmost-intro-cont or +statement-cont.) + +Works with: topmost-intro-cont." + (save-excursion + (beginning-of-line) + (c-backward-syntactic-ws (cdr langelem)) + (if (memq (char-before) '(?} ?,)) + c-basic-offset))) + (defun c-lineup-arglist (langelem) "Line up the current argument line under the first argument. -Works with: arglist-cont-nonempty." +Works with: arglist-cont-nonempty, arglist-close." + (save-excursion + (beginning-of-line) + (let ((containing-sexp (c-most-enclosing-brace (c-parse-state)))) + (goto-char (1+ containing-sexp)) + (let ((eol (c-point 'eol))) + (c-forward-syntactic-ws) + (when (< (point) eol) + (goto-char (1+ containing-sexp)) + (skip-chars-forward " \t"))) + (vector (current-column))))) + +;; Contributed by Kevin Ryde <user42@zip.com.au>. +(defun c-lineup-argcont (elem) + "Line up a continued argument. + +foo (xyz, aaa + bbb + ccc + + ddd + eee + fff); <- c-lineup-argcont + +Only continuation lines like this are touched, `nil' is returned on lines +which are the start of an argument. + +Within a gcc asm block, \":\" is recognised as an argument separator, +but of course only between operand specifications, not in the expressions +for the operands. + +Works with: arglist-cont, arglist-cont-nonempty." + (save-excursion - (let* ((containing-sexp - (save-excursion - ;; arglist-cont-nonempty gives relpos == - ;; to boi of containing-sexp paren. This - ;; is good when offset is +, but bad - ;; when it is c-lineup-arglist, so we - ;; have to special case a kludge here. - (if (memq (car langelem) '(arglist-intro arglist-cont-nonempty)) - (progn - (beginning-of-line) - (backward-up-list 1) - (skip-chars-forward " \t" (c-point 'eol))) - (goto-char (cdr langelem))) - (point))) - (langelem-col (c-langelem-col langelem t))) - (if (save-excursion - (beginning-of-line) - (looking-at "[ \t]*)")) - (progn (goto-char (match-end 0)) - (c-forward-sexp -1) - (forward-char 1) - (c-forward-syntactic-ws) - (- (current-column) langelem-col)) - (goto-char containing-sexp) - (or (eolp) - (not (memq (char-after) '(?{ ?\( ?\[))) - (let ((eol (c-point 'eol)) - (here (progn - (forward-char 1) - (skip-chars-forward " \t") - (point)))) - (c-forward-syntactic-ws) - (if (< (point) eol) - (goto-char here)))) - (- (current-column) langelem-col) - )))) + (beginning-of-line) + (let ((bol (point))) + + ;; Previous line ending in a comma means we're the start of an + ;; argument. This should quickly catch most cases not for us. + (c-backward-syntactic-ws) + (let ((c (char-before))) + (unless (eq c ?,) + + ;; In a gcc asm, ":" on the previous line means the start of an + ;; argument. And lines starting with ":" are not for us, don't + ;; want them to indent to the preceding operand. + (let ((gcc-asm (save-excursion + (goto-char bol) + (c-in-gcc-asm-p)))) + (unless (and gcc-asm + (or (eq c ?:) + (save-excursion + (goto-char bol) + (looking-at "[ \t]*:")))) + + (c-lineup-argcont-scan (if gcc-asm ?:)) + (vector (current-column))))))))) + +(defun c-lineup-argcont-scan (&optional other-match) + ;; Find the start of an argument, for `c-lineup-argcont'. + (when (eq 0 (c-backward-token-1 1 t)) + (let ((c (char-after))) + (if (or (eq c ?,) (eq c other-match)) + (progn + (forward-char) + (c-forward-syntactic-ws)) + (c-lineup-argcont-scan other-match))))) (defun c-lineup-arglist-intro-after-paren (langelem) "Line up a line just after the open paren of the surrounding paren or @@ -98,13 +158,10 @@ Works with: defun-block-intro, brace-list-intro, statement-block-intro, statement-case-intro, arglist-intro." (save-excursion - (let ((langelem-col (c-langelem-col langelem t)) - (ce-curcol (save-excursion - (beginning-of-line) - (backward-up-list 1) - (skip-chars-forward " \t" (c-point 'eol)) - (current-column)))) - (- ce-curcol langelem-col -1)))) + (beginning-of-line) + (backward-up-list 1) + (skip-chars-forward " \t" (c-point 'eol)) + (vector (1+ (current-column))))) (defun c-lineup-arglist-close-under-paren (langelem) "Line up a closing paren line under the corresponding open paren. @@ -114,12 +171,9 @@ \(for most of these, a zero offset will normally produce the same result, though)." (save-excursion - (let ((langelem-col (c-langelem-col langelem t)) - (ce-curcol (save-excursion - (beginning-of-line) - (backward-up-list 1) - (current-column)))) - (- ce-curcol langelem-col)))) + (beginning-of-line) + (backward-up-list 1) + (vector (current-column)))) (defun c-lineup-close-paren (langelem) "Line up the closing paren under its corresponding open paren if the @@ -147,7 +201,7 @@ (c-forward-syntactic-ws (c-point 'eol)) (if (eolp) 0 - (- opencol (c-langelem-col langelem t)))) + (vector opencol))) (error nil)))) (defun c-lineup-streamop (langelem) @@ -155,10 +209,10 @@ Works with: stream-op." (save-excursion - (let ((langelem-col (c-langelem-col langelem))) - (re-search-forward "<<\\|>>" (c-point 'eol) 'move) - (goto-char (match-beginning 0)) - (- (current-column) langelem-col)))) + (goto-char (cdr langelem)) + (re-search-forward "<<\\|>>" (c-point 'eol) 'move) + (goto-char (match-beginning 0)) + (vector (current-column)))) (defun c-lineup-multi-inher (langelem) "Line up the classes in C++ multiple inheritance clauses and member @@ -182,8 +236,8 @@ (here (point)) (char-after-ip (progn (skip-chars-forward " \t") - (char-after))) - (langelem-col (c-langelem-col langelem))) + (char-after)))) + (if (cdr langelem) (goto-char (cdr langelem))) ;; This kludge is necessary to support both inher-cont and ;; member-init-cont, since they have different anchor positions. @@ -199,7 +253,7 @@ (if (or (eolp) (looking-at c-comment-start-regexp)) (c-forward-syntactic-ws here)) - (- (current-column) langelem-col) + (vector (current-column)) ))) (defun c-lineup-java-inher (langelem) @@ -216,12 +270,12 @@ Works with: inher-cont." (save-excursion - (let ((langelem-col (c-langelem-col langelem))) - (forward-word 1) - (if (looking-at "[ \t]*$") - c-basic-offset - (c-forward-syntactic-ws) - (- (current-column) langelem-col))))) + (goto-char (cdr langelem)) + (forward-word 1) + (if (looking-at "[ \t]*$") + c-basic-offset + (c-forward-syntactic-ws) + (vector (current-column))))) (defun c-lineup-java-throws (langelem) "Line up Java throws declarations. @@ -246,10 +300,9 @@ (throw 'done t)))))) (if throws (if (zerop (c-forward-token-1 1 nil (c-point 'eol))) - (- (current-column) (c-langelem-col langelem)) + (vector (current-column)) (back-to-indentation) - (+ (- (current-column) (c-langelem-col langelem)) - c-basic-offset)) + (vector (+ (current-column) c-basic-offset))) c-basic-offset)))) (defun c-indent-one-line-block (langelem) @@ -332,21 +385,33 @@ (if (looking-at c-current-comment-prefix) (- (match-end 0) (point)) 0))) - (starterlen (save-excursion - (goto-char (cdr langelem)) - (looking-at comment-start-skip) - (- (save-excursion - (goto-char (match-end 0)) - (skip-chars-backward " \t") - (point)) - (or (match-end 1) (point)) - 1))) ; Don't count the first '/'. - (langelem-col (save-excursion (c-langelem-col langelem)))) + (starterlen + ;; Get the length of the comment starter, not including + ;; the first '/'. We check if the comment prefix matched + ;; on the current line matches the starter or if it + ;; matches comment-start-skip, and choose whichever is + ;; longest. + (max (save-excursion + (goto-char (1+ (cdr langelem))) + (if (and (match-string 0) + (looking-at (regexp-quote (match-string 0)))) + (- (match-end 0) (match-beginning 0)) + 0)) + (save-excursion + (goto-char (cdr langelem)) + (looking-at comment-start-skip) + (- (or (match-end 1) + (save-excursion + (goto-char (match-end 0)) + (skip-chars-backward " \t") + (point))) + (point) + 1))))) (if (and (> starterlen 10) (zerop prefixlen)) ;; The comment has a long starter and the line doesn't have ;; a nonempty comment prefix. Treat it as free form text ;; and don't change the indentation. - (- (current-column) langelem-col) + (vector (current-column)) (forward-line -1) (back-to-indentation) (if (>= (cdr langelem) (point)) @@ -356,11 +421,14 @@ ;; starter. (progn (goto-char (match-end 0)) - (if (looking-at "\\([ \t]+\\).+$") - ;; Align with the text that hangs after the - ;; comment starter. - (goto-char (match-end 1))) - (- (current-column) langelem-col)) + ;; The following should not be necessary, since + ;; comment-start-skip should match everything (i.e. + ;; typically whitespace) that leads up to the text. + ;;(if (looking-at "\\([ \t]+\\).+$") + ;; ;; Align with the text that hangs after the + ;; ;; comment starter. + ;; (goto-char (match-end 1))) + (vector (current-column))) ;; How long is the comment starter? if greater than the ;; length of the comment prefix, align left. if less ;; than or equal, align right. this should also pick up @@ -368,10 +436,9 @@ (if (> starterlen prefixlen) (progn (goto-char (cdr langelem)) - (- (current-column) -1 langelem-col)) - (goto-char (match-end 0)) - (skip-chars-backward " \t") - (- (current-column) prefixlen langelem-col))) + (vector (1+ (current-column)))) + (goto-char (+ (cdr langelem) starterlen 1)) + (vector (- (current-column) prefixlen)))) ;; Not on the second line in the comment. If the previous ;; line has a nonempty comment prefix, align with it. ;; Otherwise, align with the previous nonempty line, but @@ -389,7 +456,7 @@ ;; Align with the comment starter rather than ;; with the code before it. (goto-char (cdr langelem))))) - (- (current-column) langelem-col)))))) + (vector (current-column))))))) (defun c-lineup-comment (langelem) "Line up a comment start according to `c-comment-only-line-offset'. @@ -416,6 +483,30 @@ -1000)) ;jam it against the left side )))) +(defun c-lineup-knr-region-comment (langelem) + "Line up a comment in the \"K&R region\" with the declaration. +That is the region between the function or class header and the +beginning of the block. E.g: + +int main() +/* This is the main function. */ <- c-lineup-knr-region-comment +{ + return 0; +} + +Return nil if called in any other situation, to be useful in list +expressions. + +Works with: comment-intro." + (when (or (assq 'topmost-intro-cont c-syntactic-context) + (assq 'func-decl-cont c-syntactic-context) + (assq 'knr-argdecl-intro c-syntactic-context) + (assq 'lambda-intro-cont c-syntactic-context)) + (save-excursion + (beginning-of-line) + (c-beginning-of-statement-1) + (vector (current-column))))) + (defun c-lineup-runin-statements (langelem) "Line up statements when the first statement is on the same line as the block opening brace. E.g: @@ -431,11 +522,11 @@ Works with: The `statement' syntactic symbol." (if (eq (char-after (cdr langelem)) ?{) (save-excursion - (let ((langelem-col (c-langelem-col langelem))) - (forward-char 1) - (skip-chars-forward " \t") - (unless (eolp) - (- (current-column) langelem-col)))))) + (if (cdr langelem) (goto-char (cdr langelem))) + (forward-char 1) + (skip-chars-forward " \t") + (unless (eolp) + (vector (current-column)))))) (defun c-lineup-math (langelem) "Line up the current line after the equal sign on the first line in @@ -443,7 +534,7 @@ the current line contains an equal sign too, try to align it with the first one. -Works with: statement-cont." +Works with: statement-cont, arglist-cont, arglist-cont-nonempty." (save-excursion (let ((equalp (save-excursion (goto-char (c-point 'boi)) @@ -453,8 +544,8 @@ (= (c-forward-token-1 1 t eol) 0)))) (and (eq (char-after) ?=) (- (point) (c-point 'boi))))) - (langelem-col (c-langelem-col langelem)) donep) + (if (cdr langelem) (goto-char (cdr langelem))) (while (and (not donep) (< (point) (c-point 'eol))) (skip-chars-forward "^=" (c-point 'eol)) @@ -475,9 +566,39 @@ (forward-char 1) (skip-chars-forward " \t") (setq equalp 0))) - (- (current-column) equalp langelem-col)) + (vector (- (current-column) equalp))) ))) +(defun c-lineup-cascaded-calls (langelem) + "Line up \"cascaded calls\" under each other. +If the line begins with \"->\" and the preceding line ends with one or +more function calls preceded by \"->\", then the arrow is lined up with +the first of those \"->\". E.g: + +result = proc->add(17)->add(18) + ->add(19) + <- c-lineup-cascaded-calls + offset; <- c-lineup-cascaded-calls (inactive) + +In any other situation nil is returned to allow use in list +expressions. + +Works with: statement-cont, arglist-cont, arglist-cont-nonempty." + (save-excursion + (let ((bopl (c-point 'bopl)) col) + (back-to-indentation) + (when (and (looking-at "->") + (= (c-backward-token-1 1 t bopl) 0) + (eq (char-after) ?\() + (= (c-backward-token-1 3 t bopl) 0) + (looking-at "->")) + (setq col (current-column)) + (while (and (= (c-backward-token-1 1 t bopl) 0) + (eq (char-after) ?\() + (= (c-backward-token-1 3 t bopl) 0) + (looking-at "->")) + (setq col (current-column))) + (vector col))))) + (defun c-lineup-template-args (langelem) "Line up template argument lines under the first argument. To allow this function to be used in a list expression, nil is @@ -490,7 +611,7 @@ (backward-up-list 1) (if (and (eq (char-after) ?<) (zerop (c-forward-token-1 1 nil (c-point 'eol)))) - (- (current-column) (c-langelem-col langelem)))))) + (vector (current-column)))))) (defun c-lineup-ObjC-method-call (langelem) "Line up selector args as elisp-mode does with function args: @@ -579,10 +700,20 @@ Works with: inlambda, inexpr-statement, inexpr-class." (save-excursion (back-to-indentation) - (let ((res (or (c-looking-at-inexpr-block) - (if (c-safe (backward-up-list 1) - (eq (char-after) ?{)) - (c-looking-at-inexpr-block))))) + (let* ((paren-state (c-parse-state)) + (containing-sexp (c-most-enclosing-brace paren-state)) + (res (or (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + containing-sexp) + (and containing-sexp + (progn (goto-char containing-sexp) + (eq (char-after) ?{)) + (progn (setq containing-sexp + (c-most-enclosing-brace paren-state + (point))) + (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + containing-sexp)))))) (when res (goto-char (cdr res)) (- (current-column) @@ -614,6 +745,134 @@ 0 c-basic-offset))) +(defun c-lineup-cpp-define (langelem) + "Line up macro continuation lines according to the indentation of +the construct preceding the macro. E.g: + +v beg of preceding constr v beg of preceding constr + int dribble() { +const char msg[] = if (!running) + \"Some text.\"; error(\"Not running!\"); + +#define X(A, B) \ #define X(A, B) \ +do { \ <-> do { \ <- c-lineup-cpp-define + printf (A, B); \ printf (A, B); \ +} while (0) } while (0) + +If `c-syntactic-indentation-in-macros' is non-nil, the function +returns the relative indentation to the macro start line to allow +accumulation with other offsets. E.g. in the following cases, +cpp-define-intro is combined with the statement-block-intro that comes +from the \"do {\" that hangs on the \"#define\" line: + + int dribble() { +const char msg[] = if (!running) + \"Some text.\"; error(\"Not running!\"); + +#define X(A, B) do { \ #define X(A, B) do { \ + printf (A, B); \ <-> printf (A, B); \ <- c-lineup-cpp-define + this->refs++; \ this->refs++; \ +} while (0) <-> } while (0) <- c-lineup-cpp-define + +The relative indentation returned by `c-lineup-cpp-define' is zero and +two, respectively, in these two examples. They are then added to the +two column indentation that statement-block-intro gives in both cases +here. + +If the relative indentation is zero, then nil is returned instead. +This useful in a list expression to specify the default indentation on +the top level. + +If `c-syntactic-indentation-in-macros' is nil then this function keeps +the current indentation, except for empty lines \(ignoring the ending +backslash) where it takes the indentation from the closest preceding +nonempty line in the macro. If there's no such line in the macro then +the indentation is taken from the construct preceding it, as described +above. + +Works with: cpp-define-intro." + (let (offset) + (if c-syntactic-indentation-in-macros + ;; Go to the macro start and do a syntactic analysis of it. + ;; Then remove the cpp-macro element it should contain and + ;; calculate the indentation it then would get. + (save-excursion + (c-beginning-of-macro) + (setq offset (- (c-get-syntactic-indentation + (delete '(cpp-macro) (c-guess-basic-syntax))) + (save-excursion + (back-to-indentation) + (current-column)))) + (if (zerop offset) + nil + offset)) + ;; Do not indent syntactically inside the macro. + (save-excursion + (let ((macro-start-line (save-excursion + (goto-char (c-query-macro-start)) + (beginning-of-line) + (point)))) + (beginning-of-line) + ;; Check every line while inside the macro. + (while (and (> (point) macro-start-line) + (looking-at "[ \t]*\\\\?$") + (= (forward-line -1) 0))) + (if (<= (point) macro-start-line) + ;; If we've stepped out of the macro we take the + ;; syntactic offset. + (setq offset (c-get-syntactic-indentation + (delete '(cpp-macro) (c-guess-basic-syntax)))) + (setq offset (current-indentation))) + (if (zerop offset) + nil + (vector offset))))))) + +;; Contributed by Kevin Ryde <user42@zip.com.au>. +(defun c-lineup-gcc-asm-reg (elem) + "Line up a gcc asm register under one on a previous line. + + asm (\"foo %1, %0\\n\" + \"bar %0, %1\" + : \"=r\" (w), + \"=r\" (x) + : \"0\" (y), + \"1\" (z)); + +The \"x\" line is aligned to the text after the \":\" on the \"w\" line, and +similarly \"z\" under \"y\". + +This is done only in an \"asm\" or \"__asm__\" block, and only to those +lines mentioned. Anywhere else `nil' is returned. The usual arrangement is +to have this routine as an extra feature at the start of arglist lineups, e.g. + + (c-lineup-gcc-asm-reg c-lineup-arglist) + +Works with: arglist-cont, arglist-cont-nonempty." + + (let ((orig-pos (point)) + alignto) + (save-excursion + (and + c-opt-asm-stmt-key + + ;; Find the ":" to align to. Look for this first so as to quickly + ;; eliminate pretty much all cases which are not for us. + (re-search-backward "^[ \t]*:[ \t]*\\(.\\)?" (cdr elem) t) + + ;; Must have something after the ":". + (setq alignto (match-beginning 1)) + + ;; Don't touch ":" lines themselves. + (progn (goto-char orig-pos) + (beginning-of-line) + (not (looking-at "^[ \t]*:"))) + + ;; Only operate in an asm statement. + (progn (goto-char orig-pos) + (c-in-gcc-asm-p)) + + (vector (progn (goto-char alignto) (current-column))))))) + (defun c-lineup-dont-change (langelem) "Do not change the indentation of the current line. @@ -663,7 +922,7 @@ (setq syntax nil) (back-to-indentation) (if (zerop (current-column)) - (insert (make-string c-label-minimum-indentation 32))) + (insert-char ?\ c-label-minimum-indentation t)) )) ))))
--- a/lisp/progmodes/cc-bytecomp.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-bytecomp.el Mon Apr 22 00:35:36 2002 +0000 @@ -21,8 +21,8 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: @@ -31,6 +31,10 @@ ;; compiled regardless the environment (e.g. if an older CC Mode with ;; outdated macros are loaded during compilation). It also provides ;; features to defeat the compiler warnings for selected symbols. +;; +;; There's really nothing CC Mode specific here; this functionality +;; ought to be provided by the byte compilers or some accompanying +;; library. ;;; Code:
--- a/lisp/progmodes/cc-cmds.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-cmds.el Mon Apr 22 00:35:36 2002 +0000 @@ -25,7 +25,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. @@ -54,16 +54,231 @@ ; which looks at this. -(defun c-calculate-state (arg prevstate) - ;; Calculate the new state of PREVSTATE, t or nil, based on arg. If - ;; arg is nil or zero, toggle the state. If arg is negative, turn - ;; the state off, and if arg is positive, turn the state on - (if (or (not arg) - (zerop (setq arg (prefix-numeric-value arg)))) - (not prevstate) - (> arg 0))) +(defvar c-fix-backslashes t) + +(defun c-shift-line-indentation (shift-amt) + (let ((pos (- (point-max) (point))) + (c-macro-start c-macro-start) + tmp-char-inserted) + (if (zerop shift-amt) + nil + (when (and (c-query-and-set-macro-start) + (looking-at "[ \t]*\\\\$") + (save-excursion + (skip-chars-backward " \t") + (bolp))) + (insert ?x) + (backward-char) + (setq tmp-char-inserted t)) + (unwind-protect + (let ((col (current-indentation))) + (delete-region (c-point 'bol) (c-point 'boi)) + (beginning-of-line) + (indent-to (+ col shift-amt))) + (when tmp-char-inserted + (delete-char 1)))) + ;; If initial point was within line's indentation and we're not on + ;; a line with a line continuation in a macro, position after the + ;; indentation. Else stay at same point in text. + (if (and (< (point) (c-point 'boi)) + (not tmp-char-inserted)) + (back-to-indentation) + (if (> (- (point-max) pos) (point)) + (goto-char (- (point-max) pos)))))) + +(defun c-indent-line (&optional syntax quiet ignore-point-pos) + "Indent the current line according to the syntactic context, +if `c-syntactic-indentation' is non-nil. Optional SYNTAX is the +syntactic information for the current line. Be silent about syntactic +errors if the optional argument QUIET is non-nil, even if +`c-report-syntactic-errors' is non-nil. Normally the position of +point is used to decide where the old indentation is on a lines that +is otherwise empty \(ignoring any line continuation backslash), but +that's not done if IGNORE-POINT-POS is non-nil. Returns the amount of +indentation change \(in columns)." + (let ((line-cont-backslash (save-excursion + (end-of-line) + (eq (char-before) ?\\))) + (c-fix-backslashes c-fix-backslashes) + bs-col + shift-amt) + (when (and (not ignore-point-pos) + (save-excursion + (beginning-of-line) + (looking-at (if line-cont-backslash + "\\(\\s *\\)\\\\$" + "\\(\\s *\\)$"))) + (<= (point) (match-end 1))) + ;; Delete all whitespace after point if there's only whitespace + ;; on the line, so that any code that does back-to-indentation + ;; or similar gets the current column in this case. If this + ;; removes a line continuation backslash it'll be restored + ;; at the end. + (unless c-auto-align-backslashes + ;; Should try to keep the backslash alignment + ;; in this case. + (save-excursion + (goto-char (match-end 0)) + (setq bs-col (1- (current-column))))) + (delete-region (point) (match-end 0)) + (setq c-fix-backslashes t)) + (if c-syntactic-indentation + (setq c-parsing-error + (or (let* ((c-parsing-error nil) + (c-syntactic-context (or syntax + c-syntactic-context + (c-guess-basic-syntax))) + indent) + (setq indent (c-get-syntactic-indentation + c-syntactic-context)) + (and (not (c-echo-parsing-error quiet)) + c-echo-syntactic-information-p + (message "syntax: %s, indent: %d" + c-syntactic-context indent)) + (setq shift-amt (- indent (current-indentation))) + (c-shift-line-indentation shift-amt) + (run-hooks 'c-special-indent-hook) + c-parsing-error) + c-parsing-error)) + (let ((indent 0)) + (save-excursion + (while (and (= (forward-line -1) 0) + (if (looking-at "\\s *\\\\?$") + t + (setq indent (current-indentation)) + nil)))) + (setq shift-amt (- indent (current-indentation))) + (c-shift-line-indentation shift-amt))) + (when (and c-fix-backslashes line-cont-backslash) + (if bs-col + (save-excursion + (indent-to bs-col) + (insert ?\\)) + (when c-auto-align-backslashes + ;; Realign the line continuation backslash. + (c-backslash-region (point) (point) nil t)))) + shift-amt)) -;; Auto-newline and hungry-delete +(defun c-newline-and-indent (&optional newline-arg) + "Inserts a newline and indents the new line. +This function fixes line continuation backslashes if inside a macro, +and takes care to set the indentation before calling +`indent-according-to-mode', so that lineup functions like +`c-lineup-dont-change' works better." + ;; FIXME: Backslashes before eol in comments and literals aren't + ;; kept intact. + (let ((c-macro-start (c-query-macro-start)) + ;; Avoid calling c-backslash-region from c-indent-line if it's + ;; called during the newline call, which can happen due to + ;; c-electric-continued-statement, for example. We also don't + ;; want any backslash alignment from indent-according-to-mode. + (c-fix-backslashes nil) + has-backslash insert-backslash + start col) + (save-excursion + (beginning-of-line) + (setq start (point)) + (while (and (looking-at "[ \t]*\\\\?$") + (= (forward-line -1) 0))) + (setq col (current-indentation))) + (when c-macro-start + (if (and (eolp) (eq (char-before) ?\\)) + (setq insert-backslash t + has-backslash t) + (setq has-backslash (eq (char-before (c-point 'eol)) ?\\)))) + (newline newline-arg) + (indent-to col) + (when c-macro-start + (if insert-backslash + (progn + ;; The backslash stayed on the previous line. Insert one + ;; before calling c-backslash-region, so that + ;; bs-col-after-end in it works better. Fixup the + ;; backslashes on the newly inserted line. + (insert ?\\) + (backward-char) + (c-backslash-region (point) (point) nil t)) + ;; The backslash moved to the new line, if there was any. Let + ;; c-backslash-region fix a backslash on the previous line, + ;; and the one that might be on the new line. + ;; c-auto-align-backslashes is intentionally ignored here; + ;; maybe the moved backslash should be left alone if it's set, + ;; but we fix both lines on the grounds that the old backslash + ;; has been moved anyway and is now in a different context. + (c-backslash-region start (if has-backslash (point) start) nil t))) + (when c-syntactic-indentation + ;; Reindent syntactically. The indentation done above is not + ;; wasted, since c-indent-line might look at the current + ;; indentation. + (let ((c-syntactic-context (c-guess-basic-syntax))) + ;; We temporarily insert another line break, so that the + ;; lineup functions will see the line as empty. That makes + ;; e.g. c-lineup-cpp-define more intuitive since it then + ;; proceeds to the preceding line in this case. + (insert ?\n) + (delete-horizontal-space) + (setq start (- (point-max) (point))) + (unwind-protect + (progn + (backward-char) + (indent-according-to-mode)) + (goto-char (- (point-max) start)) + (delete-char -1))) + (when has-backslash + ;; Must align the backslash again after reindentation. The + ;; c-backslash-region call above can't be optimized to ignore + ;; this line, since it then won't align correctly with the + ;; lines below if the first line in the macro is broken. + (c-backslash-region (point) (point) nil t))))) + +(defun c-show-syntactic-information (arg) + "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 (c-guess-basic-syntax))) + (if (not (consp arg)) + (message "syntactic analysis: %s" syntax) + (indent-for-comment) + (insert-and-inherit (format "%s" syntax)) + )) + (c-keep-region-active)) + +(defun c-syntactic-information-on-region (from to) + "Inserts a comment with the syntactic analysis on every line in the region." + (interactive "*r") + (save-excursion + (save-restriction + (narrow-to-region from to) + (goto-char (point-min)) + (while (not (eobp)) + (c-show-syntactic-information '(0)) + (forward-line))))) + + +(defun c-toggle-syntactic-indentation (&optional arg) + "Toggle syntactic indentation. +Optional numeric ARG, if supplied, turns on syntactic indentation when +positive, turns it off when negative, and just toggles it when zero or +left out. + +When syntactic indentation is turned on (the default), the indentation +functions and the electric keys indent according to the syntactic +context keys, when applicable. + +When it's turned off, the electric keys does no reindentation, the +indentation functions indents every new line to the same level as the +previous nonempty line, and \\[c-indent-command] adjusts the +indentation in seps specified `c-basic-offset'. The indentation style +has no effect in this mode, nor any of the indentation associated +variables, e.g. `c-special-indent-hook'. + +This command sets the variable `c-syntactic-indentation'." + (interactive "P") + (setq c-syntactic-indentation + (c-calculate-state arg c-syntactic-indentation)) + (c-keep-region-active)) + (defun c-toggle-auto-state (&optional arg) "Toggle auto-newline feature. Optional numeric ARG, if supplied, turns on auto-newline when @@ -124,7 +339,7 @@ (c-in-literal)) (funcall c-backspace-function (prefix-numeric-value arg)) (let ((here (point))) - (skip-chars-backward " \t\n") + (c-skip-ws-backward) (if (/= (point) here) (delete-region (point) here) (funcall c-backspace-function 1) @@ -143,7 +358,7 @@ (c-in-literal)) (funcall c-delete-function (prefix-numeric-value arg)) (let ((here (point))) - (skip-chars-forward " \t\n") + (c-skip-ws-forward) (if (/= (point) here) (delete-region (point) here) (funcall c-delete-function 1))))) @@ -176,11 +391,17 @@ "Electric pound (`#') insertion. Inserts a `#' character specially depending on the variable `c-electric-pound-behavior'. If a numeric ARG is supplied, or if -point is inside a literal, nothing special happens." +point is inside a literal or a macro, nothing special happens." (interactive "*P") (if (or arg (not (memq 'alignleft c-electric-pound-behavior)) - (save-excursion (skip-chars-backward " \t") (not (bolp))) + (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 (self-insert-command (prefix-numeric-value arg)) @@ -189,7 +410,7 @@ (bolp (bolp))) (beginning-of-line) (delete-horizontal-space) - (insert-char last-command-char 1) + (insert last-command-char) (and (not bolp) (goto-char (- (point-max) pos))) ))) @@ -201,24 +422,27 @@ or \"/ah\" string on the mode line, newlines are inserted before and after braces based on the value of `c-hanging-braces-alist'. -Also, the line is re-indented unless a numeric ARG is supplied, there -are non-whitespace characters present on the line after the brace, the +Also, the line is re-indented unless a numeric ARG is supplied, the brace is inserted inside a literal, or `c-syntactic-indentation' is nil. This function does various newline cleanups based on the value of `c-cleanup-list'." (interactive "*P") - (let* ((c-state-cache (c-parse-state)) - (safepos (c-safe-position (point) c-state-cache)) - (literal (c-in-literal safepos))) - ;; if we're in a literal, or we're not at the end of the line, or - ;; a numeric arg is provided, or auto-newlining is turned off, - ;; then just insert the character. - (if (or literal - arg - (not (looking-at "[ \t]*$"))) - (self-insert-command (prefix-numeric-value arg)) + (let* ((safepos (c-safe-position (point) (c-parse-state))) + (literal (c-in-literal safepos)) + ;; We want to inhibit blinking the paren since this will be + ;; most disruptive. We'll blink it ourselves later on. + (old-blink-paren blink-paren-function) + blink-paren-function) + (cond + ((or literal arg) + (self-insert-command (prefix-numeric-value arg))) + ((not (looking-at "[ \t]*\\\\?$")) + (self-insert-command (prefix-numeric-value arg)) + (if c-syntactic-indentation + (indent-according-to-mode))) + (t (let* ((syms ;; This is the list of brace syntactic symbols that can ;; hang. If any new ones are added to c-offsets-alist, @@ -233,131 +457,112 @@ namespace-open namespace-close inexpr-class-open inexpr-class-close )) - ;; we want to inhibit blinking the paren since this will - ;; be most disruptive. we'll blink it ourselves later on - (old-blink-paren blink-paren-function) - blink-paren-function - (insertion-point (point)) - delete-temp-newline - (preserve-p (and (not (bobp)) - (eq ?\ (char-syntax (char-before))))) - ;; shut this up too - (c-echo-syntactic-information-p nil) - (syntax (progn - ;; only insert a newline if there is - ;; non-whitespace behind us - (if (save-excursion - (skip-chars-backward " \t") - (not (bolp))) - (progn (newline) - (setq delete-temp-newline t))) - (if (eq last-command-char ?{) - (setq c-state-cache (cons (point) c-state-cache))) - (self-insert-command (prefix-numeric-value arg)) - ;; state cache doesn't change - (c-guess-basic-syntax))) - (newlines (and - c-auto-newline - (or (c-lookup-lists - syms - ;; Substitute inexpr-class and class-open - ;; or class-close with inexpr-class-open - ;; or inexpr-class-close. - (if (assq 'inexpr-class syntax) - (cond ((assq 'class-open syntax) - '((inexpr-class-open))) - ((assq 'class-close syntax) - '((inexpr-class-close))) - (t syntax)) - syntax) - c-hanging-braces-alist) - '(ignore before after))))) - ;; Do not try to insert newlines around a special (Pike-style) - ;; brace list. - (if (and c-special-brace-lists - (save-excursion - (c-safe (if (= (char-before) ?{) - (forward-char -1) - (c-forward-sexp -1)) - (c-looking-at-special-brace-list)))) - (setq newlines nil)) - ;; If syntax is a function symbol, then call it using the - ;; defined semantics. - (if (and (not (consp (cdr newlines))) - (functionp (cdr newlines))) - (let ((c-syntactic-context syntax)) + (insertion-point (point)) + (preserve-p (and (not (bobp)) + (eq ?\ (char-syntax (char-before))))) + ;; shut this up too + (c-echo-syntactic-information-p nil) + delete-temp-newline syntax newlines) + ;; only insert a newline if there is non-whitespace behind us + (when (save-excursion + (skip-chars-backward " \t") + (not (bolp))) + (setq delete-temp-newline + (list (point-marker))) + (c-newline-and-indent) + (setcdr delete-temp-newline (point-marker))) + (unwind-protect + (progn + (if (eq last-command-char ?{) + (setq c-state-cache (cons (point) c-state-cache))) + (self-insert-command (prefix-numeric-value arg)) + (let ((c-syntactic-indentation-in-macros t)) + ;; Turn on syntactic macro analysis to help with auto + ;; newlines only. + (setq syntax (c-guess-basic-syntax))) (setq newlines - (funcall (cdr newlines) (car newlines) insertion-point)))) - ;; does a newline go before the open brace? - (if (memq 'before newlines) - ;; we leave the newline we've put in there before, - ;; but we need to re-indent the line above - (let (old-ind - (old-point-max (point-max)) - (pos (- (point-max) (point))) - (here (point))) - (forward-line -1) - (setq old-ind (c-point 'boi)) - (let ((c-state-cache (c-whack-state (point) c-state-cache))) - ;; we may need to update the cache. this should - ;; still be faster than recalculating the state - ;; in many cases - (save-excursion - (save-restriction - (narrow-to-region here (point)) - (if (and (c-safe (progn (backward-up-list -1) t)) - (memq (char-before) '(?\) ?})) - (progn (widen) - (c-safe (progn (c-forward-sexp -1) - t)))) - (setq c-state-cache - (c-hack-state (point) 'open c-state-cache))))) - (if c-syntactic-indentation - (indent-according-to-mode))) - (setq c-state-cache (c-adjust-state (c-point 'bol) old-point-max - (- (c-point 'boi) old-ind) - c-state-cache)) - (goto-char (- (point-max) pos)) - ;; if the buffer has changed due to the indentation, we - ;; need to recalculate syntax for the current line, but - ;; we won't need to update the state cache. - (if (/= (point) here) - (setq syntax (c-guess-basic-syntax)))) + (and + c-auto-newline + (or (c-lookup-lists + syms + ;; Substitute inexpr-class and class-open or + ;; class-close with inexpr-class-open or + ;; inexpr-class-close. + (if (assq 'inexpr-class syntax) + (cond ((assq 'class-open syntax) + '((inexpr-class-open))) + ((assq 'class-close syntax) + '((inexpr-class-close))) + (t syntax)) + syntax) + c-hanging-braces-alist) + '(ignore before after)))) + ;; Do not try to insert newlines around a special + ;; (Pike-style) brace list. + (if (and c-special-brace-lists + (save-excursion + (c-safe (if (= (char-before) ?{) + (forward-char -1) + (c-forward-sexp -1)) + (c-looking-at-special-brace-list)))) + (setq newlines nil)) + ;; If syntax is a function symbol, then call it using the + ;; defined semantics. + (if (and (not (consp (cdr newlines))) + (functionp (cdr newlines))) + (let ((c-syntactic-context syntax)) + (setq newlines + (funcall (cdr newlines) + (car newlines) + insertion-point)))) + ;; does a newline go before the open brace? + (when (memq 'before newlines) + ;; we leave the newline we've put in there before, + ;; but we need to re-indent the line above + (when delete-temp-newline + (set-marker (car delete-temp-newline) nil) + (set-marker (cdr delete-temp-newline) nil) + (setq delete-temp-newline nil)) + (when c-syntactic-indentation + (let ((pos (- (point-max) (point))) + (here (point))) + (forward-line -1) + (indent-according-to-mode) + (goto-char (- (point-max) pos)) + ;; if the buffer has changed due to the + ;; indentation, we need to recalculate syntax for + ;; the current line. + (if (/= (point) here) + (let ((c-syntactic-indentation-in-macros t)) + ;; Turn on syntactic macro analysis to help + ;; with auto newlines only. + (setq syntax (c-guess-basic-syntax)))))))) ;; must remove the newline we just stuck in (if we really did it) - (and delete-temp-newline - (save-excursion - ;; if there is whitespace before point, then preserve - ;; at least one space. - (delete-indentation) - (just-one-space) - (setq c-state-cache (c-whack-state (point) c-state-cache)) - (if (not preserve-p) - (delete-char -1)))) - ;; since we're hanging the brace, we need to recalculate - ;; syntax. Update the state to accurately reflect the - ;; beginning of the line. We punt if we cross any open or - ;; closed parens because its just too hard to modify the - ;; known state. This limitation will be fixed in v5. - (save-excursion - (let ((bol (c-point 'bol))) - (if (zerop (car (parse-partial-sexp bol (1- (point))))) - (setq syntax (c-guess-basic-syntax)) - ;; gotta punt. this requires some horrible kludgery - (beginning-of-line) - (setq c-state-cache nil - c-state-cache (c-parse-state) - syntax nil)))) - ) - ;; Now adjust the line's indentation. Don't update the state - ;; cache since c-guess-basic-syntax isn't called when - ;; c-syntactic-context is set. - (let* ((old-ind (c-point 'boi)) - (old-point-max (point-max)) - (c-syntactic-context syntax)) - (indent-according-to-mode) - (setq c-state-cache (c-adjust-state (c-point 'bol) old-point-max - (- (c-point 'boi) old-ind) - c-state-cache))) + (when delete-temp-newline + (save-excursion + (delete-region (car delete-temp-newline) + (cdr delete-temp-newline)) + (goto-char (car delete-temp-newline)) + (set-marker (car delete-temp-newline) nil) + (set-marker (cdr delete-temp-newline) nil) + ;; if there is whitespace before point, then preserve + ;; at least one space. + (just-one-space) + (if (not preserve-p) + (delete-char -1))))) + (if (not (memq 'before newlines)) + ;; since we're hanging the brace, we need to recalculate + ;; syntax. + (let ((c-syntactic-indentation-in-macros t)) + ;; Turn on syntactic macro analysis to help with auto + ;; newlines only. + (setq syntax (c-guess-basic-syntax)))) + (when c-syntactic-indentation + ;; Now adjust the line's indentation. Don't update the state + ;; cache since c-guess-basic-syntax isn't called when + ;; c-syntactic-context is set. + (let* ((c-syntactic-context syntax)) + (indent-according-to-mode))) ;; Do all appropriate clean ups (let ((here (point)) (pos (- (point-max) (point))) @@ -370,59 +575,65 @@ syntax) (progn (forward-char -1) - (skip-chars-backward " \t\n") + (c-skip-ws-backward) (eq (char-before) ?\{)) ;; make sure matching open brace isn't in a comment (not (c-in-literal))) (delete-region (point) (1- here))) ;; clean up brace-else-brace and brace-elseif-brace (when (and c-auto-newline - (eq last-command-char ?\{) - (not (c-in-literal))) + (eq last-command-char ?\{)) (cond ((and (memq 'brace-else-brace c-cleanup-list) - (re-search-backward "}[ \t\n]*else[ \t\n]*{" nil t) + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "else" + "\\([ \t\n]\\|\\\\\n\\)*" + "{") + nil t) (progn (setq mbeg (match-beginning 0) mend (match-end 0)) (eq (match-end 0) here))) (delete-region mbeg mend) - (insert "} else {")) + (insert-and-inherit "} else {")) ((and (memq 'brace-elseif-brace c-cleanup-list) (progn (goto-char (1- here)) (setq mend (point)) - (skip-chars-backward " \t\n") + (c-skip-ws-backward) (setq mbeg (point)) (eq (char-before) ?\))) (= (c-backward-token-1 1 t) 0) (eq (char-after) ?\() (progn (setq tmp (point)) - (re-search-backward "}[ \t\n]*else[ \t\n]+if[ \t\n]*" - nil t)) + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "else" + "\\([ \t\n]\\|\\\\\n\\)+" + "if" + "\\([ \t\n]\\|\\\\\n\\)*") + nil t)) (eq (match-end 0) tmp)) (delete-region mbeg mend) (goto-char mbeg) - (insert " ")))) + (insert ?\ )))) (goto-char (- (point-max) pos)) ) ;; does a newline go after the brace? (if (memq 'after newlines) - (progn - (newline) - ;; update on c-state-cache - (let* ((bufpos (- (point) 2)) - (which (if (eq (char-after bufpos) ?{) 'open 'close)) - (c-state-cache (c-hack-state bufpos which c-state-cache))) - (indent-according-to-mode)))) - ;; blink the paren - (and (eq last-command-char ?\}) - old-blink-paren - (save-excursion - (c-backward-syntactic-ws safepos) - (funcall old-blink-paren))) - )))) + (c-newline-and-indent)) + ))) + ;; blink the paren + (and (eq last-command-char ?\}) + (not executing-kbd-macro) + old-blink-paren + (save-excursion + (c-backward-syntactic-ws safepos) + (funcall old-blink-paren))))) (defun c-electric-slash (arg) "Insert a slash character. @@ -439,13 +650,14 @@ `c-syntactic-indentation' is nil, indentation is inhibited." (interactive "*P") (let* ((ch (char-before)) + (literal (c-in-literal)) (indentp (and c-syntactic-indentation (not arg) (eq last-command-char ?/) (or (and (eq ch ?/) - (not (c-in-literal))) + (not literal)) (and (eq ch ?*) - (c-in-literal))) + literal)) )) ;; shut this up (c-echo-syntactic-information-p nil)) @@ -465,7 +677,7 @@ ;; current line, unless this star introduces a comment-only line. (if (and c-syntactic-indentation (not arg) - (memq (c-in-literal) '(c)) + (eq (c-in-literal) 'c) (eq (char-before) ?*) (save-excursion (forward-char -1) @@ -485,9 +697,8 @@ the variable `c-hanging-semi&comma-criteria' for how newline insertion is determined. -When semicolon is inserted, the line is re-indented unless a numeric -arg is supplied, point is inside a literal, or there are -non-whitespace characters on the line following the semicolon, or +When a semicolon is inserted, the line is re-indented unless a numeric +arg is supplied, point is inside a literal, or `c-syntactic-indentation' is nil. Based on the value of `c-cleanup-list', this function cleans up commas @@ -498,15 +709,14 @@ (here (point)) ;; shut this up (c-echo-syntactic-information-p nil)) - (if (or literal - arg - (not (looking-at "[ \t]*$"))) + (if (or literal arg) (self-insert-command (prefix-numeric-value arg)) ;; do some special stuff with the character (self-insert-command (prefix-numeric-value arg)) ;; do all cleanups and newline insertions if c-auto-newline is ;; turned on - (if (not c-auto-newline) + (if (or (not c-auto-newline) + (not (looking-at "[ \t]*\\\\?$"))) (if c-syntactic-indentation (indent-according-to-mode)) ;; clean ups @@ -519,7 +729,7 @@ (memq 'defun-close-semi c-cleanup-list))) (progn (forward-char -1) - (skip-chars-backward " \t\n") + (c-skip-ws-backward) (eq (char-before) ?})) ;; make sure matching open brace isn't in a comment (not (c-in-literal lim))) @@ -541,8 +751,7 @@ (setq add-newline-p (not (eq answer 'stop))) )) (if add-newline-p - (progn (newline) - (indent-according-to-mode))) + (c-newline-and-indent)) ))))) (defun c-electric-colon (arg) @@ -552,8 +761,7 @@ or \"/ah\" string on the mode line, newlines are inserted before and after colons based on the value of `c-hanging-colons-alist'. -Also, the line is re-indented unless a numeric ARG is supplied, there -are non-whitespace characters present on the line after the colon, the +Also, the line is re-indented unless a numeric ARG is supplied, the colon is inserted inside a literal, or `c-syntactic-indentation' is nil. @@ -562,13 +770,17 @@ (interactive "*P") (let* ((bod (c-point 'bod)) (literal (c-in-literal bod)) - syntax newlines is-scope-op + newlines is-scope-op ;; shut this up (c-echo-syntactic-information-p nil)) - (if (or literal - arg - (not (looking-at "[ \t]*$"))) - (self-insert-command (prefix-numeric-value arg)) + (cond + ((or literal arg) + (self-insert-command (prefix-numeric-value arg))) + ((not (looking-at "[ \t]*\\\\?$")) + (self-insert-command (prefix-numeric-value arg)) + (if c-syntactic-indentation + (indent-according-to-mode))) + (t ;; insert the colon, then do any specified cleanups (self-insert-command (prefix-numeric-value arg)) (let ((pos (- (point-max) (point))) @@ -578,7 +790,7 @@ (eq (char-before) ?:) (progn (forward-char -1) - (skip-chars-backward " \t\n") + (c-skip-ws-backward) (eq (char-before) ?:)) (not (c-in-literal)) (not (eq (char-after (- (point) 2)) ?:))) @@ -586,27 +798,36 @@ (delete-region (point) (1- here)) (setq is-scope-op t))) (goto-char (- (point-max) pos))) - ;; lets do some special stuff with the colon character - (setq syntax (c-guess-basic-syntax) - ;; some language elements can only be determined by - ;; checking the following line. Lets first look for ones - ;; that can be found when looking on the line with the - ;; colon - 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) - (let ((buffer-undo-list t)) - (insert "\n") - (unwind-protect - (c-guess-basic-syntax) - (delete-char -1))) - c-hanging-colons-alist)))) ;; indent the current line if it's done syntactically. (if c-syntactic-indentation - (let ((c-syntactic-context syntax)) - (indent-according-to-mode))) + ;; 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)) + (let* ((c-syntactic-indentation-in-macros 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. Lets 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) + (let ((buffer-undo-list t)) + (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). @@ -617,16 +838,13 @@ (not (bolp)))) (let ((pos (- (point-max) (point)))) (forward-char -1) - (newline) - (indent-according-to-mode) + (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)) - (progn - (newline) - (indent-according-to-mode))) - ))) + (c-newline-and-indent)) + )))) (defun c-electric-lt-gt (arg) "Insert a less-than, or greater-than character. @@ -652,15 +870,14 @@ Some newline cleanups are done if appropriate; see the variable `c-cleanup-list'. -Also, the line is re-indented unless a numeric ARG is supplied, there -are non-whitespace characters present on the line after the -parenthesis, the parenthesis is inserted inside a literal, or -`c-syntactic-indentation' is nil." +Also, the line is re-indented unless a numeric ARG is supplied, the +parenthesis is inserted inside a literal, or `c-syntactic-indentation' +is nil." (interactive "*P") - (let (;; shut this up + (let ((literal (c-in-literal (c-point 'bod))) + ;; shut this up (c-echo-syntactic-information-p nil)) - (if (or arg - (c-in-literal (c-point 'bod))) + (if (or arg literal) (self-insert-command (prefix-numeric-value arg)) ;; do some special stuff with the character (let* (;; We want to inhibit blinking the paren since this will @@ -669,9 +886,9 @@ (old-blink-paren blink-paren-function) blink-paren-function) (self-insert-command (prefix-numeric-value arg)) - (when (looking-at "[ \t]*$") - (if c-syntactic-indentation - (indent-according-to-mode)) + (if c-syntactic-indentation + (indent-according-to-mode)) + (when (looking-at "[ \t]*\\\\?$") (when c-auto-newline ;; Do all appropriate clean ups (let ((here (point)) @@ -680,8 +897,15 @@ ;; clean up brace-elseif-brace (if (and (memq 'brace-elseif-brace c-cleanup-list) (eq last-command-char ?\() - (re-search-backward "}[ \t\n]*else[ \t\n]+if[ \t\n]*(" - nil t) + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "else" + "\\([ \t\n]\\|\\\\\n\\)+" + "if" + "\\([ \t\n]\\|\\\\\n\\)*" + "(") + nil t) (save-excursion (setq mbeg (match-beginning 0) mend (match-end 0)) @@ -689,19 +913,26 @@ (not (c-in-literal))) (progn (delete-region mbeg mend) - (insert "} else if ("))) - ;; clean up brace-catch-brace - (if (and (memq 'brace-catch-brace c-cleanup-list) - (eq last-command-char ?\() - (re-search-backward "}[ \t\n]*catch[ \t\n]*(" nil t) - (save-excursion - (setq mbeg (match-beginning 0) - mend (match-end 0)) - (= mend here)) - (not (c-in-literal))) - (progn - (delete-region mbeg mend) - (insert "} catch ("))) + (insert-and-inherit "} else if (")) + ;; clean up brace-catch-brace + (goto-char here) + (if (and (memq 'brace-catch-brace c-cleanup-list) + (eq last-command-char ?\() + (re-search-backward + (concat "}" + "\\([ \t\n]\\|\\\\\n\\)*" + "catch" + "\\([ \t\n]\\|\\\\\n\\)*" + "(") + nil t) + (save-excursion + (setq mbeg (match-beginning 0) + mend (match-end 0)) + (= mend here)) + (not (c-in-literal))) + (progn + (delete-region mbeg mend) + (insert-and-inherit "} catch (")))) (goto-char (- (point-max) pos)) ))) (let (beg (end (1- (point)))) @@ -715,7 +946,7 @@ (save-excursion (delete-region beg end) (goto-char beg) - (insert " "))) + (insert ?\ ))) ((and (memq 'compact-empty-funcall c-cleanup-list) (eq last-command-char ?\)) (save-excursion @@ -726,8 +957,9 @@ (setq beg (point)) (c-on-identifier)))) (delete-region beg end)))) - (if old-blink-paren - (funcall old-blink-paren)))))) + (and (not executing-kbd-macro) + old-blink-paren + (funcall old-blink-paren)))))) (defun c-electric-continued-statement () "Reindent the current line if appropriate. @@ -748,7 +980,15 @@ (point)) (c-point 'boi)) (not (c-in-literal (c-point 'bod)))) - (indent-according-to-mode)))) + ;; Have to temporarily insert a space so that + ;; c-guess-basic-syntax recognizes the keyword. Follow the + ;; space with a nonspace to avoid messing up any whitespace + ;; sensitive meddling that might be done, e.g. by + ;; `c-backslash-region'. + (insert-and-inherit " x") + (unwind-protect + (indent-according-to-mode) + (delete-char -2))))) ;; better movement routines for ThisStyleOfVariablesCommonInCPlusPlus @@ -780,72 +1020,320 @@ "Insert a double colon scope operator at point. No indentation or other \"electric\" behavior is performed." (interactive "*") - (insert "::")) + (insert-and-inherit "::")) (defun c-beginning-of-defun (&optional arg) "Move backward to the beginning of a defun. -With argument, do it that many times. Negative arg -N -means move forward to Nth following beginning of defun. -Returns t unless search stops due to beginning or end of buffer. +Every top level declaration that contains a brace paren block is +considered to be a defun. + +With a positive argument, move backward that many defuns. A negative +argument -N means move forward to the Nth following beginning. Return +t unless search stops due to beginning or end of buffer. Unlike the built-in `beginning-of-defun' this tries to be smarter about finding the char with open-parenthesis syntax that starts the defun." + (interactive "p") - (unless arg (setq arg 1)) + (or arg (setq arg 1)) + (if (< arg 0) - (c-end-of-defun (- arg)) - (while (> arg 0) - (let ((state (nreverse (c-parse-state))) - prevbod bod) - (while (and state (not bod)) - (setq bod (car state) - state (cdr state)) - (if (consp bod) - (setq prevbod (car bod) - bod nil))) - (cond - (bod (goto-char bod)) - (prevbod (goto-char prevbod)) - (t (goto-char (point-min)) - (setq arg 0))) - (setq arg (1- arg)))) + (when (c-end-of-defun (- arg)) + (c-forward-syntactic-ws) + t) + + (catch 'exit + (while (> arg 0) + ;; Note: Partial code duplication in `c-end-of-defun' and + ;; `c-declaration-limits'. + + (let ((paren-state (c-parse-state)) lim pos) + (unless (c-safe + (goto-char (c-least-enclosing-brace paren-state)) + ;; If we moved to the outermost enclosing paren + ;; then we can use c-safe-position to set the + ;; limit. Can't do that otherwise since the + ;; earlier paren pair on paren-state might very + ;; well be part of the declaration we should go + ;; to. + (setq lim (c-safe-position (point) paren-state)) + t) + ;; At top level. Make sure we aren't inside a literal. + (setq pos (c-literal-limits + (c-safe-position (point) paren-state))) + (if pos (goto-char (car pos)))) + + (while (let ((start (point))) + (c-beginning-of-decl-1 lim) + (if (= (point) start) + ;; Didn't move. Might be due to bob or unbalanced + ;; parens. Try to continue if it's the latter. + (unless (c-safe (goto-char + (c-down-list-backward (point)))) + ;; Didn't work, so it's bob then. + (goto-char (point-min)) + (throw 'exit nil))) + + (save-excursion + ;; Check if the declaration contains a brace + ;; block. If not, we try another one. + (setq pos (point)) + (not (and (c-syntactic-re-search-forward + "[;{]" nil t 1 t) + (or (eq (char-before) ?{) + (and c-recognize-knr-p + ;; Might have stopped on the + ;; ';' in a K&R argdecl. In + ;; that case the declaration + ;; should contain a block. + (c-in-knr-argdecl pos))))))) + (setq lim nil)) + + ;; Check if `c-beginning-of-decl-1' put us after the block + ;; in a declaration that doesn't end there. We're searching + ;; back and forth over the block here, which can be + ;; expensive. + (setq pos (point)) + (if (and c-opt-block-decls-with-vars-key + (progn + (c-backward-syntactic-ws) + (eq (char-before) ?})) + (eq (car (c-beginning-of-decl-1)) + 'previous) + (save-excursion + (c-end-of-decl-1) + (> (point) pos))) + nil + (goto-char pos)) + + (setq pos (point)) + ;; 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-forward-comment -1))) + (if (/= (point) (c-point 'boi)) + (goto-char pos)) + + (setq arg (1- arg))))) (c-keep-region-active) (= arg 0))) (defun c-end-of-defun (&optional arg) - "Move forward to next end of defun. With argument, do it that many times. -Negative argument -N means move back to Nth preceding end of defun. -Returns t unless search stops due to beginning or end of buffer. + "Move forward to the end of a top level declaration. +With argument, do it that many times. Negative argument -N means move +back to Nth preceding end. Returns t unless search stops due to +beginning or end of buffer. An end of a defun occurs right after the close-parenthesis that matches the open-parenthesis that starts a defun; see `beginning-of-defun'." + (interactive "p") - (if (not arg) - (setq arg 1)) + (or arg (setq arg 1)) + (if (< arg 0) - (c-beginning-of-defun (- arg)) - (while (> arg 0) - (let ((pos (point)) - eol) - (while (and (c-safe (down-list 1) t) - (not (eq (char-before) ?{))) - ;; skip down into the next defun-block - (forward-char -1) - (c-forward-sexp)) - (c-beginning-of-defun 1) - (setq eol (c-point 'eol)) - (c-forward-sexp) - (if (< eol (point)) - ;; Don't move to next line for one line defuns. - (forward-line 1)) - (when (<= (point) pos) - (goto-char (point-max)) - (setq arg 0)) - (setq arg (1- arg)))) + (when (c-beginning-of-defun (- arg)) + (c-backward-syntactic-ws) + t) + + (catch 'exit + (while (> arg 0) + ;; Note: Partial code duplication in `c-beginning-of-defun' + ;; and `c-declaration-limits'. + + (let ((paren-state (c-parse-state)) lim pos) + (unless (c-safe + (goto-char (c-least-enclosing-brace paren-state)) + ;; If we moved to the outermost enclosing paren + ;; then we can use c-safe-position to set the + ;; limit. Can't do that otherwise since the + ;; earlier paren pair on paren-state might very + ;; well be part of the declaration we should go + ;; to. + (setq lim (c-safe-position (point) paren-state)) + t) + ;; At top level. Make sure we aren't inside a literal. + (setq pos (car-safe (c-literal-limits + (c-safe-position (point) paren-state)))) + (if pos (goto-char pos))) + + ;; Have to move to the start first so that `c-end-of-decl-1' + ;; has the correct start position. + (setq pos (point)) + (when (memq (car (c-beginning-of-decl-1 lim)) + '(previous macro)) + ;; We moved back over the previous defun or a macro. Move + ;; to the next token; it's the start of the next + ;; declaration. We can also be directly after the block + ;; in a `c-opt-block-decls-with-vars-key' declaration, but + ;; then we won't move significantly far here. + (goto-char pos) + (c-forward-token-1 0)) + + (while (let ((start (point))) + (c-end-of-decl-1) + (if (= (point) start) + ;; Didn't move. Might be due to eob or unbalanced + ;; parens. Try to continue if it's the latter. + (if (c-safe (goto-char (c-up-list-forward (point)))) + t + ;; Didn't work, so it's eob then. + (goto-char (point-max)) + (throw 'exit nil)) + + (save-excursion + ;; Check if the declaration contains a brace + ;; block. If not, we try another one. + (setq pos (point)) + (goto-char start) + (not (c-syntactic-re-search-forward "{" pos t 1 t)))))) + + (setq pos (point)) + ;; 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-comment 1))) + (cond ((bolp)) + ((looking-at "\\s *$") + (forward-line 1)) + (t + (goto-char pos))) + + (setq arg (1- arg))))) (c-keep-region-active) (= arg 0))) +(defun c-declaration-limits (near) + ;; Return a cons of the beginning and end positions of the current + ;; top level declaration or macro. If point is not inside any then + ;; nil is returned, unless NEAR is non-nil in which case the closest + ;; following one is chosen instead (if there is any). The end + ;; position is at the next line, providing there is one before the + ;; declaration. + (save-excursion + + ;; Note: Some code duplication in `c-beginning-of-defun' and + ;; `c-end-of-defun'. + (catch 'exit + (let ((start (point)) + (paren-state (c-parse-state)) + lim pos end-pos) + (unless (c-safe + (goto-char (c-least-enclosing-brace paren-state)) + ;; If we moved to the outermost enclosing paren then we + ;; can use c-safe-position to set the limit. Can't do + ;; that otherwise since the earlier paren pair on + ;; paren-state might very well be part of the + ;; declaration we should go to. + (setq lim (c-safe-position (point) paren-state)) + t) + ;; At top level. Make sure we aren't inside a literal. + (setq pos (c-literal-limits + (c-safe-position (point) paren-state))) + (if pos (goto-char (car pos)))) + + (when (c-beginning-of-macro) + (throw 'exit + (cons (point) + (save-excursion + (c-end-of-macro) + (forward-line 1) + (point))))) + + (setq pos (point)) + (when (or (eq (car (c-beginning-of-decl-1 lim)) 'previous) + (= pos (point))) + ;; We moved back over the previous defun. Skip to the next + ;; one. Not using c-forward-syntactic-ws here since we + ;; should not skip a macro. We can also be directly after + ;; the block in a `c-opt-block-decls-with-vars-key' + ;; declaration, but then we won't move significantly far + ;; here. + (goto-char pos) + (while (c-forward-comment 10)) + + (when (and near (c-beginning-of-macro)) + (throw 'exit + (cons (point) + (save-excursion + (c-end-of-macro) + (forward-line 1) + (point)))))) + + (if (eobp) (throw 'exit nil)) + + ;; Check if `c-beginning-of-decl-1' put us after the block in a + ;; declaration that doesn't end there. We're searching back and + ;; forth over the block here, which can be expensive. + (setq pos (point)) + (if (and c-opt-block-decls-with-vars-key + (progn + (c-backward-syntactic-ws) + (eq (char-before) ?})) + (eq (car (c-beginning-of-decl-1)) + 'previous) + (save-excursion + (c-end-of-decl-1) + (and (> (point) pos) + (setq end-pos (point))))) + nil + (goto-char pos)) + + (if (and (not near) (> (point) start)) + nil + + ;; Try to be line oriented; position the limits at the + ;; closest preceding boi, and after the next newline, that + ;; isn't inside a comment, but if we hit a neighboring + ;; declaration then we instead use the exact declaration + ;; limit in that direction. + (cons (progn + (setq pos (point)) + (while (and (/= (point) (c-point 'boi)) + (c-forward-comment -1))) + (if (/= (point) (c-point 'boi)) + pos + (point))) + (progn + (if end-pos + (goto-char end-pos) + (c-end-of-decl-1)) + (setq pos (point)) + (while (and (not (bolp)) + (not (looking-at "\\s *$")) + (c-forward-comment 1))) + (cond ((bolp) + (point)) + ((looking-at "\\s *$") + (forward-line 1) + (point)) + (t + pos))))) + )))) + +(defun c-mark-function () + "Put mark at end of the current top-level declaration or macro, point at beginning. +If point is not inside any then the closest following one is chosen. + +As opposed to \\[c-beginning-of-defun] and \\[c-end-of-defun], this +function does not require the declaration to contain a brace block." + (interactive) + + ;; We try to be line oriented, unless there are several + ;; declarations on the same line. + (if (looking-at c-syntactic-eol) + (c-backward-token-1 1 nil (c-point 'bol))) + + (let ((decl-limits (c-declaration-limits t))) + (if (not decl-limits) + (error "Cannot find any declaration") + (goto-char (car decl-limits)) + (push-mark (cdr decl-limits) nil t)))) + (defun c-beginning-of-statement (&optional count lim sentence-flag) "Go to the beginning of the innermost C statement. @@ -858,7 +1346,12 @@ When called from a program, this function takes 3 optional args: the repetition count, a buffer position limit which is the farthest back to search for the syntactic context, and a flag saying whether to do -sentence motion in or near comments and multiline strings." +sentence motion in or near comments and multiline strings. + +Note that `c-beginning-of-statement-1' is usually better to use from +programs. It has much more well defined semantics than this one, +which is intended for interactive use and might therefore change to be +more \"DWIM:ey\"." (interactive (list (prefix-numeric-value current-prefix-arg) nil t)) (let* ((count (or count 1)) @@ -871,24 +1364,24 @@ (save-excursion ;; Find the comment next to point if we're not in one. (if (> count 0) - (if (c-forward-comment -1) + (if (c-forward-comment-lc -1) (setq range (cons (point) - (progn (c-forward-comment 1) (point)))) - (skip-chars-backward " \t\n\r\f") + (progn (c-forward-comment-lc 1) + (point)))) + (c-skip-ws-backward) (setq range (point)) (setq range (if (eq (char-before) ?\") (c-safe (c-backward-sexp 1) (cons (point) range))))) - ;; skip-syntax-* doesn't count \n as whitespace.. - (skip-chars-forward " \t\n\r\f") + (c-skip-ws-forward) (if (eq (char-after) ?\") (setq range (cons (point) (progn (c-forward-sexp 1) (point)))) (setq range (point)) - (setq range (if (c-forward-comment 1) + (setq range (if (c-forward-comment-lc 1) (cons range (point)) nil)))) (setq range (c-collect-line-comments range)))) @@ -987,7 +1480,7 @@ (bolp)) (goto-char (cdr range))))) (when (and (eq (point) (point-min)) - (looking-at "[ \t]*$")) + (looking-at "[ \t]*\\\\?$")) ;; Stop before instead of after the comment ;; starter if nothing follows it. (widen) @@ -1007,10 +1500,6 @@ (setq range nil)))) (goto-char (if (> count 0) (car range) (cdr range))) (setq range nil)) - ;; Below we do approximately the same as - ;; c-beginning-of-statement-1 and c-end-of-statement-1, and - ;; perhaps they should be changed, but that'd likely break a - ;; lot in cc-engine. (goto-char here) (if (> count 0) (condition-case nil @@ -1038,14 +1527,18 @@ (not (eq last-below-line here))) (goto-char last-below-line)) (throw 'done t))) + ;; Don't know why I added the following, but it + ;; doesn't work when point is preceded by a line + ;; style comment. /mast + ;;(c-skip-ws-backward) (if literal-pos - (c-forward-comment large-enough) - (when (c-forward-comment -1) + (c-forward-comment-lc large-enough) + (when (c-forward-comment-lc -1) ;; Record position of first comment. (save-excursion - (c-forward-comment 1) + (c-forward-comment-lc 1) (setq literal-pos (point))) - (c-forward-comment large-enough))) + (c-forward-comment-lc large-enough))) (unless last-below-line (if (save-excursion (re-search-forward "\\(^\\|[^\\]\\)$" last t)) @@ -1103,13 +1596,13 @@ (while t (setq last (point)) (if literal-pos - (c-forward-comment large-enough) + (c-forward-comment-lc large-enough) (if (progn - (skip-chars-forward " \t\n\r\f") + (c-skip-ws-forward) ;; Record position of first comment. (setq literal-pos (point)) - (c-forward-comment 1)) - (c-forward-comment large-enough) + (c-forward-comment-lc 1)) + (c-forward-comment-lc large-enough) (setq literal-pos nil))) (cond ((and (eq (char-after) ?{) (not (and c-special-brace-lists @@ -1131,13 +1624,13 @@ (/= here last)) (goto-char last) (throw 'done t)) - ((and (eq (char-after) ?#) - (= (point) (c-point 'boi))) - (if (= here last) - (or (re-search-forward "\\(^\\|[^\\]\\)$" nil t) - (goto-char (point-max))) - (goto-char last)) - (throw 'done t)) +; ((and (eq (char-after) ?#) +; (= (point) (c-point 'boi))) +; (if (= here last) +; (or (re-search-forward "\\(^\\|[^\\]\\)$" nil t) +; (goto-char (point-max))) +; (goto-char last)) +; (throw 'done t)) ((looking-at ";\\|};?") (goto-char (match-end 0)) (throw 'done t)) @@ -1210,36 +1703,76 @@ (put 'c-electric-delete-forward 'pending-delete 'supersede) ; pending-del -;; This is used by indent-for-comment to decide how much to indent a -;; comment in C code based on its context. +(defun c-calc-comment-indent (entry) + (if (symbolp entry) + (setq entry (or (assq entry c-indent-comment-alist) + (assq 'other c-indent-comment-alist) + '(default . (column . nil))))) + (let ((action (car (cdr entry))) + (value (cdr (cdr entry))) + (col (current-column))) + (cond ((eq action 'space) + (+ col value)) + ((eq action 'column) + (unless value (setq value comment-column)) + (if (bolp) + ;; Do not pad with one space if we're at bol. + value + (max (1+ col) value))) + ((eq action 'align) + (or (save-excursion + (beginning-of-line) + (unless (bobp) + (backward-char) + (let ((lim (c-literal-limits (c-point 'bol) t))) + (when (consp lim) + (goto-char (car lim)) + (when (looking-at "/[/*]") + ;; Found comment to align with. + (if (bolp) + ;; Do not pad with one space if we're at bol. + 0 + (max (1+ col) (current-column)))))))) + ;; Recurse to handle value as a new spec. + (c-calc-comment-indent (cdr entry))))))) + +;; To avoid warning about assignment without reference wrt +;; c-add-syntax below. +(cc-bytecomp-defvar syntactic-relpos) + (defun c-comment-indent () - (if (looking-at (concat "^\\(" c-comment-start-regexp "\\)")) - 0 ;Existing comment at bol stays there. - (let ((opoint (point)) - placeholder) - (save-excursion - (beginning-of-line) - (cond - ;; CASE 1: A comment following a solitary close-brace should - ;; have only one space. - ((looking-at (concat "[ \t]*}[ \t]*\\($\\|" - c-comment-start-regexp - "\\)")) - (search-forward "}") - (1+ (current-column))) - ;; CASE 2: 2 spaces after #endif - ((or (looking-at "[ \t]*#[ \t]*endif[ \t]*") - (looking-at "[ \t]*#[ \t]*else[ \t]*")) - 7) - ;; CASE 3: when c-indent-comments-syntactically-p is t, - ;; calculate the offset according to c-offsets-alist. - ;; E.g. identical to hitting TAB. - ((and c-indent-comments-syntactically-p - (save-excursion - (skip-chars-forward " \t") - (or (looking-at c-comment-start-regexp) - (eolp)))) - (let ((syntax (c-guess-basic-syntax))) + "Used by `indent-for-comment' to create and indent comments. +See `c-indent-comment-alist' for a description." + (save-excursion + (end-of-line) + (let* ((eot (let ((lim (c-literal-limits (c-point 'bol) t))) + (or (when (consp lim) + (goto-char (car lim)) + (when (looking-at "/[/*]") + (skip-chars-backward " \t") + (point))) + (progn + (skip-chars-backward " \t") + (point))))) + (line-type + (cond ((looking-at "^/[/*]") + 'anchored-comment) + ((progn (beginning-of-line) + (eq (point) eot)) + 'empty-line) + ((progn (back-to-indentation) + (and (eq (char-after) ?}) + (eq (point) (1- eot)))) + 'end-block) + ((and (looking-at "#[ \t]*\\(endif\\|else\\)") + (eq (match-end 0) eot)) + 'cpp-end-block) + (t + 'other)))) + (if (and (memq line-type '(anchored-comment empty-line)) + c-indent-comments-syntactically-p) + (let ((syntax (c-guess-basic-syntax)) + syntactic-relpos) ;; BOGOSITY ALERT: if we're looking at the eol, its ;; because indent-for-comment hasn't put the comment-start ;; in the buffer yet. this will screw up the syntactic @@ -1247,51 +1780,22 @@ ;; kludge is that if we're at the bol, then we really want ;; to ignore any anchoring as specified by ;; c-comment-only-line-offset since it doesn't apply here. - (if (save-excursion - (back-to-indentation) - (eolp)) + (if (eolp) (c-add-syntax 'comment-intro)) (let ((c-comment-only-line-offset (if (consp c-comment-only-line-offset) c-comment-only-line-offset (cons c-comment-only-line-offset c-comment-only-line-offset)))) - (c-get-syntactic-indentation syntax)))) - ;; CASE 4: If previous line is a comment-only line, use its - ;; indentation if it's greater than comment-column. Leave at - ;; least one space between the comment and the last nonblank - ;; character in any case. - ((save-excursion - (beginning-of-line) - (and (not (bobp)) - (forward-line -1)) - (skip-chars-forward " \t") - (prog1 - (looking-at c-comment-start-regexp) - (setq placeholder (current-column)))) - (goto-char opoint) - (skip-chars-backward " \t") - (max (if (bolp) 0 (1+ (current-column))) - placeholder - comment-column)) - ;; CASE 5: If comment-column is 0, and nothing but space - ;; before the comment, align it at 0 rather than 1. - ((progn - (goto-char opoint) - (skip-chars-backward " \t") - (and (= comment-column 0) (bolp))) - 0) - ;; CASE 6: indent at comment column except leave at least one - ;; space. - (t (max (1+ (current-column)) - comment-column)) - ))))) + (c-get-syntactic-indentation syntax))) + (goto-char eot) + (c-calc-comment-indent line-type))))) ;; used by outline-minor-mode (defun c-outline-level () - ;; This so that `current-column' DTRT in otherwise-hidden text. - (let (buffer-invisibility-spec) + (let (buffer-invisibility-spec);; This so that `current-column' DTRT + ;; in otherwise-hidden text. (save-excursion (skip-chars-forward "\t ") (current-column)))) @@ -1448,16 +1952,16 @@ but the line is always reindented. If `c-syntactic-indentation' is t, indentation is done according to -the syntactic context. If it's nil, the line is just indented one +the syntactic context. A numeric argument, regardless of its value, +means indent rigidly all the lines of the expression starting after +point so that this line becomes properly indented. The relative +indentation among the lines of the expression is preserved. + +If `c-syntactic-indentation' is nil, the line is just indented one step according to `c-basic-offset'. In this mode, a numeric argument indents a number of such steps, positive or negative, and an empty prefix argument is equivalent to -1. -If `c-syntactic-indentation' is t, then a numeric argument, regardless -of its value, means indent rigidly all the lines of the expression -starting after point so that this line becomes properly indented. The -relative indentation among the lines of the expression is preserved. - [*] The amount and kind of whitespace inserted is controlled by the variable `c-insert-tab-function', which is called to do the actual insertion of whitespace. Normally the function in this variable @@ -1465,15 +1969,22 @@ depending on the variable `indent-tabs-mode'." (interactive "p") - (let ((bod (c-point 'bod)) - (indent-function + (let ((indent-function (if c-syntactic-indentation (symbol-function 'indent-according-to-mode) (lambda () - (let ((steps (cond ((not current-prefix-arg) 1) + (let ((c-macro-start c-macro-start) + (steps (cond ((not current-prefix-arg) 1) ((equal current-prefix-arg '(4)) -1) (t arg)))) - (c-shift-line-indentation (* steps c-basic-offset))) + (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 current-prefix-arg) ;; If c-syntactic-indentation and got arg, always indent this @@ -1515,7 +2026,7 @@ ;; CASE 3: if in a literal, insert a tab, but always indent the ;; line (t - (if (c-in-literal bod) + (if (c-in-literal) (funcall c-insert-tab-function)) (funcall indent-function) ))))) @@ -1529,72 +2040,74 @@ end) (set-marker-insertion-type here t) (unwind-protect - (let ((start (progn - ;; try to be smarter about finding the range of - ;; lines to indent. skip all following - ;; whitespace, then try to find any - ;; opening paren on the current line - (skip-chars-forward " \t\n") - (save-restriction - (narrow-to-region (point-min) (c-point 'eol)) - (c-safe (1- (scan-lists (point) 1 -1))))))) - ;; find balanced expression end - (setq end (and (c-safe (progn (c-forward-sexp 1) t)) - (point))) + (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) - (forward-line) - (setq start (point)) + (setq end (c-safe (scan-sexps (point) 1))) (if (not end) (unless shutup-p (error "Cannot find end of balanced expression to indent")) - (if (< start end) - (c-indent-region start end))))) + (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 function def, struct or class declaration -syntactically." + "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)) - (c-echo-syntactic-information-p nil) - (brace (c-least-enclosing-brace (c-parse-state)))) - (goto-char (or brace (c-point 'bod))) - ;; if we're sitting at b-o-b, it might be because there was no - ;; least enclosing brace and we were sitting on the defun's open - ;; brace. - (if (and (bobp) (not (eq (char-after) ?\{))) - (goto-char here)) - ;; if defun-prompt-regexp is non-nil, b-o-d might not leave us at - ;; the open brace. I consider this an Emacs bug. - (and (boundp 'defun-prompt-regexp) - defun-prompt-regexp - (looking-at defun-prompt-regexp) - (goto-char (match-end 0))) - ;; catch all errors in c-indent-exp so we can 1. give more - ;; meaningful error message, and 2. restore point + (let ((here (point-marker)) decl-limits) + ;; We try to be line oriented, unless there are several + ;; declarations on the same line. + (if (looking-at c-syntactic-eol) + (c-backward-token-1 1 nil (c-point 'bol)) + (c-forward-token-1 0 nil (c-point 'eol))) (unwind-protect - (c-indent-exp) + (if (setq decl-limits (c-declaration-limits nil)) + (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 every line whose first char is between START and END inclusive. -Be silent about syntactic errors if the optional argument QUIET is non-nil." + "Indent syntactically every line whose first char is between START +and END inclusive. If the optional argument QUIET is non-nil then no +syntactic errors are reported, even if `c-report-syntactic-errors' is +non-nil." (save-excursion + (goto-char end) + (skip-chars-backward " \t\n\r") + (setq end (point)) (goto-char start) ;; Advance to first nonblank line. - (skip-chars-forward " \t\n") + (beginning-of-line) + (skip-chars-forward " \t\n\r") + (setq start (point)) (beginning-of-line) (setq c-parsing-error (or (let ((endmark (copy-marker end)) (c-parsing-error nil) ;; shut up any echo msgs on indiv lines - (c-echo-syntactic-information-p nil)) + (c-echo-syntactic-information-p nil) + (in-macro (and c-auto-align-backslashes + (save-excursion (c-beginning-of-macro)) + start)) + (c-fix-backslashes nil) + syntax) (unwind-protect (progn (c-progress-init start end 'c-indent-region) @@ -1603,84 +2116,49 @@ (< (point) endmark)) ;; update progress (c-progress-update) - ;; skip blank lines + ;; skip empty lines (skip-chars-forward " \t\n") (beginning-of-line) - ;; indent the current line - (c-indent-line nil t) - (forward-line))) + ;; Get syntax and indent. + (setq syntax (c-guess-basic-syntax)) + (if (and c-auto-align-backslashes + (assq 'cpp-macro syntax)) + ;; Record macro start. + (setq in-macro (point))) + (if in-macro + (if (looking-at "\\s *\\\\$") + (forward-line) + (c-indent-line syntax t t) + (if (progn (end-of-line) + (not (eq (char-before) ?\\))) + (progn + ;; Fixup macro backslashes. + (forward-line) + (c-backslash-region in-macro (point) nil) + (setq in-macro nil)) + (forward-line))) + (c-indent-line syntax t t) + (forward-line))) + (if in-macro + (c-backslash-region in-macro (c-point 'bopl) nil t))) (set-marker endmark nil) (c-progress-fini 'c-indent-region)) (c-echo-parsing-error quiet)) c-parsing-error)))) -(defun c-mark-function () - "Put mark at end of current top-level defun, point at beginning." - (interactive) - (let ((here (point)) - (eod (c-point 'eod)) - (state (c-parse-state))) - ;; Are we sitting at the top level, someplace between either the - ;; beginning of buffer, or the nearest preceding defun? If so, - ;; try first to figure out whether we're sitting on the - ;; introduction to a top-level defun, in which case we want to - ;; mark the entire defun we're sitting on. - ;; - ;; If we're sitting on anything else at the top-level, we want to - ;; just mark the statement that we're on - (if (or (and (consp (car state)) - (= (length state) 1)) - (null state)) - ;; Are we in the whitespace after the nearest preceding defun? - (if (and state - (looking-at "[ \t]*$") - (= (save-excursion - (c-backward-syntactic-ws) - (skip-chars-backward ";") - (point)) - (cdr (car state)))) - (progn - (setq eod (point)) - (goto-char (car (car state))) - (c-beginning-of-statement-1)) - (if (= ?{ (save-excursion - (c-end-of-statement-1) - (char-before))) - ;; We must be in a defuns's introduction - (progn - (c-end-of-statement-1) - (skip-chars-backward "{") - (c-beginning-of-statement-1) - (c-forward-syntactic-ws)) - ;; Just mark the statement - (c-end-of-statement-1) - (forward-line 1) - (setq eod (point)) - (c-beginning-of-statement-1))) - ;; We are inside some enclosing brace structure, so we first - ;; need to find our way to the least enclosing brace. Then, in - ;; both cases, we to mark the region from the beginning of the - ;; current statement, until the end of the next following defun - (while (and state) - (or (consp (car state)) - (goto-char (car state))) - (setq state (cdr state))) - (c-beginning-of-statement-1)) - (push-mark here) - (push-mark eod nil t))) - (defun c-fn-region-is-active-p () ;; Function version of the macro for use in places that aren't ;; compiled, e.g. in the menus. (c-region-is-active-p)) (defun c-indent-line-or-region () - "When the region is active, indent it. Otherwise indent the current line." + "When the region is active, indent it syntactically. Otherwise +indent the current line syntactically." ;; Emacs has a variable called mark-active, XEmacs uses region-active-p (interactive) (if (c-region-is-active-p) (c-indent-region (region-beginning) (region-end)) - (indent-according-to-mode))) + (c-indent-line))) ;; for progress reporting @@ -1739,71 +2217,236 @@ ;;; This page handles insertion and removal of backslashes for C macros. -(defun c-backslash-region (from to delete-flag) +(defun c-backslash-region (from to delete-flag &optional line-mode) "Insert, align, or delete end-of-line backslashes on the lines in the region. With no argument, inserts backslashes and aligns existing backslashes. -With an argument, deletes the backslashes. +With an argument, deletes the backslashes. The backslash alignment is +done according to the settings in `c-backslash-column', +`c-backslash-max-column' and `c-auto-align-backslashes'. This function does not modify blank lines at the start of the region. -If the region ends at the start of a line, it always deletes the -backslash (if any) at the end of the previous line. +If the region ends at the start of a line and the macro doesn't +continue below it, the backslash (if any) at the end of the previous +line is deleted. You can put the region around an entire macro definition and use this command to conveniently insert and align the necessary backslashes." (interactive "*r\nP") - (save-excursion - (goto-char from) - (let ((column c-backslash-column) - (endmark (make-marker))) - (move-marker endmark to) - ;; Compute the smallest column number past the ends of all the lines. - (if (not delete-flag) - (while (< (point) to) - (end-of-line) - (if (eq (char-before) ?\\) - (progn (forward-char -1) - (skip-chars-backward " \t"))) - (setq column (max column (1+ (current-column)))) - (forward-line 1))) - ;; Adjust upward to a tab column, if that doesn't push past the margin. - (if (> (% column tab-width) 0) - (let ((adjusted (* (/ (+ column tab-width -1) tab-width) tab-width))) - (if (< adjusted (window-width)) - (setq column adjusted)))) - ;; Don't modify blank lines at start of region. - (goto-char from) - (while (and (< (point) endmark) (eolp)) - (forward-line 1)) - ;; Add or remove backslashes on all the lines. - (while (< (point) endmark) - (if (and (not delete-flag) - ;; Un-backslashify the last line - ;; if the region ends right at the start of the next line. - (save-excursion - (forward-line 1) - (< (point) endmark))) - (c-append-backslash column) - (c-delete-backslash)) - (forward-line 1)) - (move-marker endmark nil)))) + (let ((endmark (make-marker)) + ;; Keep the backslash trimming functions from changing the + ;; whitespace around point, since in this case it's only the + ;; position of point that tells the indentation of the line. + (point-pos (if (save-excursion + (skip-chars-backward " \t") + (and (bolp) (looking-at "[ \t]*\\\\?$"))) + (point-marker) + (point-min))) + column longest-line-col bs-col-after-end) + (save-excursion + (goto-char to) + (if (and (not line-mode) (bobp)) + ;; Nothing to do if to is at bob, since we should back up + ;; and there's no line to back up to. + nil + (when (and (not line-mode) (bolp)) + ;; Do not back up the to line if line-mode is set, to make + ;; e.g. c-newline-and-indent consistent regardless whether + ;; the (newline) call leaves point at bol or not. + (backward-char) + (setq to (point))) + (if delete-flag + (progn + (set-marker endmark (point)) + (goto-char from) + (c-delete-backslashes-forward endmark point-pos)) + ;; Set bs-col-after-end to the column of any backslash + ;; following the region, or nil if there is none. + (setq bs-col-after-end + (and (progn (end-of-line) + (eq (char-before) ?\\)) + (= (forward-line 1) 0) + (progn (end-of-line) + (eq (char-before) ?\\)) + (1- (current-column)))) + (when line-mode + ;; Back up the to line if line-mode is set, since the line + ;; after the newly inserted line break should not be + ;; touched in c-newline-and-indent. + (setq to (max from (or (c-safe (c-point 'eopl)) from))) + (unless bs-col-after-end + ;; Set bs-col-after-end to non-nil in any case, since we + ;; do not want to delete the backslash at the last line. + (setq bs-col-after-end t))) + (if (and line-mode + (not c-auto-align-backslashes)) + (goto-char from) + ;; Compute the smallest column number past the ends of all + ;; the lines. + (setq longest-line-col 0) + (goto-char to) + (if bs-col-after-end + ;; Include one more line in the max column + ;; calculation, since the to line will be backslashed + ;; too. + (forward-line 1)) + (end-of-line) + (while (and (>= (point) from) + (progn + (if (eq (char-before) ?\\) + (forward-char -1)) + (skip-chars-backward " \t") + (setq longest-line-col (max longest-line-col + (1+ (current-column)))) + (beginning-of-line) + (not (bobp)))) + (backward-char)) + ;; Try to align with surrounding backslashes. + (goto-char from) + (beginning-of-line) + (if (and (not (bobp)) + (progn (backward-char) + (eq (char-before) ?\\))) + (progn + (setq column (1- (current-column))) + (if (numberp bs-col-after-end) + ;; Both a preceding and a following backslash. + ;; Choose the greatest of them. + (setq column (max column bs-col-after-end))) + (goto-char from)) + ;; No preceding backslash. Try to align with one + ;; following the region. Disregard the backslash at the + ;; to line since it's likely to be bogus (e.g. when + ;; called from c-newline-and-indent). + (if (numberp bs-col-after-end) + (setq column bs-col-after-end)) + ;; Don't modify blank lines at start of region. + (goto-char from) + (while (and (< (point) to) (bolp) (eolp)) + (forward-line 1))) + (if (and column (< column longest-line-col)) + ;; Don't try to align with surrounding backslashes if + ;; any line is too long. + (setq column nil)) + (unless column + ;; Impose minimum limit and tab width alignment only if + ;; we can't align with surrounding backslashes. + (if (> (% longest-line-col tab-width) 0) + (setq longest-line-col + (* (/ (+ longest-line-col tab-width -1) + tab-width) + tab-width))) + (setq column (max c-backslash-column + longest-line-col))) + ;; Always impose maximum limit. + (setq column (min column c-backslash-max-column))) + (if bs-col-after-end + ;; Add backslashes on all lines if the macro continues + ;; after the to line. + (progn + (set-marker endmark to) + (c-append-backslashes-forward endmark column point-pos)) + ;; Add backslashes on all lines except the last, and + ;; remove any on the last line. + (if (save-excursion + (goto-char to) + (beginning-of-line) + (if (not (bobp)) + (set-marker endmark (1- (point))))) + (progn + (c-append-backslashes-forward endmark column point-pos) + ;; The function above leaves point on the line + ;; following endmark. + (set-marker endmark (point))) + (set-marker endmark to)) + (c-delete-backslashes-forward endmark point-pos))))) + (set-marker endmark nil) + (if (markerp point-pos) + (set-marker point-pos nil)))) -(defun c-append-backslash (column) - (end-of-line) - (if (eq (char-before) ?\\) - (progn (forward-char -1) - (delete-horizontal-space) - (indent-to column)) - (indent-to column) - (insert "\\"))) +(defun c-append-backslashes-forward (to-mark column point-pos) + (let ((state (parse-partial-sexp (c-point 'bol) (point)))) + (if column + (while + (and + (<= (point) to-mark) + + (let ((start (point)) (inserted nil) end col) + (end-of-line) + (unless (eq (char-before) ?\\) + (insert ?\\) + (setq inserted t)) + (setq state (parse-partial-sexp + start (point) nil nil state)) + (backward-char) + (setq col (current-column)) + + ;; Avoid unnecessary changes of the buffer. + (cond ((and (not inserted) (nth 3 state)) + ;; Don't realign backslashes in string literals + ;; since that would change them. + ) + + ((< col column) + (delete-region + (point) + (progn + (skip-chars-backward + " \t" (if (>= (point) point-pos) point-pos)) + (point))) + (indent-to column)) + + ((and (= col column) + (memq (char-before) '(?\ ?\t)))) -(defun c-delete-backslash () - (end-of-line) - (or (bolp) - (progn - (forward-char -1) - (if (looking-at "\\\\") - (delete-region (1+ (point)) - (progn (skip-chars-backward " \t") (point))))))) + ((progn + (setq end (point)) + (or (/= (skip-chars-backward + " \t" (if (>= (point) point-pos) point-pos)) + -1) + (/= (char-after) ?\ ))) + (delete-region (point) end) + (indent-to column 1))) + + (= (forward-line 1) 0)))) + + ;; Make sure there are backslashes with at least one space in + ;; front of them. + (while + (and + (<= (point) to-mark) + + (let ((start (point))) + (end-of-line) + (setq state (parse-partial-sexp + start (point) nil nil state)) + + (if (eq (char-before) ?\\) + (unless (nth 3 state) + (backward-char) + (unless (and (memq (char-before) '(?\ ?\t)) + (/= (point) point-pos)) + (insert ?\ ))) + + (if (and (memq (char-before) '(?\ ?\t)) + (/= (point) point-pos)) + (insert ?\\) + (insert ?\ ?\\))) + + (= (forward-line 1) 0))))))) + +(defun c-delete-backslashes-forward (to-mark point-pos) + (while + (and (<= (point) to-mark) + (progn + (end-of-line) + (if (eq (char-before) ?\\) + (delete-region + (point) + (progn (backward-char) + (skip-chars-backward " \t" (if (>= (point) point-pos) + point-pos)) + (point)))) + (= (forward-line 1) 0))))) @@ -1854,7 +2497,7 @@ (start (point))) (unwind-protect (progn - (insert ?\n fill-prefix) + (insert-and-inherit "\n" fill-prefix) (current-column)) (delete-region start (point)) (set-buffer-modified-p buffer-modified)))))) @@ -1882,38 +2525,45 @@ (goto-char (match-end 0)) (forward-char 2) (skip-chars-forward " \t")) - (setq res - (if (eq (c-point 'boi) (car lit-limits)) - ;; There is only whitespace before the comment - ;; starter; take the prefix straight from this - ;; line. - (cons (buffer-substring-no-properties + (let (str col) + (if (eq (c-point 'boi) (car lit-limits)) + ;; There is only whitespace before the comment + ;; starter; take the prefix straight from this line. + (setq str (buffer-substring-no-properties (c-point 'bol) (point)) - (current-column)) - ;; There is code before the comment starter, so we - ;; have to temporarily insert and indent a new - ;; line to get the right space/tab mix in the - ;; indentation. - (let ((buffer-modified (buffer-modified-p)) - (buffer-undo-list t) - (prefix-len (- (point) (car lit-limits))) - tmp) - (unwind-protect - (progn - (goto-char (car lit-limits)) - (indent-to (prog1 (current-column) - (insert ?\n))) - (setq tmp (point)) - (forward-char prefix-len) - (cons (buffer-substring-no-properties + col (current-column)) + ;; There is code before the comment starter, so we + ;; have to temporarily insert and indent a new line to + ;; get the right space/tab mix in the indentation. + (let ((buffer-modified (buffer-modified-p)) + (buffer-undo-list t) + (prefix-len (- (point) (car lit-limits))) + tmp) + (unwind-protect + (progn + (goto-char (car lit-limits)) + (indent-to (prog1 (current-column) + (insert ?\n))) + (setq tmp (point)) + (forward-char prefix-len) + (setq str (buffer-substring-no-properties (c-point 'bol) (point)) - (current-column))) - (delete-region (car lit-limits) tmp) - (set-buffer-modified-p buffer-modified)))) - ))))) + col (current-column))) + (delete-region (car lit-limits) tmp) + (set-buffer-modified-p buffer-modified)))) + (setq res + (if (or (string-match "\\s \\'" str) (not (eolp))) + (cons str col) + ;; The prefix ends the line with no whitespace + ;; after it. Default to a single space. + (cons (concat str " ") (1+ col)))) + ))))) (t + (setq comment-text-end + (save-excursion + (goto-char (- (cdr lit-limits) 2)) + (if (looking-at "\\*/") (point) (cdr lit-limits)))) (save-excursion - (setq comment-text-end (- (cdr lit-limits) 2)) (beginning-of-line) (if (and (> (point) (car lit-limits)) (not (and (looking-at "[ \t]*\\*/") @@ -1931,7 +2581,7 @@ (<= (1- (cdr lit-limits)) (match-end 0))) (and (< here (point)) (or (not (match-beginning 0)) - (looking-at "[ \t]*$")))) + (looking-at "[ \t]*\\\\?$")))) ;; The comment is either one line or the next line ;; contains just the comment ender. Also, if point is ;; on the comment opener line and the following line is @@ -1953,7 +2603,8 @@ (progn (goto-char (car lit-limits)) (if (looking-at comment-start-regexp) - (goto-char (match-end 0)) + (goto-char (min (match-end 0) + comment-text-end)) (forward-char 2) (skip-chars-forward " \t")) (when (eq (char-syntax (char-before)) ?\ ) @@ -1975,7 +2626,7 @@ ;; character before the line break and ;; after comment-prefix in case it's ;; "" or ends with whitespace. - (insert "x\n" comment-prefix ?x) + (insert-and-inherit "x\n" comment-prefix "x") (setq tmp-post (point-marker)) (indent-according-to-mode) (goto-char (1- tmp-post)) @@ -2050,10 +2701,13 @@ (when fb-string ;; A good line wasn't found, but at least we have a ;; fallback that matches the comment prefix regexp. - (cond ((string-match "\\s \\'" fb-string) - ;; There are ws after the prefix, so let's use it. - (cons fb-string - (progn (goto-char fb-endpos) (current-column)))) + (cond ((or (string-match "\\s \\'" fb-string) + (progn + (goto-char fb-endpos) + (not (eolp)))) + ;; There are ws or text after the prefix, so + ;; let's use it. + (cons fb-string (current-column))) ((progn ;; Check if there's any whitespace padding ;; on the comment start line that we can @@ -2063,7 +2717,8 @@ (goto-char (match-end 0)) (forward-char 2) (skip-chars-forward " \t")) - (eq (char-syntax (char-before)) ?\ )) + (or (not (eolp)) + (eq (char-syntax (char-before)) ?\ ))) (setq fb-string (buffer-substring-no-properties (save-excursion (skip-chars-backward " \t") @@ -2078,7 +2733,7 @@ ;; ensure the column gets correct. :P (unwind-protect (progn - (insert fb-string) + (insert-and-inherit fb-string) (cons (buffer-substring-no-properties (c-point 'bol) (point)) @@ -2106,6 +2761,264 @@ '("" . 0)))))) )) +(defun c-mask-comment (fill-include-ender apply-outside-literal fun &rest args) + ;; Calls FUN with ARGS ar arguments. If point is inside a comment, + ;; the comment starter and ender are masked and the buffer is + ;; narrowed to make it look like a normal paragraph during the call. + (let (fill + ;; beg and end limits the region to narrow. end is a marker. + beg end + ;; tmp-pre and tmp-post mark strings that are temporarily + ;; inserted at the start and end of the region. tmp-pre is a + ;; cons of the positions of the prepended string. tmp-post is + ;; a marker pointing to the single character of the appended + ;; string. + tmp-pre tmp-post + ;; If hang-ender-stuck isn't nil, the comment ender is + ;; hanging. In that case it's set to the number of spaces + ;; that should be between the text and the ender. + hang-ender-stuck + (here (point)) + (c-lit-limits c-lit-limits) + (c-lit-type c-lit-type)) + ;; Restore point on undo. It's necessary since we do a lot of + ;; hidden inserts and deletes below that should be as transparent + ;; as possible. + (if (and buffer-undo-list (not (eq buffer-undo-list t))) + (setq buffer-undo-list (cons (point) buffer-undo-list))) + (save-restriction + ;; Widen to catch comment limits correctly. + (widen) + (unless c-lit-limits + (setq c-lit-limits (c-literal-limits nil t))) + (setq c-lit-limits (c-collect-line-comments c-lit-limits)) + (unless c-lit-type + (setq c-lit-type (c-literal-type c-lit-limits)))) + (save-excursion + (unless (c-safe (backward-char) + (forward-paragraph) + (>= (point) here)) + (goto-char here) + (forward-paragraph)) + (setq end (point-marker))) + (save-excursion + (unless (c-safe (forward-char) + (backward-paragraph) + (<= (point) here)) + (goto-char here) + (backward-paragraph)) + (setq beg (point))) + (unwind-protect + (progn + (cond + ((eq c-lit-type 'c++) ; Line comment. + (save-excursion + ;; Limit to the comment or paragraph end, whichever + ;; comes first. + (set-marker end (min end (cdr c-lit-limits))) + (when (<= beg (car c-lit-limits)) + ;; The region includes the comment starter, so we must + ;; check it. + (goto-char (car c-lit-limits)) + (back-to-indentation) + (if (eq (point) (car c-lit-limits)) + ;; Include the first line in the region. + (setq beg (c-point 'bol)) + ;; The first line contains code before the + ;; comment. We must fake a line that doesn't. + (setq tmp-pre t))) + )) + ((eq c-lit-type 'c) ; Block comment. + (when (>= end (cdr c-lit-limits)) + ;; The region includes the comment ender which we might + ;; want to keep together with the last word. + (unless (save-excursion + (goto-char (cdr c-lit-limits)) + (beginning-of-line) + (and (looking-at (concat "[ \t]*\\(" + c-current-comment-prefix + "\\)\\*/")) + (eq (cdr c-lit-limits) (match-end 0)) + ;; Leave the comment ender on its own line. + (set-marker end (point)))) + (when fill-include-ender + ;; The comment ender should hang. Replace all cruft + ;; between it and the last word with one or two 'x' + ;; and include it in the region. We'll change them + ;; back to spaces afterwards. + (let* ((ender-start (save-excursion + (goto-char (cdr c-lit-limits)) + (skip-syntax-backward "^w ") + (point))) + (point-rel (- ender-start here)) + spaces) + (save-excursion + (goto-char (cdr c-lit-limits)) + (setq tmp-post (point-marker)) + (insert ?\n) + (set-marker end (point)) + (forward-line -1) + (if (and (looking-at (concat "[ \t]*\\(\\(" + c-current-comment-prefix + "\\)[ \t]*\\)")) + (eq ender-start (match-end 0))) + ;; The comment ender is prefixed by nothing + ;; but a comment line prefix. Remove it + ;; along with surrounding ws. + (setq spaces (- (match-end 1) (match-end 2))) + (goto-char ender-start)) + (skip-chars-backward " \t\r\n") + (if (/= (point) ender-start) + (progn + (if (<= here (point)) + ;; Don't adjust point below if it's + ;; before the string we replace. + (setq point-rel -1)) + ;; Keep one or two spaces between the text and + ;; the ender, depending on how many there are now. + (unless spaces + (setq spaces (- ender-start (point)))) + (setq spaces + (max (min spaces + (if sentence-end-double-space 2 1)) + 1)) + ;; Insert the filler first to keep marks right. + (insert-char ?x spaces t) + (delete-region (point) (+ ender-start spaces)) + (setq hang-ender-stuck spaces) + (setq point-rel + (and (>= point-rel 0) + (- (point) (min point-rel spaces))))) + (setq point-rel nil))) + (if point-rel + ;; Point was in the middle of the string we + ;; replaced above, so put it back in the same + ;; relative position, counting from the end. + (goto-char point-rel)) + )))) + (when (<= beg (car c-lit-limits)) + ;; The region includes the comment starter. + (save-excursion + (goto-char (car c-lit-limits)) + (if (looking-at (concat "\\(" comment-start-skip "\\)$")) + ;; Begin with the next line. + (setq beg (c-point 'bonl)) + ;; Fake the fill prefix in the first line. + (setq tmp-pre t))))) + ((eq c-lit-type 'string) ; String. + (save-excursion + (when (>= end (cdr c-lit-limits)) + (goto-char (1- (cdr c-lit-limits))) + (setq tmp-post (point-marker)) + (insert ?\n) + (set-marker end (point))) + (when (<= beg (car c-lit-limits)) + (goto-char (1+ (car c-lit-limits))) + (setq beg (if (looking-at "\\\\$") + ;; Leave the start line if it's + ;; nothing but an escaped newline. + (1+ (match-end 0)) + (point)))))) + (t (setq beg nil))) + (when tmp-pre + ;; Temporarily insert the fill prefix after the comment + ;; starter so that the first line looks like any other + ;; comment line in the narrowed region. + (setq fill (c-guess-fill-prefix c-lit-limits c-lit-type)) + (unless (string-match (concat "\\`[ \t]*\\(" + c-current-comment-prefix + "\\)[ \t]*\\'") + (car fill)) + ;; Oops, the prefix doesn't match the comment prefix + ;; regexp. This could produce very confusing + ;; results with adaptive fill packages together with + ;; the insert prefix magic below, since the prefix + ;; often doesn't appear at all. So let's warn about + ;; it. + (message "\ +Warning: Regexp from `c-comment-prefix-regexp' doesn't match the comment prefix %S" + (car fill))) + ;; Find the right spot on the line, break it, insert + ;; the fill prefix and make sure we're back in the + ;; same column by temporarily prefixing the first word + ;; with a number of 'x'. + (save-excursion + (goto-char (car c-lit-limits)) + (if (looking-at (if (eq c-lit-type 'c++) + c-current-comment-prefix + comment-start-skip)) + (goto-char (match-end 0)) + (forward-char 2) + (skip-chars-forward " \t")) + (while (< (current-column) (cdr fill)) (forward-char 1)) + (let ((col (current-column))) + (setq beg (1+ (point)) + tmp-pre (list (point))) + (unwind-protect + (progn + (insert-and-inherit "\n" (car fill)) + (insert-char ?x (- col (current-column)) t)) + (setcdr tmp-pre (point)))))) + (if beg + (let ((fill-prefix + (or fill-prefix + ;; Kludge: If the function that adapts the + ;; fill prefix doesn't produce the required + ;; comment starter for line comments, then + ;; force it by setting fill-prefix. + (when (and (eq c-lit-type 'c++) + ;; Kludge the kludge: + ;; filladapt-mode doesn't have + ;; this problem, but it doesn't + ;; override fill-context-prefix + ;; currently (version 2.12). + (not (and (boundp 'filladapt-mode) + filladapt-mode)) + (not (string-match + "\\`[ \t]*//" + (or (fill-context-prefix beg end) + "")))) + (car (or fill (c-guess-fill-prefix + c-lit-limits c-lit-type)))))) + ;; Don't remember why I added this, but it doesn't + ;; work correctly since `here' can point anywhere + ;; after the deletes and inserts above. + ;(point-rel (cond ((< here beg) (- here beg)) + ; ((> here end) (- here end)))) + ) + ;; Preparations finally done! Now we can call the + ;; actual function. + (prog1 + (save-restriction + (narrow-to-region beg end) + (apply fun args)) + ;(if point-rel + ; ;; Restore point if it was outside the region. + ; (if (< point-rel 0) + ; (goto-char (+ beg point-rel)) + ; (goto-char (+ end point-rel)))) + )) + (when apply-outside-literal + (apply fun args)))) + (when (consp tmp-pre) + (delete-region (car tmp-pre) (cdr tmp-pre))) + (when tmp-post + (save-excursion + (goto-char tmp-post) + (delete-char 1)) + (when hang-ender-stuck + ;; Preserve point even if it's in the middle of the string + ;; we replace; save-excursion doesn't work in that case. + (setq here (point)) + (goto-char tmp-post) + (skip-syntax-backward "^w ") + (forward-char (- hang-ender-stuck)) + (insert-char ?\ hang-ender-stuck t) + (delete-char hang-ender-stuck) + (goto-char here)) + (set-marker tmp-post nil)) + (set-marker end nil)))) + (defun c-fill-paragraph (&optional arg) "Like \\[fill-paragraph] but handles C and C++ style comments. If any of the current line is a comment or within a comment, fill the @@ -2127,243 +3040,11 @@ Optional prefix ARG means justify paragraph as well." (interactive "*P") - (let (lit-limits lit-type fill - ;; beg and end limits the region to be filled. end is a marker. - beg end - ;; tmp-pre and tmp-post mark strings that are temporarily - ;; inserted at the start and end of the region. tmp-pre is a - ;; cons of the positions of the prepended string. tmp-post is - ;; a marker pointing to the single character of the appended - ;; string. - tmp-pre tmp-post - ;; If hang-ender-stuck isn't nil, the comment ender is - ;; hanging. In that case it's set to the number of spaces - ;; that should be between the text and the ender. - hang-ender-stuck - (here (point))) - ;; Restore point on undo. It's necessary since we do a lot of - ;; hidden inserts and deletes below that should be as transparent - ;; as possible. - (if (and buffer-undo-list (not (eq buffer-undo-list t))) - (setq buffer-undo-list (cons (point) buffer-undo-list))) - (save-restriction - ;; Widen to catch comment limits correctly. - (widen) - (setq lit-limits (c-collect-line-comments (c-literal-limits nil t)) - lit-type (c-literal-type lit-limits))) - (save-excursion - (unless (c-safe (backward-char) - (forward-paragraph) - (>= (point) here)) - (goto-char here) - (forward-paragraph)) - (setq end (point-marker))) - (save-excursion - (unless (c-safe (forward-char) - (backward-paragraph) - (<= (point) here)) - (goto-char here) - (backward-paragraph)) - (setq beg (point))) - (unwind-protect - (progn - (cond - ((eq lit-type 'c++) ; Line comment. - (save-excursion - ;; Fill to the comment or paragraph end, whichever - ;; comes first. - (set-marker end (min end (cdr lit-limits))) - (when (<= beg (car lit-limits)) - ;; The region to be filled includes the comment - ;; starter, so we must check it. - (goto-char (car lit-limits)) - (back-to-indentation) - (if (eq (point) (car lit-limits)) - ;; Include the first line in the fill. - (setq beg (c-point 'bol)) - ;; The first line contains code before the - ;; comment. We must fake a line that doesn't. - (setq tmp-pre t))) - )) - ((eq lit-type 'c) ; Block comment. - (when (>= end (cdr lit-limits)) - ;; The region to be filled includes the comment ender. - (unless (save-excursion - (goto-char (cdr lit-limits)) - (beginning-of-line) - (and (looking-at (concat "[ \t]*\\(" - c-current-comment-prefix - "\\)\\*/")) - (eq (cdr lit-limits) (match-end 0)) - ;; Leave the comment ender on its own line. - (set-marker end (point)))) - ;; The comment ender should hang. Replace all cruft - ;; between it and the last word with one or two 'x' - ;; and include it in the fill. We'll change them back - ;; spaces afterwards. - (let* ((ender-start (save-excursion - (goto-char (cdr lit-limits)) - (skip-syntax-backward "^w ") - (point))) - (point-rel (- ender-start here)) - spaces) - (save-excursion - (goto-char (cdr lit-limits)) - (setq tmp-post (point-marker)) - (insert ?\n) - (set-marker end (point)) - (forward-line -1) - (if (and (looking-at (concat "[ \t]*\\(\\(" - c-current-comment-prefix - "\\)[ \t]*\\)")) - (eq ender-start (match-end 0))) - ;; The comment ender is prefixed by nothing - ;; but a comment line prefix. Remove it - ;; along with surrounding ws. - (setq spaces (- (match-end 1) (match-end 2))) - (goto-char ender-start)) - (skip-chars-backward " \t\r\n") - (if (/= (point) ender-start) - (progn - (if (<= here (point)) - ;; Don't adjust point below if it's - ;; before the string we replace. - (setq point-rel -1)) - ;; Keep one or two spaces between the text and - ;; the ender, depending on how many there are now. - (unless spaces (setq spaces (- ender-start (point)))) - (setq spaces (max (min spaces 2) 1)) - ;; Insert the filler first to keep marks right. - (insert (make-string spaces ?x)) - (delete-region (point) (+ ender-start spaces)) - (setq hang-ender-stuck spaces) - (setq point-rel - (and (>= point-rel 0) - (- (point) (min point-rel spaces))))) - (setq point-rel nil))) - (if point-rel - ;; Point was in the middle of the string we - ;; replaced above, so put it back in the same - ;; relative position, counting from the end. - (goto-char point-rel)) - ))) - (when (<= beg (car lit-limits)) - ;; The region to be filled includes the comment starter. - (save-excursion - (goto-char (car lit-limits)) - (if (looking-at (concat "\\(" comment-start-skip "\\)$")) - ;; Begin filling with the next line. - (setq beg (c-point 'bonl)) - ;; Fake the fill prefix in the first line. - (setq tmp-pre t))))) - ((eq lit-type 'string) ; String. - (save-excursion - (when (>= end (cdr lit-limits)) - (goto-char (1- (cdr lit-limits))) - (setq tmp-post (point-marker)) - (insert ?\n) - (set-marker end (point))) - (when (<= beg (car lit-limits)) - (goto-char (1+ (car lit-limits))) - (setq beg (if (looking-at "\\\\$") - ;; Leave the start line if it's - ;; nothing but an escaped newline. - (1+ (match-end 0)) - (point)))))) - (t (setq beg nil))) - (when tmp-pre - ;; Temporarily insert the fill prefix after the comment - ;; starter so that the first line looks like any other - ;; comment line in the narrowed region. - (setq fill (c-guess-fill-prefix lit-limits lit-type)) - (unless (string-match (concat "\\`[ \t]*\\(" - c-current-comment-prefix - "\\)[ \t]*\\'") - (car fill)) - ;; Oops, the prefix doesn't match the comment prefix - ;; regexp. This could produce very confusing - ;; results with adaptive fill packages together with - ;; the insert prefix magic below, since the prefix - ;; often doesn't appear at all. So let's warn about - ;; it. - (message "\ -Warning: Regexp from `c-comment-prefix-regexp' doesn't match the comment prefix %S" - (car fill))) - ;; Find the right spot on the line, break it, insert - ;; the fill prefix and make sure we're back in the - ;; same column by temporarily prefixing the first word - ;; with a number of 'x'. - (save-excursion - (goto-char (car lit-limits)) - (if (looking-at (if (eq lit-type 'c++) - c-current-comment-prefix - comment-start-skip)) - (goto-char (match-end 0)) - (forward-char 2) - (skip-chars-forward " \t")) - (while (< (current-column) (cdr fill)) (forward-char 1)) - (let ((col (current-column))) - (setq beg (1+ (point)) - tmp-pre (list (point))) - (unwind-protect - (progn - (insert ?\n (car fill)) - (insert (make-string (- col (current-column)) ?x))) - (setcdr tmp-pre (point)))))) - (when beg - (let ((fill-paragraph-function - ;; Avoid infinite recursion. - (if (not (eq fill-paragraph-function 'c-fill-paragraph)) - fill-paragraph-function)) - (fill-prefix - (or fill-prefix - ;; Kludge: If the function that adapts the fill prefix - ;; doesn't produce the required comment starter for line - ;; comments, then force it by setting fill-prefix. - (when (and (eq lit-type 'c++) - ;; Kludge the kludge: filladapt-mode doesn't - ;; have this problem, but it doesn't override - ;; fill-context-prefix currently (version - ;; 2.12). - (not (and (boundp 'filladapt-mode) - filladapt-mode)) - (not (string-match - "\\`[ \t]*//" - (or (fill-context-prefix beg end) - "")))) - (car (or fill (c-guess-fill-prefix - lit-limits lit-type)))))) - (point-rel (cond ((< here beg) (- here beg)) - ((> here end) (- here end))))) - ;; Preparations finally done! Now we can call the - ;; real fill function. - (save-restriction - (narrow-to-region beg end) - (fill-paragraph arg)) - (if point-rel - ;; Restore point if it was outside the region. - (if (< point-rel 0) - (goto-char (+ beg point-rel)) - (goto-char (+ end point-rel)))) - ))) - (when (consp tmp-pre) - (delete-region (car tmp-pre) (cdr tmp-pre))) - (when tmp-post - (save-excursion - (goto-char tmp-post) - (delete-char 1)) - (when hang-ender-stuck - ;; Preserve point even if it's in the middle of the string - ;; we replace; save-excursion doesn't work in that case. - (setq here (point)) - (goto-char tmp-post) - (skip-syntax-backward "^w ") - (forward-char (- hang-ender-stuck)) - (insert (make-string hang-ender-stuck ?\ )) - (delete-char hang-ender-stuck) - (goto-char here)) - (set-marker tmp-post nil)) - (set-marker end nil))) + (let ((fill-paragraph-function + ;; Avoid infinite recursion. + (if (not (eq fill-paragraph-function 'c-fill-paragraph)) + fill-paragraph-function))) + (c-mask-comment 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. @@ -2380,40 +3061,44 @@ ;; also used to detect whether fill-prefix is user set or ;; generated automatically by do-auto-fill. fill-prefix)) - (do-auto-fill))) + (c-mask-comment nil t 'do-auto-fill))) -(defun c-indent-new-comment-line (&optional soft) - "Break line at point and indent, continuing comment if within one. +(defun c-indent-new-comment-line (&optional soft allow-auto-fill) + "Break line at point and indent, continuing comment or macro if within one. If inside a comment and `comment-multi-line' is non-nil, the indentation and line prefix are preserved (see the `c-comment-prefix-regexp' and `c-block-comment-prefix' variables for details). If inside a single line comment and `comment-multi-line' is nil, a new comment of the same type is started on the next line and -indented as appropriate for comments. +indented as appropriate for comments. If inside a macro, a line +continuation backslash is inserted and aligned as appropriate, and the +new line is indented according to `c-syntactic-indentation'. If a fill prefix is specified, it overrides all the above." + ;; allow-auto-fill is used from c-context-line-break to allow auto + ;; filling to break the line more than once. Since this function is + ;; used from auto-fill itself, that's normally disabled to avoid + ;; unnecessary recursion. (interactive) (let ((fill-prefix fill-prefix) (do-line-break (lambda () - (delete-region (progn (skip-chars-backward " \t") (point)) - (progn (skip-chars-forward " \t") (point))) - (if soft (insert-and-inherit ?\n) (newline 1)))) + (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-lit-type c-lit-type) + (c-macro-start c-macro-start)) (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 ((eq c-lit-type 'pound) - ;; Come to think about it, "pound" is a bit - ;; of a misnomer, so call it "cpp" instead - ;; in user interaction. - 'cpp) + (if (memq (cond ((c-query-and-set-macro-start) 'cpp) ((null c-lit-type) 'code) (t c-lit-type)) c-ignore-auto-fill) @@ -2441,10 +3126,11 @@ (insert-and-inherit fill-prefix)) ((progn (unless c-lit-limits - (setq c-lit-limits (c-literal-limits nil nil t))) + (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)) @@ -2455,35 +3141,44 @@ (setq c-lit-limits (c-collect-line-comments c-lit-limits)) c-lit-type)) - (pos (point))) - (if (save-excursion - (back-to-indentation) - (> (point) (car c-lit-limits)) - (looking-at c-current-comment-prefix)) + (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". + (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 - ;; Skip forward past the fill prefix in case - ;; we're standing in it. - (while (and (< (current-column) (cdr fill)) - (not (eolp))) - (forward-char 1)) - (if (> (point) (if (and (eq c-lit-type 'c) - (save-excursion - (forward-char -2) - (looking-at "\\*/"))) - (- (cdr c-lit-limits) 2) - (cdr c-lit-limits))) - (progn - ;; The skip takes us out of the 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)) - (funcall do-line-break) - (insert-and-inherit (car fill)))) + ;; 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)))) ;; Inside a comment that should be broken. @@ -2509,13 +3204,24 @@ (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 - (while (progn (back-to-indentation) - (and (looking-at "^\\s *$") - (= (forward-line -1) 0)))) - (current-column)))) + (beginning-of-line) + (while (and (looking-at "[ \t]*\\\\?$") + (= (forward-line -1) 0))) + (current-indentation)))) (funcall do-line-break) (indent-to col)))))) @@ -2537,37 +3243,70 @@ (defun c-context-line-break () "Do a line break suitable to the context. -When point is outside a comment, insert a newline and indent according -to the syntactic context. +When point is outside a comment or macro, insert a newline and indent +according to the syntactic context, unless `c-syntactic-indentation' +is nil, in which case the new line is indented as the previous +non-empty line instead. + +When point is inside the content of a preprocessor directive, a line +continuation backslash is inserted before the line break and aligned +appropriately. The end of the cpp directive doesn't count as inside +it. When point is inside a comment, continue it with the appropriate comment prefix (see the `c-comment-prefix-regexp' and `c-block-comment-prefix' variables for details). The end of a -C++-style line comment doesn't count as inside the comment, though." +C++-style line comment doesn't count as inside it." (interactive "*") (let* ((c-lit-limits (c-literal-limits nil nil t)) - (c-lit-type (c-literal-type c-lit-limits))) + (c-lit-type (c-literal-type c-lit-limits)) + (c-macro-start c-macro-start)) (if (or (eq c-lit-type 'c) (and (eq c-lit-type 'c++) - (< (point) + (< (save-excursion + (skip-chars-forward " \t") + (point)) (1- (cdr (setq c-lit-limits - (c-collect-line-comments c-lit-limits))))))) + (c-collect-line-comments c-lit-limits)))))) + (and (or (not (looking-at "\\s *$")) + (eq (char-before) ?\\)) + (c-query-and-set-macro-start) + (<= (save-excursion + (goto-char c-macro-start) + (if (looking-at "#[ \t]*[a-zA-Z0-9!]+") + (goto-char (match-end 0))) + (point)) + (point)))) (let ((comment-multi-line t) (fill-prefix nil)) - (c-indent-new-comment-line)) - (delete-region (point) (progn (skip-chars-backward " \t") (point))) + (c-indent-new-comment-line nil 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 (forward-line -1) - (while (progn (back-to-indentation) - (and (looking-at "^\\s *$") - (= (forward-line -1) 0)))) - (current-column)))) + (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. +This is the `c-context-line-break' equivalent to `open-line', which is +normally bound to C-o. See `c-context-line-break' for the details." + (interactive "*") + (let ((here (point))) + (unwind-protect + (progn + ;; Temporarily insert a non-whitespace char to keep any + ;; preceding whitespace intact. + (insert ?x) + (c-context-line-break)) + (goto-char here) + (delete-char 1)))) + (cc-provide 'cc-cmds)
--- a/lisp/progmodes/cc-compat.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-compat.el Mon Apr 22 00:35:36 2002 +0000 @@ -23,7 +23,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA.
--- a/lisp/progmodes/cc-defs.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-defs.el Mon Apr 22 00:35:36 2002 +0000 @@ -25,7 +25,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. @@ -57,6 +57,7 @@ ;; Silence the compiler. (cc-bytecomp-defvar c-enable-xemacs-performance-kludge-p) ; In cc-vars.el +(cc-bytecomp-defvar c-buffer-is-cc-mode) ; In cc-vars.el (cc-bytecomp-defun buffer-syntactic-context-depth) ; XEmacs (cc-bytecomp-defun region-active-p) ; XEmacs (cc-bytecomp-defvar zmacs-region-stays) ; XEmacs @@ -83,13 +84,17 @@ ;; eol -- end of line ;; bod -- beginning of defun ;; eod -- end of defun - ;; boi -- back to indentation + ;; boi -- beginning of indentation ;; ionl -- indentation of next line ;; iopl -- indentation of previous line ;; bonl -- beginning of next line + ;; eonl -- end of next line ;; bopl -- beginning of previous line + ;; eopl -- end of previous line ;; - ;; This function does not modify point or mark. + ;; If the referenced position doesn't exist, the closest accessible + ;; point to it is returned. This function does not modify point or + ;; mark. `(save-excursion ,(if point `(goto-char ,point)) ,(if (and (eq (car-safe position) 'quote) @@ -99,10 +104,16 @@ ((eq position 'bol) `(beginning-of-line)) ((eq position 'eol) `(end-of-line)) ((eq position 'boi) `(back-to-indentation)) + ((eq position 'bod) `(c-beginning-of-defun-1)) ((eq position 'bonl) `(forward-line 1)) ((eq position 'bopl) `(forward-line -1)) - ((eq position 'bod) `(c-beginning-of-defun-1)) ((eq position 'eod) `(c-end-of-defun-1)) + ((eq position 'eopl) `(progn + (beginning-of-line) + (or (bobp) (backward-char)))) + ((eq position 'eonl) `(progn + (forward-line 1) + (end-of-line))) ((eq position 'iopl) `(progn (forward-line -1) (back-to-indentation))) @@ -116,10 +127,16 @@ ((eq position 'bol) (beginning-of-line)) ((eq position 'eol) (end-of-line)) ((eq position 'boi) (back-to-indentation)) + ((eq position 'bod) (c-beginning-of-defun-1)) ((eq position 'bonl) (forward-line 1)) ((eq position 'bopl) (forward-line -1)) - ((eq position 'bod) (c-beginning-of-defun-1)) ((eq position 'eod) (c-end-of-defun-1)) + ((eq position 'eopl) (progn + (beginning-of-line) + (or (bobp) (backward-char)))) + ((eq position 'eonl) (progn + (forward-line 1) + (end-of-line))) ((eq position 'iopl) (progn (forward-line -1) (back-to-indentation))) @@ -134,6 +151,7 @@ `(condition-case nil (progn ,@body) (error nil))) +(put 'c-safe 'lisp-indent-function 0) (defmacro c-forward-sexp (&optional arg) ;; like forward-sexp except @@ -153,29 +171,30 @@ (or arg (setq arg 1)) `(c-forward-sexp ,(if (numberp arg) (- arg) `(- ,arg)))) +;; Wrappers for common scan-lists cases, mainly because it's almost +;; impossible to get a feel for how that function works. +(defmacro c-up-list-forward (pos) + `(c-safe (scan-lists ,pos 1 1))) +(defmacro c-up-list-backward (pos) + `(c-safe (scan-lists ,pos -1 1))) +(defmacro c-down-list-forward (pos) + `(c-safe (scan-lists ,pos 1 -1))) +(defmacro c-down-list-backward (pos) + `(c-safe (scan-lists ,pos -1 -1))) + (defmacro c-add-syntax (symbol &optional relpos) ;; a simple macro to append the syntax in symbol to the syntax list. ;; try to increase performance by using this macro - `(setq syntax (cons (cons ,symbol ,relpos) syntax))) + `(let ((relpos-tmp ,relpos)) + (if relpos-tmp (setq syntactic-relpos relpos-tmp)) + (setq syntax (cons (cons ,symbol relpos-tmp) syntax)))) -(defmacro c-add-class-syntax (symbol classkey) - ;; The inclass and class-close syntactic symbols are added in - ;; several places and some work is needed to fix everything. - ;; Therefore it's collected here. This is a macro mostly because - ;; c-add-syntax doesn't work otherwise. - `(save-restriction - (widen) - (let ((symbol ,symbol) - (classkey ,classkey) - inexpr) - (goto-char (aref classkey 1)) - (if (and (eq symbol 'inclass) (= (point) (c-point 'boi))) - (c-add-syntax symbol (point)) - (c-add-syntax symbol (aref classkey 0)) - (if (and c-inexpr-class-key - (setq inexpr (c-looking-at-inexpr-block)) - (/= (cdr inexpr) (c-point 'boi (cdr inexpr)))) - (c-add-syntax 'inexpr-class)))))) +(defmacro c-benign-error (format &rest args) + ;; Formats an error message for the echo area and dings, i.e. like + ;; `error' but doesn't abort. + `(progn + (message ,format ,@args) + (ding))) (defmacro c-update-modeline () ;; set the c-auto-hungry-string for the correct designation on the modeline @@ -197,6 +216,66 @@ (set-syntax-table c-with-syntax-table-orig-table)))) (put 'c-with-syntax-table 'lisp-indent-function 1) +(defmacro c-skip-ws-forward (&optional limit) + "Skip over any whitespace following point. +This function skips over horizontal and vertical whitespace and line +continuations." + (if limit + `(let ((-limit- (or ,limit (point-max)))) + (while (progn + ;; skip-syntax-* doesn't count \n as whitespace.. + (skip-chars-forward " \t\n\r\f" -limit-) + (when (and (eq (char-after) ?\\) + (< (point) -limit-)) + (forward-char) + (or (eolp) + (progn (backward-char) nil)))))) + '(while (progn + (skip-chars-forward " \t\n\r\f") + (when (eq (char-after) ?\\) + (forward-char) + (or (eolp) + (progn (backward-char) nil))))))) + +(defmacro c-skip-ws-backward (&optional limit) + "Skip over any whitespace preceding point. +This function skips over horizontal and vertical whitespace and line +continuations." + (if limit + `(let ((-limit- (or ,limit (point-min)))) + (while (progn + ;; skip-syntax-* doesn't count \n as whitespace.. + (skip-chars-backward " \t\n\r\f" -limit-) + (and (eolp) + (eq (char-before) ?\\) + (> (point) -limit-))) + (backward-char))) + '(while (progn + (skip-chars-backward " \t\n\r\f") + (and (eolp) + (eq (char-before) ?\\))) + (backward-char)))) + +;; Make edebug understand the macros. +(eval-after-load "edebug" + '(progn + (def-edebug-spec c-paren-re t) + (def-edebug-spec c-identifier-re t) + (def-edebug-spec c-point ([&or symbolp form] &optional form)) + (def-edebug-spec c-safe t) + (def-edebug-spec c-forward-sexp (&optional [&or numberp form])) + (def-edebug-spec c-backward-sexp (&optional [&or numberp form])) + (def-edebug-spec c-up-list-forward t) + (def-edebug-spec c-up-list-backward t) + (def-edebug-spec c-down-list-forward t) + (def-edebug-spec c-down-list-backward t) + (def-edebug-spec c-add-syntax t) + (def-edebug-spec c-add-class-syntax t) + (def-edebug-spec c-benign-error t) + (def-edebug-spec c-with-syntax-table t) + (def-edebug-spec c-skip-ws-forward t) + (def-edebug-spec c-skip-ws-backward t))) + ;;; Inline functions. ;; Note: All these after the macros, to be on safe side in avoiding @@ -262,43 +341,6 @@ (if (< (point) start) (goto-char (point-max))))) -(defsubst c-forward-comment (count) - ;; Insulation from various idiosyncrasies in implementations of - ;; `forward-comment'. - ;; - ;; Note: Some emacsen considers incorrectly that any line comment - ;; ending with a backslash continues to the next line. I can't - ;; think of any way to work around that in a reliable way without - ;; changing the buffer though. Suggestions welcome. ;) - ;; - ;; Another note: When moving backwards over a block comment, there's - ;; a bug in forward-comment that can make it stop at "/*" inside a - ;; line comment. Haven't yet found a reasonably cheap way to kludge - ;; around that one either. :\ - (let ((here (point))) - (if (>= count 0) - (when (forward-comment count) - ;; Emacs includes the ending newline in a b-style (c++) - ;; comment, but XEmacs doesn't. We depend on the Emacs - ;; behavior (which also is symmetric). - (if (and (eolp) (nth 7 (parse-partial-sexp here (point)))) - (condition-case nil (forward-char 1))) - t) - ;; When we got newline terminated comments, - ;; forward-comment in all supported emacsen so far will - ;; stop at eol of each line not ending with a comment when - ;; moving backwards. The following corrects for it when - ;; count is -1. The other common case, when count is - ;; large and negative, works regardless. It's too much - ;; work to correct for the rest of the cases. - (skip-chars-backward " \t\n\r\f") - (if (bobp) - ;; Some emacsen return t when moving backwards at bob. - nil - (re-search-forward "[\n\r]" here t) - (if (forward-comment count) - (if (eolp) (forward-comment -1) t)))))) - (defsubst c-intersect-lists (list alist) ;; return the element of ALIST that matches the first element found ;; in LIST. Uses assq. @@ -346,7 +388,7 @@ (t (mark t)))) (defsubst c-major-mode-is (mode) - (eq (derived-mode-class major-mode) mode)) + (eq c-buffer-is-cc-mode mode)) (cc-provide 'cc-defs)
--- a/lisp/progmodes/cc-engine.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-engine.el Mon Apr 22 00:35:36 2002 +0000 @@ -25,12 +25,22 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: +;; The functions which have docstring documentation can be considered +;; part of an API which other packages can use in CC Mode buffers. +;; Otoh, undocumented functions and functions with the documentation +;; in comments are considered purely internal and can change semantics +;; or even disappear in the future. +;; +;; (This policy applies to CC Mode as a whole, not just this file. It +;; probably also applies to many other Emacs packages, but here it's +;; clearly spelled out.) + ;;; Code: (eval-when-compile @@ -49,8 +59,18 @@ (cc-bytecomp-defun buffer-syntactic-context) ; XEmacs -(defvar c-state-cache nil) +(defun c-calculate-state (arg prevstate) + ;; Calculate the new state of PREVSTATE, t or nil, based on arg. If + ;; arg is nil or zero, toggle the state. If arg is negative, turn + ;; the state off, and if arg is positive, turn the state on + (if (or (not arg) + (zerop (setq arg (prefix-numeric-value arg)))) + (not prevstate) + (> arg 0))) + + (defvar c-in-literal-cache t) +(defvar c-parsing-error nil) ;; KLUDGE ALERT: c-maybe-labelp is used to pass information between ;; c-crosses-statement-barrier-p and c-beginning-of-statement-1. A @@ -58,285 +78,657 @@ ;; the byte compiler. (defvar c-maybe-labelp nil) -;; WARNING WARNING WARNING -;; -;; Be *exceptionally* careful about modifications to this function! -;; Much of CC Mode depends on this Doing The Right Thing. If you -;; break it you will be sorry. If you think you know how this works, -;; you probably don't. No human on Earth does! :-) -;; -;; WARNING WARNING WARNING +;; Macros used internally in c-beginning-of-statement-1 for the +;; automaton actions. +(defmacro c-bos-push-state () + '(setq stack (cons (cons state saved-pos) + stack))) +(defmacro c-bos-pop-state (&optional do-if-done) + `(if (setq state (car (car stack)) + saved-pos (cdr (car stack)) + stack (cdr stack)) + t + ,do-if-done + (throw 'loop nil))) +(defmacro c-bos-pop-state-and-retry () + '(throw 'loop (setq state (car (car stack)) + saved-pos (cdr (car stack)) + ;; Throw nil if stack is empty, else throw non-nil. + stack (cdr stack)))) +(defmacro c-bos-save-pos () + '(setq saved-pos (vector pos tok ptok pptok))) +(defmacro c-bos-restore-pos () + '(unless (eq (elt saved-pos 0) start) + (setq pos (elt saved-pos 0) + tok (elt saved-pos 1) + ptok (elt saved-pos 2) + pptok (elt saved-pos 3)) + (goto-char pos) + (setq sym nil))) +(defmacro c-bos-save-error-info (missing got) + `(setq saved-pos (vector pos ,missing ,got))) +(defmacro c-bos-report-error () + '(unless noerror + (setq c-parsing-error + (format "No matching `%s' found for `%s' on line %d" + (elt saved-pos 1) + (elt saved-pos 2) + (1+ (count-lines (point-min) + (c-point 'bol (elt saved-pos 0)))))))) + +(defun c-beginning-of-statement-1 (&optional lim ignore-labels + noerror comma-delim) + "Move to the start of the current statement or declaration, or to +the previous one if already at the beginning of one. Only +statements/declarations on the same level are considered, i.e. don't +move into or out of sexps (not even normal expression parentheses). + +Stop at statement continuations like \"else\", \"catch\", \"finally\" +and the \"while\" in \"do ... while\" if the start point is within +them. If starting at such a continuation, move to the corresponding +statement start. If at the beginning of a statement, move to the +closest containing statement if there is any. This might also stop at +a continuation clause. + +Labels are treated as separate statements if IGNORE-LABELS is non-nil. +The function is not overly intelligent in telling labels from other +uses of colons; if used outside a statement context it might trip up +on e.g. inherit colons, so IGNORE-LABELS should be used then. There +should be no such mistakes in a statement context, however. + +Macros are ignored unless point is within one, in which case the +content of the macro is treated as normal code. Aside from any normal +statement starts found in it, stop at the first token of the content +in the macro, i.e. the expression of an \"#if\" or the start of the +definition in a \"#define\". Also stop at start of macros before +leaving them. + +Return 'label if stopped at a label, 'same if stopped at the beginning +of the current statement, 'up if stepped to a containing statement, +'previous if stepped to a preceding statement, 'beginning if stepped +from a statement continuation clause to its start clause, or 'macro if +stepped to a macro start. Note that 'same and not 'label is returned +if stopped at the same label without crossing the colon character. + +LIM may be given to limit the search. If the search hits the limit, +point will be left at the closest following token, or at the start +position if that is less ('same is returned in this case). + +NOERROR turns off error logging to `c-parsing-error'. + +Normally only ';' is considered to delimit statements, but if +COMMA-DELIM is non-nil then ',' is treated likewise." -(defun c-beginning-of-statement-1 (&optional lim) - ;; move to the start of the current statement, or the previous - ;; statement if already at the beginning of one. - (let ((firstp t) - (substmt-p t) - donep c-in-literal-cache saved - (last-begin (point))) - ;; first check for bare semicolon - (if (and (progn (c-backward-syntactic-ws lim) - (eq (char-before) ?\;)) - (c-safe (progn (forward-char -1) - (setq saved (point)) - t)) - (progn (c-backward-syntactic-ws lim) - (memq (char-before) '(?\; ?{ ?:))) - ) - (setq last-begin saved) - (goto-char last-begin) - (while (not donep) - ;; stop at beginning of buffer - (if (bobp) (setq donep t) - ;; go backwards one balanced expression, but be careful of - ;; unbalanced paren being reached - (if (not (c-safe (progn (c-backward-sexp 1) t))) - (progn - (if firstp - (backward-up-list 1) - (goto-char last-begin)) - ;; skip over any unary operators, or other special - ;; characters appearing at front of identifier - (save-excursion - (c-backward-syntactic-ws lim) - (skip-chars-backward "-+!*&:.~@ \t\n") - (if (eq (char-before) ?\() - (setq last-begin (point)))) - (goto-char last-begin) - (setq donep t))) + ;; The bulk of this function is a pushdown automaton that looks at + ;; statement boundaries and the tokens in c-opt-block-stmt-key. + ;; + ;; Note: The position of a boundary is the following token. + ;; + ;; Begin with current token, stop when stack is empty and the + ;; position has been moved. + ;; + ;; Common state: + ;; "else": Push state, goto state `else': + ;; boundary: Goto state `else-boundary': + ;; "if": Pop state. + ;; boundary: Error, pop state. + ;; other: See common state. + ;; other: Error, pop state, retry token. + ;; "while": Push state, goto state `while': + ;; boundary: Save position, goto state `while-boundary': + ;; "do": Pop state. + ;; boundary: Restore position if it's not at start, pop state. + ;; other: See common state. + ;; other: Pop state, retry token. + ;; "catch" or "finally": Push state, goto state `catch': + ;; boundary: Goto state `catch-boundary': + ;; "try": Pop state. + ;; "catch": Goto state `catch'. + ;; boundary: Error, pop state. + ;; other: See common state. + ;; other: Error, pop state, retry token. + ;; other: Do nothing special. + ;; + ;; In addition to the above there is some special handling of labels + ;; and macros. + + (let ((case-fold-search nil) + (start (point)) + macro-start + (delims (if comma-delim '(?\; ?,) '(?\;))) + (c-stmt-delim-chars (if comma-delim + c-stmt-delim-chars-with-comma + c-stmt-delim-chars)) + pos ; Current position. + boundary-pos ; Position of last boundary. + after-labels-pos ; Value of tok after first found colon. + last-label-pos ; Value of tok after last found colon. + sym ; Current symbol in the alphabet. + state ; Current state in the automaton. + saved-pos ; Current saved positions. + stack ; Stack of conses (state . saved-pos). + (cond-key (or c-opt-block-stmt-key + "\\<\\>")) ; Matches nothing. + (ret 'same) + tok ptok pptok ; Pos of last three sexps or bounds. + c-in-literal-cache c-maybe-labelp saved) + + (save-restriction + (if lim (narrow-to-region lim (point-max))) + + (if (save-excursion + (and (c-beginning-of-macro) + (/= (point) start))) + (setq macro-start (point))) + + ;; Try to skip over unary operator characters, to register + ;; that we've moved. + (while (progn + (setq pos (point)) + (c-backward-syntactic-ws) + (/= (skip-chars-backward "-+!*&~@`#") 0))) + + ;; First check for bare semicolon. Later on we ignore the + ;; boundaries for statements that doesn't contain any sexp. + ;; The only thing that is affected is that the error checking + ;; is a little less strict, and we really don't bother. + (if (and (memq (char-before) delims) + (progn (forward-char -1) + (setq saved (point)) + (c-backward-syntactic-ws) + (or (memq (char-before) delims) + (memq (char-before) '(?: nil)) + (eq (char-syntax (char-before)) ?\()))) + (setq ret 'previous + pos saved) + + ;; Begin at start and not pos to detect macros if we stand + ;; directly after the #. + (goto-char start) + (if (looking-at "\\<\\|\\W") + ;; Record this as the first token if not starting inside it. + (setq tok start)) + + (while + (catch 'loop ;; Throw nil to break, non-nil to continue. + (cond + ;; Check for macro start. + ((save-excursion + (and macro-start + (looking-at "[ \t]*[a-zA-Z0-9!]") + (progn (skip-chars-backward " \t") + (eq (char-before) ?#)) + (progn (setq saved (1- (point))) + (beginning-of-line) + (not (eq (char-before (1- (point))) ?\\))) + (progn (skip-chars-forward " \t") + (eq (point) saved)))) + (goto-char saved) + (if (and (c-forward-to-cpp-define-body) + (progn (c-forward-syntactic-ws start) + (< (point) start))) + ;; Stop at the first token in the content of the macro. + (setq pos (point) + ignore-labels t) ; Avoid the label check on exit. + (setq pos saved + ret 'macro + ignore-labels t)) + (throw 'loop nil)) + + ;; Do a round through the automaton if we found a + ;; boundary or if looking at a statement keyword. + ((or sym + (and (looking-at cond-key) + (setq sym (intern (match-string 1))))) + + (when (and (< pos start) (null stack)) + (throw 'loop nil)) - (setq c-maybe-labelp nil) - ;; see if we're in a literal. if not, then this bufpos may be - ;; a candidate for stopping - (cond - ;; CASE 0: did we hit the error condition above? - (donep) - ;; CASE 1: are we in a literal? - ((eq (c-in-literal lim) 'pound) - (beginning-of-line)) - ;; CASE 2: some other kind of literal? - ((c-in-literal lim)) - ;; CASE 3: are we looking at a conditional keyword? - ((or (and c-conditional-key (looking-at c-conditional-key)) - (and (eq (char-after) ?\() - (save-excursion - (c-forward-sexp 1) - (c-forward-syntactic-ws) - (not (eq (char-after) ?\;))) - (let ((here (point)) - (foundp (progn - (c-backward-syntactic-ws lim) - (forward-word -1) - (and lim - (<= lim (point)) - (not (c-in-literal lim)) - (not (eq (char-before) ?_)) - c-conditional-key - (looking-at c-conditional-key) - )))) - ;; did we find a conditional? - (if (not foundp) - (goto-char here)) - foundp))) - ;; are we in the middle of an else-if clause? - (if (save-excursion - (and (not substmt-p) - (c-safe (progn (c-forward-sexp -1) t)) - (looking-at "\\<else\\>[ \t\n]+\\<if\\>") - (not (c-in-literal lim)))) - (progn - (c-forward-sexp -1) - (c-backward-to-start-of-if lim))) - ;; are we sitting at an else clause, that we are not a - ;; substatement of? - (if (and (not substmt-p) - (looking-at "\\<else\\>[^_]")) - (c-backward-to-start-of-if lim)) - ;; a finally or a series of catches? - (if (not substmt-p) - (while (looking-at "\\<\\(catch\\|finally\\)\\>[^_]") - (c-safe (c-backward-sexp 2)) - (if (eq (char-after) ?\() - (c-safe (c-backward-sexp))))) - ;; are we sitting at the while of a do-while? - (if (and (looking-at "\\<while\\>[^_]") - (c-backward-to-start-of-do lim)) - (setq substmt-p nil)) - (setq last-begin (point) - donep substmt-p)) - ;; CASE 4: are we looking at a label? (But we handle - ;; switch labels later.) - ((and (looking-at c-label-key) - (not (looking-at "default\\>")) - (not (and (c-major-mode-is 'pike-mode) - (save-excursion - ;; Not inside a Pike type declaration? - (and (c-safe (backward-up-list 1) t) - (eq (char-after) ?\())))))) - ;; CASE 5: is this the first time we're checking? - (firstp (setq firstp nil - substmt-p (not (c-crosses-statement-barrier-p - (point) last-begin)) - last-begin (point))) - ;; CASE 6: have we crossed a statement barrier? - ((save-excursion - ;; Move over in-expression blocks before checking the - ;; barrier - (if (or (memq (char-after) '(?\( ?\[)) - (and (eq (char-after) ?{) - (c-looking-at-inexpr-block lim))) - (c-forward-sexp 1)) - (c-crosses-statement-barrier-p (point) last-begin)) - (setq donep t)) - ;; CASE 7: ignore labels - ((and c-maybe-labelp - (or (and c-access-key (looking-at c-access-key)) - ;; with switch labels, we have to go back further - ;; to try to pick up the case or default - ;; keyword. Potential bogosity alert: we assume - ;; `case' or `default' is first thing on line - (let ((here (point))) - (beginning-of-line) - (c-forward-syntactic-ws here) - (if (looking-at c-switch-label-key) - t - (goto-char here) - nil))))) - ;; CASE 8: ObjC or Java method def - ((and c-method-key - (setq last-begin (c-in-method-def-p))) - (setq donep t)) - ;; CASE 9: Normal token. At bob, we can end up at ws or a - ;; comment, and last-begin shouldn't be updated then. - ((not (looking-at "\\s \\|/[/*]")) - (setq last-begin (point))) - )))) - (goto-char last-begin) - ;; We always want to skip over the non-whitespace modifier - ;; characters that can start a statement. - (let ((lim (point))) - (skip-chars-backward "-+!*&~@`# \t\n" (c-point 'boi)) - (skip-chars-forward " \t\n" lim)))) + ;; The state handling. Continue in the common state for + ;; unhandled cases. + (or (cond + ((eq state 'else) + (if (eq sym 'boundary) + (setq state 'else-boundary) + (c-bos-report-error) + (c-bos-pop-state-and-retry))) + + ((eq state 'else-boundary) + (cond ((eq sym 'if) + (c-bos-pop-state (setq ret 'beginning))) + ((eq sym 'boundary) + (c-bos-report-error) + (c-bos-pop-state)))) + + ((eq state 'while) + (if (and (eq sym 'boundary) + ;; Since this can cause backtracking we do a + ;; little more careful analysis to avoid it: + ;; If there's a label in front of the while + ;; it can't be part of a do-while. + (not after-labels-pos)) + (progn (c-bos-save-pos) + (setq state 'while-boundary)) + (c-bos-pop-state-and-retry))) + + ((eq state 'while-boundary) + (cond ((eq sym 'do) + (c-bos-pop-state (setq ret 'beginning))) + ((eq sym 'boundary) + (c-bos-restore-pos) + (c-bos-pop-state)))) + + ((eq state 'catch) + (if (eq sym 'boundary) + (setq state 'catch-boundary) + (c-bos-report-error) + (c-bos-pop-state-and-retry))) + + ((eq state 'catch-boundary) + (cond + ((eq sym 'try) + (c-bos-pop-state (setq ret 'beginning))) + ((eq sym 'catch) + (setq state 'catch)) + ((eq sym 'boundary) + (c-bos-report-error) + (c-bos-pop-state))))) + + ;; This is state common. + (cond ((eq sym 'boundary) + (if (< pos start) + (c-bos-pop-state) + (c-bos-push-state))) + ((eq sym 'else) + (c-bos-push-state) + (c-bos-save-error-info 'if 'else) + (setq state 'else)) + ((eq sym 'while) + (when (or (not pptok) + (memq (char-after pptok) delims)) + ;; Since this can cause backtracking we do a + ;; little more careful analysis to avoid it: If + ;; the while isn't followed by a semicolon it + ;; can't be a do-while. + (c-bos-push-state) + (setq state 'while))) + ((memq sym '(catch finally)) + (c-bos-push-state) + (c-bos-save-error-info 'try sym) + (setq state 'catch)))) + + (when c-maybe-labelp + ;; We're either past a statement boundary or at the + ;; start of a statement, so throw away any label data + ;; for the previous one. + (setq after-labels-pos nil + last-label-pos nil + c-maybe-labelp nil)))) -(defun c-end-of-statement-1 () - (condition-case nil - (let (beg end found) - (while (and (not (eobp)) + ;; Step to next sexp, but not if we crossed a boundary, since + ;; that doesn't consume an sexp. + (if (eq sym 'boundary) + (setq ret 'previous) + (while (progn - (setq beg (point)) - (c-forward-sexp 1) - (setq end (point)) - (goto-char beg) - (setq found nil) - (while (and (not found) - (re-search-forward "[;{}]" end t)) - (if (not (c-in-literal beg)) - (setq found t))) - (not found))) - (goto-char end)) - (re-search-backward "[;{}]") - (forward-char 1)) - (error - (let ((beg (point))) - (c-safe (backward-up-list -1)) - (let ((end (point))) - (goto-char beg) - (search-forward ";" end 'move))) - ))) + (or (c-safe (goto-char (scan-sexps (point) -1)) t) + (throw 'loop nil)) + (cond ((looking-at "\\\\$") + ;; Step again if we hit a line continuation. + t) + (macro-start + ;; If we started inside a macro then this + ;; sexp is always interesting. + nil) + (t + ;; Otherwise check that we didn't step + ;; into a macro from the end. + (let ((macro-start + (save-excursion + (and (c-beginning-of-macro) + (point))))) + (when macro-start + (goto-char macro-start) + t)))))) + + ;; Check for statement boundary. + (when (save-excursion + (if (if (eq (char-after) ?{) + (c-looking-at-inexpr-block lim nil) + (eq (char-syntax (char-after)) ?\()) + ;; Need to move over parens and + ;; in-expression blocks to get a good start + ;; position for the boundary check. + (c-forward-sexp 1)) + (setq boundary-pos (c-crosses-statement-barrier-p + (point) pos))) + (setq pptok ptok + ptok tok + tok boundary-pos + sym 'boundary) + (throw 'loop t))) + + (when (and (numberp c-maybe-labelp) (not ignore-labels)) + ;; c-crosses-statement-barrier-p has found a colon, so + ;; we might be in a label now. + (if (not after-labels-pos) + (setq after-labels-pos tok)) + (setq last-label-pos tok + c-maybe-labelp t)) + + ;; ObjC method def? + (when (and c-opt-method-key + (setq saved (c-in-method-def-p))) + (setq pos saved + ignore-labels t) ; Avoid the label check on exit. + (throw 'loop nil)) + + (setq sym nil + pptok ptok + ptok tok + tok (point) + pos tok))) ; Not nil. + + ;; If the stack isn't empty there might be errors to report. + (while stack + (if (and (vectorp saved-pos) (eq (length saved-pos) 3)) + (c-bos-report-error)) + (setq saved-pos (cdr (car stack)) + stack (cdr stack))) + + (when (and (eq ret 'same) + (not (memq sym '(boundary ignore nil)))) + ;; Need to investigate closer whether we've crossed + ;; between a substatement and its containing statement. + (if (setq saved (if (looking-at c-block-stmt-1-key) + ptok + pptok)) + (cond ((> start saved) (setq pos saved)) + ((= start saved) (setq ret 'up))))) + + (when (and c-maybe-labelp (not ignore-labels) after-labels-pos) + ;; We're in a label. Maybe we should step to the statement + ;; after it. + (if (< after-labels-pos start) + (setq pos after-labels-pos) + (setq ret 'label) + (if (< last-label-pos start) + (setq pos last-label-pos))))) + + ;; Skip over the unary operators that can start the statement. + (goto-char pos) + (while (progn + (c-backward-syntactic-ws) + (/= (skip-chars-backward "-+!*&~@`#") 0)) + (setq pos (point))) + (goto-char pos) + ret))) + +(defun c-crosses-statement-barrier-p (from to) + "Return non-nil if buffer positions FROM to TO cross one or more +statement or declaration boundaries. The returned value is actually +the position of the earliest boundary char. + +The variable `c-maybe-labelp' is set to the position of the first `:' that +might start a label (i.e. not part of `::' and not preceded by `?'). If a +single `?' is found, then `c-maybe-labelp' is cleared." + (let ((skip-chars c-stmt-delim-chars) + lit-range) + (save-excursion + (catch 'done + (goto-char from) + (while (progn (skip-chars-forward skip-chars to) + (< (point) to)) + (if (setq lit-range (c-literal-limits from)) + (goto-char (setq from (cdr lit-range))) + (cond ((eq (char-after) ?:) + (forward-char) + (if (and (eq (char-after) ?:) + (< (point) to)) + ;; Ignore scope operators. + (forward-char) + (setq c-maybe-labelp (1- (point))))) + ((eq (char-after) ??) + ;; A question mark. Can't be a label, so stop + ;; looking for more : and ?. + (setq c-maybe-labelp nil + skip-chars (substring c-stmt-delim-chars 0 -2))) + (t (throw 'done (point)))))) + nil)))) -(defun c-crosses-statement-barrier-p (from to) - ;; Does buffer positions FROM to TO cross a C statement boundary? - (let ((here (point)) - (lim from) - crossedp) - (condition-case () - (progn - (goto-char from) - (while (and (not crossedp) - (< (point) to)) - (skip-chars-forward "^;{}:" (1- to)) - (if (not (c-in-literal lim)) - (progn - (if (memq (char-after) '(?\; ?{ ?})) - (setq crossedp t) - (if (eq (char-after) ?:) - (setq c-maybe-labelp t)) - (forward-char 1)) - (setq lim (point))) - (forward-char 1)))) - (error (setq crossedp nil))) - (goto-char here) - crossedp)) +;; This is a dynamically bound cache used together with +;; c-query-macro-start and c-query-and-set-macro-start. It only works +;; as long as point doesn't cross a macro boundary. +(defvar c-macro-start 'unknown) + +(defsubst c-query-and-set-macro-start () + (if (symbolp c-macro-start) + (setq c-macro-start (save-excursion + (and (c-beginning-of-macro) + (point)))) + c-macro-start)) + +(defsubst c-query-macro-start () + (if (symbolp c-macro-start) + (save-excursion + (and (c-beginning-of-macro) + (point))) + c-macro-start)) + +(defun c-beginning-of-macro (&optional lim) + "Go to the beginning of a cpp macro definition. +Leave point at the beginning of the macro and return t if in a cpp +macro definition, otherwise return nil and leave point unchanged." + (let ((here (point))) + (save-restriction + (if lim (narrow-to-region lim (point-max))) + (beginning-of-line) + (while (eq (char-before (1- (point))) ?\\) + (forward-line -1)) + (back-to-indentation) + (if (and (<= (point) here) + (looking-at "#[ \t]*[a-zA-Z0-9!]")) + t + (goto-char here) + nil)))) + +(defun c-end-of-macro () + "Go to the end of a cpp macro definition. +More accurately, move point to the end of the closest following line +that doesn't end with a line continuation backslash." + (while (progn + (end-of-line) + (when (and (eq (char-before) ?\\) + (not (eobp))) + (forward-char) + t)))) - -(defun c-beginning-of-macro (&optional lim) - ;; Go to the beginning of a cpp macro definition. Leaves point at - ;; the beginning of the macro and returns t if in a cpp macro - ;; definition, otherwise returns nil and leaves point unchanged. - ;; `lim' is currently ignored, but the interface requires it. +(defun c-forward-comment (count) + ;; Insulation from various idiosyncrasies in implementations of + ;; `forward-comment'. + ;; + ;; Note: Some emacsen considers incorrectly that any line comment + ;; ending with a backslash continues to the next line. I can't + ;; think of any way to work around that in a reliable way without + ;; changing the buffer, though. Suggestions welcome. ;) (No, + ;; temporarily changing the syntax for backslash doesn't work since + ;; we must treat escapes in string literals correctly.) + ;; + ;; Another note: When moving backwards over a block comment, there's + ;; a bug in forward-comment that can make it stop at "/*" inside a + ;; line comment. Haven't yet found a reasonably cheap way to kludge + ;; around that one either. :\ (let ((here (point))) - (beginning-of-line) - (while (eq (char-before (1- (point))) ?\\) - (forward-line -1)) - (back-to-indentation) - (if (and (<= (point) here) - (eq (char-after) ?#)) - t - (goto-char here) - nil))) + (if (>= count 0) + (when (forward-comment count) + (if (eobp) + ;; Some emacsen (e.g. XEmacs 21) return t when moving + ;; forwards at eob. + nil + ;; Emacs includes the ending newline in a b-style (c++) + ;; comment, but XEmacs doesn't. We depend on the Emacs + ;; behavior (which also is symmetric). + (if (and (eolp) (nth 7 (parse-partial-sexp here (point)))) + (condition-case nil (forward-char 1))) + t)) + ;; When we got newline terminated comments, + ;; forward-comment in all supported emacsen so far will + ;; stop at eol of each line not ending with a comment when + ;; moving backwards. The following corrects for it when + ;; count is -1. The other common case, when count is + ;; large and negative, works regardless. It's too much + ;; work to correct for the rest of the cases. + (skip-chars-backward " \t\n\r\f") + (if (bobp) + ;; Some emacsen return t when moving backwards at bob. + nil + (re-search-forward "[\n\r]" here t) + (let* ((res (if (forward-comment count) + (if (eolp) (forward-comment -1) t))) + (savepos (point))) + ;; XEmacs treats line continuations as whitespace (but only + ;; in the backward direction). + (while (and (progn (end-of-line) (< (point) here)) + (eq (char-before) ?\\)) + (setq res nil + savepos (point)) + (forward-line)) + (goto-char savepos) + res))))) -;; Skipping of "syntactic whitespace", defined as lexical whitespace, -;; C and C++ style comments, and preprocessor directives. Search no -;; farther back or forward than optional LIM. If LIM is omitted, -;; `beginning-of-defun' is used for backward skipping, point-max is -;; used for forward skipping. +(defun c-forward-comment-lc (count) + ;; Like `c-forward-comment', but treat line continuations as + ;; whitespace. + (catch 'done + (if (> count 0) + (while (if (c-forward-comment 1) + (progn + (setq count (1- count)) + (> count 0)) + (if (looking-at "\\\\$") + (progn + (forward-char) + t) + (throw 'done nil)))) + (while (if (c-forward-comment -1) + (progn + (setq count (1+ count)) + (< count 0)) + (if (and (eolp) (eq (char-before) ?\\)) + (progn + (backward-char) + t) + (throw 'done nil))))) + t)) (defun c-forward-syntactic-ws (&optional lim) - ;; Forward skip of syntactic whitespace for Emacs 19. - (let* ((here (point-max)) - (hugenum (point-max))) + "Forward skip of syntactic whitespace. +Syntactic whitespace is defined as whitespace characters, comments, +and preprocessor directives. However if point starts inside a comment +or preprocessor directive, the content of it is not treated as +whitespace. LIM sets an upper limit of the forward movement, if +specified." + (let ((here (point-max))) + (or lim (setq lim here)) (while (/= here (point)) + ;; If forward-comment in at least XEmacs 21 is given a large + ;; positive value, it'll loop all the way through if it hits eob. + (while (c-forward-comment 5)) (setq here (point)) - (c-forward-comment hugenum) - ;; skip preprocessor directives - (when (and (eq (char-after) ?#) - (= (c-point 'boi) (point))) - (while (and (eq (char-before (c-point 'eol)) ?\\) - (= (forward-line 1) 0))) - (end-of-line)) - ) - (if lim (goto-char (min (point) lim))))) + (cond + ;; Skip line continuations. + ((looking-at "\\\\$") + (forward-char)) + ;; Skip preprocessor directives. + ((and (looking-at "#[ \t]*[a-zA-Z0-9!]") + (progn (skip-chars-backward " \t") + (bolp))) + (end-of-line) + (while (and (<= (point) lim) + (eq (char-before) ?\\) + (= (forward-line 1) 0)) + (end-of-line)) + (when (> (point) lim) + ;; Don't move past the macro if that'd take us past the limit. + (goto-char here))) + ;; Skip in-comment line continuations (used for Pike refdoc). + ((and c-opt-in-comment-lc (looking-at c-opt-in-comment-lc)) + (goto-char (match-end 0))))) + (goto-char (min (point) lim)))) (defun c-backward-syntactic-ws (&optional lim) - ;; Backward skip over syntactic whitespace for Emacs 19. - (let* ((here (point-min)) - (hugenum (- (point-max)))) + "Backward skip of syntactic whitespace. +Syntactic whitespace is defined as whitespace characters, comments, +and preprocessor directives. However if point starts inside a comment +or preprocessor directive, the content of it is not treated as +whitespace. LIM sets a lower limit of the backward movement, if +specified." + (let ((start-line (c-point 'bol)) + (here (point-min)) + (line-cont 'maybe) + prev-pos) + (or lim (setq lim here)) (while (/= here (point)) + (setq prev-pos (point)) + ;; If forward-comment in Emacs 19.34 is given a large negative + ;; value, it'll loop all the way through if it hits bob. + (while (c-forward-comment -5)) (setq here (point)) - (c-forward-comment hugenum) - (c-beginning-of-macro)) - (if lim (goto-char (max (point) lim))))) - - -;; Moving by tokens, where a token is defined as all symbols and -;; identifiers which aren't syntactic whitespace (note that "->" is -;; considered to be two tokens). Point is always either left at the -;; beginning of a token or not moved at all. COUNT specifies the -;; number of tokens to move; a negative COUNT moves in the opposite -;; direction. A COUNT of 0 moves to the next token beginning only if -;; not already at one. If BALANCED is true, move over balanced -;; parens, otherwise move into them. Also, if BALANCED is true, never -;; move out of an enclosing paren. LIM sets the limit for the -;; movement and defaults to the point limit. Returns the number of -;; tokens left to move (positive or negative). If BALANCED is true, a -;; move over a balanced paren counts as one. Note that if COUNT is 0 -;; and no appropriate token beginning is found, 1 will be returned. -;; Thus, a return value of 0 guarantees that point is at the requested -;; position and a return value less (without signs) than COUNT -;; guarantees that point is at the beginning of some token. + (cond + ((and (eolp) + (eq (char-before) ?\\) + (if (<= prev-pos (c-point 'eonl)) + t + ;; Passed a line continuation, but not from the line we + ;; started on. + (forward-char) + (setq line-cont nil))) + (backward-char) + (setq line-cont t)) + ((progn + (when (eq line-cont 'maybe) + (save-excursion + (end-of-line) + (setq line-cont (eq (char-before) ?\\)))) + (or line-cont + (and (< (point) start-line) + (c-beginning-of-macro)))) + (if (< (point) lim) + ;; Don't move past the macro if we began inside it or at + ;; the end of the same line, or if the move would take us + ;; past the limit. + (goto-char here)) + (setq line-cont nil)) + ;; Skip in-comment line continuations (used for Pike refdoc). + ((and c-opt-in-comment-lc + (save-excursion + (and (c-safe (beginning-of-line) + (backward-char 2) + t) + (looking-at c-opt-in-comment-lc) + (eq (match-end 0) here)))) + (goto-char (match-beginning 0))))) + (goto-char (max (point) lim)))) (defun c-forward-token-1 (&optional count balanced lim) + "Move forward by tokens. +A token is defined as all symbols and identifiers which aren't +syntactic whitespace \(note that e.g. \"->\" is considered to be two +tokens). Point is always either left at the beginning of a token or +not moved at all. COUNT specifies the number of tokens to move; a +negative COUNT moves in the opposite direction. A COUNT of 0 moves to +the next token beginning only if not already at one. If BALANCED is +true, move over balanced parens, otherwise move into them. Also, if +BALANCED is true, never move out of an enclosing paren. LIM sets the +limit for the movement and defaults to the point limit. + +Return the number of tokens left to move \(positive or negative). If +BALANCED is true, a move over a balanced paren counts as one. Note +that if COUNT is 0 and no appropriate token beginning is found, 1 will +be returned. Thus, a return value of 0 guarantees that point is at +the requested position and a return value less \(without signs) than +COUNT guarantees that point is at the beginning of some token." (or count (setq count 1)) (if (< count 0) (- (c-backward-token-1 (- count) balanced lim)) @@ -371,7 +763,7 @@ (if (memq (char-syntax (char-after)) jump-syntax) (goto-char (scan-sexps (point) 1)) (forward-char)) - (c-forward-syntactic-ws lim) + (c-forward-syntactic-ws) (setq count (1- count))) (error (goto-char last))) (when (eobp) @@ -380,6 +772,8 @@ count))) (defun c-backward-token-1 (&optional count balanced lim) + "Move backward by tokens. +See `c-forward-token-1' for details." (or count (setq count 1)) (if (< count 0) (- (c-forward-token-1 (- count) balanced lim)) @@ -391,7 +785,9 @@ (or (and (memq (char-syntax (or (char-after) ? )) '(?w ?_)) (memq (char-syntax (or (char-before) ? )) '(?w ?_))) (/= (point) - (save-excursion (c-forward-syntactic-ws) (point))) + (save-excursion + (c-forward-syntactic-ws (1+ lim)) + (point))) (eobp))) ;; If count is zero we should jump if in the middle of a ;; token or if there is whitespace between point and the @@ -406,7 +802,7 @@ (while (progn (setq last (point)) (> count 0)) - (c-backward-syntactic-ws lim) + (c-backward-syntactic-ws) (if (memq (char-syntax (char-before)) jump-syntax) (goto-char (scan-sexps (point) -1)) (backward-char)) @@ -415,16 +811,93 @@ (if (bobp) (goto-char last))))) count))) +(defun c-syntactic-re-search-forward (regexp &optional bound noerror count + paren-level) + ;; Like `re-search-forward', but only report matches that are found + ;; in syntactically significant text. I.e. matches that begins in + ;; comments, macros or string literals are ignored. The start point + ;; is assumed to be outside any comment, macro or string literal, or + ;; else the content of that region is taken as syntactically + ;; significant text. If PAREN-LEVEL is non-nil, an additional + ;; restriction is added to ignore matches in nested paren sexps, and + ;; the search will also not go outside the current paren sexp. + (or bound (setq bound (point-max))) + (or count (setq count 1)) + (if paren-level (setq paren-level -1)) + (let ((start (point)) + (pos (point)) + match-pos state) + (condition-case err + (while (and (> count 0) + (re-search-forward regexp bound noerror)) + (setq match-pos (point) + state (parse-partial-sexp pos (match-beginning 0) + paren-level nil state) + pos (point)) + (cond ((nth 3 state) + ;; Match inside a string. Skip to the end of it + ;; before continuing. + (let ((ender (make-string 1 (nth 3 state)))) + (while (progn + (search-forward ender bound noerror) + (setq state (parse-partial-sexp pos (point) + nil nil state) + pos (point)) + (nth 3 state))))) + ((nth 7 state) + ;; Match inside a line comment. Skip to eol. Use + ;; re-search-forward for it to get the right bound + ;; behavior. + (re-search-forward "[\n\r]" bound noerror)) + ((nth 4 state) + ;; Match inside a block comment. Skip to the '*/'. + (re-search-forward "\\*/" bound noerror)) + ((save-excursion (c-beginning-of-macro start)) + ;; Match inside a macro. Skip to the end of it. + (c-end-of-macro)) + ((and paren-level (/= (car state) 0)) + (if (> (car state) 0) + ;; Match inside a nested paren sexp. Skip out of it. + (setq state (parse-partial-sexp pos bound 0 nil state) + pos (point)) + ;; Have exited the current paren sexp. The + ;; parse-partial-sexp above has left us just after + ;; the closing paren in this case. Just make + ;; re-search-forward above fail in the appropriate + ;; way; we'll adjust the leave off point below if + ;; necessary. + (setq bound (point)))) + (t + ;; A real match. + (setq count (1- count))))) + (error + (goto-char start) + (signal (car err) (cdr err)))) + (if (= count 0) + (progn + (goto-char match-pos) + match-pos) + ;; Search failed. Set point as appropriate. + (cond ((eq noerror t) + (goto-char start)) + (paren-level + (if (eq (car (parse-partial-sexp pos bound -1 nil state)) -1) + (backward-char))) + (t + (goto-char bound))) + nil))) + -;; Return `c' if in a C-style comment, `c++' if in a C++ style -;; comment, `string' if in a string literal, `pound' if on a -;; preprocessor line, or nil if not in a comment at all. Optional LIM -;; is used as the backward limit of the search. If omitted, or nil, -;; `beginning-of-defun' is used." +(defun c-in-literal (&optional lim detect-cpp) + "Return the type of literal point is in, if any. +The return value is `c' if in a C-style comment, `c++' if in a C++ +style comment, `string' if in a string literal, `pound' if DETECT-CPP +is non-nil and on a preprocessor line, or nil if somewhere else. +Optional LIM is used as the backward limit of the search. If omitted, +or nil, `c-beginning-of-defun' is used. -(defun c-in-literal (&optional lim) - ;; Determine if point is in a C++ literal. we cache the last point - ;; calculated if the cache is enabled +The last point calculated is cached if the cache is enabled, i.e. if +`c-in-literal-cache' is bound to a two element vector." (if (and (vectorp c-in-literal-cache) (= (point) (aref c-in-literal-cache 0))) (aref c-in-literal-cache 1) @@ -434,7 +907,7 @@ (cond ((nth 3 state) 'string) ((nth 4 state) (if (nth 7 state) 'c++ 'c)) - ((c-beginning-of-macro lim) 'pound) + ((and detect-cpp (c-beginning-of-macro lim)) 'pound) (t nil)))))) ;; cache this result if the cache is enabled (if (not c-in-literal-cache) @@ -443,30 +916,30 @@ ;; XEmacs has a built-in function that should make this much quicker. ;; I don't think we even need the cache, which makes our lives more -;; complicated anyway. In this case, lim is ignored. -(defun c-fast-in-literal (&optional lim) +;; complicated anyway. In this case, lim is only used to detect +;; cpp directives. +(defun c-fast-in-literal (&optional lim detect-cpp) (let ((context (buffer-syntactic-context))) (cond ((eq context 'string) 'string) ((eq context 'comment) 'c++) ((eq context 'block-comment) 'c) - ((save-excursion (c-beginning-of-macro lim)) 'pound)))) + ((and detect-cpp (save-excursion (c-beginning-of-macro lim))) 'pound)))) (if (fboundp 'buffer-syntactic-context) (defalias 'c-in-literal 'c-fast-in-literal)) (defun c-literal-limits (&optional lim near not-in-delimiter) - ;; Returns a cons of the beginning and end positions of the comment - ;; or string surrounding point (including both delimiters), or nil - ;; if point isn't in one. If LIM is non-nil, it's used as the - ;; "safe" position to start parsing from. If NEAR is non-nil, then - ;; the limits of any literal next to point is returned. "Next to" - ;; means there's only [ \t] between point and the literal. The - ;; search for such a literal is done first in forward direction. If - ;; NOT-IN-DELIMITER is non-nil, the case when point is inside a - ;; starting delimiter won't be recognized. This only has effect for - ;; comments, which have starting delimiters with more than one - ;; character. + "Return a cons of the beginning and end positions of the comment or +string surrounding point (including both delimiters), or nil if point +isn't in one. If LIM is non-nil, it's used as the \"safe\" position +to start parsing from. If NEAR is non-nil, then the limits of any +literal next to point is returned. \"Next to\" means there's only [ +\t] between point and the literal. The search for such a literal is +done first in forward direction. If NOT-IN-DELIMITER is non-nil, the +case when point is inside a starting delimiter won't be recognized. +This only has effect for comments, which have starting delimiters with +more than one character." (save-excursion (let* ((pos (point)) (lim (or lim (c-point 'bod))) @@ -586,12 +1059,12 @@ (defalias 'c-literal-limits 'c-literal-limits-fast)) (defun c-collect-line-comments (range) - ;; If the argument is a cons of two buffer positions (such as - ;; returned by c-literal-limits), and that range contains a C++ - ;; style line comment, then an extended range is returned that - ;; contains all adjacent line comments (i.e. all comments that - ;; starts in the same column with no empty lines or non-whitespace - ;; characters between them). Otherwise the argument is returned. + "If the argument is a cons of two buffer positions (such as returned by +`c-literal-limits'), and that range contains a C++ style line comment, +then an extended range is returned that contains all adjacent line +comments (i.e. all comments that starts in the same column with no +empty lines or non-whitespace characters between them). Otherwise the +argument is returned." (save-excursion (condition-case nil (if (and (consp range) (progn @@ -620,10 +1093,10 @@ (error range)))) (defun c-literal-type (range) - ;; Convenience function that given the result of c-literal-limits, - ;; returns nil or the type of literal that the range surrounds. - ;; It's much faster than using c-in-literal and is intended to be - ;; used when you need both the type of a literal and its limits. + "Convenience function that given the result of `c-literal-limits', +returns nil or the type of literal that the range surrounds. It's +much faster than using `c-in-literal' and is intended to be used when +you need both the type of a literal and its limits." (if (consp range) (save-excursion (goto-char (car range)) @@ -635,215 +1108,301 @@ ;; utilities for moving and querying around syntactic elements -(defvar c-parsing-error nil) + +(defvar c-state-cache nil) +(make-variable-buffer-local 'c-state-cache) +;; The state cache used by `c-parse-state' to cut down the amount of +;; searching. It's the result from some earlier `c-parse-state' call. +;; The use of the cached info is more effective if the next +;; `c-parse-state' call is on a line close by the one the cached state +;; was made at; the cache can actually slow down a little if the +;; cached state was made very far back in the buffer. The cache is +;; most effective if `c-parse-state' is used on each line while moving +;; forward. + +(defvar c-state-cache-start nil) +;; This (point-min) when `c-state-cache' was calculated, to detect +;; that the start point hasn't changed due to narrowing. (defun c-parse-state () - ;; Finds and records all open parens between some important point - ;; earlier in the file and point. + ;; Finds and records all noteworthy parens between some good point + ;; earlier in the file and point. That good point is at least the + ;; beginning of the top-level construct we are in, or the beginning + ;; of the preceding top-level construct if we aren't in one. ;; - ;; if there's a state cache, return it - (if c-state-cache c-state-cache - (let* (at-bob - (pos (save-excursion + ;; The returned value is a list of the noteworthy parens with the + ;; last one first. If an element in the list is an integer, it's + ;; the position of an open paren which has not been closed before + ;; point. If an element is a cons, it gives the position of a + ;; closed brace paren pair; the car is the start paren position and + ;; the cdr is the position following the closing paren. Only the + ;; last closed brace paren pair before each open paren is recorded, + ;; and thus the state never contains two cons elements in + ;; succession. + (save-restriction + (let* ((here (point)) + (c-macro-start (c-query-macro-start)) + (in-macro-start (or c-macro-start (point))) + old-state last-pos pairs pos) + ;; Somewhat ugly use of c-check-state-cache to get rid of the + ;; part of the state cache that is after point. Can't use + ;; c-whack-state-after for the same reasons as in that function. + (c-check-state-cache (point) nil nil) + ;; Get the latest position we know are directly inside the + ;; closest containing paren of the cached state. + (setq last-pos (and c-state-cache + (if (consp (car c-state-cache)) + (cdr (car c-state-cache)) + (1+ (car c-state-cache))))) + ;; Check if the found last-pos is in a macro. If it is, and + ;; we're not in the same macro, we must discard everything on + ;; c-state-cache that is inside the macro before using it. + (when last-pos + (save-excursion + (goto-char last-pos) + (when (and (c-beginning-of-macro) + (/= (point) in-macro-start)) + (c-check-state-cache (point) nil nil) + ;; Set last-pos again, just like above. + (setq last-pos (and c-state-cache + (if (consp (car c-state-cache)) + (cdr (car c-state-cache)) + (1+ (car c-state-cache)))))))) + (setq pos + ;; Find the start position for the forward search. (Can't + ;; search in the backward direction since point might be + ;; in some kind of literal.) + (or (when last-pos + ;; There's a cached state with a containing paren. Pop + ;; off the stale containing sexps from it by going + ;; forward out of parens as far as possible. + (narrow-to-region (point-min) here) + (let (placeholder pair-beg) + (while (and c-state-cache + (setq placeholder + (c-up-list-forward last-pos))) + (setq last-pos placeholder) + (if (consp (car c-state-cache)) + (setq pair-beg (car-safe (cdr c-state-cache)) + c-state-cache (cdr-safe (cdr c-state-cache))) + (setq pair-beg (car c-state-cache) + c-state-cache (cdr c-state-cache)))) + (when (and pair-beg (eq (char-after pair-beg) ?{)) + ;; The last paren pair we moved out from was a brace + ;; pair. Modify the state to record this as a closed + ;; pair now. + (if (consp (car-safe c-state-cache)) + (setq c-state-cache (cdr c-state-cache))) + (setq c-state-cache (cons (cons pair-beg last-pos) + c-state-cache)))) + ;; Check if the preceding balanced paren is within a + ;; macro; it should be ignored if we're outside the + ;; macro. There's no need to check any further upwards; + ;; if the macro contains an unbalanced opening paren then + ;; we're smoked anyway. + (when (and (<= (point) in-macro-start) + (consp (car c-state-cache))) + (save-excursion + (goto-char (car (car c-state-cache))) + (when (c-beginning-of-macro) + (setq here (point) + c-state-cache (cdr c-state-cache))))) + (when c-state-cache + (setq old-state c-state-cache) + last-pos)) + (save-excursion ;; go back 2 bods, but ignore any bogus positions - ;; returned by beginning-of-defun (i.e. open paren - ;; in column zero) + ;; returned by beginning-of-defun (i.e. open paren in + ;; column zero) + (goto-char here) (let ((cnt 2)) - (while (not (or at-bob (zerop cnt))) - (goto-char (c-point 'bod)) - (if (and - (eq (char-after) ?\{) - ;; The following catches an obscure special - ;; case where the brace is preceded by an - ;; open paren. That can only legally occur - ;; with blocks inside expressions and in - ;; Pike special brace lists. Even so, this - ;; test is still bogus then, but hopefully - ;; good enough. (We don't want to use - ;; up-list here since it might be slow.) - (save-excursion - (c-backward-syntactic-ws) - (not (eq (char-before) ?\()))) - (setq cnt (1- cnt))) - (if (bobp) - (setq at-bob t)))) - (point))) - (here (save-excursion - ;;(skip-chars-forward " \t}") - (point))) - (last-bod here) (last-pos pos) - placeholder state sexp-end) - ;; cache last bod position - (while (catch 'backup-bod - (setq state nil) - (while (and pos (< pos here)) - (setq last-pos pos) - (if (and (setq pos (c-safe (scan-lists pos 1 -1))) - (<= pos here)) - (progn - (setq sexp-end (c-safe (scan-sexps (1- pos) 1))) - (if (and sexp-end - (<= sexp-end here)) - ;; we want to record both the start and end - ;; of this sexp, but we only want to record - ;; the last-most of any of them before here - (progn - (if (eq (char-after (1- pos)) ?\{) - (setq state (cons (cons (1- pos) sexp-end) - (if (consp (car state)) - (cdr state) - state)))) - (setq pos sexp-end)) - ;; we're contained in this sexp so put pos on - ;; front of list - (setq state (cons (1- pos) state)))) - ;; something bad happened. check to see if we - ;; crossed an unbalanced close brace. if so, we - ;; didn't really find the right `important bufpos' - ;; so lets back up and try again - (if (and (not pos) (not at-bob) - (setq placeholder - (c-safe (scan-lists last-pos 1 1))) - ;;(char-after (1- placeholder)) - (<= placeholder here) - (eq (char-after (1- placeholder)) ?\})) - (while t - (setq last-bod (c-safe (scan-lists last-pos -1 1))) - (if (not last-bod) - (save-excursion - ;; bogus, but what can we do here? - (goto-char placeholder) - (beginning-of-line) - (setq c-parsing-error - (format "\ -Unbalanced close brace at line %d" (1+ (count-lines 1 (point))))) - (throw 'backup-bod nil)) - (setq at-bob (= last-bod (point-min)) - pos last-bod) - (if (= (char-after last-bod) ?\{) - (throw 'backup-bod t))) - )) ;end-if - )) ;end-while - nil)) - state))) + (while (not (or (bobp) (zerop cnt))) + (c-beginning-of-defun-1) + (if (eq (char-after) ?\{) + (setq cnt (1- cnt))))) + (point)))) + (narrow-to-region (point-min) here) + (while pos + ;; Find the balanced brace pairs. + (setq pairs nil) + (while (and (setq last-pos (c-down-list-forward pos)) + (setq pos (c-up-list-forward last-pos))) + (if (eq (char-before last-pos) ?{) + (setq pairs (cons (cons last-pos pos) pairs)))) + ;; Should ignore any pairs that are in a macro, providing + ;; we're not in the same one. + (when (and pairs (< (car (car pairs)) in-macro-start)) + (while (and (save-excursion + (goto-char (car (car pairs))) + (c-beginning-of-macro)) + (setq pairs (cdr pairs))))) + ;; Record the last brace pair. + (when pairs + (if (and (eq c-state-cache old-state) + (consp (car-safe c-state-cache))) + ;; There's a closed pair on the cached state but we've + ;; found a later one, so remove it. + (setq c-state-cache (cdr c-state-cache))) + (setq pairs (car pairs)) + (setcar pairs (1- (car pairs))) + (setq c-state-cache (cons pairs c-state-cache))) + (if last-pos + ;; Prepare to loop, but record the open paren only if it's + ;; outside a macro or within the same macro as point. + (progn + (setq pos last-pos) + (if (or (>= last-pos in-macro-start) + (save-excursion + (goto-char last-pos) + (not (c-beginning-of-macro)))) + (setq c-state-cache (cons (1- pos) c-state-cache)))) + (if (setq last-pos (c-up-list-forward pos)) + ;; Found a close paren without a corresponding opening + ;; one. Maybe we didn't go back far enough, so try to + ;; scan backward for the start paren and then start over. + (progn + (setq pos (c-up-list-backward pos) + c-state-cache nil) + (unless pos + (setq pos last-pos + c-parsing-error + (format "Unbalanced close paren at line %d" + (1+ (count-lines (point-min) + (c-point 'bol last-pos))))))) + (setq pos nil)))) + c-state-cache))) -(defun c-whack-state (bufpos state) - ;; whack off any state information that appears on STATE which lies - ;; after the bounds of BUFPOS. - (let (newstate car) - (while state - (setq car (car state) - state (cdr state)) - (if (consp car) - ;; just check the car, because in a balanced brace - ;; expression, it must be impossible for the corresponding - ;; close brace to be before point, but the open brace to be - ;; after. - (if (<= bufpos (car car)) - nil ; whack it off - ;; its possible that the open brace is before bufpos, but - ;; the close brace is after. In that case, convert this - ;; to a non-cons element. - (if (<= bufpos (cdr car)) - (setq newstate (append newstate (list (car car)))) - ;; we know that both the open and close braces are - ;; before bufpos, so we also know that everything else - ;; on state is before bufpos, so we can glom up the - ;; whole thing and exit. - (setq newstate (append newstate (list car) state) - state nil))) - (if (<= bufpos car) - nil ; whack it off - ;; it's before bufpos, so everything else should too - (setq newstate (append newstate (list car) state) - state nil)))) - newstate)) +;; Debug tool to catch cache inconsistencies. +(defvar c-debug-parse-state nil) +(unless (fboundp 'c-real-parse-state) + (fset 'c-real-parse-state (symbol-function 'c-parse-state))) +(cc-bytecomp-defun c-real-parse-state) +(defun c-debug-parse-state () + (let ((res1 (c-real-parse-state)) res2) + (let ((c-state-cache nil)) + (setq res2 (c-real-parse-state))) + (unless (equal res1 res2) + (error "c-parse-state inconsistency: using cache: %s, from scratch: %s" + res1 res2)) + res1)) +(defun c-toggle-parse-state-debug (&optional arg) + (interactive "P") + (setq c-debug-parse-state (c-calculate-state arg c-debug-parse-state)) + (fset 'c-parse-state (symbol-function (if c-debug-parse-state + 'c-debug-parse-state + 'c-real-parse-state))) + (c-keep-region-active)) + +(defun c-check-state-cache (beg end old-length) + ;; Used on `after-change-functions' to adjust `c-state-cache'. + ;; Prefer speed to finesse here, since there will be many more calls + ;; to this function than times `c-state-cache' is used. + ;; + ;; This is much like `c-whack-state-after', but it never changes a + ;; paren pair element into an open paren element. Doing that would + ;; mean that the new open paren wouldn't have the required preceding + ;; paren pair element. + (if (not (eq c-state-cache-start (point-min))) + (setq c-state-cache-start (point-min) + c-state-cache nil) + (while (and c-state-cache + (let ((elem (car c-state-cache))) + (if (consp elem) + (or (<= beg (car elem)) + (< beg (cdr elem))) + (<= beg elem)))) + (setq c-state-cache (cdr c-state-cache))))) -(defun c-hack-state (bufpos which state) - ;; Using BUFPOS buffer position, and WHICH (must be 'open or - ;; 'close), hack the c-parse-state STATE and return the results. - (if (eq which 'open) - (let ((car (car state))) - (if (or (null car) - (consp car) - (/= bufpos car)) - (cons bufpos state) - state)) - (if (not (eq which 'close)) - (error "c-hack-state, bad argument: %s" which)) - ;; 'close brace - (let ((car (car state)) - (cdr (cdr state))) - (if (consp car) - (setq car (car cdr) - cdr (cdr cdr))) - ;; TBD: is this test relevant??? - (if (consp car) - state ;on error, don't change - ;; watch out for balanced expr already on cdr of list - (cons (cons car bufpos) - (if (consp (car cdr)) - (cdr cdr) cdr)) - )))) +(defun c-whack-state-before (bufpos paren-state) + ;; Whack off any state information from PAREN-STATE which lies + ;; before BUFPOS. Not destructive on PAREN-STATE. + (let* ((newstate (list nil)) + (ptr newstate) + car) + (while paren-state + (setq car (car paren-state) + paren-state (cdr paren-state)) + (if (< (if (consp car) (car car) car) bufpos) + (setq paren-state nil) + (setcdr ptr (list car)) + (setq ptr (cdr ptr)))) + (cdr newstate))) -(defun c-adjust-state (from to shift state) - ;; Adjust all points in state that lie in the region FROM..TO by - ;; SHIFT amount. - (mapcar - (function - (lambda (e) - (if (consp e) - (let ((car (car e)) - (cdr (cdr e))) - (if (and (<= from car) (< car to)) - (setcar e (+ shift car))) - (if (and (<= from cdr) (< cdr to)) - (setcdr e (+ shift cdr)))) - (if (and (<= from e) (< e to)) - (setq e (+ shift e)))) - e)) - state)) +(defun c-whack-state-after (bufpos paren-state) + ;; Whack off any state information from PAREN-STATE which lies at or + ;; after BUFPOS. Not destructive on PAREN-STATE. + (catch 'done + (while paren-state + (let ((car (car paren-state))) + (if (consp car) + ;; just check the car, because in a balanced brace + ;; expression, it must be impossible for the corresponding + ;; close brace to be before point, but the open brace to + ;; be after. + (if (<= bufpos (car car)) + nil ; whack it off + (if (< bufpos (cdr car)) + ;; its possible that the open brace is before + ;; bufpos, but the close brace is after. In that + ;; case, convert this to a non-cons element. The + ;; rest of the state is before bufpos, so we're + ;; done. + (throw 'done (cons (car car) (cdr paren-state))) + ;; we know that both the open and close braces are + ;; before bufpos, so we also know that everything else + ;; on state is before bufpos. + (throw 'done paren-state))) + (if (<= bufpos car) + nil ; whack it off + ;; it's before bufpos, so everything else should too. + (throw 'done paren-state))) + (setq paren-state (cdr paren-state))) + nil))) (defun c-beginning-of-inheritance-list (&optional lim) ;; Go to the first non-whitespace after the colon that starts a ;; multiple inheritance introduction. Optional LIM is the farthest ;; back we should search. - (let* ((lim (or lim (c-point 'bod))) - (placeholder (progn - (back-to-indentation) - (point))) - (chr (char-after))) - (c-backward-syntactic-ws lim) - (while (and (> (point) lim) - (or (eq chr ?,) - (memq (char-before) '(?, ?:))) - (progn - (beginning-of-line) - (setq placeholder (point)) - (skip-chars-forward " \t") - (setq chr (char-after)) - (not (looking-at c-class-key)) - )) - (c-backward-syntactic-ws lim)) - (goto-char placeholder) - (skip-chars-forward "^:" (c-point 'eol)))) + (let* ((lim (or lim (c-point 'bod)))) + (c-with-syntax-table c++-template-syntax-table + (c-backward-token-1 0 t lim) + (while (and (looking-at "[_a-zA-Z<,]") + (= (c-backward-token-1 1 t lim) 0))) + (skip-chars-forward "^:")))) (defun c-in-method-def-p () ;; Return nil if we aren't in a method definition, otherwise the ;; position of the initial [+-]. (save-excursion (beginning-of-line) - (and c-method-key - (looking-at c-method-key) + (and c-opt-method-key + (looking-at c-opt-method-key) (point)) )) +;; Contributed by Kevin Ryde <user42@zip.com.au>. +(defun c-in-gcc-asm-p () + ;; Return non-nil if point is within a gcc \"asm\" block. + ;; + ;; This should be called with point inside an argument list. + ;; + ;; Only one level of enclosing parentheses is considered, so for + ;; instance `nil' is returned when in a function call within an asm + ;; operand. + + (and c-opt-asm-stmt-key + (save-excursion + (beginning-of-line) + (backward-up-list 1) + (c-beginning-of-statement-1 (point-min) nil t) + (looking-at c-opt-asm-stmt-key)))) + (defun c-at-toplevel-p () "Return a determination as to whether point is at the `top-level'. Being at the top-level means that point is either outside any -enclosing block (such function definition), or inside a class -definition, but outside any method blocks. +enclosing block (such function definition), or inside a class, +namespace or extern definition, but outside any method blocks. If point is not at the top-level (e.g. it is inside a method definition), then nil is returned. Otherwise, if point is at a @@ -852,25 +1411,42 @@ buffer position of the start of the class declaration, and the first element is the buffer position of the enclosing class's opening brace." - (let ((state (c-parse-state))) - (or (not (c-most-enclosing-brace state)) - (c-search-uplist-for-classkey state)))) + (let ((paren-state (c-parse-state))) + (or (not (c-most-enclosing-brace paren-state)) + (c-search-uplist-for-classkey paren-state)))) -(defun c-just-after-func-arglist-p (&optional containing) +(defun c-forward-to-cpp-define-body () + ;; Assuming point is at the "#" that introduces a preprocessor + ;; directive, it's moved forward to the start of the definition body + ;; if it's a "#define". Non-nil is returned in this case, in all + ;; other cases nil is returned and point isn't moved. + (when (and (looking-at + (concat "#[ \t]*" + "define[ \t]+\\(\\sw\\|_\\)+\\(\([^\)]*\)\\)?" + "\\([ \t]\\|\\\\\n\\)*")) + (not (= (match-end 0) (c-point 'eol)))) + (goto-char (match-end 0)))) + +(defun c-just-after-func-arglist-p (&optional containing lim) ;; Return t if we are between a function's argument list closing ;; paren and its opening brace. Note that the list close brace ;; could be followed by a "const" specifier or a member init hanging ;; colon. Optional CONTAINING is position of containing s-exp open - ;; brace. If not supplied, point is used as search start. + ;; brace. If not supplied, point is used as search start. LIM is + ;; used as bound for some backward buffer searches; the search might + ;; continue past it. + ;; + ;; Note: This test is easily fooled. It only works reasonably well + ;; in the situations where `c-guess-basic-syntax' uses it. (save-excursion - (c-backward-syntactic-ws) + (c-backward-syntactic-ws lim) (let ((checkpoint (or containing (point)))) (goto-char checkpoint) ;; could be looking at const specifier (if (and (eq (char-before) ?t) (forward-word -1) - (looking-at "\\<const\\>")) - (c-backward-syntactic-ws) + (looking-at "\\<const\\>[^_]")) + (c-backward-syntactic-ws lim) ;; otherwise, we could be looking at a hanging member init ;; colon (goto-char checkpoint) @@ -882,22 +1458,30 @@ (if (eq (char-before) ?\)) (c-backward-sexp 2) (c-backward-sexp 1)) - (c-backward-syntactic-ws)) + (c-backward-syntactic-ws lim)) (if (and (eq (char-before) ?:) (progn (forward-char -1) - (c-backward-syntactic-ws) - (looking-at "[ \t\n]*:\\([^:]+\\|$\\)"))) + (c-backward-syntactic-ws lim) + (looking-at "\\([ \t\n]\\|\\\\\n\\)*:\\([^:]+\\|$\\)"))) nil (goto-char checkpoint)) ) + (setq checkpoint (point)) (and (eq (char-before) ?\)) - ;; check if we are looking at a method def - (or (not c-method-key) + ;; Check that it isn't a cpp expression, e.g. the + ;; expression of an #if directive or the "function header" + ;; of a #define. + (or (not (c-beginning-of-macro)) + (and (c-forward-to-cpp-define-body) + (< (point) checkpoint))) + ;; check if we are looking at an ObjC method def + (or (not c-opt-method-key) (progn + (goto-char checkpoint) (c-forward-sexp -1) (forward-char -1) - (c-backward-syntactic-ws) + (c-backward-syntactic-ws lim) (not (or (memq (char-before) '(?- ?+)) ;; or a class category (progn @@ -906,118 +1490,234 @@ ))))) ))) -;; defuns to look backwards for things -(defun c-backward-to-start-of-do (&optional lim) - ;; Move to the start of the last "unbalanced" do expression. - ;; Optional LIM is the farthest back to search. If none is found, - ;; nil is returned and point is left unchanged, otherwise t is returned. - (let ((do-level 1) - (case-fold-search nil) - (lim (or lim (c-point 'bod))) - (here (point)) - foundp) - (while (not (zerop do-level)) - ;; we protect this call because trying to execute this when the - ;; while is not associated with a do will throw an error - (condition-case nil - (progn - (c-backward-sexp 1) - (cond - ;; break infloop for illegal C code - ((bobp) (setq do-level 0)) - ((memq (c-in-literal lim) '(c c++))) - ((looking-at "while\\b[^_]") - (setq do-level (1+ do-level))) - ((looking-at "do\\b[^_]") - (if (zerop (setq do-level (1- do-level))) - (setq foundp t))) - ((<= (point) lim) - (setq do-level 0) - (goto-char lim)))) - (error - (goto-char lim) - (setq do-level 0)))) - (if (not foundp) - (goto-char here)) - foundp)) - -(defun c-backward-to-start-of-if (&optional lim) - ;; Move to the start of the last "unbalanced" if and return t. If - ;; none is found, and we are looking at an if clause, nil is - ;; returned. - (let ((if-level 1) - (here (c-point 'bol)) - (case-fold-search nil) - (lim (or (and lim (>= (point) lim) lim) - (c-point 'bod))) - (at-if (looking-at "if\\b[^_]"))) - (catch 'orphan-if - (while (and (not (bobp)) - (not (zerop if-level))) - (c-backward-syntactic-ws) - (condition-case nil - (c-backward-sexp 1) - (error - (unless at-if - (goto-char here) - (c-beginning-of-statement-1) - (setq c-parsing-error - (format "No matching `if' found for `else' on line %d" - (1+ (count-lines (point-min) here)))) - (throw 'orphan-if nil)))) - (cond - ((looking-at "else\\b[^_]") - (setq if-level (1+ if-level))) - ((looking-at "if\\b[^_]") - ;; check for else if... skip over - (let ((here (point))) - (c-safe (c-forward-sexp -1)) - (if (looking-at "\\<else\\>[ \t]+\\<if\\>[^_]") - nil - (setq if-level (1- if-level)) - (goto-char here)))) - ((< (point) lim) - (setq if-level 0) - (goto-char lim)) - )) - t))) +(defun c-in-knr-argdecl (&optional lim) + ;; Return the position of the first argument declaration if point is + ;; inside a K&R style argument declaration list, nil otherwise. + ;; `c-recognize-knr-p' is not checked. If LIM is non-nil, it's a + ;; position that bounds the backward search for the argument list. + ;; + ;; Note: A declaration level context is assumed; the test can return + ;; false positives for statements and #define headers. This test is + ;; even more easily fooled than `c-just-after-func-arglist-p'. + (save-excursion + (save-restriction + ;; Go back to the closest preceding normal parenthesis sexp. We + ;; take that as the argument list in the function header. Then + ;; check that it's followed by some symbol before the next ';' + ;; or '{'. If it does, it's the header of the K&R argdecl we're + ;; in. + (if lim (narrow-to-region lim (point))) + (let (paren-end) + (and (c-safe (setq paren-end (c-down-list-backward (point)))) + (eq (char-after paren-end) ?\)) + (progn + (goto-char (1+ paren-end)) + (c-forward-syntactic-ws) + (looking-at "\\w\\|\\s_")) + (c-safe (c-up-list-backward paren-end)) + (point)))))) (defun c-skip-conditional () ;; skip forward over conditional at point, including any predicate ;; statements in parentheses. No error checking is performed. (c-forward-sexp (cond ;; else if() - ((looking-at "\\<else\\>[ \t]+\\<if\\>\\([^_]\\|$\\)") 3) + ((looking-at (concat "\\<else" + "\\([ \t\n]\\|\\\\\n\\)+" + "if\\>\\([^_]\\|$\\)")) + 3) ;; do, else, try, finally - ((looking-at - "\\<\\(do\\|else\\|try\\|finally\\)\\>\\([^_]\\|$\\)") + ((looking-at (concat "\\<\\(" + "do\\|else\\|try\\|finally" + "\\)\\>\\([^_]\\|$\\)")) 1) ;; for, if, while, switch, catch, synchronized, foreach (t 2)))) -(defun c-beginning-of-closest-statement (&optional lim) - ;; Go back to the closest preceding statement start. +(defun c-after-conditional (&optional lim) + ;; If looking at the token after a conditional then return the + ;; position of its start, otherwise return nil. + (save-excursion + (and (= (c-backward-token-1 1 t lim) 0) + (or (looking-at c-block-stmt-1-key) + (and (eq (char-after) ?\() + (= (c-backward-token-1 1 t lim) 0) + (looking-at c-block-stmt-2-key))) + (point)))) + +(defsubst c-backward-to-block-anchor (&optional lim) + ;; Assuming point is at a brace that opens a statement block of some + ;; kind, move to the proper anchor point for that block. It might + ;; need to be adjusted further by c-add-stmt-syntax, but the + ;; position at return is suitable as start position for that + ;; function. + (unless (= (point) (c-point 'boi)) + (let ((start (c-after-conditional lim))) + (if start + (goto-char start))))) + +(defun c-backward-to-decl-anchor (&optional lim) + ;; Assuming point is at a brace that opens the block of a top level + ;; declaration of some kind, move to the proper anchor point for + ;; that block. + (unless (= (point) (c-point 'boi)) + ;; What we have below is actually an extremely stripped variant of + ;; c-beginning-of-statement-1. + (let ((pos (point))) + ;; Switch syntax table to avoid stopping at line continuations. + (save-restriction + (if lim (narrow-to-region lim (point-max))) + (while (and (progn + (c-backward-syntactic-ws) + (c-safe (goto-char (scan-sexps (point) -1)) t)) + (not (c-crosses-statement-barrier-p (point) pos))) + (setq pos (point))) + (goto-char pos))))) + +(defsubst c-search-decl-header-end () + ;; Search forward for the end of the "header" of the current + ;; declaration. That's the position where the definition body + ;; starts, or the first variable initializer, or the ending + ;; semicolon. I.e. search forward for the closest following + ;; (syntactically relevant) '{', '=' or ';' token. Point is left + ;; _after_ the first found token, or at point-max if none is found. + (c-with-syntax-table (if (c-major-mode-is 'c++-mode) + c++-template-syntax-table + (syntax-table)) + (while (and (c-syntactic-re-search-forward "[;{=]" nil 'move 1 t) + ;; In Pike it can be an operator identifier containing + ;; '='. + (c-major-mode-is 'pike-mode) + (eq (char-before) ?=) + (c-on-identifier))))) + +(defun c-beginning-of-decl-1 (&optional lim) + ;; Go to the beginning of the current declaration, or the beginning + ;; of the previous one if already at the start of it. Point won't + ;; be moved out of any surrounding paren. Return a cons cell on the + ;; form (MOVE . KNR-POS). MOVE is like the return value from + ;; `c-beginning-of-statement-1'. If point skipped over some K&R + ;; style argument declarations (and they are to be recognized) then + ;; KNR-POS is set to the start of the first such argument + ;; declaration, otherwise KNR-POS is nil. If LIM is non-nil, it's a + ;; position that bounds the backward search. + ;; + ;; NB: Cases where the declaration continues after the block, as in + ;; "struct foo { ... } bar;", are currently recognized as two + ;; declarations, e.g. "struct foo { ... }" and "bar;" in this case. + (catch 'return + (let* ((start (point)) + (last-stmt-start (point)) + (move (c-beginning-of-statement-1 lim nil t))) + + (while (and (/= last-stmt-start (point)) + (save-excursion + (c-backward-syntactic-ws lim) + (not (memq (char-before) '(?\; ?} ?: nil))))) + ;; `c-beginning-of-statement-1' stops at a block start, but we + ;; want to continue if the block doesn't begin a top level + ;; construct, i.e. if it isn't preceded by ';', '}', ':', or bob. + (setq last-stmt-start (point) + move (c-beginning-of-statement-1 lim nil t))) + + (when c-recognize-knr-p + (let ((fallback-pos (point)) knr-argdecl-start) + ;; Handle K&R argdecls. Back up after the "statement" jumped + ;; over by `c-beginning-of-statement-1', unless it was the + ;; function body, in which case we're sitting on the opening + ;; brace now. Then test if we're in a K&R argdecl region and + ;; that we started at the other side of the first argdecl in + ;; it. + (unless (eq (char-after) ?{) + (goto-char last-stmt-start)) + (if (and (setq knr-argdecl-start (c-in-knr-argdecl lim)) + (< knr-argdecl-start start) + (progn + (goto-char knr-argdecl-start) + (not (eq (c-beginning-of-statement-1 lim nil t) 'macro)))) + (throw 'return + (cons (if (eq (char-after fallback-pos) ?{) + 'previous + 'same) + knr-argdecl-start)) + (goto-char fallback-pos)))) + + ;; `c-beginning-of-statement-1' counts each brace block as a + ;; separate statement, so the result will be 'previous if we've + ;; moved over any. If they were brace list initializers we might + ;; not have moved over a declaration boundary though, so change it + ;; to 'same if we've moved past a '=' before '{', but not ';'. + ;; (This ought to be integrated into `c-beginning-of-statement-1', + ;; so we avoid this extra pass which potentially can search over a + ;; large amount of text.) + (if (and (eq move 'previous) + (c-with-syntax-table (if (c-major-mode-is 'c++-mode) + c++-template-syntax-table + (syntax-table)) + (save-excursion + (and (c-syntactic-re-search-forward "[;={]" start t 1 t) + (eq (char-before) ?=) + (c-syntactic-re-search-forward "[;{]" start t 1 t) + (eq (char-before) ?{) + (c-safe (goto-char (c-up-list-forward (point))) t) + (not (c-syntactic-re-search-forward ";" start t 1 t)))))) + (cons 'same nil) + (cons move nil))))) + +(defun c-end-of-decl-1 () + ;; Assuming point is at the start of a declaration (as detected by + ;; e.g. `c-beginning-of-decl-1'), go to the end of it. Unlike + ;; `c-beginning-of-decl-1', this function handles the case when a + ;; block is followed by identifiers in e.g. struct declarations in C + ;; or C++. If a proper end was found then t is returned, otherwise + ;; point is moved as far as possible within the current sexp and nil + ;; is returned. This function doesn't handle macros; use + ;; `c-end-of-macro' instead in those cases. (let ((start (point)) - (label-re (concat c-label-key "\\|" - c-switch-label-key)) - stmtbeg) - (if c-access-key - (setq label-re (concat label-re "\\|" c-access-key))) - (c-beginning-of-statement-1 lim) - (while (and (when (<= (point) start) - (setq stmtbeg (point))) - (cond - ((looking-at label-re) - ;; Skip a label. - (goto-char (match-end 0)) - t) - ((looking-at c-conditional-key) - ;; Skip a conditional statement. - (c-safe (c-skip-conditional) t)) - (t nil))) - (c-forward-syntactic-ws start)) - (if stmtbeg - (goto-char stmtbeg)))) + (decl-syntax-table (if (c-major-mode-is 'c++-mode) + c++-template-syntax-table + (syntax-table)))) + (catch 'return + (c-search-decl-header-end) + + (when (and c-recognize-knr-p + (eq (char-before) ?\;) + (c-in-knr-argdecl start)) + ;; Stopped at the ';' in a K&R argdecl section which is + ;; detected using the same criteria as in + ;; `c-beginning-of-decl-1'. Move to the following block + ;; start. + (c-syntactic-re-search-forward "{" nil 'move 1 t)) + + (when (eq (char-before) ?{) + ;; Encountered a block in the declaration. Jump over it. + (condition-case nil + (goto-char (c-up-list-forward (point))) + (goto-char (point-max)) + (throw 'return nil)) + (if (or (not c-opt-block-decls-with-vars-key) + (save-excursion + (c-with-syntax-table decl-syntax-table + (let ((lim (point))) + (goto-char start) + (not (and (c-syntactic-re-search-forward + (concat "[;=\(\[{]\\|\\<\\(" + c-opt-block-decls-with-vars-key + "\\)") + lim t 1 t) + (match-beginning 1) + (not (eq (char-before) ?_)))))))) + ;; The declaration doesn't have any of the + ;; `c-opt-block-decls-with-vars' keywords in the + ;; beginning, so it ends here at the end of the block. + (throw 'return t))) + + (c-with-syntax-table decl-syntax-table + (while (progn + (if (eq (char-before) ?\;) + (throw 'return t)) + (c-syntactic-re-search-forward ";" nil 'move 1 t)))) + nil))) (defun c-beginning-of-member-init-list (&optional limit) ;; Goes to the beginning of a member init list (i.e. just after the @@ -1055,61 +1755,26 @@ (and (< limit (point)) (eq (char-before) ?:))) -(defun c-skip-case-statement-forward (state &optional lim) - ;; skip forward over case/default bodies, with optional maximal - ;; limit. if no next case body is found, nil is returned and point - ;; is not moved - (let ((lim (or lim (point-max))) - (here (point)) - donep foundp bufpos - (safepos (point)) - (balanced (car state))) - ;; search until we've passed the limit, or we've found our match - (while (and (< (point) lim) - (not donep)) - (setq safepos (point)) - ;; see if we can find a case statement, not in a literal - (if (and (re-search-forward c-switch-label-key lim 'move) - (setq bufpos (match-beginning 0)) - (not (c-in-literal safepos)) - (/= bufpos here)) - ;; if we crossed into a balanced sexp, we know the case is - ;; not part of our switch statement, so just bound over the - ;; sexp and keep looking. - (if (and (consp balanced) - (> bufpos (car balanced)) - (< bufpos (cdr balanced))) - (goto-char (cdr balanced)) - (goto-char bufpos) - (setq donep t - foundp t)))) - (if (not foundp) - (goto-char here)) - foundp)) - -(defun c-search-uplist-for-classkey (brace-state) +(defun c-search-uplist-for-classkey (paren-state) ;; search for the containing class, returning a 2 element vector if ;; found. aref 0 contains the bufpos of the boi of the class key ;; line, and aref 1 contains the bufpos of the open brace. - (if (null brace-state) - ;; no brace-state means we cannot be inside a class + (if (null paren-state) + ;; no paren-state means we cannot be inside a class nil - (let ((carcache (car brace-state)) + (let ((carcache (car paren-state)) search-start search-end) (if (consp carcache) ;; a cons cell in the first element means that there is some ;; balanced sexp before the current bufpos. this we can ;; ignore. the nth 1 and nth 2 elements define for us the ;; search boundaries - (setq search-start (nth 2 brace-state) - search-end (nth 1 brace-state)) + (setq search-start (nth 2 paren-state) + search-end (nth 1 paren-state)) ;; if the car was not a cons cell then nth 0 and nth 1 define ;; for us the search boundaries - (setq search-start (nth 1 brace-state) - search-end (nth 0 brace-state))) - ;; search-end cannot be a cons cell - (and (consp search-end) - (error "consp search-end: %s" search-end)) + (setq search-start (nth 1 paren-state) + search-end (nth 0 paren-state))) ;; if search-end is nil, or if the search-end character isn't an ;; open brace, we are definitely not in a class (if (or (not search-end) @@ -1132,22 +1797,18 @@ (save-excursion (save-restriction (goto-char search-start) - (let ((search-key (concat c-class-key "\\|" c-extra-toplevel-key)) - foundp class match-end) - (if c-inexpr-class-key - (setq search-key (concat search-key "\\|" - c-inexpr-class-key))) + (let (foundp class match-end) (while (and (not foundp) (progn - (c-forward-syntactic-ws) + (c-forward-syntactic-ws search-end) (> search-end (point))) - (re-search-forward search-key search-end t)) + (re-search-forward c-decl-block-key search-end t)) (setq class (match-beginning 0) match-end (match-end 0)) + (goto-char class) (if (c-in-literal search-start) - nil ; its in a comment or string, ignore - (goto-char class) - (skip-chars-forward " \t\n") + (goto-char match-end) ; its in a comment or string, ignore + (c-skip-ws-forward) (setq foundp (vector (c-point 'boi) search-end)) (cond ;; check for embedded keywords @@ -1157,15 +1818,14 @@ (goto-char match-end) (setq foundp nil)) ;; make sure we're really looking at the start of a - ;; class definition, and not a forward decl, return - ;; arg, template arg list, or an ObjC or Java method. - ((and c-method-key - (re-search-forward c-method-key search-end t) + ;; class definition, and not an ObjC method. + ((and c-opt-method-key + (re-search-forward c-opt-method-key search-end t) (not (c-in-literal class))) (setq foundp nil)) ;; Check if this is an anonymous inner class. - ((and c-inexpr-class-key - (looking-at c-inexpr-class-key)) + ((and c-opt-inexpr-class-key + (looking-at c-opt-inexpr-class-key)) (while (and (= (c-forward-token-1 1 t) 0) (looking-at "(\\|\\w\\|\\s_\\|\\."))) (if (eq (point) search-end) @@ -1198,7 +1858,7 @@ foundp)) ))))) -(defun c-inside-bracelist-p (containing-sexp brace-state) +(defun c-inside-bracelist-p (containing-sexp paren-state) ;; return the buffer position of the beginning of the brace list ;; statement if we're inside a brace list, otherwise return nil. ;; CONTAINING-SEXP is the buffer pos of the innermost containing @@ -1215,10 +1875,10 @@ (goto-char containing-sexp) (c-forward-sexp -1) (let (bracepos) - (if (and (or (looking-at "enum[\t\n ]+") + (if (and (or (looking-at "enum\\>[^_]") (progn (c-forward-sexp -1) - (looking-at "enum[\t\n ]+"))) - (setq bracepos (c-safe (scan-lists (point) 1 -1))) + (looking-at "enum\\>[^_]"))) + (setq bracepos (c-down-list-forward (point))) (not (c-crosses-statement-barrier-p (point) (- bracepos 2)))) (point))))) @@ -1228,24 +1888,28 @@ ;; Pike can have class definitions anywhere, so we must ;; check for the class key here. (and (c-major-mode-is 'pike-mode) - (concat c-class-key "\\|" c-extra-toplevel-key))) - bufpos lim braceassignp) + c-decl-block-key)) + bufpos braceassignp lim next-containing) (while (and (not bufpos) containing-sexp) - (if (consp containing-sexp) - (setq containing-sexp (car brace-state) - brace-state (cdr brace-state)) + (when paren-state + (if (consp (car paren-state)) + (setq lim (cdr (car paren-state)) + paren-state (cdr paren-state)) + (setq lim (car paren-state))) + (when paren-state + (setq next-containing (car paren-state) + paren-state (cdr paren-state)))) (goto-char containing-sexp) - (if (c-looking-at-inexpr-block) - ;; We're in an in-expression block of some kind. Do - ;; not check nesting. + (if (c-looking-at-inexpr-block next-containing next-containing) + ;; We're in an in-expression block of some kind. Do not + ;; check nesting. We deliberately set the limit to the + ;; containing sexp, so that c-looking-at-inexpr-block + ;; doesn't check for an identifier before it. (setq containing-sexp nil) ;; see if the open brace is preceded by = or [...] in ;; this statement, but watch out for operator= - (setq lim (if (consp (car brace-state)) - (cdr (car brace-state)) - (car brace-state)) - braceassignp 'dontknow) + (setq braceassignp 'dontknow) (c-backward-token-1 1 t lim) ;; Checks to do only on the first sexp before the brace. (when (and (c-major-mode-is 'java-mode) @@ -1280,7 +1944,7 @@ (setq braceassignp (cond ;; Check for operator = - ((looking-at "operator\\>") nil) + ((looking-at "operator\\>[^_]") nil) ;; Check for `<opchar>= in Pike. ((and (c-major-mode-is 'pike-mode) (or (eq (char-after) ?`) @@ -1293,17 +1957,18 @@ ((looking-at "\\s.") 'maybe) ;; make sure we're not in a C++ template ;; argument assignment - ((and (c-major-mode-is 'c++-mode) - (save-excursion - (let ((here (point)) - (pos< (progn - (skip-chars-backward "^<>") - (point)))) - (and (eq (char-before) ?<) - (not (c-crosses-statement-barrier-p - pos< here)) - (not (c-in-literal)) - )))) + ((and + (c-major-mode-is 'c++-mode) + (save-excursion + (let ((here (point)) + (pos< (progn + (skip-chars-backward "^<>") + (point)))) + (and (eq (char-before) ?<) + (not (c-crosses-statement-barrier-p + pos< here)) + (not (c-in-literal)) + )))) nil) (t t)))))) (if (and (eq braceassignp 'dontknow) @@ -1313,15 +1978,15 @@ (if (eq (char-after) ?\;) ;; Brace lists can't contain a semicolon, so we're done. (setq containing-sexp nil) - ;; lets see if we're nested. find the most nested - ;; containing brace - (setq containing-sexp (car brace-state) - brace-state (cdr brace-state))) + ;; Go up one level. + (setq containing-sexp next-containing + lim nil + next-containing nil)) ;; we've hit the beginning of the aggregate list (c-beginning-of-statement-1 - (c-most-enclosing-brace brace-state)) + (c-most-enclosing-brace paren-state)) (setq bufpos (point)))) - )) + ) bufpos)) )) @@ -1375,82 +2040,126 @@ (cons (list beg) type))))) (error nil)))) -(defun c-looking-at-bos () - ;; Returns nil if inside a statement or declaration. +(defun c-looking-at-bos (&optional lim) + ;; Return non-nil if between two statements or declarations, assuming + ;; point is not inside a literal or comment. (save-excursion - (c-backward-syntactic-ws) + (c-backward-syntactic-ws lim) (or (bobp) - (memq (char-before) '(?\; ?})) + ;; Return t if at the start inside some parenthesis expression + ;; too, to catch macros that have statements as arguments. + (memq (char-before) '(?\; ?} ?\()) (and (eq (char-before) ?{) (not (and c-special-brace-lists (progn (backward-char) (c-looking-at-special-brace-list)))))))) -(defun c-looking-at-inexpr-block (&optional lim) +(defun c-looking-at-inexpr-block (lim containing-sexp) ;; Returns non-nil if we're looking at the beginning of a block ;; inside an expression. The value returned is actually a cons of ;; either 'inlambda, 'inexpr-statement or 'inexpr-class and the ;; position of the beginning of the construct. LIM limits the - ;; backward search. + ;; backward search. CONTAINING-SEXP is the start position of the + ;; closest containing list. If it's nil, the containing paren isn't + ;; used to decide whether we're inside an expression or not. If + ;; both LIM and CONTAINING-SEXP is used, LIM needs to be farther + ;; back. (save-excursion - (or lim (setq lim (point-min))) - (let ((block-follows (eq (char-after) ?{))) - ;; Look at the character after point only as a last resort when - ;; we can't disambiguate. - (if (and block-follows - (progn (c-backward-syntactic-ws) (> (point) lim)) - (eq (char-before) ?\() - (not (and c-special-brace-lists - (c-looking-at-special-brace-list)))) - (cons 'inexpr-statement (point)) - (let (res) - (while (and (not res) - (= (c-backward-token-1 1 t lim) 0) - (>= (point) lim) - (looking-at "(\\|\\w\\|\\s_\\|\\.")) - (setq res - (cond ((and block-follows - c-inexpr-class-key - (looking-at c-inexpr-class-key) - (or (not (looking-at c-class-key)) - (let ((prev (point))) - (while (and (= (c-backward-token-1 1 t lim) - 0) - (>= (point) lim) - (eq (char-syntax (char-after)) - ?w)) - (setq prev (point))) - (goto-char prev) - (not (c-looking-at-bos))))) - (cons 'inexpr-class (point))) - ((and c-inexpr-block-key - (looking-at c-inexpr-block-key)) - (cons 'inexpr-statement (point))) - ((and c-lambda-key - (looking-at c-lambda-key)) - (cons 'inlambda (point)))))) - res))))) + (let ((res 'maybe) passed-bracket + (closest-lim (or containing-sexp lim (point-min))) + ;; Look at the character after point only as a last resort + ;; when we can't disambiguate. + (block-follows (and (eq (char-after) ?{) (point)))) + (while (and (eq res 'maybe) + (progn (c-backward-syntactic-ws) + (> (point) closest-lim)) + (not (bobp)) + (progn (backward-char) + (looking-at "[\]\).]\\|\\w\\|\\s_")) + (progn (forward-char) + (goto-char (scan-sexps (point) -1)))) + (setq res + (cond + ((and block-follows + c-opt-inexpr-class-key + (looking-at c-opt-inexpr-class-key)) + (and (not passed-bracket) + (or (not (looking-at c-class-key)) + ;; If the class definition is at the start of + ;; a statement, we don't consider it an + ;; in-expression class. + (let ((prev (point))) + (while (and + (= (c-backward-token-1 1 nil closest-lim) 0) + (eq (char-syntax (char-after)) ?w)) + (setq prev (point))) + (goto-char prev) + (not (c-looking-at-bos))) + ;; Also, in Pike we treat it as an + ;; in-expression class if it's used in an + ;; object clone expression. + (save-excursion + (and (c-major-mode-is 'pike-mode) + (progn (goto-char block-follows) + (= (c-forward-token-1 1 t) 0)) + (eq (char-after) ?\()))) + (cons 'inexpr-class (point)))) + ((and c-opt-inexpr-block-key + (looking-at c-opt-inexpr-block-key)) + (cons 'inexpr-statement (point))) + ((and c-opt-lambda-key + (looking-at c-opt-lambda-key)) + (cons 'inlambda (point))) + ((and c-opt-block-stmt-key + (looking-at c-opt-block-stmt-key)) + nil) + (t + (if (eq (char-after) ?\[) + (setq passed-bracket t)) + 'maybe)))) + (if (eq res 'maybe) + (when (and block-follows + containing-sexp + (eq (char-after containing-sexp) ?\()) + (goto-char containing-sexp) + (if (or (save-excursion + (c-backward-syntactic-ws lim) + (and (> (point) (or lim (point-min))) + (c-on-identifier))) + (and c-special-brace-lists + (c-looking-at-special-brace-list))) + nil + (cons 'inexpr-statement (point)))) + res)))) -(defun c-looking-at-inexpr-block-backward (&optional lim) +(defun c-looking-at-inexpr-block-backward (paren-state) ;; Returns non-nil if we're looking at the end of an in-expression ;; block, otherwise the same as `c-looking-at-inexpr-block'. + ;; PAREN-STATE is the paren state relevant at the current position. (save-excursion - (let ((lim (or lim (c-point 'bod)))) - (c-safe - (c-backward-syntactic-ws lim) - (if (eq (char-before) ?}) ; Recognize only a block currently. - (progn - (c-forward-sexp -1) - (if (>= (point) lim) - (c-looking-at-inexpr-block lim)))))))) + ;; We currently only recognize a block. + (let ((here (point)) + (elem (car-safe paren-state)) + containing-sexp) + (when (and (consp elem) + (progn (goto-char (cdr elem)) + (c-forward-syntactic-ws here) + (= (point) here))) + (goto-char (car elem)) + (if (setq paren-state (cdr paren-state)) + (setq containing-sexp (car-safe paren-state))) + (c-looking-at-inexpr-block (c-safe-position containing-sexp + paren-state) + containing-sexp))))) (defun c-on-identifier () - ;; Returns non-nil if we're on or directly after an identifier. + "Return non-nil if we're on or directly after an identifier. +Keywords are recognized and not considered identifiers." (if (or (memq (char-syntax (or (char-after) ? )) '(?w ?_)) (memq (char-syntax (or (char-before) ? )) '(?w ?_))) (save-excursion (skip-syntax-backward "w_") - (not (looking-at c-keywords))) + (not (looking-at c-keywords-regexp))) (if (c-major-mode-is 'pike-mode) ;; Handle the `<operator> syntax in Pike. (save-excursion @@ -1467,49 +2176,73 @@ (looking-at "[-!%&*+/<=>^|~]\\|()\\|\\[]")))))) -(defun c-most-enclosing-brace (state) - ;; return the bufpos of the most enclosing brace that hasn't been - ;; narrowed out by any enclosing class, or nil if none was found +(defun c-most-enclosing-brace (paren-state &optional bufpos) + ;; Return the bufpos of the innermost enclosing brace before bufpos + ;; that hasn't been narrowed out, or nil if none was found. (let (enclosingp) - (while (and state (not enclosingp)) - (setq enclosingp (car state) - state (cdr state)) - (if (consp enclosingp) + (or bufpos (setq bufpos 134217727)) + (while paren-state + (setq enclosingp (car paren-state) + paren-state (cdr paren-state)) + (if (or (consp enclosingp) + (>= enclosingp bufpos)) (setq enclosingp nil) - (if (> (point-min) enclosingp) + (if (< enclosingp (point-min)) (setq enclosingp nil)) - (setq state nil))) + (setq paren-state nil))) enclosingp)) -(defun c-least-enclosing-brace (state) - ;; return the bufpos of the least (highest) enclosing brace that - ;; hasn't been narrowed out by any enclosing class, or nil if none - ;; was found. - (c-most-enclosing-brace (nreverse state))) +(defun c-least-enclosing-brace (paren-state &optional bufpos) + ;; Return the bufpos of the outermost enclosing brace before bufpos + ;; that hasn't been narrowed out, or nil if none was found. + (let (pos elem) + (or bufpos (setq bufpos 134217727)) + (while paren-state + (setq elem (car paren-state) + paren-state (cdr paren-state)) + (unless (or (consp elem) + (>= elem bufpos)) + (if (>= elem (point-min)) + (setq pos elem)))) + pos)) -(defun c-safe-position (bufpos state) - ;; return the closest known safe position higher up than point - (let ((safepos nil)) - (while state - (setq safepos - (if (consp (car state)) - (cdr (car state)) - (car state))) - (if (< safepos bufpos) - (setq state nil) - (setq state (cdr state)))) - safepos)) +(defun c-safe-position (bufpos paren-state) + ;; Return the closest known safe position higher up than BUFPOS, or + ;; nil if PAREN-STATE doesn't contain one. Return nil if BUFPOS is + ;; nil, which is useful to find the closest limit before a given + ;; limit that might be nil. + (when bufpos + (let ((c-macro-start (c-query-macro-start)) safepos) + (if (and c-macro-start + (< c-macro-start bufpos)) + ;; Make sure bufpos is outside the macro we might be in. + (setq bufpos c-macro-start)) + (catch 'done + (while paren-state + (setq safepos + (if (consp (car paren-state)) + (cdr (car paren-state)) + (car paren-state))) + (if (< safepos bufpos) + (throw 'done safepos) + (setq paren-state (cdr paren-state)))) + (if (eq c-macro-start bufpos) + ;; Backed up bufpos to the macro start and got outside the + ;; state. We know the macro is at the top level in this case, + ;; so we can use the macro start as the safe position. + c-macro-start))))) -(defun c-narrow-out-enclosing-class (state lim) - ;; narrow the buffer so that the enclosing class is hidden - (setq state (c-whack-state (point) state)) +(defun c-narrow-out-enclosing-class (paren-state lim) + ;; Narrow the buffer so that the enclosing class is hidden. Uses + ;; and returns the value from c-search-uplist-for-classkey. + (setq paren-state (c-whack-state-after (point) paren-state)) (let (inclass-p) - (and state - (setq inclass-p (c-search-uplist-for-classkey state)) + (and paren-state + (setq inclass-p (c-search-uplist-for-classkey paren-state)) (narrow-to-region (progn (goto-char (1+ (aref inclass-p 1))) - (skip-chars-forward " \t\n" lim) + (c-skip-ws-forward lim) ;; if point is now left of the class opening brace, we're ;; hosed, so try a different tact (if (<= (point) (aref inclass-p 1)) @@ -1525,24 +2258,305 @@ inclass-p)) -;; This function implements the main decision tree for determining the -;; syntactic analysis of the current line of code. Yes, it's huge and -;; bloated! +;; c-guess-basic-syntax implements the main decision tree for +;; determining the syntactic analysis of the current line of code. +;; Yes, it's huge and bloated! + +;; It's useful to break out some parts of the decision tree to +;; separate functions, which are all collected below. Use dynamic +;; binding to propagate back the syntax results from them. +(defvar syntax) +(defvar syntactic-relpos) + +(defun c-add-stmt-syntax (syntax-symbol + stop-at-boi-only + containing-sexp + paren-state + &optional at-block-start) + ;; Do the generic processing to anchor the given syntax symbol on + ;; the preceding statement: Skip over any labels and containing + ;; statements on the same line, and then search backward until we + ;; find a statement or block start that begins at boi without a + ;; label or comment. + ;; + ;; Point is assumed to be at the prospective anchor point for the + ;; given SYNTAX-SYMBOL. More syntax entries are added if we need to + ;; skip past block opens and containing statement. All the added + ;; syntax elements will get the same anchor point. + ;; + ;; If STOP-AT-BOI-ONLY is nil, we might stop in the middle of the + ;; line if another statement precedes the current one on this line. + ;; + ;; If AT-BLOCK-START is non-nil, point is taken to be at the + ;; beginning of a block or brace list, which then might be nested + ;; inside an expression. If AT-BLOCK-START is nil, this is found + ;; out by checking whether the character at point is "{" or not. + (if (= (point) (c-point 'boi)) + ;; This is by far the most common case, so let's give it special + ;; treatment. + (c-add-syntax syntax-symbol (point)) + + (let* ((savepos (point)) + (syms (list syntax-symbol)) + (syms-tail syms) + (boi (c-point 'boi)) + (prev-paren (if at-block-start ?{ (char-after))) + step-type step-tmp at-comment add-inexpr-stmt) + + ;; Begin by skipping any labels and containing statements that + ;; are on the same line. + (while (and (/= (point) boi) + (if (memq (setq step-tmp + (c-beginning-of-statement-1 boi nil t)) + '(up label)) + t + (goto-char savepos) + nil) + (/= (point) savepos)) + (setq savepos (point) + step-type step-tmp)) + + ;; Skip over any comments that stands between the statement and + ;; boi. If stop-at-boi-only is nil and we're not at boi after + ;; this, then we're done. + (while (and (/= (setq savepos (point)) boi) + (c-forward-comment -1)) + (setq at-comment t + boi (c-point 'boi))) + (goto-char savepos) + + (when (or stop-at-boi-only + (= (point) boi)) + (catch 'done + ;; Loop if we have to back out of the containing block. + (while + (progn + ;; Loop if we have to back up another statement. + (while + (progn + ;; Always start by skipping over any comments that + ;; stands between the statement and boi. + (while (and (/= (setq savepos (point)) boi) + (c-forward-comment -1)) + (setq at-comment t + boi (c-point 'boi))) + (goto-char savepos) + (and (or at-comment + (eq step-type 'label) + (/= savepos boi)) + (progn + ;; Current position not good enough; skip + ;; backward another statement. + (setq stop-at-boi-only t + step-type (c-beginning-of-statement-1 + containing-sexp)) + ;; Record this a substatement if we skipped + ;; up one level, but not if we're still on + ;; the same line. This so e.g. a sequence + ;; of "else if" clauses won't indent deeper + ;; and deeper. + (when (and (eq step-type 'up) + (< (point) boi)) + (setcdr syms-tail (list 'substatement)) + (setq syms-tail (cdr syms-tail))) + (setq boi (c-point 'boi)) + (/= (point) savepos)))) + (setq savepos (point) + at-comment nil)) + (setq at-comment nil) + + (when (and (eq step-type 'same) + containing-sexp) + (goto-char containing-sexp) + (setq paren-state (c-whack-state-after containing-sexp + paren-state) + containing-sexp (c-most-enclosing-brace paren-state)) + + (when (and (prog1 + (eq prev-paren ?{) + (setq prev-paren (char-after))) + (eq prev-paren ?\()) + (c-backward-syntactic-ws containing-sexp) + (when (c-on-identifier) + ;; Arrived at a function arglist start. Exit with + ;; the position of the first argument inside it. + (goto-char savepos) + (throw 'done t)) + ;; We're in an in-expression statement. Remember + ;; this. We'll iterate below, but won't add any + ;; syntax element. + (setq add-inexpr-stmt t)) + + (setq savepos (point) + boi (c-point 'boi) + step-type (c-beginning-of-statement-1 containing-sexp)) + + (let ((at-bod (and (eq step-type 'same) + (/= savepos (point)) + (eq prev-paren ?{)))) + (when (= savepos boi) + ;; If the open brace was at boi, we're always + ;; done. The c-beginning-of-statement-1 call + ;; above is necessary anyway, to decide the type + ;; of block-intro to add. + (goto-char savepos) + (setq savepos nil)) + + (when (eq prev-paren ?{) + (setcdr syms-tail (list (if at-bod + 'defun-block-intro + 'statement-block-intro))) + (setq syms-tail (cdr syms-tail))) + + (when (and (not at-bod) savepos) + ;; Loop if the brace wasn't at boi, and we didn't + ;; arrive at a defun block. + (if (eq step-type 'same) + ;; Avoid backing up another sexp if the point + ;; we're at now is found to be good enough in + ;; the loop above. + (setq step-type nil)) + (setq stop-at-boi-only t + boi (c-point 'boi))))) + )))) + + (while syms + (c-add-syntax (car syms) (point)) + (setq syms (cdr syms))) + (if add-inexpr-stmt + (c-add-syntax 'inexpr-statement)) + ))) + +(defun c-add-class-syntax (symbol classkey paren-state) + ;; The inclass and class-close syntactic symbols are added in + ;; several places and some work is needed to fix everything. + ;; Therefore it's collected here. + (save-restriction + (widen) + (let (inexpr anchor containing-sexp) + (goto-char (aref classkey 1)) + (if (and (eq symbol 'inclass) (= (point) (c-point 'boi))) + (c-add-syntax symbol (setq anchor (point))) + (c-add-syntax symbol (setq anchor (aref classkey 0))) + (if (and c-opt-inexpr-class-key + (setq containing-sexp (c-most-enclosing-brace paren-state + (point)) + inexpr (cdr (c-looking-at-inexpr-block + (c-safe-position containing-sexp + paren-state) + containing-sexp))) + (/= inexpr (c-point 'boi inexpr))) + (c-add-syntax 'inexpr-class))) + anchor))) + +(defun c-guess-continued-construct (indent-point + char-after-ip + beg-of-same-or-containing-stmt + containing-sexp + paren-state) + ;; This function contains the decision tree reached through both + ;; cases 18 and 10. It's a continued statement or top level + ;; construct of some kind. + (let (special-brace-list) + (goto-char indent-point) + (skip-chars-forward " \t") + (cond + ;; (CASE A removed.) + ;; CASE B: open braces for class or brace-lists + ((setq special-brace-list + (or (and c-special-brace-lists + (c-looking-at-special-brace-list)) + (eq char-after-ip ?{))) + (cond + ;; CASE B.1: class-open + ((save-excursion + (goto-char indent-point) + (skip-chars-forward " \t{") + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) + (and decl + (setq beg-of-same-or-containing-stmt (aref decl 0))) + )) + (c-add-syntax 'class-open beg-of-same-or-containing-stmt)) + ;; CASE B.2: brace-list-open + ((or (consp special-brace-list) + (save-excursion + (goto-char beg-of-same-or-containing-stmt) + (looking-at "enum\\>[^_]")) + (save-excursion + (goto-char indent-point) + (while (and (> (point) beg-of-same-or-containing-stmt) + (= (c-backward-token-1 1 t) 0) + (/= (char-after) ?=))) + (eq (char-after) ?=))) + ;; The most semantically accurate symbol here is + ;; brace-list-open, but we report it simply as a statement-cont. + ;; The reason is that one normally adjusts brace-list-open for + ;; brace lists as top-level constructs, and brace lists inside + ;; statements is a completely different context. + (c-beginning-of-statement-1 containing-sexp) + (c-add-stmt-syntax 'statement-cont nil containing-sexp paren-state)) + ;; CASE B.3: The body of a function declared inside a normal + ;; block. Can occur e.g. in Pike and when using gcc + ;; extensions. Might also trigger it with some macros followed + ;; by blocks, and this gives sane indentation then too. + ;; C.f. cases 16F and 17G. + ((progn + (goto-char indent-point) + (and (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 containing-sexp nil nil t) + 'same))) + (c-add-stmt-syntax 'defun-open t containing-sexp paren-state)) + ;; CASE B.4: Continued statement with block open. + (t + (goto-char beg-of-same-or-containing-stmt) + (c-add-stmt-syntax 'statement-cont nil containing-sexp paren-state) + (c-add-syntax 'block-open)) + )) + ;; CASE C: iostream insertion or extraction operator + ((and (looking-at "<<\\|>>") + (save-excursion + (goto-char beg-of-same-or-containing-stmt) + (while (and (re-search-forward "<<\\|>>" indent-point 'move) + (c-in-literal beg-of-same-or-containing-stmt))) + ;; if we ended up at indent-point, then the first streamop is on a + ;; separate line. Indent the line like a statement-cont instead + (when (/= (point) indent-point) + (c-add-syntax 'stream-op (c-point 'boi)) + t)))) + ;; CASE D: continued statement. + (t + (c-beginning-of-statement-1 containing-sexp) + (c-add-stmt-syntax 'statement-cont nil containing-sexp paren-state)) + ))) (defun c-guess-basic-syntax () + "Return the syntactic context of the current line." (save-excursion (save-restriction (beginning-of-line) (let* ((indent-point (point)) (case-fold-search nil) - (fullstate (c-parse-state)) - (state fullstate) + (paren-state (c-parse-state)) literal containing-sexp char-before-ip char-after-ip lim - syntax placeholder c-in-literal-cache inswitch-p + syntax placeholder c-in-literal-cache step-type tmpsymbol keyword injava-inher special-brace-list ;; narrow out any enclosing class or extern "C" block - (inclass-p (c-narrow-out-enclosing-class state indent-point)) - inenclosing-p) + (inclass-p (c-narrow-out-enclosing-class paren-state + indent-point)) + ;; c-state-cache is shadowed here. That means we must + ;; not do any changes during the execution of this + ;; function, since c-check-state-cache then would change + ;; this local variable and leave a bogus value in the + ;; global one. + (c-state-cache (if inclass-p + (c-whack-state-before (point-min) paren-state) + paren-state)) + (c-state-cache-start (point-min)) + inenclosing-p macro-start in-macro-expr + ;; There's always at most one syntactic element which got + ;; a relpos. It's stored in syntactic-relpos. + syntactic-relpos + (c-stmt-delim-chars c-stmt-delim-chars)) ;; check for meta top-level enclosing constructs, possible ;; extern language definitions, possibly (in C++) namespace ;; definitions. @@ -1552,7 +2566,7 @@ (if (and inclass-p (progn (goto-char (aref inclass-p 0)) - (looking-at (concat c-extra-toplevel-key "[^_]")))) + (looking-at c-other-decl-block-key))) (let ((enclosing (match-string 1))) (cond ((string-equal enclosing "extern") @@ -1560,45 +2574,62 @@ ((string-equal enclosing "namespace") (setq inenclosing-p 'namespace)) ))))) - ;; get the buffer position of the most nested opening brace, - ;; if there is one, and it hasn't been narrowed out - (save-excursion - (goto-char indent-point) - (skip-chars-forward " \t}") - (skip-chars-backward " \t") - (while (and state - (not containing-sexp)) - (setq containing-sexp (car state) - state (cdr state)) - (if (consp containing-sexp) - ;; if cdr == point, then containing sexp is the brace - ;; that opens the sexp we close - (if (= (cdr containing-sexp) (point)) - (setq containing-sexp (car containing-sexp)) - ;; otherwise, ignore this element - (setq containing-sexp nil)) - ;; ignore the bufpos if its been narrowed out by the - ;; containing class or does not contain the indent point - (if (or (<= containing-sexp (point-min)) - (>= containing-sexp indent-point)) - (setq containing-sexp nil))))) - ;; set the limit on the farthest back we need to search - (setq lim (or containing-sexp - (if (consp (car fullstate)) - (cdr (car fullstate)) - nil) - (point-min))) + ;; Init some position variables: + ;; + ;; containing-sexp is the open paren of the closest + ;; surrounding sexp or nil if there is none that hasn't been + ;; narrowed out. + ;; + ;; lim is the position after the closest preceding brace sexp + ;; (nested sexps are ignored), or the position after + ;; containing-sexp if there is none, or (point-min) if + ;; containing-sexp is nil. + ;; + ;; c-state-cache is the state from c-parse-state at + ;; indent-point, without any parens outside the region + ;; narrowed by c-narrow-out-enclosing-class. + ;; + ;; paren-state is the state from c-parse-state outside + ;; containing-sexp, or at indent-point if containing-sexp is + ;; nil. paren-state is not limited to the narrowed region, as + ;; opposed to c-state-cache. + (if c-state-cache + (progn + (setq containing-sexp (car paren-state) + paren-state (cdr paren-state)) + (if (consp containing-sexp) + (progn + (setq lim (cdr containing-sexp)) + (if (cdr c-state-cache) + ;; Ignore balanced paren. The next entry + ;; can't be another one. + (setq containing-sexp (car (cdr c-state-cache)) + paren-state (cdr paren-state)) + ;; If there is no surrounding open paren then + ;; put the last balanced pair back on paren-state. + (setq paren-state (cons containing-sexp paren-state) + containing-sexp nil))) + (setq lim (1+ containing-sexp)))) + (setq lim (point-min))) + + ;; If we're in a parenthesis list then ',' delimits the + ;; "statements" rather than being an operator (with the + ;; exception of the "for" clause). This difference is + ;; typically only noticeable when statements are used in macro + ;; arglists. + (when (and containing-sexp + (eq (char-after containing-sexp) ?\()) + (setq c-stmt-delim-chars c-stmt-delim-chars-with-comma)) ;; cache char before and after indent point, and move point to ;; the most likely position to perform the majority of tests (goto-char indent-point) - (skip-chars-forward " \t") - (setq char-after-ip (char-after)) (c-backward-syntactic-ws lim) (setq char-before-ip (char-before)) (goto-char indent-point) (skip-chars-forward " \t") + (setq char-after-ip (char-after)) ;; are we in a literal? (setq literal (c-in-literal lim)) @@ -1606,21 +2637,142 @@ ;; now figure out syntactic qualities of the current line (cond ;; CASE 1: in a string. - ((memq literal '(string)) + ((eq literal 'string) (c-add-syntax 'string (c-point 'bopl))) ;; CASE 2: in a C or C++ style comment. ((memq literal '(c c++)) (c-add-syntax literal (car (c-literal-limits lim)))) ;; CASE 3: in a cpp preprocessor macro continuation. - ((and (eq literal 'pound) - (/= (save-excursion - (c-beginning-of-macro lim) - (setq placeholder (point))) - (c-point 'boi))) - (c-add-syntax 'cpp-macro-cont placeholder)) - ;; CASE 4: In-expression statement. - ((and (or c-inexpr-class-key c-inexpr-block-key c-lambda-key) - (setq placeholder (c-looking-at-inexpr-block))) + ((and (save-excursion + (when (c-beginning-of-macro) + (setq macro-start (point)))) + (/= macro-start (c-point 'boi)) + (progn + (setq tmpsymbol 'cpp-macro-cont) + (or (not c-syntactic-indentation-in-macros) + (save-excursion + (goto-char macro-start) + ;; If at the beginning of the body of a #define + ;; directive then analyze as cpp-define-intro + ;; only. Go on with the syntactic analysis + ;; otherwise. in-macro-expr is set if we're in a + ;; cpp expression, i.e. before the #define body + ;; or anywhere in a non-#define directive. + (if (c-forward-to-cpp-define-body) + (let ((indent-boi (c-point 'boi indent-point))) + (setq in-macro-expr (> (point) indent-boi) + tmpsymbol 'cpp-define-intro) + (= (point) indent-boi)) + (setq in-macro-expr t) + nil))))) + (c-add-syntax tmpsymbol macro-start) + (setq macro-start nil)) + ;; CASE 11: an else clause? + ((looking-at "else\\>[^_]") + (c-beginning-of-statement-1 containing-sexp) + (c-add-stmt-syntax 'else-clause t containing-sexp paren-state)) + ;; CASE 12: while closure of a do/while construct? + ((and (looking-at "while\\>[^_]") + (save-excursion + (prog1 (eq (c-beginning-of-statement-1 containing-sexp) + 'beginning) + (setq placeholder (point))))) + (goto-char placeholder) + (c-add-stmt-syntax 'do-while-closure t containing-sexp paren-state)) + ;; CASE 13: A catch or finally clause? This case is simpler + ;; than if-else and do-while, because a block is required + ;; after every try, catch and finally. + ((save-excursion + (and (cond ((c-major-mode-is 'c++-mode) + (looking-at "catch\\>[^_]")) + ((c-major-mode-is 'java-mode) + (looking-at "\\(catch\\|finally\\)\\>[^_]"))) + (and (c-safe (c-backward-syntactic-ws) + (c-backward-sexp) + t) + (eq (char-after) ?{) + (c-safe (c-backward-syntactic-ws) + (c-backward-sexp) + t) + (if (eq (char-after) ?\() + (c-safe (c-backward-sexp) t) + t)) + (looking-at "\\(try\\|catch\\)\\>[^_]") + (setq placeholder (point)))) + (goto-char placeholder) + (c-add-stmt-syntax 'catch-clause t containing-sexp paren-state)) + ;; CASE 18: A substatement we can recognize by keyword. + ((save-excursion + (and c-opt-block-stmt-key + (not (eq char-before-ip ?\;)) + (not (memq char-after-ip '(?\) ?\] ?,))) + (or (not (eq char-before-ip ?})) + (c-looking-at-inexpr-block-backward c-state-cache)) + (> (point) + (progn + ;; Ought to cache the result from the + ;; c-beginning-of-statement-1 calls here. + (setq placeholder (point)) + (while (eq (setq step-type + (c-beginning-of-statement-1 lim)) + 'label)) + (if (eq step-type 'previous) + (goto-char placeholder) + (setq placeholder (point)) + (if (and (eq step-type 'same) + (not (looking-at c-opt-block-stmt-key))) + ;; Step up to the containing statement if we + ;; stayed in the same one. + (let (step) + (while (eq + (setq step + (c-beginning-of-statement-1 lim)) + 'label)) + (if (eq step 'up) + (setq placeholder (point)) + ;; There was no containing statement afterall. + (goto-char placeholder))))) + placeholder)) + (if (looking-at c-block-stmt-2-key) + ;; Require a parenthesis after these keywords. + ;; Necessary to catch e.g. synchronized in Java, + ;; which can be used both as statement and + ;; modifier. + (and (= (c-forward-token-1 1 nil) 0) + (eq (char-after) ?\()) + (looking-at c-opt-block-stmt-key)))) + (if (eq step-type 'up) + ;; CASE 18A: Simple substatement. + (progn + (goto-char placeholder) + (cond + ((eq char-after-ip ?{) + (c-add-stmt-syntax 'substatement-open nil + containing-sexp paren-state)) + ((save-excursion + (goto-char indent-point) + (back-to-indentation) + (looking-at c-label-key)) + (c-add-stmt-syntax 'substatement-label nil + containing-sexp paren-state)) + (t + (c-add-stmt-syntax 'substatement nil + containing-sexp paren-state)))) + ;; CASE 18B: Some other substatement. This is shared + ;; with case 10. + (c-guess-continued-construct indent-point + char-after-ip + placeholder + lim + paren-state))) + ;; CASE 4: In-expression statement. C.f. cases 7B, 16A and + ;; 17E. + ((and (or c-opt-inexpr-class-key + c-opt-inexpr-block-key + c-opt-lambda-key) + (setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + containing-sexp))) (setq tmpsymbol (assq (car placeholder) '((inexpr-class . class-open) (inexpr-statement . block-open)))) @@ -1635,7 +2787,9 @@ 'lambda-intro-cont))) (goto-char (cdr placeholder)) (back-to-indentation) - (c-add-syntax tmpsymbol (point)) + (c-add-stmt-syntax tmpsymbol t + (c-most-enclosing-brace c-state-cache (point)) + (c-whack-state-after (point) paren-state)) (unless (eq (point) (cdr placeholder)) (c-add-syntax (car placeholder)))) ;; CASE 5: Line is at top level. @@ -1653,7 +2807,7 @@ (goto-char indent-point) (skip-chars-forward " \t") (and (c-safe (progn (c-backward-sexp 2) t)) - (looking-at (concat c-extra-toplevel-key "[^_]")) + (looking-at c-other-decl-block-key) (setq keyword (match-string 1) placeholder (point)) (or (and (string-equal keyword "namespace") @@ -1671,25 +2825,15 @@ ((save-excursion (goto-char indent-point) (skip-chars-forward " \t{") - ;; TBD: watch out! there could be a bogus - ;; c-state-cache in place when we get here. we have - ;; to go through much chicanery to ignore the cache. - ;; But of course, there may not be! BLECH! BOGUS! - (let ((decl - (let ((c-state-cache nil)) - (c-search-uplist-for-classkey (c-parse-state)) - ))) + (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) (and decl (setq placeholder (aref decl 0))) )) (c-add-syntax 'class-open placeholder)) ;; CASE 5A.3: brace list open ((save-excursion - (c-beginning-of-statement-1 lim) - ;; c-b-o-s could have left us at point-min - (and (bobp) - (c-forward-syntactic-ws indent-point)) - (if (looking-at "typedef[^_]") + (c-beginning-of-statement-1 lim t) + (if (looking-at "typedef\\>[^_]") (progn (c-forward-sexp 1) (c-forward-syntactic-ws indent-point))) (setq placeholder (c-point 'boi)) @@ -1704,7 +2848,7 @@ (looking-at "new\\>[^_]")) (setq tmpsymbol 'topmost-intro-cont))) (eq (char-after) ?=)) - (looking-at "enum[ \t\n]+")) + (looking-at "enum\\>[^_]")) (save-excursion (while (and (< (point) indent-point) (= (c-forward-token-1 1 t) 0) @@ -1723,22 +2867,22 @@ ;; case 10B.2. (progn (c-beginning-of-statement-1 lim) - (c-forward-syntactic-ws) (c-add-syntax 'topmost-intro-cont (c-point 'boi))) (c-add-syntax 'brace-list-open placeholder))) ;; CASE 5A.4: inline defun open ((and inclass-p (not inenclosing-p)) (c-add-syntax 'inline-open) - (c-add-class-syntax 'inclass inclass-p)) + (c-add-class-syntax 'inclass inclass-p paren-state)) ;; CASE 5A.5: ordinary defun open (t (goto-char placeholder) - (if inclass-p + (if (or inclass-p macro-start) (c-add-syntax 'defun-open (c-point 'boi)) + ;; Bogus to use bol here, but it's the legacy. (c-add-syntax 'defun-open (c-point 'bol))) ))) ;; CASE 5B: first K&R arg decl or member init - ((c-just-after-func-arglist-p) + ((c-just-after-func-arglist-p nil lim) (cond ;; CASE 5B.1: a member init ((or (eq char-before-ip ?:) @@ -1769,8 +2913,10 @@ ) ;; CASE 5B.2: K&R arg decl intro (c-recognize-knr-p + (c-beginning-of-statement-1 lim) (c-add-syntax 'knr-argdecl-intro (c-point 'boi)) - (if inclass-p (c-add-class-syntax 'inclass inclass-p))) + (if inclass-p + (c-add-class-syntax 'inclass inclass-p paren-state))) ;; CASE 5B.3: Inside a member init list. ((c-beginning-of-member-init-list lim) (c-forward-syntactic-ws) @@ -1783,12 +2929,12 @@ ))) ;; CASE 5C: inheritance line. could be first inheritance ;; line, or continuation of a multiple inheritance - ((or (and c-baseclass-key + ((or (and (c-major-mode-is 'c++-mode) (progn (when (eq char-after-ip ?,) (skip-chars-forward " \t") (forward-char)) - (looking-at c-baseclass-key))) + (looking-at c-opt-decl-spec-key))) (and (or (eq char-before-ip ?:) ;; watch out for scope operator (save-excursion @@ -1812,7 +2958,7 @@ cont done) (save-excursion (while (not done) - (cond ((looking-at c-Java-special-key) + (cond ((looking-at c-opt-decl-spec-key) (setq injava-inher (cons cont (point)) done t)) ((or (not (c-safe (c-forward-sexp -1) t)) @@ -1827,21 +2973,23 @@ (cond ;; CASE 5C.1: non-hanging colon on an inher intro ((eq char-after-ip ?:) - (c-backward-syntactic-ws lim) + (c-beginning-of-statement-1 lim) (c-add-syntax 'inher-intro (c-point 'boi)) ;; don't add inclass symbol since relative point already ;; contains any class offset ) ;; CASE 5C.2: hanging colon on an inher intro ((eq char-before-ip ?:) + (c-beginning-of-statement-1 lim) (c-add-syntax 'inher-intro (c-point 'boi)) - (if inclass-p (c-add-class-syntax 'inclass inclass-p))) + (if inclass-p + (c-add-class-syntax 'inclass inclass-p paren-state))) ;; CASE 5C.3: in a Java implements/extends (injava-inher (let ((where (cdr injava-inher)) (cont (car injava-inher))) (goto-char where) - (cond ((looking-at "throws[ \t\n]") + (cond ((looking-at "throws\\>[^_]") (c-add-syntax 'func-decl-cont (progn (c-beginning-of-statement-1 lim) (c-point 'boi)))) @@ -1858,16 +3006,21 @@ ;; don't add inclass symbol since relative point already ;; contains any class offset ))) - ;; CASE 5D: this could be a top-level compound statement, a + ;; CASE 5D: this could be a top-level initialization, a ;; member init list continuation, or a template argument ;; list continuation. ((c-with-syntax-table (if (c-major-mode-is 'c++-mode) c++-template-syntax-table (syntax-table)) (save-excursion + ;; Note: We use the fact that lim is always after any + ;; preceding brace sexp. (while (and (= (c-backward-token-1 1 t lim) 0) - (not (looking-at "[;{<,]")))) - (eq (char-after) ?,))) + (not (looking-at "[;<,=]")))) + (or (memq (char-after) '(?, ?=)) + (and (c-major-mode-is 'c++-mode) + (= (c-backward-token-1 1 nil lim) 0) + (eq (char-after) ?<))))) (goto-char indent-point) (c-beginning-of-member-init-list lim) (cond @@ -1886,9 +3039,11 @@ (parse-partial-sexp (point) placeholder))) 0) (and - (if c-access-key (not (looking-at c-access-key)) t) + (if c-opt-access-key + (not (looking-at c-opt-access-key)) t) (not (looking-at c-class-key)) - (if c-bitfield-key (not (looking-at c-bitfield-key)) t)) + (if c-opt-bitfield-key + (not (looking-at c-opt-bitfield-key)) t)) ))) (goto-char placeholder) (c-forward-syntactic-ws) @@ -1902,43 +3057,61 @@ (eq (char-after) ?:)) (skip-chars-forward " \t:") (c-add-syntax 'member-init-cont (point))) - ;; CASE 5D.3: perhaps a multiple inheritance line? - ((save-excursion - (c-beginning-of-statement-1 lim) - (setq placeholder (point)) - (looking-at c-inher-key)) + ;; CASE 5D.3: perhaps a template list continuation? + ((and (c-major-mode-is 'c++-mode) + (save-excursion + (save-restriction + (c-with-syntax-table c++-template-syntax-table + (goto-char indent-point) + (setq placeholder (c-up-list-backward (point))) + (and placeholder + (eq (char-after placeholder) ?<)))))) + ;; we can probably indent it just like an arglist-cont + (goto-char placeholder) + (c-beginning-of-statement-1 lim t) + (c-add-syntax 'template-args-cont (c-point 'boi))) + ;; CASE 5D.4: perhaps a multiple inheritance line? + ((and (c-major-mode-is 'c++-mode) + (save-excursion + (c-beginning-of-statement-1 lim) + (setq placeholder (point)) + (if (looking-at "static\\>[^_]") + (c-forward-token-1 1 nil indent-point)) + (and (looking-at c-class-key) + (= (c-forward-token-1 2 nil indent-point) 0) + (if (eq (char-after) ?<) + (c-with-syntax-table c++-template-syntax-table + (= (c-forward-token-1 1 t indent-point) 0)) + t) + (eq (char-after) ?:)))) (goto-char placeholder) (c-add-syntax 'inher-cont (c-point 'boi))) - ;; CASE 5D.4: perhaps a template list continuation? - ((save-excursion - (goto-char indent-point) - (skip-chars-backward "^<" lim) - ;; not sure if this is the right test, but it should - ;; be fast and mostly accurate. - (setq placeholder (point)) - (and (eq (char-before) ?<) - (not (c-in-literal lim)))) - ;; we can probably indent it just like an arglist-cont - (goto-char placeholder) - (c-beginning-of-statement-1 lim) - (c-add-syntax 'template-args-cont (c-point 'boi))) - ;; CASE 5D.5: perhaps a top-level statement-cont + ;; CASE 5D.5: Continuation of the "expression part" of a + ;; top level construct. (t - (c-beginning-of-statement-1 lim) - ;; skip over any access-specifiers - (and inclass-p c-access-key - (while (looking-at c-access-key) - (forward-line 1))) - ;; skip over comments, whitespace - (c-forward-syntactic-ws indent-point) - (c-add-syntax 'statement-cont (c-point 'boi))) + (while (and (eq (car (c-beginning-of-decl-1 containing-sexp)) + 'same) + (save-excursion + (c-backward-syntactic-ws) + (eq (char-before) ?})))) + (c-add-stmt-syntax + (if (eq char-before-ip ?,) + ;; A preceding comma at the top level means that a + ;; new variable declaration starts here. Use + ;; topmost-intro-cont for it, for consistency with + ;; the first variable declaration. C.f. case 5N. + 'topmost-intro-cont + 'statement-cont) + nil containing-sexp paren-state)) )) ;; CASE 5E: we are looking at a access specifier ((and inclass-p - c-access-key - (looking-at c-access-key)) - (c-add-syntax 'access-label (c-point 'bonl)) - (c-add-class-syntax 'inclass inclass-p)) + c-opt-access-key + (looking-at c-opt-access-key)) + (setq placeholder (c-add-class-syntax 'inclass inclass-p + paren-state)) + ;; Append access-label with the same anchor point as inclass gets. + (nconc syntax (list (cons 'access-label placeholder)))) ;; CASE 5F: extern-lang-close or namespace-close? ((and inenclosing-p (eq char-after-ip ?})) @@ -1957,66 +3130,72 @@ (and (c-safe (progn (c-backward-sexp 1) t)) (= (point) (aref inclass-p 1)) )))) - (c-add-class-syntax 'class-close inclass-p)) + (c-add-class-syntax 'class-close inclass-p paren-state)) ;; CASE 5H: we could be looking at subsequent knr-argdecls ((and c-recognize-knr-p - ;; here we essentially use the hack that is used in - ;; Emacs' c-mode.el to limit how far back we should - ;; look. The assumption is made that argdecls are - ;; indented at least one space and that function - ;; headers are not indented. - (let ((limit (save-excursion - (re-search-backward "^[^ \^L\t\n#]" nil 'move) - (point)))) - (save-excursion - (c-backward-syntactic-ws limit) - (setq placeholder (point)) - (while (and (memq (char-before) '(?\; ?,)) - (> (point) limit)) - (beginning-of-line) - (setq placeholder (point)) - (c-backward-syntactic-ws limit)) - (and (eq (char-before) ?\)) - (or (not c-method-key) - (progn - (c-forward-sexp -1) - (forward-char -1) - (c-backward-syntactic-ws) - (not (or (memq (char-before) '(?- ?+)) - ;; or a class category - (progn - (c-forward-sexp -2) - (looking-at c-class-key)) - ))))) - )) + (not (eq char-before-ip ?})) (save-excursion - (c-beginning-of-statement-1) - (not (looking-at "typedef[ \t\n]+")))) + (setq placeholder (cdr (c-beginning-of-decl-1 lim))) + (and placeholder + ;; Do an extra check to avoid tripping up on + ;; statements that occur in invalid contexts + ;; (e.g. in macro bodies where we don't really + ;; know the context of what we're looking at). + (not (and c-opt-block-stmt-key + (looking-at c-opt-block-stmt-key))))) + (< placeholder indent-point)) (goto-char placeholder) - (c-add-syntax 'knr-argdecl (c-point 'boi))) + (c-add-syntax 'knr-argdecl (point))) ;; CASE 5I: ObjC method definition. - ((and c-method-key - (looking-at c-method-key)) + ((and c-opt-method-key + (looking-at c-opt-method-key)) + (c-beginning-of-statement-1 lim) (c-add-syntax 'objc-method-intro (c-point 'boi))) - ;; CASE 5J: we are at the topmost level, make sure we skip - ;; back past any access specifiers + ;; CASE 5N: At a variable declaration that follows a class + ;; definition or some other block declaration that doesn't + ;; end at the closing '}'. C.f. case 5D.5. ((progn (c-backward-syntactic-ws lim) + (and (eq (char-before) ?}) + (save-excursion + (let ((start (point))) + (if paren-state + ;; Speed up the backward search a bit. + (goto-char (car (car paren-state)))) + (c-beginning-of-decl-1 containing-sexp) + (setq placeholder (point)) + (if (= start (point)) + ;; The '}' is unbalanced. + nil + (c-end-of-decl-1) + (> (point) indent-point)))))) + (goto-char placeholder) + (c-add-stmt-syntax 'topmost-intro-cont nil + containing-sexp paren-state)) + ;; CASE 5J: we are at the topmost level, make + ;; sure we skip back past any access specifiers + ((progn (while (and inclass-p - c-access-key + c-opt-access-key (not (bobp)) (save-excursion (c-safe (progn (c-backward-sexp 1) t)) - (looking-at c-access-key))) + (looking-at c-opt-access-key))) (c-backward-sexp 1) (c-backward-syntactic-ws lim)) (or (bobp) - (memq (char-before) '(?\; ?\})))) + (memq (char-before) '(?\; ?})) + (and (c-major-mode-is 'objc-mode) + (progn + (c-beginning-of-statement-1 lim) + (eq (char-after) ?@))))) ;; real beginning-of-line could be narrowed out due to ;; enclosure in a class block (save-restriction (widen) (c-add-syntax 'topmost-intro (c-point 'bol)) + ;; Using bol instead of boi above is highly bogus, and + ;; it makes our lives hard to remain compatible. :P (if inclass-p (progn (goto-char (aref inclass-p 1)) @@ -2027,29 +3206,32 @@ (c-add-syntax 'inextern-lang (c-point 'boi))) ((eq inenclosing-p 'namespace) (c-add-syntax 'innamespace (c-point 'boi))) - (t (c-add-class-syntax 'inclass inclass-p))) + (t (c-add-class-syntax 'inclass inclass-p paren-state))) )) + (when (and c-syntactic-indentation-in-macros + macro-start + (/= macro-start (c-point 'boi indent-point))) + (c-add-syntax 'cpp-define-intro) + (setq macro-start nil)) )) - ;; CASE 5K: we are at an ObjC or Java method definition + ;; CASE 5K: we are at an ObjC method definition ;; continuation line. - ((and c-method-key + ((and c-opt-method-key (progn (c-beginning-of-statement-1 lim) (beginning-of-line) - (looking-at c-method-key))) + (looking-at c-opt-method-key))) (c-add-syntax 'objc-method-args-cont (point))) ;; CASE 5L: we are at the first argument of a template ;; arglist that begins on the previous line. ((eq (char-before) ?<) - (c-beginning-of-statement-1 lim) - (c-forward-syntactic-ws) + (c-beginning-of-statement-1 (c-safe-position (point) paren-state)) (c-add-syntax 'template-args-cont (c-point 'boi))) ;; CASE 5M: we are at a topmost continuation line (t - (c-beginning-of-statement-1 lim) - (c-forward-syntactic-ws) + (c-beginning-of-statement-1 (c-safe-position (point) paren-state)) (c-add-syntax 'topmost-intro-cont (c-point 'boi))) - )) ; end CASE 5 + )) ;; (CASE 6 has been removed.) ;; CASE 7: line is an expression, not a statement. Most ;; likely we are either in a function prototype or a function @@ -2059,14 +3241,9 @@ (goto-char containing-sexp) (c-looking-at-special-brace-list))) (eq (char-after containing-sexp) ?{))) - (c-backward-syntactic-ws containing-sexp) (cond ;; CASE 7A: we are looking at the arglist closing paren - ((and (or (c-major-mode-is 'pike-mode) - ;; Don't check this in Pike since it allows a - ;; comma after the last arg. - (not (eq char-before-ip ?,))) - (memq char-after-ip '(?\) ?\]))) + ((memq char-after-ip '(?\) ?\])) (goto-char containing-sexp) (setq placeholder (c-point 'boi)) (when (and (c-safe (backward-up-list 1) t) @@ -2076,18 +3253,31 @@ (setq placeholder (point))) (c-add-syntax 'arglist-close placeholder)) ;; CASE 7B: Looking at the opening brace of an - ;; in-expression block or brace list. - ((eq char-after-ip ?{) - (goto-char indent-point) - (setq placeholder (c-point 'boi)) - (goto-char containing-sexp) - (if (c-inside-bracelist-p placeholder - (cons containing-sexp state)) - (progn - (c-add-syntax 'brace-list-open (c-point 'boi)) - (c-add-syntax 'inexpr-class)) - (c-add-syntax 'block-open (c-point 'boi)) - (c-add-syntax 'inexpr-statement))) + ;; in-expression block or brace list. C.f. cases 4, 16A + ;; and 17E. + ((and (eq char-after-ip ?{) + (progn + (setq placeholder (c-inside-bracelist-p (point) + c-state-cache)) + (if placeholder + (setq tmpsymbol '(brace-list-open . inexpr-class)) + (setq tmpsymbol '(block-open . inexpr-statement) + placeholder + (cdr-safe (c-looking-at-inexpr-block + (c-safe-position containing-sexp + paren-state) + containing-sexp))) + ;; placeholder is nil if it's a block directly in + ;; a function arglist. That makes us skip out of + ;; this case. + ))) + (goto-char placeholder) + (back-to-indentation) + (c-add-stmt-syntax (car tmpsymbol) t + (c-most-enclosing-brace paren-state (point)) + (c-whack-state-after (point) paren-state)) + (if (/= (point) placeholder) + (c-add-syntax (cdr tmpsymbol)))) ;; CASE 7C: we are looking at the first argument in an empty ;; argument list. Use arglist-close if we're actually ;; looking at a close paren or bracket. @@ -2102,23 +3292,22 @@ (c-add-syntax 'arglist-intro placeholder)) ;; CASE 7D: we are inside a conditional test clause. treat ;; these things as statements - ((save-excursion + ((progn (goto-char containing-sexp) (and (c-safe (progn (c-forward-sexp -1) t)) (looking-at "\\<for\\>[^_]"))) (goto-char (1+ containing-sexp)) (c-forward-syntactic-ws indent-point) - (c-beginning-of-statement-1 containing-sexp) (if (eq char-before-ip ?\;) (c-add-syntax 'statement (point)) (c-add-syntax 'statement-cont (point)) )) - ;; CASE 7E: maybe a continued method call. This is the case - ;; when we are inside a [] bracketed exp, and what precede - ;; the opening bracket is not an identifier. - ((and c-method-key + ;; CASE 7E: maybe a continued ObjC method call. This is the + ;; case when we are inside a [] bracketed exp, and what + ;; precede the opening bracket is not an identifier. + ((and c-opt-method-key (eq (char-after containing-sexp) ?\[) - (save-excursion + (progn (goto-char (1- containing-sexp)) (c-backward-syntactic-ws (c-point 'bod)) (if (not (looking-at c-symbol-key)) @@ -2129,10 +3318,11 @@ ;; opening paren. This case includes multi-line ;; mathematical paren groupings, but we could be on a ;; for-list continuation line - ((save-excursion + ((progn (goto-char (1+ containing-sexp)) (skip-chars-forward " \t") - (not (eolp))) + (and (not (eolp)) + (not (looking-at "\\\\$")))) (goto-char containing-sexp) (setq placeholder (c-point 'boi)) (when (and (c-safe (backward-up-list 1) t) @@ -2143,17 +3333,15 @@ (c-add-syntax 'arglist-cont-nonempty placeholder)) ;; CASE 7G: we are looking at just a normal arglist ;; continuation line - (t (c-beginning-of-statement-1 containing-sexp) - (forward-char 1) - (c-forward-syntactic-ws indent-point) + (t (c-forward-syntactic-ws indent-point) (c-add-syntax 'arglist-cont (c-point 'boi))) )) ;; CASE 8: func-local multi-inheritance line - ((and c-baseclass-key + ((and (c-major-mode-is 'c++-mode) (save-excursion (goto-char indent-point) (skip-chars-forward " \t") - (looking-at c-baseclass-key))) + (looking-at c-opt-decl-spec-key))) (goto-char indent-point) (skip-chars-forward " \t") (cond @@ -2175,7 +3363,7 @@ (save-excursion (goto-char containing-sexp) (c-looking-at-special-brace-list))) - (c-inside-bracelist-p containing-sexp state))) + (c-inside-bracelist-p containing-sexp paren-state))) (cond ;; CASE 9A: In the middle of a special brace list opener. ((and (consp special-brace-list) @@ -2189,9 +3377,10 @@ (assoc 'statement-cont (setq placeholder (c-guess-basic-syntax)))) (setq syntax placeholder) - (c-beginning-of-statement-1 lim) + (c-beginning-of-statement-1 + (c-safe-position (1- containing-sexp) paren-state)) (c-forward-token-1 0) - (if (looking-at "typedef\\>") (c-forward-token-1 1)) + (if (looking-at "typedef\\>[^_]") (c-forward-token-1 1)) (c-add-syntax 'brace-list-open (c-point 'boi)))) ;; CASE 9B: brace-list-close brace ((if (consp special-brace-list) @@ -2211,11 +3400,15 @@ (eq (1+ (point)) (cdr (car special-brace-list))))))) ;; Normal brace list check. (and (eq char-after-ip ?}) - (c-safe (progn (forward-char 1) - (c-backward-sexp 1) + (c-safe (progn (goto-char (c-up-list-backward (point))) t)) (= (point) containing-sexp))) - (c-add-syntax 'brace-list-close (c-point 'boi))) + (if (eq (point) (c-point 'boi)) + (c-add-syntax 'brace-list-close (point)) + (setq lim (c-most-enclosing-brace c-state-cache (point))) + (c-beginning-of-statement-1 lim) + (c-add-stmt-syntax 'brace-list-close t lim + (c-whack-state-after (point) paren-state) t))) (t ;; Prepare for the rest of the cases below by going to the ;; token following the opening brace @@ -2228,13 +3421,20 @@ (let ((start (point))) (c-forward-syntactic-ws indent-point) (goto-char (max start (c-point 'bol)))) - (skip-chars-forward " \t\n\r" indent-point) + (c-skip-ws-forward indent-point) (cond ;; CASE 9C: we're looking at the first line in a brace-list ((= (point) indent-point) - (goto-char containing-sexp) - (c-add-syntax 'brace-list-intro (c-point 'boi)) - ) ; end CASE 9C + (if (consp special-brace-list) + (goto-char (car (car special-brace-list))) + (goto-char containing-sexp)) + (if (eq (point) (c-point 'boi)) + (c-add-syntax 'brace-list-intro (point)) + (setq lim (c-most-enclosing-brace c-state-cache (point))) + (c-beginning-of-statement-1 lim) + (c-add-stmt-syntax 'brace-list-intro t lim + (c-whack-state-after (point) paren-state) + t))) ;; CASE 9D: this is just a later brace-list-entry or ;; brace-entry-open (t (if (or (eq char-after-ip ?{) @@ -2245,184 +3445,63 @@ (c-looking-at-special-brace-list (point))))) (c-add-syntax 'brace-entry-open (point)) (c-add-syntax 'brace-list-entry (point)) - )) ; end CASE 9D - )))) ; end CASE 9 - ;; CASE 10: A continued statement + )) + )))) + ;; CASE 10: A continued statement or top level construct. ((and (not (memq char-before-ip '(?\; ?:))) (or (not (eq char-before-ip ?})) - (c-looking-at-inexpr-block-backward containing-sexp)) + (c-looking-at-inexpr-block-backward c-state-cache)) (> (point) (save-excursion (c-beginning-of-statement-1 containing-sexp) - (c-forward-syntactic-ws) (setq placeholder (point)))) (/= placeholder containing-sexp)) - (goto-char indent-point) - (skip-chars-forward " \t") - (let ((after-cond-placeholder - (save-excursion - (goto-char placeholder) - (if (and c-conditional-key (looking-at c-conditional-key)) - (progn - (c-safe (c-skip-conditional)) - (c-forward-syntactic-ws) - (if (eq (char-after) ?\;) - (progn - (forward-char 1) - (c-forward-syntactic-ws))) - (point)) - nil)))) - (cond - ;; CASE 10A: substatement - ((and after-cond-placeholder - (>= after-cond-placeholder indent-point)) - (goto-char placeholder) - (if (eq char-after-ip ?{) - (c-add-syntax 'substatement-open (c-point 'boi)) - (c-add-syntax 'substatement (c-point 'boi)))) - ;; CASE 10B: open braces for class or brace-lists - ((setq special-brace-list - (or (and c-special-brace-lists - (c-looking-at-special-brace-list)) - (eq char-after-ip ?{))) - (cond - ;; CASE 10B.1: class-open - ((save-excursion - (goto-char indent-point) - (skip-chars-forward " \t{") - (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) - (and decl - (setq placeholder (aref decl 0))) - )) - (c-add-syntax 'class-open placeholder)) - ;; CASE 10B.2: brace-list-open - ((or (consp special-brace-list) - (save-excursion - (goto-char placeholder) - (looking-at "\\<enum\\>")) - (save-excursion - (goto-char indent-point) - (while (and (> (point) placeholder) - (= (c-backward-token-1 1 t) 0) - (/= (char-after) ?=))) - (eq (char-after) ?=))) - ;; The most semantically accurate symbol here is - ;; brace-list-open, but we report it simply as a - ;; statement-cont. The reason is that one normally - ;; adjusts brace-list-open for brace lists as - ;; top-level constructs, and brace lists inside - ;; statements is a completely different context. - (goto-char indent-point) - (c-beginning-of-closest-statement) - (c-add-syntax 'statement-cont (c-point 'boi))) - ;; CASE 10B.3: The body of a function declared inside a - ;; normal block. This can only occur in Pike. - ((and (c-major-mode-is 'pike-mode) - (progn - (goto-char indent-point) - (not (c-looking-at-bos)))) - (c-beginning-of-closest-statement) - (c-add-syntax 'defun-open (c-point 'boi))) - ;; CASE 10B.4: catch-all for unknown construct. - (t - ;; Can and should I add an extensibility hook here? - ;; Something like c-recognize-hook so support for - ;; unknown constructs could be added. It's probably a - ;; losing proposition, so I dunno. - (goto-char placeholder) - (c-add-syntax 'statement-cont (c-point 'boi)) - (c-add-syntax 'block-open)) - )) - ;; CASE 10C: iostream insertion or extraction operator - ((looking-at "<<\\|>>") - (goto-char placeholder) - (and after-cond-placeholder - (goto-char after-cond-placeholder)) - (while (and (re-search-forward "<<\\|>>" indent-point 'move) - (c-in-literal placeholder))) - ;; if we ended up at indent-point, then the first - ;; streamop is on a separate line. Indent the line like - ;; a statement-cont instead - (if (/= (point) indent-point) - (c-add-syntax 'stream-op (c-point 'boi)) - (c-backward-syntactic-ws lim) - (c-add-syntax 'statement-cont (c-point 'boi)))) - ;; CASE 10D: continued statement. find the accurate - ;; beginning of statement or substatement - (t - (c-beginning-of-statement-1 after-cond-placeholder) - ;; KLUDGE ALERT! c-beginning-of-statement-1 can leave - ;; us before the lim we're passing in. It should be - ;; fixed, but I'm worried about side-effects at this - ;; late date. Fix for v5. - (goto-char (or (and after-cond-placeholder - (max after-cond-placeholder (point))) - (point))) - (c-add-syntax 'statement-cont (point))) - ))) - ;; CASE 11: an else clause? - ((looking-at "\\<else\\>[^_]") - (c-backward-to-start-of-if containing-sexp) - (c-add-syntax 'else-clause (c-point 'boi))) - ;; CASE 12: Statement. But what kind? Lets see if its a - ;; while closure of a do/while construct - ((progn - (goto-char indent-point) - (skip-chars-forward " \t") - (and (looking-at "while\\b[^_]") - (save-excursion - (c-backward-to-start-of-do containing-sexp) - (setq placeholder (point)) - (looking-at "do\\b[^_]")) - )) - (goto-char placeholder) - (c-add-syntax 'do-while-closure (c-point 'boi))) - ;; CASE 13: A catch or finally clause? This case is simpler - ;; than if-else and do-while, because a block is required - ;; after every try, catch and finally. - ((save-excursion - (and (cond ((c-major-mode-is 'c++-mode) - (looking-at "\\<catch\\>[^_]")) - ((c-major-mode-is 'java-mode) - (looking-at "\\<\\(catch\\|finally\\)\\>[^_]"))) - (c-safe (c-backward-sexp) t) - (eq (char-after) ?{) - (c-safe (c-backward-sexp) t) - (if (eq (char-after) ?\() - (c-safe (c-backward-sexp) t) - t) - (looking-at "\\<\\(try\\|catch\\)\\>[^_]") - (setq placeholder (c-point 'boi)))) - (c-add-syntax 'catch-clause placeholder)) + ;; This is shared with case 18. + (c-guess-continued-construct indent-point + char-after-ip + placeholder + containing-sexp + paren-state)) ;; CASE 14: A case or default label - ((looking-at c-switch-label-key) + ((looking-at c-label-kwds-regexp) (goto-char containing-sexp) - ;; check for hanging braces - (if (/= (point) (c-point 'boi)) - (c-forward-sexp -1)) - (c-add-syntax 'case-label (c-point 'boi))) + (setq lim (c-most-enclosing-brace c-state-cache containing-sexp)) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'case-label t lim paren-state)) ;; CASE 15: any other label ((looking-at c-label-key) (goto-char containing-sexp) - ;; check for hanging braces - (if (/= (point) (c-point 'boi)) - (c-forward-sexp -1)) - (c-add-syntax 'label (c-point 'boi))) + (setq lim (c-most-enclosing-brace c-state-cache containing-sexp)) + (save-excursion + (setq tmpsymbol + (if (and (eq (c-beginning-of-statement-1 lim) 'up) + (looking-at "switch\\>[^_]")) + ;; If the surrounding statement is a switch then + ;; let's analyze all labels as switch labels, so + ;; that they get lined up consistently. + 'case-label + 'label))) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax tmpsymbol t lim paren-state)) ;; CASE 16: block close brace, possibly closing the defun or ;; the class ((eq char-after-ip ?}) - (let* ((lim (c-safe-position containing-sexp fullstate)) - (relpos (save-excursion - (goto-char containing-sexp) - (if (/= (point) (c-point 'boi)) - (c-beginning-of-statement-1 lim)) - (c-point 'boi)))) + ;; From here on we have the next containing sexp in lim. + (setq lim (c-most-enclosing-brace paren-state)) + (goto-char containing-sexp) (cond + ;; CASE 16E: Closing a statement block? This catches + ;; cases where it's preceded by a statement keyword, + ;; which works even when used in an "invalid" context, + ;; e.g. a macro argument. + ((c-after-conditional) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'block-close t lim paren-state)) ;; CASE 16A: closing a lambda defun or an in-expression - ;; block? - ((save-excursion - (goto-char containing-sexp) - (setq placeholder (c-looking-at-inexpr-block))) + ;; block? C.f. cases 4, 7B and 17E. + ((setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + nil)) (setq tmpsymbol (if (eq (car placeholder) 'inlambda) 'inline-close 'block-close)) @@ -2432,32 +3511,56 @@ (c-add-syntax tmpsymbol (point)) (goto-char (cdr placeholder)) (back-to-indentation) - (c-add-syntax tmpsymbol (point)) + (c-add-stmt-syntax tmpsymbol t + (c-most-enclosing-brace paren-state (point)) + (c-whack-state-after (point) paren-state)) (if (/= (point) (cdr placeholder)) (c-add-syntax (car placeholder))))) ;; CASE 16B: does this close an inline or a function in ;; an extern block or namespace? - ((progn - (goto-char containing-sexp) - (setq placeholder (c-search-uplist-for-classkey state))) - (goto-char (aref placeholder 0)) - (if (looking-at (concat c-extra-toplevel-key "[^_]")) - (c-add-syntax 'defun-close relpos) - (c-add-syntax 'inline-close relpos))) + ((setq placeholder (c-search-uplist-for-classkey paren-state)) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (if (save-excursion + (goto-char (aref placeholder 0)) + (looking-at c-other-decl-block-key)) + (c-add-syntax 'defun-close (point)) + (c-add-syntax 'inline-close (point)))) + ;; CASE 16F: Can be a defun-close of a function declared + ;; in a statement block, e.g. in Pike or when using gcc + ;; extensions. Might also trigger it with some macros + ;; followed by blocks, and this gives sane indentation + ;; then too. Let it through to be handled below. + ;; C.f. cases B.3 and 17G. + ((and (not inenclosing-p) + lim + (save-excursion + (and (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 lim nil nil t) 'same) + (setq placeholder (point))))) + (back-to-indentation) + (if (/= (point) containing-sexp) + (goto-char placeholder)) + (c-add-stmt-syntax 'defun-close t lim paren-state)) ;; CASE 16C: if there an enclosing brace that hasn't ;; been narrowed out by a class, then this is a - ;; block-close - ((and (not inenclosing-p) - (c-most-enclosing-brace state) - (or (not (c-major-mode-is 'pike-mode)) - ;; In Pike it can be a defun-close of a - ;; function declared in a statement block. Let - ;; it through to be handled below. - (or (c-looking-at-bos) - (progn - (c-beginning-of-statement-1) - (looking-at c-conditional-key))))) - (c-add-syntax 'block-close relpos)) + ;; block-close. C.f. case 17H. + ((and (not inenclosing-p) lim) + ;; If the block is preceded by a case/switch label on + ;; the same line, we anchor at the first preceding label + ;; at boi. The default handling in c-add-stmt-syntax is + ;; really fixes it better, but we do like this to keep + ;; the indentation compatible with version 5.28 and + ;; earlier. + (while (and (/= (setq placeholder (point)) (c-point 'boi)) + (eq (c-beginning-of-statement-1 lim) 'label))) + (goto-char placeholder) + (if (looking-at c-label-kwds-regexp) + (c-add-syntax 'block-close (point)) + (goto-char containing-sexp) + ;; c-backward-to-block-anchor not necessary here; those + ;; situations are handled in case 16E above. + (c-add-stmt-syntax 'block-close t lim paren-state))) ;; CASE 16D: find out whether we're closing a top-level ;; class or a defun (t @@ -2465,204 +3568,182 @@ (narrow-to-region (point-min) indent-point) (let ((decl (c-search-uplist-for-classkey (c-parse-state)))) (if decl - (c-add-class-syntax 'class-close decl) - (c-add-syntax 'defun-close relpos))))) - ))) - ;; CASE 17: statement catchall + (c-add-class-syntax 'class-close decl paren-state) + (goto-char containing-sexp) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (c-add-syntax 'defun-close (point))))) + ))) + ;; CASE 17: Statement or defun catchall. (t - ;; we know its a statement, but we need to find out if it is - ;; the first statement in a block - (goto-char containing-sexp) - (forward-char 1) - (c-forward-syntactic-ws indent-point) - ;; now skip forward past any case/default clauses we might find. - (while (or (c-skip-case-statement-forward fullstate indent-point) - (and (looking-at c-switch-label-key) - (not inswitch-p))) - (setq inswitch-p t)) - ;; we want to ignore non-case labels when skipping forward - (while (and (looking-at c-label-key) - (goto-char (match-end 0))) - (c-forward-syntactic-ws indent-point)) + (goto-char indent-point) + ;; Back up statements until we find one that starts at boi. + (while (let* ((prev-point (point)) + (last-step-type (c-beginning-of-statement-1 + containing-sexp))) + (if (= (point) prev-point) + (progn + (setq step-type (or step-type last-step-type)) + nil) + (setq step-type last-step-type) + (/= (point) (c-point 'boi))))) (cond - ;; CASE 17A: we are inside a case/default clause inside a - ;; switch statement. find out if we are at the statement - ;; just after the case/default label. - ((and inswitch-p - (progn - (goto-char indent-point) - (c-beginning-of-statement-1 containing-sexp) - (setq placeholder (point)) - (beginning-of-line) - (when (re-search-forward c-switch-label-key - (max placeholder (c-point 'eol)) t) - (setq placeholder (match-beginning 0))))) - (goto-char indent-point) - (skip-chars-forward " \t") - (if (eq (char-after) ?{) - (c-add-syntax 'statement-case-open placeholder) - (c-add-syntax 'statement-case-intro placeholder))) ;; CASE 17B: continued statement - ((eq char-before-ip ?,) - (goto-char indent-point) - (c-beginning-of-closest-statement) - (c-add-syntax 'statement-cont (c-point 'boi))) - ;; CASE 17C: a question/colon construct? But make sure - ;; what came before was not a label, and what comes after - ;; is not a globally scoped function call! - ((or (and (memq char-before-ip '(?: ??)) - (save-excursion - (goto-char indent-point) - (c-backward-syntactic-ws lim) - (back-to-indentation) - (not (looking-at c-label-key)))) - (and (memq char-after-ip '(?: ??)) - (save-excursion - (goto-char indent-point) - (skip-chars-forward " \t") - ;; watch out for scope operator - (not (looking-at "::"))))) - (goto-char indent-point) - (c-beginning-of-closest-statement) - (c-add-syntax 'statement-cont (c-point 'boi))) + ((and (eq step-type 'same) + (/= (point) indent-point)) + (c-add-stmt-syntax 'statement-cont nil + containing-sexp paren-state)) + ;; CASE 17A: After a case/default label? + ((progn + (while (and (eq step-type 'label) + (not (looking-at c-label-kwds-regexp))) + (setq step-type + (c-beginning-of-statement-1 containing-sexp))) + (eq step-type 'label)) + (c-add-stmt-syntax (if (eq char-after-ip ?{) + 'statement-case-open + 'statement-case-intro) + t containing-sexp paren-state)) ;; CASE 17D: any old statement - ((< (point) indent-point) - (let ((safepos (c-most-enclosing-brace fullstate)) - relpos done) - (goto-char indent-point) - (c-beginning-of-statement-1 safepos) - ;; It is possible we're on the brace that opens a nested - ;; function. - (if (and (eq (char-after) ?{) - (save-excursion - (c-backward-syntactic-ws safepos) - (not (eq (char-before) ?\;)))) - (c-beginning-of-statement-1 safepos)) - (if (and inswitch-p - (looking-at c-switch-label-key)) - (progn - (goto-char (match-end 0)) - (c-forward-syntactic-ws))) - (setq relpos (c-point 'boi)) - (while (and (not done) - (<= safepos (point)) - (/= relpos (point))) - (c-beginning-of-statement-1 safepos) - (if (= relpos (c-point 'boi)) - (setq done t)) - (setq relpos (c-point 'boi))) - (c-add-syntax 'statement relpos) - (if (eq char-after-ip ?{) - (c-add-syntax 'block-open)))) - ;; CASE 17E: first statement in an in-expression block - ((setq placeholder - (save-excursion - (goto-char containing-sexp) - (c-looking-at-inexpr-block))) - (goto-char containing-sexp) + ((progn + (while (eq step-type 'label) + (setq step-type + (c-beginning-of-statement-1 containing-sexp))) + (eq step-type 'previous)) + (c-add-stmt-syntax 'statement t containing-sexp paren-state) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17I: Inside a substatement block. + ((progn + ;; The following tests are all based on containing-sexp. + (goto-char containing-sexp) + ;; From here on we have the next containing sexp in lim. + (setq lim (c-most-enclosing-brace paren-state containing-sexp)) + (c-after-conditional)) + (c-backward-to-block-anchor lim) + (c-add-stmt-syntax 'statement-block-intro t lim paren-state) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) + ;; CASE 17E: first statement in an in-expression block. + ;; C.f. cases 4, 7B and 16A. + ((setq placeholder (c-looking-at-inexpr-block + (c-safe-position containing-sexp paren-state) + nil)) + (setq tmpsymbol (if (eq (car placeholder) 'inlambda) + 'defun-block-intro + 'statement-block-intro)) (back-to-indentation) - (let ((block-intro (if (eq (car placeholder) 'inlambda) - 'defun-block-intro - 'statement-block-intro))) - (if (= containing-sexp (point)) - (c-add-syntax block-intro (point)) - (goto-char (cdr placeholder)) - (back-to-indentation) - (c-add-syntax block-intro (point)) - (if (/= (point) (cdr placeholder)) - (c-add-syntax (car placeholder))))) + (if (= containing-sexp (point)) + (c-add-syntax tmpsymbol (point)) + (goto-char (cdr placeholder)) + (back-to-indentation) + (c-add-stmt-syntax tmpsymbol t + (c-most-enclosing-brace c-state-cache (point)) + (c-whack-state-after (point) paren-state)) + (if (/= (point) (cdr placeholder)) + (c-add-syntax (car placeholder)))) (if (eq char-after-ip ?{) (c-add-syntax 'block-open))) ;; CASE 17F: first statement in an inline, or first ;; statement in a top-level defun. we can tell this is it ;; if there are no enclosing braces that haven't been - ;; narrowed out by a class (i.e. don't use bod here!) + ;; narrowed out by a class (i.e. don't use bod here). + ;; However, we first check for statements that we can + ;; recognize by keywords. That increases the robustness in + ;; cases where statements are used on the top level, + ;; e.g. in macro definitions. ((save-excursion (save-restriction (widen) - (goto-char containing-sexp) - (c-narrow-out-enclosing-class state containing-sexp) - (not (c-most-enclosing-brace state)))) - (goto-char containing-sexp) - ;; if not at boi, then defun-opening braces are hung on - ;; right side, so we need a different relpos - (if (/= (point) (c-point 'boi)) - (progn - (c-backward-syntactic-ws) - (c-safe (c-forward-sexp (if (eq (char-before) ?\)) - -1 -2))) - ;; looking at a Java throws clause following a - ;; method's parameter list - (c-beginning-of-statement-1) - )) - (c-add-syntax 'defun-block-intro (c-point 'boi))) + (c-narrow-out-enclosing-class paren-state containing-sexp) + (not (c-most-enclosing-brace paren-state)))) + (c-backward-to-decl-anchor lim) + (back-to-indentation) + (c-add-syntax 'defun-block-intro (point))) ;; CASE 17G: First statement in a function declared inside - ;; a normal block. This can only occur in Pike. - ((and (c-major-mode-is 'pike-mode) - (progn - (goto-char containing-sexp) - (and (not (c-looking-at-bos)) - (progn - (c-beginning-of-statement-1) - (not (looking-at c-conditional-key)))))) - (c-add-syntax 'defun-block-intro (c-point 'boi))) - ;; CASE 17H: first statement in a block - (t (goto-char containing-sexp) - (if (/= (point) (c-point 'boi)) - (c-beginning-of-statement-1 - (if (= (point) lim) - (c-safe-position (point) state) lim))) - (c-add-syntax 'statement-block-intro (c-point 'boi)) - (if (eq char-after-ip ?{) - (c-add-syntax 'block-open))) + ;; a normal block. This can occur in Pike and with + ;; e.g. the gcc extensions. Might also trigger it with + ;; some macros followed by blocks, and this gives sane + ;; indentation then too. C.f. cases B.3 and 16F. + ((save-excursion + (and (not (c-looking-at-bos)) + (eq (c-beginning-of-statement-1 lim nil nil t) 'same) + (setq placeholder (point)))) + (back-to-indentation) + (if (/= (point) containing-sexp) + (goto-char placeholder)) + (c-add-stmt-syntax 'defun-block-intro t lim paren-state)) + ;; CASE 17H: First statement in a block. C.f. case 16C. + (t + ;; If the block is preceded by a case/switch label on the + ;; same line, we anchor at the first preceding label at + ;; boi. The default handling in c-add-stmt-syntax is + ;; really fixes it better, but we do like this to keep the + ;; indentation compatible with version 5.28 and earlier. + (while (and (/= (setq placeholder (point)) (c-point 'boi)) + (eq (c-beginning-of-statement-1 lim) 'label))) + (goto-char placeholder) + (if (looking-at c-label-kwds-regexp) + (c-add-syntax 'statement-block-intro (point)) + (goto-char containing-sexp) + ;; c-backward-to-block-anchor not necessary here; those + ;; situations are handled in case 17I above. + (c-add-stmt-syntax 'statement-block-intro t lim paren-state)) + (if (eq char-after-ip ?{) + (c-add-syntax 'block-open))) )) ) ;; now we need to look at any modifiers (goto-char indent-point) (skip-chars-forward " \t") - (cond - ;; are we looking at a comment only line? - ((and (looking-at c-comment-start-regexp) - (/= (c-forward-token-1 0 nil (c-point 'eol)) 0)) + ;; are we looking at a comment only line? + (when (and (looking-at c-comment-start-regexp) + (/= (c-forward-token-1 0 nil (c-point 'eol)) 0)) (c-add-syntax 'comment-intro)) - ;; we might want to give additional offset to friends (in C++). - ((and (c-major-mode-is 'c++-mode) - (looking-at c-C++-friend-key)) + ;; we might want to give additional offset to friends (in C++). + (when (and c-opt-friend-key + (looking-at c-opt-friend-key)) (c-add-syntax 'friend)) - ;; Start of a preprocessor directive? - ((and (eq literal 'pound) - (= (save-excursion - (c-beginning-of-macro lim) - (setq placeholder (point))) - (c-point 'boi)) - (not (and (c-major-mode-is 'pike-mode) - (eq (char-after (1+ placeholder)) ?\")))) - (c-add-syntax 'cpp-macro))) + ;; Start of or a continuation of a preprocessor directive? + (if (and macro-start + (eq macro-start (c-point 'boi)) + (not (and (c-major-mode-is 'pike-mode) + (eq (char-after (1+ macro-start)) ?\")))) + (c-add-syntax 'cpp-macro) + (when (and c-syntactic-indentation-in-macros macro-start) + (if in-macro-expr + (when (or (< syntactic-relpos macro-start) + (not (or (assq 'arglist-intro syntax) + (assq 'arglist-cont syntax) + (assq 'arglist-cont-nonempty syntax) + (assq 'arglist-close syntax)))) + ;; If inside a cpp expression, i.e. anywhere in a + ;; cpp directive except a #define body, we only let + ;; through the syntactic analysis that is internal + ;; in the expression. That means the arglist + ;; elements, if they are anchored inside the cpp + ;; expression. + (setq syntax `((cpp-macro-cont . ,macro-start)))) + (when (and (eq macro-start syntactic-relpos) + (not (assq 'cpp-define-intro syntax)) + (save-excursion + (goto-char macro-start) + (or (not (c-forward-to-cpp-define-body)) + (<= (point) (c-point 'boi indent-point))))) + ;; Inside a #define body and the syntactic analysis is + ;; anchored on the start of the #define. In this case + ;; we add cpp-define-intro to get the extra + ;; indentation of the #define body. + (c-add-syntax 'cpp-define-intro))))) ;; return the syntax syntax)))) (defun c-echo-parsing-error (&optional quiet) - (when (and c-parsing-error (not quiet)) - (message "%s" c-parsing-error) - (ding)) + (when (and c-report-syntactic-errors c-parsing-error (not quiet)) + (c-benign-error "%s" c-parsing-error)) c-parsing-error) -(defun c-shift-line-indentation (shift-amt) - (let ((pos (- (point-max) (point))) - (col (current-indentation))) - (if (zerop shift-amt) - nil - (delete-region (c-point 'bol) (c-point 'boi)) - (beginning-of-line) - (indent-to (+ col shift-amt))) - (if (< (point) (c-point 'boi)) - (back-to-indentation) - ;; If initial point was within line's indentation, position after - ;; the indentation. Else stay at same point in text. - (if (> (- (point-max) pos) (point)) - (goto-char (- (point-max) pos)))))) - (defun c-evaluate-offset (offset langelem symbol) ;; offset can be a number, a function, a variable, a list, or one of ;; the symbols + or - @@ -2683,113 +3764,59 @@ (while (and (not done) offset) (setq done (c-evaluate-offset (car offset) langelem symbol) offset (cdr offset))) - (if (not done) - (if c-strict-syntax-p - (error "No offset found for syntactic symbol %s" symbol)) - done))) + (if (and c-strict-syntax-p (not done)) + (c-benign-error "No offset found for syntactic symbol %s" symbol)) + done)) (t (symbol-value offset)) )) (defun c-get-offset (langelem) - ;; Get offset from LANGELEM which is a cons cell of the form: - ;; (SYMBOL . RELPOS). The symbol is matched against - ;; c-offsets-alist and the offset found there is either returned, - ;; or added to the indentation at RELPOS. If RELPOS is nil, then - ;; the offset is simply returned. + "Get offset from LANGELEM which is a cons cell of the form: +\(SYMBOL . RELPOS). The symbol is matched against `c-offsets-alist' +and the offset found there is returned." (let* ((symbol (car langelem)) - (relpos (cdr langelem)) (match (assq symbol c-offsets-alist)) (offset (cdr-safe match))) - (if (not match) - (if c-strict-syntax-p - (error "No offset found for syntactic symbol %s" symbol) - (setq offset 0 - relpos 0)) - (setq offset (c-evaluate-offset offset langelem symbol))) + (if match + (setq offset (c-evaluate-offset offset langelem symbol)) + (if c-strict-syntax-p + (c-benign-error "No offset found for syntactic symbol %s" symbol)) + (setq offset 0)) (if (vectorp offset) offset - (+ (if (and relpos - (< relpos (c-point 'bol))) - (save-excursion - (goto-char relpos) - (current-column)) - 0) - (or (and (numberp offset) offset) - (and (symbolp offset) (symbol-value offset)) - 0))) + (or (and (numberp offset) offset) + (and (symbolp offset) (symbol-value offset)) + 0)) )) (defun c-get-syntactic-indentation (langelems) - ;; Apply c-get-offset to a list of langelem cells to get the total - ;; syntactic indentation. Special treatment is needed for vectors - ;; containing absolute columns. - (let ((indent 0)) + "Apply `c-get-offset' to a list of langelem cells to get the total +syntactic indentation. The anchor position, whose column is used as a +base for all the collected offsets, is taken from the first element +with a relpos." + ;; Note that topmost-intro always has a relpos at bol, for + ;; historical reasons. It's often used together with other symbols + ;; that has more sane positions. Since we always use the first + ;; found relpos, we rely on that these other symbols always precede + ;; topmost-intro in the LANGELEMS list. + (let ((indent 0) anchor) (catch 'done (while langelems (let ((res (c-get-offset (car langelems)))) (if (vectorp res) (throw 'done (elt res 0)) + (unless anchor + (let ((relpos (cdr (car langelems)))) + (if relpos + (setq anchor relpos)))) (setq indent (+ indent res) langelems (cdr langelems))))) - indent))) - -(defun c-indent-line (&optional syntax quiet) - ;; Indent the current line according to the syntactic context, if - ;; c-syntactic-indentation is non-nil. Optional SYNTAX is the - ;; syntactic information for the current line. Be silent about - ;; syntactic errors if the optional argument QUIET is non-nil. - ;; Returns the amount of indentation change (in columns). - (let (shift-amt) - (if c-syntactic-indentation - (setq c-parsing-error - (or (let* ((c-parsing-error nil) - (c-syntactic-context (or syntax - c-syntactic-context - (c-guess-basic-syntax))) - (indent (c-get-syntactic-indentation c-syntactic-context))) - (and (not (c-echo-parsing-error quiet)) - c-echo-syntactic-information-p - (message "syntax: %s, indent: %d" - c-syntactic-context indent)) - (setq shift-amt (- indent (current-indentation))) - (c-shift-line-indentation shift-amt) - (run-hooks 'c-special-indent-hook) - c-parsing-error) - c-parsing-error)) - (let ((indent 0)) - (save-excursion - (while (and (= (forward-line -1) 0) - (if (looking-at "\\s-*$") - t - (back-to-indentation) - (setq indent (current-indentation)) - nil)))) - (setq shift-amt (- indent (current-indentation))) - (c-shift-line-indentation shift-amt))) - shift-amt)) - -(defun c-show-syntactic-information (arg) - "Show syntactic information for current line. -With universal argument, inserts the analysis as a comment on that line." - (interactive "P") - (let ((syntax (c-guess-basic-syntax))) - (if (not (consp arg)) - (message "syntactic analysis: %s" syntax) - (indent-for-comment) - (insert (format "%s" syntax)) - )) - (c-keep-region-active)) - -(defun c-syntactic-information-on-region (from to) - "Inserts a comment with the syntactic analysis on every line in the region." - (interactive "*r") - (save-excursion - (save-restriction - (narrow-to-region from to) - (goto-char (point-min)) - (while (not (eobp)) - (c-show-syntactic-information '(0)) - (forward-line))))) + (+ indent + (if anchor + (save-excursion + (goto-char anchor) + (current-column)) + 0))))) (cc-provide 'cc-engine)
--- a/lisp/progmodes/cc-langs.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-langs.el Mon Apr 22 00:35:36 2002 +0000 @@ -25,7 +25,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. @@ -44,384 +44,585 @@ (cc-require 'cc-defs) (cc-require 'cc-vars) +(require 'cl) + -(defvar c-buffer-is-cc-mode nil - "Non-nil for all buffers with a `major-mode' derived from CC Mode. -Otherwise, this variable is nil. I.e. this variable is non-nil for -`c-mode', `c++-mode', `objc-mode', `java-mode', `idl-mode', -`pike-mode', and any other non-CC Mode mode that calls -`c-initialize-cc-mode' (e.g. `awk-mode').") -(make-variable-buffer-local 'c-buffer-is-cc-mode) -(put 'c-buffer-is-cc-mode 'permanent-local t) +;; Some support functions that are used when the language specific +;; constants are built. Since the constants are built during compile +;; time, these need to be defined then too. + +(eval-and-compile + ;; `require' in XEmacs doesn't have the third NOERROR argument. + (condition-case nil (require 'regexp-opt) (file-error nil)) + + (if (fboundp 'regexp-opt) + (fset 'c-regexp-opt (symbol-function 'regexp-opt)) + ;; Emacs 19.34 doesn't have the regexp-opt package. + (defun c-regexp-opt (strings &optional paren) + (if paren + (concat "\\(" (mapconcat 'regexp-quote strings "\\|") "\\)") + (mapconcat 'regexp-quote strings "\\|")))) + + (if (fboundp 'regexp-opt-depth) + (fset 'c-regexp-opt-depth (symbol-function 'regexp-opt-depth)) + ;; Emacs 19.34 doesn't have the regexp-opt package. + (defun c-regexp-opt-depth (regexp) + ;; This is the definition of `regexp-opt-depth' in Emacs 20. + (save-match-data + ;; Hack to signal an error if REGEXP does not have balanced + ;; parentheses. + (string-match regexp "") + ;; Count the number of open parentheses in REGEXP. + (let ((count 0) start) + (while (string-match "\\\\(" regexp start) + (setq count (1+ count) start (match-end 0))) + count)))) + + (defun c-make-keywords-re (adorn &rest lists) + "Make a regexp that matches all the strings in all the lists. +Duplicates in the lists are removed. The regexp may contain zero or +more submatch expressions. If ADORN is non-nil there will be at least +one submatch which matches the whole keyword, and the regexp will also +not match a prefix of any identifier. Adorned regexps cannot be +appended." + (setq lists (delete-duplicates (apply 'append (nconc lists '(nil))) + :test 'string-equal)) + (if lists + (let ((re (c-regexp-opt lists))) + ;; Add our own grouping parenthesis around re instead of + ;; passing adorn to regexp-opt, since it in XEmacs makes the + ;; top level grouping "shy". + (if adorn + (concat "\\(" re "\\)\\>\\([^_]\\|$\\)") + re)) + "\\<\\>" ; Matches nothing. + )) + (put 'c-make-keywords-re 'lisp-indent-function 1) + ) -;; Regular expressions and other values which must be parameterized on -;; a per-language basis. +;; Building of constants that are parameterized on a per-language +;; basis. + +(eval-and-compile + (defvar c-macroexpand-mode nil + ;; Dynamically bound to the mode symbol during `c-lang-defconst' + ;; so that `c-lang-var' can do the right expansion. + ) + + (defmacro c-lang-defconst (var &rest args) + ;; Sets the mode specific values of the constant VAR. The rest of + ;; the arguments are one or more repetitions of MODE VAL. MODE is + ;; the mode name without the "-mode" suffix, or a list of such + ;; mode names, or `all' as a shortcut for a list of all modes. + ;; VAL is evaluated (during compilation) for each mode with + ;; `c-macroexpand-mode' temporarily bound, so `c-lang-var' without + ;; an explicit mode may be used within it. The assignments in + ;; ARGS are processed in sequence, similar to `setq'. + (let* ((res (list 'progn)) + (res-tail res)) + (while args + (let ((mode (car args))) + (cond ((eq mode 'all) + (setq mode '(c c++ objc java idl pike))) + ((symbolp mode) + (setq mode (list mode)))) + (while mode + (let* ((c-macroexpand-mode + (intern (concat (symbol-name (car mode)) "-mode"))) + (val (eval (car (cdr args))))) + ;; Need to install the value also during compilation, + ;; since val might refer to earlier mode specific + ;; values. + (put var c-macroexpand-mode val) + (setcdr res-tail (list `(put ',var ',c-macroexpand-mode ',val))) + (setq res-tail (cdr res-tail))) + (setq mode (cdr mode)))) + (setq args (cdr (cdr args)))) + res)) + (put 'c-lang-defconst 'lisp-indent-function 1) + + (defmacro c-lang-var (var &optional mode) + ;; Get the mode specific value of the variable VAR in mode MODE. + ;; MODE is the mode name without the "-mode" suffix. It may also + ;; be nil to use the current value of `c-macroexpand-mode' (which + ;; is useful inside `c-lang-defconst') or `c-buffer-is-cc-mode' + ;; (which is useful inside `c-lang-defvar'). + `(get ',var ,(if (eq mode 'nil) + (if c-macroexpand-mode + ;; In the macro expansion of c-lang-defconst. + `(quote ,c-macroexpand-mode) + `c-buffer-is-cc-mode) + `(quote ,(intern (concat (symbol-name mode) "-mode")))))) -;; Regex describing a `symbol' in all languages. We cannot use just -;; `word' syntax class since `_' cannot be in word class. Putting -;; underscore in word class breaks forward word movement behavior that -;; users are familiar with. Besides, this runs counter to Emacs -;; convention. + ;; These are used to collect the init forms from the subsequent + ;; `c-lang-defvar'. They become a big setq in the + ;; `c-init-lang-defvars' lambda below. + (defconst c-lang-defvar-init-form (list 'setq)) + (defconst c-lang-defvar-init-form-tail c-lang-defvar-init-form) + + (defmacro c-lang-defvar (var val) + ;; Declares the buffer local variable VAR to get the value VAL at + ;; mode initialization, at which point VAL is evaluated. + ;; `c-lang-var' is typically used in VAL to get the right value + ;; according to `c-buffer-is-cc-mode'. + (setcdr c-lang-defvar-init-form-tail (list var val)) + (setq c-lang-defvar-init-form-tail + (cdr (cdr c-lang-defvar-init-form-tail))) + `(progn + (defvar ,var nil) + (make-variable-buffer-local ',var))) + (put 'c-lang-defvar 'lisp-indent-function 1) + ) + +;; Regexp describing a `symbol' in all languages, not excluding +;; keywords. We cannot use just `word' syntax class since `_' cannot +;; be in word class. Putting underscore in word class breaks forward +;; word movement behavior that users are familiar with. Besides, it +;; runs counter to Emacs convention. ;; -;; I suspect this definition isn't correct in light of Java's -;; definition of a symbol as being Unicode. I know so little about -;; I18N (except how to sound cool and say I18N :-) that I'm willing to -;; punt on this for now. -(defconst c-symbol-key "[_a-zA-Z]\\(\\w\\|\\s_\\)*") +;; This definition isn't correct for the first character in the +;; languages that accept the full range of Unicode word constituents +;; in identifiers (e.g. Java and Pike). For that we'd need to make a +;; regexp that matches all characters in the word constituent class +;; except 0-9, and the regexp engine currently can't do that. +(c-lang-defconst c-symbol-key + (c c++ objc java idl) "[_a-zA-Z]\\(\\w\\|\\s_\\)*" + pike (concat "\\(" (c-lang-var c-symbol-key c) "\\|" + (c-make-keywords-re nil + '("`+" "`-" "`&" "`|" "`^" "`<<" "`>>" "`*" "`/" "`%" "`~" + "`==" "`<" "`>" "`!" "`[]" "`[]=" "`->" "`->=" "`()" "``+" + "``-" "``&" "``|" "``^" "``<<" "``>>" "``*" "``/" "``%" + "`+=")) + "\\)")) +(c-lang-defvar c-symbol-key (c-lang-var c-symbol-key)) + +;; Number of regexp grouping parens in c-symbol-key. +(c-lang-defvar c-symbol-key-depth (c-regexp-opt-depth c-symbol-key)) + +(defvar c-stmt-delim-chars "^;{}?:") +;; The characters that should be considered to bound statements. To +;; optimize c-crosses-statement-barrier-p somewhat, it's assumed to +;; begin with "^" to negate the set. If ? : operators should be +;; detected then the string must end with "?:". + +(defvar c-stmt-delim-chars-with-comma "^;,{}?:") +;; Variant of c-stmt-delim-chars that additionally contains ','. ;; HELPME: Many of the following keyword lists are more or less bogus ;; for some languages (notably ObjC and IDL). The effects of the -;; erroneous values in the language handling is miniscule since these -;; constants are not used very much (yet, anyway) in the actual syntax -;; detection code, but I'd still appreciate help to get them correct. +;; erroneous values in the language handling are mostly negligible +;; since the constants that actually matter in the syntax detection +;; code are mostly correct in the situations they are used, but I'd +;; still appreciate help to get them correct for other uses. ;; Primitive type keywords. -(defconst c-C-primitive-type-kwds - "char\\|double\\|float\\|int\\|long\\|short\\|signed\\|unsigned\\|void") -(defconst c-C++-primitive-type-kwds c-C-primitive-type-kwds) -(defconst c-ObjC-primitive-type-kwds c-C-primitive-type-kwds) -(defconst c-Java-primitive-type-kwds - "boolean\\|byte\\|char\\|double\\|float\\|int\\|long\\|short\\|void") -(defconst c-IDL-primitive-type-kwds c-C-primitive-type-kwds) -(defconst c-Pike-primitive-type-kwds - (concat "constant\\|float\\|int\\|mapping\\|multiset\\|object\\|" - "program\\|string\\|void")) +(c-lang-defconst c-primitive-type-kwds + (c c++ objc idl) '("char" "double" "float" "int" "long" "short" + "signed" "unsigned" "void") + java '("boolean" "byte" "char" "double" "float" "int" "long" "short" "void") + pike '("constant" "float" "int" "mapping" "multiset" "object" "program" + "string" "void")) ;; Declaration specifier keywords. -(defconst c-C-specifier-kwds - "auto\\|const\\|extern\\|register\\|static\\|volatile") -(defconst c-C++-specifier-kwds - (concat c-C-specifier-kwds "\\|friend\\|inline\\|virtual")) -(defconst c-ObjC-specifier-kwds c-C++-specifier-kwds) -(defconst c-Java-specifier-kwds - ;; Note: `const' is not used, but it's still a reserved keyword. - (concat "abstract\\|const\\|final\\|native\\|private\\|protected\\|" - "public\\|static\\|synchronized\\|transient\\|volatile")) -(defconst c-IDL-specifier-kwds c-C++-specifier-kwds) -(defconst c-Pike-specifier-kwds - (concat "final\\|inline\\|local\\|nomask\\|optional\\|private\\|" - "protected\\|static\\|variant")) +(c-lang-defconst c-specifier-kwds + c '("auto" "const" "extern" "register" "static" "volatile") + (c++ objc idl) (append '("friend" "inline" "virtual") + (c-lang-var c-specifier-kwds c)) + ;; Note: `const' is not used in Java, but it's still a reserved keyword. + java '("abstract" "const" "final" "native" "private" "protected" + "public" "static" "synchronized" "transient" "volatile") + pike '("final" "inline" "local" "nomask" "optional" "private" + "protected" "static" "variant")) ;; Class/struct declaration keywords. -(defconst c-C-class-kwds "struct\\|union") -(defconst c-C++-class-kwds (concat c-C-class-kwds "\\|class")) -(defconst c-ObjC-class-kwds "interface\\|implementation") -(defconst c-Java-class-kwds "class\\|interface") -(defconst c-IDL-class-kwds - (concat c-C++-class-kwds "\\|interface\\|valuetype")) -(defconst c-Pike-class-kwds "class") +(c-lang-defconst c-class-kwds + c '("struct" "union") + c++ '("class" "struct" "union") + objc '("interface" "implementation") + java '("class" "interface") + idl '("interface" "valuetype" "class" "struct" "union") + pike '("class")) + +;; Regexp matching the start of a class. +(c-lang-defconst c-class-key + all (c-make-keywords-re t (c-lang-var c-class-kwds))) +(c-lang-defconst c-class-key ; ObjC needs some tuning of the regexp. + objc (concat "@" (c-lang-var c-class-key))) +(c-lang-defvar c-class-key (c-lang-var c-class-key)) + +;; Keywords introducing blocks besides classes that contain another +;; declaration level. +(c-lang-defconst c-other-decl-block-kwds + c '("extern") + c++ '("namespace" "extern") + idl '("module")) + +;; Regexp matching the start of blocks besides classes that contain +;; another declaration level. +(c-lang-defconst c-other-decl-block-key + all (c-make-keywords-re t (c-lang-var c-other-decl-block-kwds))) +(c-lang-defvar c-other-decl-block-key (c-lang-var c-other-decl-block-key)) -;; Keywords introducing other declaration-level blocks. -(defconst c-C-extra-toplevel-kwds "extern") -(defconst c-C++-extra-toplevel-kwds - (concat c-C-extra-toplevel-kwds "\\|namespace")) -;;(defconst c-ObjC-extra-toplevel-kwds nil) -;;(defconst c-Java-extra-toplevel-kwds nil) -(defconst c-IDL-extra-toplevel-kwds "module") -;;(defconst c-Pike-extra-toplevel-kwds nil) +;; Keywords introducing declarations that can contain a block which +;; might be followed by variable declarations, e.g. like "foo" in +;; "class Foo { ... } foo;". So if there is a block in a declaration +;; like that, it ends with the following ';' and not right away. +(c-lang-defconst c-block-decls-with-vars + c '("struct" "union" "enum" "typedef") + c++ '("class" "struct" "union" "enum" "typedef")) -;; Keywords introducing other declaration-level constructs. -(defconst c-C-other-decl-kwds "enum\\|typedef") -(defconst c-C++-other-decl-kwds (concat c-C-other-decl-kwds "\\|template")) -;;(defconst c-ObjC-other-decl-kwds nil) -(defconst c-Java-other-decl-kwds "import\\|package") -;;(defconst c-IDL-other-decl-kwds nil) -(defconst c-Pike-other-decl-kwds "import\\|inherit") +;; Regexp matching the `c-block-decls-with-vars' keywords, or nil in +;; languages without such constructs. +(c-lang-defconst c-opt-block-decls-with-vars-key + all (and (c-lang-var c-block-decls-with-vars) + (c-make-keywords-re t (c-lang-var c-block-decls-with-vars)))) +(c-lang-defvar c-opt-block-decls-with-vars-key + (c-lang-var c-opt-block-decls-with-vars-key)) -;; Keywords that occur in declaration-level constructs. -;;(defconst c-C-decl-level-kwds nil) -;;(defconst c-C++-decl-level-kwds nil) -;;(defconst c-ObjC-decl-level-kwds nil) -(defconst c-Java-decl-level-kwds "extends\\|implements\\|throws") -;;(defconst c-IDL-decl-level-kwds nil) -;;(defconst c-Pike-decl-level-kwds nil) +;; Keywords introducing declarations that has not been accounted for +;; by any of the above. +(c-lang-defconst c-other-decl-kwds + ;; FIXME: Shouldn't "template" be moved to c-specifier-kwds for C++? + c++ '("template") + java '("import" "package") + pike '("import" "inherit")) + +;; Keywords introducing extra declaration specifiers in the region +;; between the header and the body (i.e. the "K&R-region") in +;; declarations. +(c-lang-defconst c-decl-spec-kwds java '("extends" "implements" "throws")) ;; Protection label keywords in classes. -;;(defconst c-C-protection-kwds nil) -(defconst c-C++-protection-kwds "private\\|protected\\|public") -(defconst c-ObjC-protection-kwds c-C++-protection-kwds) -;;(defconst c-Java-protection-kwds nil) -;;(defconst c-IDL-protection-kwds nil) -;;(defconst c-Pike-protection-kwds nil) +(c-lang-defconst c-protection-kwds + (c++ objc) '("private" "protected" "public")) + +;; Statement keywords followed directly by a substatement. +(c-lang-defconst c-block-stmt-1-kwds + (c pike) '("do" "else") + (c++ objc) '("do" "else" "asm" "try") + java '("do" "else" "finally" "try")) + +;; Regexp matching the start of any statement followed directly by a +;; substatement (doesn't match a bare block, however). +(c-lang-defconst c-block-stmt-1-key + all (c-make-keywords-re t (c-lang-var c-block-stmt-1-kwds))) +(c-lang-defvar c-block-stmt-1-key (c-lang-var c-block-stmt-1-key)) -;; Statement keywords followed directly by a block. -(defconst c-C-block-stmt-1-kwds "do\\|else") -(defconst c-C++-block-stmt-1-kwds - (concat c-C-block-stmt-1-kwds "\\|asm\\|try")) -(defconst c-ObjC-block-stmt-1-kwds c-C++-block-stmt-1-kwds) -(defconst c-Java-block-stmt-1-kwds - (concat c-C-block-stmt-1-kwds "\\|finally\\|try")) -;;(defconst c-IDL-block-stmt-1-kwds nil) -(defconst c-Pike-block-stmt-1-kwds c-C-block-stmt-1-kwds) +;; Statement keywords followed by a paren sexp and then by a substatement. +(c-lang-defconst c-block-stmt-2-kwds + c '("for" "if" "switch" "while") + (c++ objc) '("for" "if" "switch" "while" "catch") + java '("for" "if" "switch" "while" "catch" "synchronized") + pike '("for" "if" "switch" "while" "foreach")) -;; Statement keywords followed by a paren sexp and then by a block. -(defconst c-C-block-stmt-2-kwds "for\\|if\\|switch\\|while") -(defconst c-C++-block-stmt-2-kwds (concat c-C-block-stmt-2-kwds "\\|catch")) -(defconst c-ObjC-block-stmt-2-kwds c-C++-block-stmt-2-kwds) -(defconst c-Java-block-stmt-2-kwds - (concat c-C++-block-stmt-2-kwds "\\|synchronized")) -;;(defconst c-IDL-block-stmt-2-kwds nil) -(defconst c-Pike-block-stmt-2-kwds c-C-block-stmt-2-kwds) +;; Regexp matching the start of any statement followed by a paren sexp +;; and then by a substatement. +(c-lang-defconst c-block-stmt-2-key + all (c-make-keywords-re t (c-lang-var c-block-stmt-2-kwds))) +(c-lang-defvar c-block-stmt-2-key (c-lang-var c-block-stmt-2-key)) + +;; Regexp matching the start of any statement that has a substatement +;; (except a bare block). Nil in languages that doesn't have such +;; constructs. +(c-lang-defconst c-opt-block-stmt-key + all (if (or (c-lang-var c-block-stmt-1-kwds) + (c-lang-var c-block-stmt-2-kwds)) + (c-make-keywords-re t + (c-lang-var c-block-stmt-1-kwds) + (c-lang-var c-block-stmt-2-kwds)))) +(c-lang-defvar c-opt-block-stmt-key (c-lang-var c-opt-block-stmt-key)) ;; Statement keywords followed by an expression or nothing. -(defconst c-C-simple-stmt-kwds "break\\|continue\\|goto\\|return") -(defconst c-C++-simple-stmt-kwds c-C-simple-stmt-kwds) -(defconst c-ObjC-simple-stmt-kwds c-C-simple-stmt-kwds) -(defconst c-Java-simple-stmt-kwds - ;; Note: `goto' is not a valid statement, but the keyword is still reserved. - (concat c-C-simple-stmt-kwds "\\|throw")) -;;(defconst c-IDL-simple-stmt-kwds nil) -(defconst c-Pike-simple-stmt-kwds "break\\|continue\\|return") +(c-lang-defconst c-simple-stmt-kwds + (c c++ objc) '("break" "continue" "goto" "return") + ;; Note: `goto' is not valid in Java, but the keyword is still reserved. + java '("break" "continue" "goto" "return" "throw") + pike '("break" "continue" "return")) + +;; Statement keywords followed by an assembler expression. +(c-lang-defconst c-asm-stmt-kwds + (c c++) '("asm" "__asm__")) + +;; Regexp matching the start of an assembler statement. Nil in +;; languages that doesn't support that. +(c-lang-defconst c-opt-asm-stmt-key + all (if (c-lang-var c-asm-stmt-kwds) + (c-make-keywords-re t (c-lang-var c-asm-stmt-kwds)))) +(c-lang-defvar c-opt-asm-stmt-key (c-lang-var c-opt-asm-stmt-key)) ;; Keywords introducing labels in blocks. -(defconst c-C-label-kwds "case\\|default") -(defconst c-C++-label-kwds c-C-label-kwds) -(defconst c-ObjC-label-kwds c-C-label-kwds) -(defconst c-Java-label-kwds c-C-label-kwds) -;;(defconst c-IDL-label-kwds nil) -(defconst c-Pike-label-kwds c-C-label-kwds) +(c-lang-defconst c-label-kwds (c c++ objc java pike) '("case" "default")) + +;; Regexp matching any keyword that introduces a label. +(c-lang-defconst c-label-kwds-regexp + all (c-make-keywords-re t (c-lang-var c-label-kwds))) +(c-lang-defvar c-label-kwds-regexp (c-lang-var c-label-kwds-regexp)) ;; Keywords that can occur anywhere in expressions. -(defconst c-C-expr-kwds "sizeof") -(defconst c-C++-expr-kwds - (concat c-C-expr-kwds "\\|delete\\|new\\|operator\\|this\\|throw")) -(defconst c-ObjC-expr-kwds c-C-expr-kwds) -(defconst c-Java-expr-kwds "instanceof\\|new\\|super\\|this") -;;(defconst c-IDL-expr-kwds nil) -(defconst c-Pike-expr-kwds - (concat c-C-expr-kwds "\\|catch\\|class\\|gauge\\|lambda\\|predef")) +(c-lang-defconst c-expr-kwds + (c objc) '("sizeof") + c++ '("sizeof" "delete" "new" "operator" "this" "throw") + java '("instanceof" "new" "super" "this") + pike '("sizeof" "catch" "class" "gauge" "lambda" "predef")) + +;; Keywords that start lambda constructs, i.e. function definitions in +;; expressions. +(c-lang-defconst c-lambda-kwds pike '("lambda")) + +;; Regexp matching the start of lambda constructs, or nil in languages +;; that doesn't have such things. +(c-lang-defconst c-opt-lambda-key + pike (c-make-keywords-re t (c-lang-var c-lambda-kwds))) +(c-lang-defvar c-opt-lambda-key (c-lang-var c-opt-lambda-key)) + +;; Keywords that start constructs followed by statement blocks which +;; can be used in expressions (the gcc extension for this in C and C++ +;; is handled separately). +(c-lang-defconst c-inexpr-block-kwds pike '("catch" "gauge")) + +;; Regexp matching the start of in-expression statements, or nil in +;; languages that doesn't have such things. +(c-lang-defconst c-opt-inexpr-block-key + pike (c-make-keywords-re t (c-lang-var c-inexpr-block-kwds))) +(c-lang-defvar c-opt-inexpr-block-key (c-lang-var c-opt-inexpr-block-key)) + +;; Keywords that start classes in expressions. +(c-lang-defconst c-inexpr-class-kwds + java '("new") + pike '("class")) + +;; Regexp matching the start of a class in an expression, or nil in +;; languages that doesn't have such things. +(c-lang-defconst c-opt-inexpr-class-key + (java pike) (c-make-keywords-re t (c-lang-var c-inexpr-class-kwds))) +(c-lang-defvar c-opt-inexpr-class-key (c-lang-var c-opt-inexpr-class-key)) + +;; Regexp matching the start of any class, both at top level and in +;; expressions. +(c-lang-defconst c-any-class-key + all (c-make-keywords-re t + (c-lang-var c-class-kwds) + (c-lang-var c-inexpr-class-kwds))) +(c-lang-defconst c-any-class-key ; ObjC needs some tuning of the regexp. + objc (concat "@" (c-lang-var c-any-class-key))) +(c-lang-defvar c-any-class-key (c-lang-var c-any-class-key)) -;; All keywords. -(defconst c-C-keywords - (concat c-C-primitive-type-kwds "\\|" c-C-specifier-kwds - "\\|" c-C-class-kwds "\\|" c-C-extra-toplevel-kwds - "\\|" c-C-other-decl-kwds - ;; "\\|" c-C-decl-level-kwds "\\|" c-C-protection-kwds - "\\|" c-C-block-stmt-1-kwds "\\|" c-C-block-stmt-2-kwds - "\\|" c-C-simple-stmt-kwds "\\|" c-C-label-kwds - "\\|" c-C-expr-kwds)) -(defconst c-C++-keywords - (concat c-C++-primitive-type-kwds "\\|" c-C++-specifier-kwds - "\\|" c-C++-class-kwds "\\|" c-C++-extra-toplevel-kwds - "\\|" c-C++-other-decl-kwds - ;; "\\|" c-C++-decl-level-kwds - "\\|" c-C++-protection-kwds - "\\|" c-C++-block-stmt-1-kwds "\\|" c-C++-block-stmt-2-kwds - "\\|" c-C++-simple-stmt-kwds "\\|" c-C++-label-kwds - "\\|" c-C++-expr-kwds)) -(defconst c-ObjC-keywords - (concat c-ObjC-primitive-type-kwds "\\|" c-ObjC-specifier-kwds - "\\|" c-ObjC-class-kwds - ;; "\\|" c-ObjC-extra-toplevel-kwds - ;; "\\|" c-ObjC-other-decl-kwds "\\|" c-ObjC-decl-level-kwds - "\\|" c-ObjC-protection-kwds - "\\|" c-ObjC-block-stmt-1-kwds "\\|" c-ObjC-block-stmt-2-kwds - "\\|" c-ObjC-simple-stmt-kwds "\\|" c-ObjC-label-kwds - "\\|" c-ObjC-expr-kwds)) -(defconst c-Java-keywords - (concat c-Java-primitive-type-kwds "\\|" c-Java-specifier-kwds - "\\|" c-Java-class-kwds - ;; "\\|" c-Java-extra-toplevel-kwds - "\\|" c-Java-other-decl-kwds "\\|" c-Java-decl-level-kwds - ;; "\\|" c-Java-protection-kwds - "\\|" c-Java-block-stmt-1-kwds "\\|" c-Java-block-stmt-2-kwds - "\\|" c-Java-simple-stmt-kwds "\\|" c-Java-label-kwds - "\\|" c-Java-expr-kwds)) -(defconst c-IDL-keywords - (concat c-IDL-primitive-type-kwds "\\|" c-IDL-specifier-kwds - "\\|" c-IDL-class-kwds "\\|" c-IDL-extra-toplevel-kwds - ;; "\\|" c-IDL-other-decl-kwds "\\|" c-IDL-decl-level-kwds - ;; "\\|" c-IDL-protection-kwds - ;; "\\|" c-IDL-block-stmt-1-kwds "\\|" c-IDL-block-stmt-2-kwds - ;; "\\|" c-IDL-simple-stmt-kwds "\\|" c-IDL-label-kwds - ;; "\\|" c-IDL-expr-kwds) - )) -(defconst c-Pike-keywords - (concat c-Pike-primitive-type-kwds "\\|" c-Pike-specifier-kwds - "\\|" c-Pike-class-kwds - ;; "\\|" c-Pike-extra-toplevel-kwds - "\\|" c-Pike-other-decl-kwds - ;; "\\|" c-Pike-decl-level-kwds "\\|" c-Pike-protection-kwds - "\\|" c-Pike-block-stmt-1-kwds "\\|" c-Pike-block-stmt-2-kwds - "\\|" c-Pike-simple-stmt-kwds "\\|" c-Pike-label-kwds - "\\|" c-Pike-expr-kwds)) +;; Regexp matching the start of any declaration-level block that +;; contain another declaration level, i.e. that isn't a function +;; block. +(c-lang-defconst c-decl-block-key + all (c-make-keywords-re t + (c-lang-var c-class-kwds) + (c-lang-var c-other-decl-block-kwds) + (c-lang-var c-inexpr-class-kwds))) +(c-lang-defconst c-decl-block-key ; ObjC needs some tuning of the regexp. + objc (concat "@" (c-lang-var c-decl-block-key))) +(c-lang-defvar c-decl-block-key (c-lang-var c-decl-block-key)) + +;; Keywords that can introduce bitfields. +(c-lang-defconst c-bitfield-kwds + (c c++) '("char" "int" "long" "signed" "unsigned")) + +;; Regexp matching the start of a bitfield (not uniquely), or nil in +;; languages without bitfield support. +(c-lang-defconst c-opt-bitfield-key + (c c++) (c-make-keywords-re t (c-lang-var c-bitfield-kwds))) +(c-lang-defvar c-opt-bitfield-key (c-lang-var c-opt-bitfield-key)) -(defvar c-keywords nil) -(make-variable-buffer-local 'c-keywords) - -;; Keywords defining protection levels -(defconst c-protection-key "\\<\\(public\\|protected\\|private\\)\\>") +;; All keywords as a list. +(c-lang-defconst c-keywords + all (delete-duplicates (append (c-lang-var c-primitive-type-kwds) + (c-lang-var c-specifier-kwds) + (c-lang-var c-class-kwds) + (c-lang-var c-other-decl-block-kwds) + (c-lang-var c-block-decls-with-vars) + (c-lang-var c-other-decl-kwds) + (c-lang-var c-decl-spec-kwds) + (c-lang-var c-protection-kwds) + (c-lang-var c-block-stmt-1-kwds) + (c-lang-var c-block-stmt-2-kwds) + (c-lang-var c-simple-stmt-kwds) + (c-lang-var c-asm-stmt-kwds) + (c-lang-var c-label-kwds) + (c-lang-var c-expr-kwds) + (c-lang-var c-lambda-kwds) + (c-lang-var c-inexpr-block-kwds) + (c-lang-var c-inexpr-class-kwds) + (c-lang-var c-bitfield-kwds) + nil) + :test 'string-equal)) +(c-lang-defvar c-keywords (c-lang-var c-keywords)) -;; Regexps introducing class definitions. -(defconst c-C-class-key (c-paren-re c-C-class-kwds)) -(defconst c-C++-class-key (c-paren-re c-C++-class-kwds)) -(defconst c-IDL-class-key (c-paren-re c-IDL-class-kwds)) -(defconst c-ObjC-class-key - (concat - "@\\(" c-ObjC-class-kwds "\\)\\s +" - c-symbol-key ;name of the class - "\\(\\s *:\\s *" c-symbol-key "\\)?" ;maybe followed by the superclass - "\\(\\s *<[^>]+>\\)?" ;and maybe the adopted protocols list - )) -(defconst c-Java-class-key - (concat - "\\(" c-protection-key "\\s +\\)?" - "\\(" c-Java-class-kwds "\\)\\s +" - c-symbol-key ;name of the class - "\\(\\s *extends\\s *" c-symbol-key "\\)?" ;maybe followed by superclass - ;;"\\(\\s *implements *[^{]+{\\)?" ;maybe the adopted protocols list - )) -(defconst c-Pike-class-key (c-paren-re c-Pike-class-kwds)) +;; All keywords as an adorned regexp. +(c-lang-defconst c-keywords-regexp + all (c-make-keywords-re t (c-lang-var c-keywords))) +(c-lang-defvar c-keywords-regexp (c-lang-var c-keywords-regexp)) -(defvar c-class-key c-C-class-key) -(make-variable-buffer-local 'c-class-key) +;; Regexp matching an access protection label in a class, or nil in +;; languages that doesn't have such things. +(c-lang-defconst c-opt-access-key + c++ (concat "\\(" + (c-make-keywords-re nil (c-lang-var c-protection-kwds)) + "\\)[ \t\n\r]*:")) +(c-lang-defconst c-opt-access-key + objc (concat "@" (c-make-keywords-re t (c-lang-var c-protection-kwds)))) +(c-lang-defvar c-opt-access-key (c-lang-var c-opt-access-key)) + +;; Regexp matching a normal label, i.e. not a label that's recognized +;; with a keyword, like switch labels. It's only used at the +;; beginning of a statement. +(c-lang-defconst c-label-key + all (concat (c-lang-var c-symbol-key) "[ \t\n\r]*:\\([^:]\\|$\\)")) +(c-lang-defvar c-label-key (c-lang-var c-label-key)) -(defconst c-C-extra-toplevel-key (c-paren-re c-C-extra-toplevel-kwds)) -(defconst c-C++-extra-toplevel-key (c-paren-re c-C++-extra-toplevel-kwds)) -(defconst c-IDL-extra-toplevel-key (c-paren-re c-IDL-extra-toplevel-kwds)) - -(defvar c-extra-toplevel-key c-C-extra-toplevel-key) -(make-variable-buffer-local 'c-extra-toplevel-key) - -;; Keywords that can introduce bitfields in the languages that supports that. -(defconst c-C-bitfield-key "\\(char\\|int\\|long\\|signed\\|unsigned\\)") +;; Regexp matching the beginning of a declaration specifier in the +;; region between the header and the body of a declaration. +;; +;; FIXME: This is currently not used in a uniformly; c++-mode and +;; java-mode each have their own ways of using it. +(c-lang-defconst c-opt-decl-spec-key + c++ (concat ":?[ \t\n\r]*\\(virtual[ \t\n\r]+\\)?\\(" + (c-make-keywords-re nil (c-lang-var c-protection-kwds)) + "\\)[ \t\n\r]+" + (c-lang-var c-symbol-key)) + java (c-make-keywords-re t (c-lang-var c-decl-spec-kwds))) +(c-lang-defvar c-opt-decl-spec-key (c-lang-var c-opt-decl-spec-key)) -(defvar c-bitfield-key nil) -(make-variable-buffer-local 'c-bitfield-key) - -;; regexp describing access protection clauses. language specific -(defvar c-access-key nil) -(make-variable-buffer-local 'c-access-key) -(defconst c-C++-access-key - (concat "\\<\\(" c-C++-protection-kwds "\\)\\>[ \t]*:")) -;;(defconst c-IDL-access-key nil) -(defconst c-ObjC-access-key (concat "@" c-protection-key)) -;;(defconst c-Java-access-key nil) -;;(defconst c-Pike-access-key nil) +;; Regexp describing friend declarations classes, or nil in languages +;; that doesn't have such things. +(c-lang-defconst c-opt-friend-key + ;; FIXME: Ought to use c-specifier-kwds or similar, and the template + ;; skipping isn't done properly. + c++ "friend[ \t]+\\|template[ \t]*<.+>[ \t]*friend[ \t]+") +(c-lang-defvar c-opt-friend-key (c-lang-var c-opt-friend-key)) -;; keywords introducing conditional blocks -(defconst c-C-conditional-key nil) -(defconst c-C++-conditional-key nil) -(defconst c-IDL-conditional-key nil) -(defconst c-ObjC-conditional-key nil) -(defconst c-Java-conditional-key nil) -(defconst c-Pike-conditional-key nil) +;; Special regexp to match the start of methods. +(c-lang-defconst c-opt-method-key + objc (concat + "^\\s *[+-]\\s *" + "\\(([^)]*)\\)?" ; return type + ;; \\s- in objc syntax table does not include \n + ;; since it is considered the end of //-comments. + "[ \t\n]*" (c-lang-var c-symbol-key))) +(c-lang-defvar c-opt-method-key (c-lang-var c-opt-method-key)) + +;; Name of functions in cpp expressions that take an identifier as the +;; argument. +(c-lang-defconst c-cpp-defined-fns + (c c++) '("defined") + pike '("defined" "efun" "constant")) -(let ((all-kws "for\\|if\\|do\\|else\\|while\\|switch") - (exc-kws "\\|try\\|catch") - (thr-kws "\\|finally\\|synchronized") - (front "\\<\\(") - (back "\\)\\>[^_]")) - (setq c-C-conditional-key (concat front all-kws back) - c-C++-conditional-key (concat front all-kws exc-kws back) - ;; c-IDL-conditional-key is nil. - c-ObjC-conditional-key c-C-conditional-key - c-Java-conditional-key (concat front all-kws exc-kws thr-kws back) - c-Pike-conditional-key (concat front all-kws "\\|foreach" back))) +;; List of open- and close-chars that makes up a pike-style brace +;; list, i.e. for a `([ ])' list there should be a cons (?\[ . ?\]) in +;; this list. +(c-lang-defconst c-special-brace-lists pike '((?{ . ?}) + (?\[ . ?\]) + (?< . ?>))) +(c-lang-defvar c-special-brace-lists (c-lang-var c-special-brace-lists)) -(defvar c-conditional-key c-C-conditional-key) -(make-variable-buffer-local 'c-conditional-key) +;; Non-nil means K&R style argument declarations are valid. +(c-lang-defconst c-recognize-knr-p c t) +(c-lang-defvar c-recognize-knr-p (c-lang-var c-recognize-knr-p)) + +;; Regexp to match the start of any type of comment. +;; +;; FIXME: Ought to use c-comment-prefix-regexp with some modifications +;; instead of this. +(c-lang-defconst c-comment-start-regexp + (c c++ objc idl pike) "/[/*]" + ;; We need to match all 3 Java style comments + ;; 1) Traditional C block; 2) javadoc /** ...; 3) C++ style + java "/\\(/\\|[*][*]?\\)") +(c-lang-defvar c-comment-start-regexp (c-lang-var c-comment-start-regexp)) -;; keywords describing method definition introductions -(defvar c-method-key nil) -(make-variable-buffer-local 'c-method-key) - -(defconst c-ObjC-method-key - (concat - "^\\s *[+-]\\s *" - "\\(([^)]*)\\)?" ; return type - ;; \\s- in objc syntax table does not include \n - ;; since it is considered the end of //-comments. - "[ \t\n]*" c-symbol-key)) +;; Strings that starts and ends comments inserted with M-; etc. +;; comment-start and comment-end are initialized from these. +(c-lang-defconst comment-start + c "/* " + (c++ objc java idl pike) "// ") +(c-lang-defvar comment-start (c-lang-var comment-start)) +(c-lang-defconst comment-end + c "*/" + (c++ objc java idl pike) "") +(c-lang-defvar comment-end (c-lang-var comment-end)) -;; comment starter definitions for various languages. language specific -(defconst c-C++-comment-start-regexp "/[/*]") -(defconst c-C-comment-start-regexp c-C++-comment-start-regexp) -(defconst c-IDL-comment-start-regexp c-C++-comment-start-regexp) -(defconst c-ObjC-comment-start-regexp c-C++-comment-start-regexp) -(defconst c-Pike-comment-start-regexp c-C++-comment-start-regexp) -;; We need to match all 3 Java style comments -;; 1) Traditional C block; 2) javadoc /** ...; 3) C++ style -(defconst c-Java-comment-start-regexp "/\\(/\\|[*][*]?\\)") -(defvar c-comment-start-regexp c-C++-comment-start-regexp) -(make-variable-buffer-local 'c-comment-start-regexp) +;; Regexp that matches when there is no syntactically significant text +;; before eol. Macros are regarded as syntactically significant text +;; here. +(c-lang-defvar c-syntactic-eol + (concat (concat + ;; Match horizontal whitespace and block comments that + ;; doesn't contain newlines. + "\\(\\s \\|" + (concat "/\\*" + "\\([^*\n\r]\\|\\*[^/\n\r]\\)*" + "\\*/") + "\\)*") + (concat + ;; Match eol (possibly inside a block comment), or the + ;; beginning of a line comment. Note: This has to be + ;; modified for awk where line comments start with '#'. + "\\(" + (concat "\\(" + "/\\*\\([^*\n\r]\\|\\*[^/\n\r]\\)*" + "\\)?" + "$") + "\\|//\\)"))) + +;; Regexp to append to paragraph-start. +(c-lang-defconst paragraph-start + (c c++ objc idl) "$" + java "\\(@[a-zA-Z]+\\>\\|$\\)" ; For Javadoc. + pike "\\(@[a-zA-Z]+\\>\\([^{]\\|$\\)\\|$\\)") ; For Pike refdoc. -;; Regexp describing a switch's case or default label for all languages -(defconst c-switch-label-key "\\(\\(case[( \t]+\\S .*\\)\\|default[ \t]*\\):") -;; Regexp describing any label. -(defconst c-label-key (concat c-symbol-key ":\\([^:]\\|$\\)")) +;; Regexp to append to paragraph-separate. +(c-lang-defconst paragraph-separate + (c c++ objc java idl) "$" + pike (c-lang-var paragraph-start)) + +;; Prefix added to `c-current-comment-prefix' to set +;; `c-opt-in-comment-lc', or nil if it should be nil. +(c-lang-defconst c-in-comment-lc-prefix pike "@[\n\r]\\s *") -;; Regexp describing class inheritance declarations. TBD: this should -;; be language specific, and only makes sense for C++ -(defconst c-inher-key - (concat "\\(\\<static\\>\\s +\\)?" - c-C++-class-key "[ \t]+" c-symbol-key - "\\([ \t]*:[ \t]*\\)\\s *[^;]")) +;; Regexp to match in-comment line continuations, or nil in languages +;; where that isn't applicable. It's assumed that it only might match +;; from and including the last character on a line. Built from +;; *-in-comment-lc-prefix and the current value of +;; c-current-comment-prefix. +(c-lang-defvar c-opt-in-comment-lc + (if (c-lang-var c-in-comment-lc-prefix) + (concat (c-lang-var c-in-comment-lc-prefix) + c-current-comment-prefix))) -;; Regexp describing C++ base classes in a derived class definition. -;; TBD: this should be language specific, and only makes sense for C++ -(defvar c-baseclass-key - (concat - ":?[ \t]*\\(virtual[ \t]+\\)?\\(" - c-protection-key "[ \t]+\\)" c-symbol-key)) -(make-variable-buffer-local 'c-baseclass-key) +(defconst c-init-lang-defvars + ;; Make a lambda of the collected `c-lang-defvar' initializations. + (cc-eval-when-compile + (if (cc-bytecomp-is-compiling) + (byte-compile-lambda `(lambda () ,c-lang-defvar-init-form)) + `(lambda () ,c-lang-defvar-init-form)))) -;; Regexp describing friend declarations in C++ classes. -(defconst c-C++-friend-key - "friend[ \t]+\\|template[ \t]*<.+>[ \t]*friend[ \t]+") +(defun c-init-language-vars () + ;; Initialize all `c-lang-defvar' variables according to + ;; `c-buffer-is-cc-mode'. + (if (not (memq c-buffer-is-cc-mode + '(c-mode c++-mode objc-mode java-mode idl-mode pike-mode))) + (error "Cannot initialize language variables for unknown mode %s" + c-buffer-is-cc-mode)) + (funcall c-init-lang-defvars)) -;; Regexp describing Java inheritance and throws clauses. -(defconst c-Java-special-key "\\(implements\\|extends\\|throws\\)[^_]") - -;; Regexp describing the beginning of a Java top-level definition. +;; Regexp trying to describe the beginning of a Java top-level +;; definition. This is not used by CC Mode, nor is it maintained +;; since it's practically impossible to write a regexp that reliably +;; matches such a construct. Other tools are necessary. (defconst c-Java-defun-prompt-regexp "^[ \t]*\\(\\(\\(public\\|protected\\|private\\|const\\|abstract\\|synchronized\\|final\\|static\\|threadsafe\\|transient\\|native\\|volatile\\)\\s-+\\)*\\(\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*[][_$.a-zA-Z0-9]+\\|[[a-zA-Z]\\)\\s-*\\)\\s-+\\)\\)?\\(\\([[a-zA-Z][][_$.a-zA-Z0-9]*\\s-+\\)\\s-*\\)?\\([_a-zA-Z][^][ \t:;.,{}()=]*\\|\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)\\)\\s-*\\(([^);{}]*)\\)?\\([] \t]*\\)\\(\\s-*\\<throws\\>\\s-*\\(\\([_$a-zA-Z][_$.a-zA-Z0-9]*\\)[, \t\n\r\f]*\\)+\\)?\\s-*") -;; Regexp to append to paragraph-start. -(defvar c-append-paragraph-start "$") -(make-variable-buffer-local 'c-append-paragraph-start) -(defconst c-Java-javadoc-paragraph-start - "\\(@[a-zA-Z]+\\>\\|$\\)") -(defconst c-Pike-pikedoc-paragraph-start - "\\(@[a-zA-Z]+\\>\\([^{]\\|$\\)\\|$\\)") - -;; Regexp to append to paragraph-separate. -(defvar c-append-paragraph-separate "$") -(make-variable-buffer-local 'c-append-paragraph-separate) -(defconst c-Pike-pikedoc-paragraph-separate c-Pike-pikedoc-paragraph-start) - -;; Regexp that starts lambda constructs. -(defvar c-lambda-key nil) -(make-variable-buffer-local 'c-lambda-key) -(defconst c-Pike-lambda-key "\\<lambda\\>") - -;; Regexp that are followed by a statement block in expressions. -(defvar c-inexpr-block-key nil) -(make-variable-buffer-local 'c-inexpr-block-key) -(defconst c-Pike-inexpr-block-key "\\<\\(catch\\|gauge\\)\\>") - -;; Regexp that may be followed by an anonymous class in expressions. -(defvar c-inexpr-class-key nil) -(make-variable-buffer-local 'c-inexpr-class-key) -(defconst c-Java-inexpr-class-key "\\<new\\>") -(defconst c-Pike-inexpr-class-key "\\<class\\>") - -;; List of open- and close-chars that makes up a pike-style brace -;; list, ie for a `([ ])' list there should be a cons (?\[ . ?\]) in -;; this list. -(defvar c-special-brace-lists nil) -(make-variable-buffer-local 'c-special-brace-lists) -(defconst c-Pike-special-brace-lists '((?{ . ?}) - (?\[ . ?\]) - (?< . ?>))) - ;; Syntax tables. (defun c-populate-syntax-table (table) ;; Populate the syntax TABLE - ;; DO NOT TRY TO SET _ (UNDERSCORE) TO WORD CLASS! (modify-syntax-entry ?_ "_" table) (modify-syntax-entry ?\\ "\\" table) (modify-syntax-entry ?+ "." table) @@ -466,15 +667,7 @@ (if c++-mode-syntax-table () (setq c++-mode-syntax-table (make-syntax-table)) - (c-populate-syntax-table c++-mode-syntax-table) - ;; TBD: does it make sense for colon to be symbol class in C++? - ;; I'm not so sure, since c-label-key is busted on lines like: - ;; Foo::bar( i ); - ;; maybe c-label-key should be fixed instead of commenting this out, - ;; but it also bothers me that this only seems appropriate for C++ - ;; and not C. - ;;(modify-syntax-entry ?: "_" c++-mode-syntax-table) - ) + (c-populate-syntax-table c++-mode-syntax-table)) (defvar c++-template-syntax-table nil "A variant of `c++-mode-syntax-table' that defines `<' and `>' as @@ -537,10 +730,6 @@ (defvar c-auto-hungry-string nil) (make-variable-buffer-local 'c-auto-hungry-string) -;; Non-nil means K&R style argument declarations are valid. -(defvar c-recognize-knr-p t) -(make-variable-buffer-local 'c-recognize-knr-p) - (cc-provide 'cc-langs)
--- a/lisp/progmodes/cc-menus.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-menus.el Mon Apr 22 00:35:36 2002 +0000 @@ -25,7 +25,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. @@ -110,9 +110,9 @@ "[^()]*" ; no parentheses before "[^a-zA-Z0-9_:<>~]" ; match any non-identifier char "\\([a-zA-Z_][a-zA-Z0-9_:<>~]*\\)" ; match function name - "[ \t]*(" ; see above, BUT - "[ \t]*\\([^ \t(*][^)]*\\)?)" ; the arg list must not start - "[ \t]*[^ \t;(]" ; with an asterisk or parentheses + "\\([ \t\n]\\|\\\\\n\\)*(" ; see above, BUT the arg list + "\\([ \t\n]\\|\\\\\n\\)*\\([^ \t\n(*][^)]*\\)?)" ; must not start + "\\([ \t\n]\\|\\\\\n\\)*[^ \t\n;(]" ; with an asterisk or parentheses ) 1) ;; Special case for definitions using phony prototype macros like: ;; `int main _PROTO( (int argc,char *argv[]) )'. @@ -139,7 +139,7 @@ "[a-zA-Z0-9_]+" ; class name "\\(<[^>]+>\\)?" ; possibly explicitly specialized "\\)" - "[ \t\n]*[:{]" + "\\([ \t\n]\\|\\\\\n\\)*[:{]" ) 3)) "Imenu generic expression for C++ mode. See `imenu-generic-expression'.")
--- a/lisp/progmodes/cc-mode.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-mode.el Mon Apr 22 00:35:36 2002 +0000 @@ -24,11 +24,11 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. -(defconst c-version "5.28" +(defconst c-version "5.29" "CC Mode version number.") ;; NOTE: Read the commentary below for the right way to submit bug reports! @@ -115,8 +115,14 @@ ;; use: ;; ;; (require 'cc-mode) +;; +;; And in the major mode function: +;; ;; (c-initialize-cc-mode) +(defun c-leave-cc-mode-mode () + (setq c-buffer-is-cc-mode nil)) + ;;;###autoload (defun c-initialize-cc-mode () (setq c-buffer-is-cc-mode t) @@ -131,6 +137,7 @@ ;; Fix obsolete variables. (if (boundp 'c-comment-continuation-stars) (setq c-block-comment-prefix c-comment-continuation-stars)) + (add-hook 'change-major-mode-hook 'c-leave-cc-mode-mode) (setq c-initialization-ok t)) ;; Will try initialization hooks again if they failed. (put 'c-initialize-cc-mode initprop c-initialization-ok))) @@ -154,6 +161,19 @@ (t (error "CC Mode is incompatible with this version of Emacs"))) map)) +(defun c-define-abbrev-table (name defs) + ;; Compatibility wrapper for `define-abbrev' which passes a non-nil + ;; sixth argument for SYSTEM-FLAG in emacsen that support it + ;; (currently only Emacs 21.2). + (define-abbrev-table name nil) + (let ((table (symbol-value name))) + (while defs + (condition-case nil + (apply 'define-abbrev table (append (car defs) '(t))) + (wrong-number-of-arguments + (apply 'define-abbrev table (car defs)))) + (setq defs (cdr defs))))) + (if c-mode-base-map nil ;; TBD: should we even worry about naming this keymap. My vote: no, @@ -181,6 +201,12 @@ (substitute-key-definition 'indent-new-comment-line 'c-indent-new-comment-line c-mode-base-map global-map) + (when (fboundp 'comment-indent-new-line) + ;; indent-new-comment-line has changed name to + ;; comment-indent-new-line in Emacs 21. + (substitute-key-definition 'comment-indent-new-line + 'c-indent-new-comment-line + c-mode-base-map global-map)) ;; RMS says don't make these the default. ;; (define-key c-mode-base-map "\e\C-a" 'c-beginning-of-defun) ;; (define-key c-mode-base-map "\e\C-e" 'c-end-of-defun) @@ -243,7 +269,7 @@ (comment-region (region-beginning) (region-end) '(4)) (c-fn-region-is-active-p)] ["Fill Comment Paragraph" c-fill-paragraph t] - "---" + "----" ["Indent Expression" c-indent-exp (memq (char-after) '(?\( ?\[ ?\{))] ["Indent Line or Region" c-indent-line-or-region t] @@ -252,18 +278,25 @@ ["Forward Conditional" c-forward-conditional t] ["Backward Statement" c-beginning-of-statement t] ["Forward Statement" c-end-of-statement t] - "---" + "----" ["Macro Expand Region" c-macro-expand (c-fn-region-is-active-p)] ["Backslashify" c-backslash-region (c-fn-region-is-active-p)] + "----" + ("Toggle..." + ["Syntactic indentation" c-toggle-syntactic-indentation t] + ["Auto newline" c-toggle-auto-state t] + ["Hungry delete" c-toggle-hungry-state t]) ))) (cons modestr m))) ;; We don't require the outline package, but we configure it a bit anyway. (cc-bytecomp-defvar outline-level) -(defun c-common-init () +(defun c-common-init (mode) ;; Common initializations for all modes. + (setq c-buffer-is-cc-mode mode) + ;; these variables should always be buffer local; they do not affect ;; indentation style. (make-local-variable 'require-final-newline) @@ -284,12 +317,14 @@ (make-local-variable 'adaptive-fill-mode) (make-local-variable 'adaptive-fill-regexp) (make-local-variable 'imenu-generic-expression) ;set in the mode functions + ;; X/Emacs 20 only (and (boundp 'comment-line-break-function) (progn (make-local-variable 'comment-line-break-function) (setq comment-line-break-function 'c-indent-new-comment-line))) + ;; now set their values (setq require-final-newline t parse-sexp-ignore-comments t @@ -301,10 +336,14 @@ comment-column 32 comment-start-skip "/\\*+ *\\|//+ *" comment-multi-line t) + + ;; Fix keyword regexps. + (c-init-language-vars) + ;; now set the mode style based on c-default-style (let ((style (if (stringp c-default-style) c-default-style - (or (cdr (assq major-mode c-default-style)) + (or (cdr (assq mode c-default-style)) (cdr (assq 'other c-default-style)) "gnu")))) ;; Override style variables if `c-old-style-variable-behavior' is @@ -319,56 +358,29 @@ c-indentation-style (not (string-equal c-indentation-style style))))))) - ;; Fix things up for paragraph recognition and filling inside - ;; comments by using c-current-comment-prefix in the relevant - ;; places. We use adaptive filling for this to make it possible to - ;; use filladapt or some other fancy package. - (setq c-current-comment-prefix - (if (listp c-comment-prefix-regexp) - (cdr-safe (or (assoc major-mode c-comment-prefix-regexp) - (assoc 'other c-comment-prefix-regexp))) - c-comment-prefix-regexp)) - (let ((comment-line-prefix - (concat "[ \t]*\\(" c-current-comment-prefix "\\)[ \t]*"))) - (setq paragraph-start (concat comment-line-prefix - c-append-paragraph-start - "\\|" - page-delimiter) - paragraph-separate (concat comment-line-prefix - c-append-paragraph-separate - "\\|" - page-delimiter) - paragraph-ignore-fill-prefix t - adaptive-fill-mode t - adaptive-fill-regexp - (concat comment-line-prefix - (if adaptive-fill-regexp - (concat "\\(" adaptive-fill-regexp "\\)") - ""))) - (when (boundp 'adaptive-fill-first-line-regexp) - ;; XEmacs (20.x) adaptive fill mode doesn't have this. - (make-local-variable 'adaptive-fill-first-line-regexp) - (setq adaptive-fill-first-line-regexp - (concat "\\`" comment-line-prefix - ;; Maybe we should incorporate the old value here, - ;; but then we have to do all sorts of kludges to - ;; deal with the \` and \' it probably contains. - "\\'")))) + (c-setup-paragraph-variables) + ;; we have to do something special for c-offsets-alist so that the ;; buffer local value has its own alist structure. (setq c-offsets-alist (copy-alist c-offsets-alist)) + ;; setup the comment indent variable in a Emacs version portable way - ;; ignore any byte compiler warnings you might get here (make-local-variable 'comment-indent-function) (setq comment-indent-function 'c-comment-indent) + ;; add menus to menubar (easy-menu-add (c-mode-menu mode-name)) + ;; put auto-hungry designators onto minor-mode-alist, but only once (or (assq 'c-auto-hungry-string minor-mode-alist) (setq minor-mode-alist (cons '(c-auto-hungry-string c-auto-hungry-string) minor-mode-alist))) - ) + + ;; Install the function that ensures `c-state-cache' doesn't become + ;; invalid. + (make-local-variable 'after-change-functions) + (add-hook 'after-change-functions 'c-check-state-cache)) (defun c-postprocess-file-styles () "Function that post processes relevant file local variables. @@ -385,10 +397,10 @@ (c-set-style c-file-style)) (and c-file-offsets (mapcar - (lambda (langentry) - (let ((langelem (car langentry)) - (offset (cdr langentry))) - (c-set-offset langelem offset))) + (lambda (langentry) + (let ((langelem (car langentry)) + (offset (cdr langentry))) + (c-set-offset langelem offset))) c-file-offsets))) (add-hook 'hack-local-variables-hook 'c-postprocess-file-styles) @@ -398,9 +410,9 @@ (defvar c-mode-abbrev-table nil "Abbreviation table used in c-mode buffers.") -(define-abbrev-table 'c-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0 t) - ("while" "while" c-electric-continued-statement 0 t))) +(c-define-abbrev-table 'c-mode-abbrev-table + '(("else" "else" c-electric-continued-statement 0) + ("while" "while" c-electric-continued-statement 0))) (defvar c-mode-map () "Keymap used in c-mode buffers.") @@ -431,24 +443,15 @@ Key bindings: \\{c-mode-map}" (interactive) + (kill-all-local-variables) (c-initialize-cc-mode) - (kill-all-local-variables) (set-syntax-table c-mode-syntax-table) (setq major-mode 'c-mode mode-name "C" local-abbrev-table c-mode-abbrev-table abbrev-mode t) (use-local-map c-mode-map) - (c-common-init) - (setq comment-start "/* " - comment-end " */" - c-keywords (c-identifier-re c-C-keywords) - c-conditional-key c-C-conditional-key - c-class-key c-C-class-key - c-baseclass-key nil - c-comment-start-regexp c-C-comment-start-regexp - c-bitfield-key c-C-bitfield-key - ) + (c-common-init 'c-mode) (cc-imenu-init cc-imenu-c-generic-expression) (run-hooks 'c-mode-common-hook) (run-hooks 'c-mode-hook) @@ -459,10 +462,10 @@ (defvar c++-mode-abbrev-table nil "Abbreviation table used in c++-mode buffers.") -(define-abbrev-table 'c++-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0 t) - ("while" "while" c-electric-continued-statement 0 t) - ("catch" "catch" c-electric-continued-statement 0 t))) +(c-define-abbrev-table 'c++-mode-abbrev-table + '(("else" "else" c-electric-continued-statement 0) + ("while" "while" c-electric-continued-statement 0) + ("catch" "catch" c-electric-continued-statement 0))) (defvar c++-mode-map () "Keymap used in c++-mode buffers.") @@ -496,26 +499,15 @@ Key bindings: \\{c++-mode-map}" (interactive) + (kill-all-local-variables) (c-initialize-cc-mode) - (kill-all-local-variables) (set-syntax-table c++-mode-syntax-table) (setq major-mode 'c++-mode mode-name "C++" local-abbrev-table c++-mode-abbrev-table abbrev-mode t) (use-local-map c++-mode-map) - (c-common-init) - (setq comment-start "// " - comment-end "" - c-keywords (c-identifier-re c-C++-keywords) - c-conditional-key c-C++-conditional-key - c-comment-start-regexp c-C++-comment-start-regexp - c-class-key c-C++-class-key - c-extra-toplevel-key c-C++-extra-toplevel-key - c-access-key c-C++-access-key - c-recognize-knr-p nil - c-bitfield-key c-C-bitfield-key - ) + (c-common-init 'c++-mode) (cc-imenu-init cc-imenu-c++-generic-expression) (run-hooks 'c-mode-common-hook) (run-hooks 'c++-mode-hook) @@ -526,9 +518,9 @@ (defvar objc-mode-abbrev-table nil "Abbreviation table used in objc-mode buffers.") -(define-abbrev-table 'objc-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0 t) - ("while" "while" c-electric-continued-statement 0 t))) +(c-define-abbrev-table 'objc-mode-abbrev-table + '(("else" "else" c-electric-continued-statement 0) + ("while" "while" c-electric-continued-statement 0))) (defvar objc-mode-map () "Keymap used in objc-mode buffers.") @@ -559,25 +551,15 @@ Key bindings: \\{objc-mode-map}" (interactive) + (kill-all-local-variables) (c-initialize-cc-mode) - (kill-all-local-variables) (set-syntax-table objc-mode-syntax-table) (setq major-mode 'objc-mode mode-name "ObjC" local-abbrev-table objc-mode-abbrev-table abbrev-mode t) (use-local-map objc-mode-map) - (c-common-init) - (setq comment-start "// " - comment-end "" - c-keywords (c-identifier-re c-ObjC-keywords) - c-conditional-key c-ObjC-conditional-key - c-comment-start-regexp c-ObjC-comment-start-regexp - c-class-key c-ObjC-class-key - c-baseclass-key nil - c-access-key c-ObjC-access-key - c-method-key c-ObjC-method-key - ) + (c-common-init 'objc-mode) (cc-imenu-init cc-imenu-objc-generic-expression) (run-hooks 'c-mode-common-hook) (run-hooks 'objc-mode-hook) @@ -588,11 +570,11 @@ (defvar java-mode-abbrev-table nil "Abbreviation table used in java-mode buffers.") -(define-abbrev-table 'java-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0 t) - ("while" "while" c-electric-continued-statement 0 t) - ("catch" "catch" c-electric-continued-statement 0 t) - ("finally" "finally" c-electric-continued-statement 0 t))) +(c-define-abbrev-table 'java-mode-abbrev-table + '(("else" "else" c-electric-continued-statement 0) + ("while" "while" c-electric-continued-statement 0) + ("catch" "catch" c-electric-continued-statement 0) + ("finally" "finally" c-electric-continued-statement 0))) (defvar java-mode-map () "Keymap used in java-mode buffers.") @@ -625,28 +607,15 @@ Key bindings: \\{java-mode-map}" (interactive) + (kill-all-local-variables) (c-initialize-cc-mode) - (kill-all-local-variables) (set-syntax-table java-mode-syntax-table) (setq major-mode 'java-mode mode-name "Java" local-abbrev-table java-mode-abbrev-table - abbrev-mode t - c-append-paragraph-start c-Java-javadoc-paragraph-start) + abbrev-mode t) (use-local-map java-mode-map) - (c-common-init) - (setq comment-start "// " - comment-end "" - c-keywords (c-identifier-re c-Java-keywords) - c-conditional-key c-Java-conditional-key - c-comment-start-regexp c-Java-comment-start-regexp - c-class-key c-Java-class-key - c-method-key nil - c-baseclass-key nil - c-recognize-knr-p nil - c-inexpr-class-key c-Java-inexpr-class-key - ;defun-prompt-regexp c-Java-defun-prompt-regexp - ) + (c-common-init 'java-mode) (cc-imenu-init cc-imenu-java-generic-expression) (run-hooks 'c-mode-common-hook) (run-hooks 'java-mode-hook) @@ -657,7 +626,7 @@ (defvar idl-mode-abbrev-table nil "Abbreviation table used in idl-mode buffers.") -(define-abbrev-table 'idl-mode-abbrev-table ()) +(c-define-abbrev-table 'idl-mode-abbrev-table nil) (defvar idl-mode-map () "Keymap used in idl-mode buffers.") @@ -688,25 +657,14 @@ Key bindings: \\{idl-mode-map}" (interactive) + (kill-all-local-variables) (c-initialize-cc-mode) - (kill-all-local-variables) (set-syntax-table idl-mode-syntax-table) (setq major-mode 'idl-mode mode-name "IDL" local-abbrev-table idl-mode-abbrev-table) (use-local-map idl-mode-map) - (c-common-init) - (setq comment-start "// " - comment-end "" - c-keywords (c-identifier-re c-IDL-keywords) - c-conditional-key c-IDL-conditional-key - c-comment-start-regexp c-IDL-comment-start-regexp - c-class-key c-IDL-class-key - c-method-key nil - c-baseclass-key nil - c-extra-toplevel-key c-IDL-extra-toplevel-key - c-recognize-knr-p nil - ) + (c-common-init 'idl-mode) ;;(cc-imenu-init cc-imenu-idl-generic-expression) ;FIXME (run-hooks 'c-mode-common-hook) (run-hooks 'idl-mode-hook) @@ -717,9 +675,9 @@ (defvar pike-mode-abbrev-table nil "Abbreviation table used in pike-mode buffers.") -(define-abbrev-table 'pike-mode-abbrev-table - '(("else" "else" c-electric-continued-statement 0 t) - ("while" "while" c-electric-continued-statement 0 t))) +(c-define-abbrev-table 'pike-mode-abbrev-table + '(("else" "else" c-electric-continued-statement 0) + ("while" "while" c-electric-continued-statement 0))) (defvar pike-mode-map () "Keymap used in pike-mode buffers.") @@ -735,8 +693,8 @@ ;;;###autoload (defun pike-mode () "Major mode for editing Pike code. -To submit a problem report, enter `\\[c-submit-bug-report]' from an -idl-mode buffer. This automatically sets up a mail buffer with +To submit a problem report, enter `\\[c-submit-bug-report]' from a +pike-mode buffer. This automatically sets up a mail buffer with version information already added. You just need to add a description of the problem, including a reproducible test case, and send the message. @@ -750,80 +708,26 @@ Key bindings: \\{pike-mode-map}" (interactive) + (kill-all-local-variables) (c-initialize-cc-mode) - (kill-all-local-variables) (set-syntax-table pike-mode-syntax-table) (setq major-mode 'pike-mode mode-name "Pike" local-abbrev-table pike-mode-abbrev-table - abbrev-mode t - c-append-paragraph-start c-Pike-pikedoc-paragraph-start - c-append-paragraph-separate c-Pike-pikedoc-paragraph-separate) + abbrev-mode t) (use-local-map pike-mode-map) - (c-common-init) - (setq comment-start "// " - comment-end "" - c-keywords (c-identifier-re c-Pike-keywords) - c-conditional-key c-Pike-conditional-key - c-comment-start-regexp c-Pike-comment-start-regexp - c-class-key c-Pike-class-key - c-method-key nil - c-baseclass-key nil - c-recognize-knr-p nil - c-lambda-key c-Pike-lambda-key - c-inexpr-block-key c-Pike-inexpr-block-key - c-inexpr-class-key c-Pike-inexpr-class-key - c-special-brace-lists c-Pike-special-brace-lists - ) + (c-common-init 'pike-mode) ;;(cc-imenu-init cc-imenu-pike-generic-expression) ;FIXME (run-hooks 'c-mode-common-hook) (run-hooks 'pike-mode-hook) (c-update-modeline)) -;; Helper for setting up Filladapt mode. It's not used by CC Mode itself. - -(cc-bytecomp-defvar filladapt-token-table) -(cc-bytecomp-defvar filladapt-token-match-table) -(cc-bytecomp-defvar filladapt-token-conversion-table) - -(defun c-setup-filladapt () - "Convenience function to configure Kyle E. Jones' Filladapt mode for -CC Mode by making sure the proper entries are present on -`filladapt-token-table', `filladapt-token-match-table', and -`filladapt-token-conversion-table'. This is intended to be used on -`c-mode-common-hook' or similar." - ;; This function is intended to be used explicitly by the end user - ;; only. - ;; - ;; The default configuration already handles C++ comments, but we - ;; need to add handling of C block comments. A new filladapt token - ;; `c-comment' is added for that. - (let (p) - (setq p filladapt-token-table) - (while (and p (not (eq (car-safe (cdr-safe (car-safe p))) 'c-comment))) - (setq p (cdr-safe p))) - (if p - (setcar (car p) c-current-comment-prefix) - (setq filladapt-token-table - (append (list (car filladapt-token-table) - (list c-current-comment-prefix 'c-comment)) - (cdr filladapt-token-table))))) - (unless (assq 'c-comment filladapt-token-match-table) - (setq filladapt-token-match-table - (append '((c-comment c-comment)) - filladapt-token-match-table))) - (unless (assq 'c-comment filladapt-token-conversion-table) - (setq filladapt-token-conversion-table - (append '((c-comment . exact)) - filladapt-token-conversion-table)))) - - ;; bug reporting (defconst c-mode-help-address - "bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org" - "Addresses for CC Mode bug reports.") + "bug-cc-mode@gnu.org" + "Address(es) for CC Mode bug reports.") (defun c-version () "Echo the current version of CC Mode in the minibuffer." @@ -892,9 +796,9 @@ defun-prompt-regexp)) vars) (lambda () - (run-hooks 'c-prepare-bug-report-hooks) - (insert (format "Buffer Style: %s\n\nc-emacs-features: %s\n" - style c-features))))))) + (run-hooks 'c-prepare-bug-report-hooks) + (insert (format "Buffer Style: %s\n\nc-emacs-features: %s\n" + style c-features))))))) (cc-provide 'cc-mode)
--- a/lisp/progmodes/cc-styles.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-styles.el Mon Apr 22 00:35:36 2002 +0000 @@ -25,7 +25,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. @@ -42,7 +42,14 @@ (require 'cc-bytecomp))) (cc-require 'cc-defs) +(cc-require 'cc-langs) (cc-require 'cc-vars) +(cc-require 'cc-align) +;; cc-align is only indirectly required: Styles added with +;; `c-add-style' often contains references to functions defined there. + +;; Silence the compiler. +(cc-bytecomp-defvar adaptive-fill-first-line-regexp) ; Emacs ;; Warning: don't eval-defun this constant or you'll break style inheritance. @@ -53,6 +60,7 @@ (c-offsets-alist . ((statement-block-intro . +) (knr-argdecl-intro . 5) (substatement-open . +) + (substatement-label . 0) (label . 0) (statement-case-open . +) (statement-cont . +) @@ -70,6 +78,7 @@ (c-offsets-alist . ((statement-block-intro . +) (knr-argdecl-intro . 0) (substatement-open . 0) + (substatement-label . 0) (label . 0) (statement-cont . +) )) @@ -80,6 +89,7 @@ (c-offsets-alist . ((statement-block-intro . +) (knr-argdecl-intro . +) (substatement-open . 0) + (substatement-label . 0) (label . 0) (statement-cont . +) (inline-open . 0) @@ -91,6 +101,7 @@ (c-comment-only-line-offset . 0) (c-offsets-alist . ((statement-block-intro . +) (substatement-open . 0) + (substatement-label . 0) (label . 0) (statement-cont . +) )) @@ -102,6 +113,7 @@ (label . 0) (statement-cont . +) (substatement-open . +) + (substatement-label . +) (block-open . +) (statement-block-intro . c-lineup-whitesmith-in-block) (block-close . c-lineup-whitesmith-in-block) @@ -130,8 +142,7 @@ (c-comment-only-line-offset . 0) (c-hanging-braces-alist . ((substatement-open before after))) (c-offsets-alist . ((topmost-intro . 0) - (topmost-intro-cont . 0) - (substatement . +) + (substatement . +) (substatement-open . 0) (case-label . +) (access-label . -) @@ -150,6 +161,7 @@ (c-offsets-alist . ((statement-block-intro . +) (knr-argdecl-intro . 0) (substatement-open . 0) + (substatement-label . 0) (label . 0) (statement-cont . +) )) @@ -180,7 +192,8 @@ (topmost-intro-cont . +) (statement-block-intro . +) (knr-argdecl-intro . 5) - (substatement-open . +) + (substatement-open . +) + (substatement-label . +) (label . +) (statement-case-open . +) (statement-cont . +) @@ -225,7 +238,6 @@ modify existing styles -- you should create a new style that inherits the existing style.") - ;; Functions that manipulate styles (defun c-set-style-1 (conscell dont-override) @@ -257,29 +269,33 @@ (mapcar add-func (if dont-override (reverse val) val)) (funcall add-func val)))) ;; all other variables - (t (if (or (not dont-override) - (not (memq attr c-style-variables)) - (eq (symbol-value attr) 'set-from-style)) - (set attr val)))) - )) + (t (when (or (not dont-override) + (not (memq attr c-style-variables)) + (eq (symbol-value attr) 'set-from-style)) + (set attr val) + ;; Must update a number of other variables if + ;; c-comment-prefix-regexp is set. + (if (eq attr 'c-comment-prefix-regexp) + (c-setup-paragraph-variables))))))) (defun c-get-style-variables (style basestyles) ;; Return all variables in a style by resolving inheritances. - (let ((vars (cdr (or (assoc (downcase style) c-style-alist) - (assoc (upcase style) c-style-alist) - (assoc style c-style-alist) - (error "Undefined style: %s" style))))) - (if (string-equal style "user") - (copy-alist vars) - (let ((base (if (stringp (car vars)) - (prog1 - (downcase (car vars)) - (setq vars (cdr vars))) - "user"))) + (if (not style) + (copy-alist c-fallback-style) + (let ((vars (cdr (or (assoc (downcase style) c-style-alist) + (assoc (upcase style) c-style-alist) + (assoc style c-style-alist) + (progn + (c-benign-error "Undefined style: %s" style) + nil))))) + (let ((base (and (stringp (car-safe vars)) + (prog1 + (downcase (car vars)) + (setq vars (cdr vars)))))) (if (memq base basestyles) - (error "Style loop detected: %s in %s" base basestyles)) - (nconc (c-get-style-variables base (cons base basestyles)) - (copy-alist vars)))))) + (c-benign-error "Style loop detected: %s in %s" base basestyles) + (nconc (c-get-style-variables base (cons base basestyles)) + (copy-alist vars))))))) (defvar c-set-style-history nil) @@ -302,15 +318,33 @@ Obviously, specifying DONT-OVERRIDE is useful mainly when the initial style is chosen for a CC Mode buffer by a major mode. Since this is done internally by CC Mode, there's hardly ever a reason to use it." - (interactive (list (let ((completion-ignore-case t) - (prompt (format "Which %s indentation style? " - mode-name))) - (completing-read prompt c-style-alist nil t - nil - 'c-set-style-history - c-indentation-style)))) + (interactive + (list (let ((completion-ignore-case t) + (prompt (format "Which %s indentation style? " + mode-name))) + (condition-case nil + ;; The default argument is preferred over + ;; initial-contents, but it only exists in Emacs >= 20 + ;; and XEmacs >= 21. + (completing-read prompt c-style-alist nil t nil + 'c-set-style-history + c-indentation-style) + (wrong-number-of-arguments + ;; If the call above failed, we fall back to the old way + ;; of specifying the default value. + (completing-read prompt c-style-alist nil t + (cons c-indentation-style 0) + 'c-set-style-history)))))) (c-initialize-builtin-style) (let ((vars (c-get-style-variables stylename nil))) + (unless dont-override + ;; Since we always add to c-special-indent-hook we must reset it + ;; first, or else the hooks from the preceding style will + ;; remain. This is not necessary for c-offsets-alist, since + ;; c-get-style-variables contains every valid offset type in the + ;; fallback entry. + (setq c-special-indent-hook + (default-value 'c-special-indent-hook))) (mapcar (lambda (elem) (c-set-style-1 elem dont-override)) ;; Need to go through the variables backwards when we @@ -343,7 +377,6 @@ (setq c-style-alist (cons (cons style descrip) c-style-alist)))) (and set-p (c-set-style style))) - (defvar c-read-offset-history nil) @@ -359,35 +392,24 @@ "or [+,-,++,--,*,/] " defstr)) (prompt (concat symname " offset " defstr)) - offset input interned raw) + (keymap (make-sparse-keymap)) + (minibuffer-completion-table obarray) + (minibuffer-completion-predicate 'fboundp) + offset input) + ;; In principle completing-read is used here, but SPC is unbound + ;; to make it less annoying to enter lists. + (set-keymap-parent keymap minibuffer-local-completion-map) + (define-key keymap " " 'self-insert-command) (while (not offset) - (setq input (completing-read prompt obarray 'fboundp nil nil - 'c-read-offset-history) - offset (cond ((string-equal "" input) oldoff) ; default - ((string-equal "+" input) '+) - ((string-equal "-" input) '-) - ((string-equal "++" input) '++) - ((string-equal "--" input) '--) - ((string-equal "*" input) '*) - ((string-equal "/" input) '/) - ((string-match "^-?[0-9]+$" input) - (string-to-int input)) - ;; a symbol with a function binding - ((fboundp (setq interned (intern input))) - interned) - ;; a symbol with variable binding - ((boundp interned) interned) - ;; a lambda function or a vector - ((progn - (c-safe (setq raw (read input))) - (or (functionp raw) - (vectorp raw))) - raw) - ;; error, but don't signal one, keep trying - ;; to read an input value - (t (ding) - (setq prompt errmsg) - nil)))) + (setq input (read-from-minibuffer prompt nil keymap t + 'c-read-offset-history + (format "%s" oldoff))) + (if (c-valid-offset input) + (setq offset input) + ;; error, but don't signal one, keep trying + ;; to read an input value + (ding) + (setq prompt errmsg))) offset)) ;;;###autoload @@ -418,18 +440,94 @@ (offset (c-read-offset langelem))) (list langelem offset current-prefix-arg))) ;; sanity check offset - (unless (c-valid-offset offset) - (error (concat "Offset must be int, func, var, vector, list, " - "or in [+,-,++,--,*,/]: %s") - offset)) - (let ((entry (assq symbol c-offsets-alist))) - (if entry - (setcdr entry offset) - (if (assq symbol (get 'c-offsets-alist 'c-stylevar-fallback)) - (setq c-offsets-alist (cons (cons symbol offset) c-offsets-alist)) - (error "%s is not a valid syntactic symbol" symbol)))) + (if (c-valid-offset offset) + (let ((entry (assq symbol c-offsets-alist))) + (if entry + (setcdr entry offset) + (if (assq symbol (get 'c-offsets-alist 'c-stylevar-fallback)) + (setq c-offsets-alist (cons (cons symbol offset) + c-offsets-alist)) + (c-benign-error "%s is not a valid syntactic symbol" symbol)))) + (c-benign-error "Invalid indentation setting for symbol %s: %s" + symbol offset)) (c-keep-region-active)) + +(defun c-setup-paragraph-variables () + "Fix things up for paragraph recognition and filling inside comments by +incorporating the value of `c-comment-prefix-regexp' in the relevant +variables." + (setq c-current-comment-prefix + (if (listp c-comment-prefix-regexp) + (cdr-safe (or (assoc major-mode c-comment-prefix-regexp) + (assoc 'other c-comment-prefix-regexp))) + c-comment-prefix-regexp)) + (let ((comment-line-prefix + (concat "[ \t]*\\(" c-current-comment-prefix "\\)[ \t]*"))) + (setq paragraph-start (concat comment-line-prefix + (c-lang-var paragraph-start) + "\\|" + page-delimiter) + paragraph-separate (concat comment-line-prefix + (c-lang-var paragraph-separate) + "\\|" + page-delimiter) + paragraph-ignore-fill-prefix t + adaptive-fill-mode t + adaptive-fill-regexp + (concat comment-line-prefix + (if (default-value 'adaptive-fill-regexp) + (concat "\\(" + (default-value 'adaptive-fill-regexp) + "\\)") + ""))) + (when (boundp 'adaptive-fill-first-line-regexp) + ;; XEmacs (20.x) adaptive fill mode doesn't have this. + (make-local-variable 'adaptive-fill-first-line-regexp) + (setq adaptive-fill-first-line-regexp + (concat "\\`" comment-line-prefix + ;; Maybe we should incorporate the old value here, + ;; but then we have to do all sorts of kludges to + ;; deal with the \` and \' it probably contains. + "\\'"))))) + + +;; Helper for setting up Filladapt mode. It's not used by CC Mode itself. + +(cc-bytecomp-defvar filladapt-token-table) +(cc-bytecomp-defvar filladapt-token-match-table) +(cc-bytecomp-defvar filladapt-token-conversion-table) + +(defun c-setup-filladapt () + "Convenience function to configure Kyle E. Jones' Filladapt mode for +CC Mode by making sure the proper entries are present on +`filladapt-token-table', `filladapt-token-match-table', and +`filladapt-token-conversion-table'. This is intended to be used on +`c-mode-common-hook' or similar." + ;; This function is intended to be used explicitly by the end user + ;; only. + ;; + ;; The default configuration already handles C++ comments, but we + ;; need to add handling of C block comments. A new filladapt token + ;; `c-comment' is added for that. + (let (p) + (setq p filladapt-token-table) + (while (and p (not (eq (car-safe (cdr-safe (car-safe p))) 'c-comment))) + (setq p (cdr-safe p))) + (if p + (setcar (car p) c-current-comment-prefix) + (setq filladapt-token-table + (append (list (car filladapt-token-table) + (list c-current-comment-prefix 'c-comment)) + (cdr filladapt-token-table))))) + (unless (assq 'c-comment filladapt-token-match-table) + (setq filladapt-token-match-table + (append '((c-comment c-comment)) + filladapt-token-match-table))) + (unless (assq 'c-comment filladapt-token-conversion-table) + (setq filladapt-token-conversion-table + (append '((c-comment . exact)) + filladapt-token-conversion-table)))) (defun c-initialize-builtin-style () @@ -440,31 +538,22 @@ (unless (get 'c-initialize-builtin-style 'is-run) (put 'c-initialize-builtin-style 'is-run t) ;;(c-initialize-cc-mode) - (or (assoc "cc-mode" c-style-alist) - (assoc "user" c-style-alist) - (progn - (c-add-style - "user" - (mapcar - (lambda (var) - (let ((val (symbol-value var))) - (cons var - (cond ((eq var 'c-offsets-alist) - (mapcar - (lambda (langentry) - (setq langentry (or (assq (car langentry) val) - langentry)) - (cons (car langentry) - (cdr langentry))) - (get var 'c-stylevar-fallback))) - ((eq var 'c-special-indent-hook) - val) - (t - (if (eq val 'set-from-style) - (get var 'c-stylevar-fallback) - val)))))) - c-style-variables)) - (c-add-style "cc-mode" '("user")))) + (unless (assoc "user" c-style-alist) + (let ((vars c-style-variables) var val uservars) + (while vars + (setq var (car vars) + val (symbol-value var) + vars (cdr vars)) + (cond ((eq var 'c-offsets-alist) + (or (null val) + (setq uservars (cons (cons 'c-offsets-alist val) + uservars)))) + ((not (eq val 'set-from-style)) + (setq uservars (cons (cons var val) + uservars))))) + (c-add-style "user" uservars))) + (unless (assoc "cc-mode" c-style-alist) + (c-add-style "cc-mode" '("user"))) (if c-style-variables-are-local-p (c-make-styles-buffer-local))))
--- a/lisp/progmodes/cc-vars.el Sun Apr 21 18:21:47 2002 +0000 +++ b/lisp/progmodes/cc-vars.el Mon Apr 22 00:35:36 2002 +0000 @@ -25,7 +25,7 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to +;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. @@ -66,8 +66,20 @@ (cc-bytecomp-defmacro define-widget (name class doc &rest args)) (cc-bytecomp-defmacro defcustom (symbol value doc &rest args) `(defvar ,symbol ,value ,doc)) + (cc-bytecomp-defmacro custom-declare-variable (symbol value doc + &rest args) + `(defvar ,(eval symbol) ,(eval value) ,doc)) nil)))) +(cc-eval-when-compile + ;; Need the function form of `backquote', which isn't standardized + ;; between Emacsen. It's called `bq-process' in XEmacs, and + ;; `backquote-process' in Emacs. `backquote-process' returns a + ;; slightly more convoluted form, so let `bq-process' be the norm. + (if (fboundp 'backquote-process) + (cc-bytecomp-defmacro bq-process (form) + `(cdr (backquote-process ,form))))) + ;;; Helpers @@ -103,41 +115,56 @@ (match-string 0 value))) value))) +(define-widget 'c-integer-or-nil 'sexp + "An integer or the value nil." + :value nil + :tag "Optional integer" + :match (lambda (widget value) (or (integerp value) (null value)))) + (defvar c-style-variables - '(c-basic-offset c-comment-only-line-offset c-block-comment-prefix + '(c-basic-offset c-comment-only-line-offset c-indent-comment-alist + c-indent-comments-syntactically-p c-block-comment-prefix c-comment-prefix-regexp c-cleanup-list c-hanging-braces-alist c-hanging-colons-alist c-hanging-semi&comma-criteria c-backslash-column - c-special-indent-hook c-label-minimum-indentation c-offsets-alist) + c-backslash-max-column c-special-indent-hook c-label-minimum-indentation + c-offsets-alist) "List of the style variables.") +(defvar c-fallback-style nil) + +(defsubst c-set-stylevar-fallback (name val) + (put name 'c-stylevar-fallback val) + (setq c-fallback-style (cons (cons name val) c-fallback-style))) + (defmacro defcustom-c-stylevar (name val doc &rest args) "Defines a style variable." - `(progn - (put ',name 'c-stylevar-fallback ,val) - (defcustom ,name 'set-from-style - ,(concat doc " + `(let ((-value- ,val)) + (c-set-stylevar-fallback ',name -value-) + (custom-declare-variable + ',name ''set-from-style + ,(concat doc " This is a style variable. Apart from the valid values described above, it can be set to the symbol `set-from-style'. In that case, it takes its value from the style system (see `c-default-style' and -`c-styles-alist') when a CC Mode buffer is initialized. Otherwise, +`c-style-alist') when a CC Mode buffer is initialized. Otherwise, the value set here overrides the style system (there is a variable `c-old-style-variable-behavior' that changes this, though).") - ,@(plist-put - args ':type - `'(radio - (const :tag "Use style settings" - set-from-style) - ,(let ((type (eval (plist-get args ':type)))) - (unless (consp type) - (setq type (list type))) - (unless (c-safe (plist-get (cdr type) ':value)) - (setcdr type (append `(:value ,val) - (cdr type)))) - (unless (c-safe (plist-get (cdr type) ':tag)) - (setcdr type (append '(:tag "Override style settings") - (cdr type)))) - type)))))) + ,@(plist-put + args ':type + `(` (radio + (const :tag "Use style settings" + set-from-style) + ,(, (let ((type (eval (plist-get args ':type)))) + (unless (consp type) + (setq type (list type))) + (unless (c-safe (plist-get (cdr type) ':value)) + (setcdr type (append '(:value (, -value-)) + (cdr type)))) + (unless (c-safe (plist-get (cdr type) ':tag)) + (setcdr type (append '(:tag "Override style settings") + (cdr type)))) + (bq-process type))))))))) (defun c-valid-offset (offset) "Return non-nil iff OFFSET is a valid offset for a syntactic symbol. @@ -149,11 +176,13 @@ (eq offset '*) (eq offset '/) (integerp offset) - (vectorp offset) (functionp offset) (and (symbolp offset) (or (boundp offset) (fboundp offset))) + (and (vectorp offset) + (= (length offset) 1) + (integerp (elt offset 0))) (progn (while (and (consp offset) (c-valid-offset (car offset))) @@ -182,6 +211,18 @@ :type 'boolean :group 'c) +(defcustom c-report-syntactic-errors nil + "*If non-nil, certain syntactic errors are reported with a ding +and a message, for example when an \"else\" is indented for which +there's no corresponding \"if\". + +Note however that CC Mode doesn't make any special effort to check for +syntactic errors; that's the job of the compiler. The reason it can +report cases like the one above is that it can't find the correct +anchoring position to indent the line in that case." + :type 'boolean + :group 'c) + (defcustom-c-stylevar c-basic-offset 4 "*Amount of basic offset used by + and - symbols in `c-offsets-alist'. Also used as the indentation step when `c-syntactic-indentation' is @@ -206,11 +247,9 @@ Note: indentation of lines containing only comments is also controlled by the `c-comment-only-line-offset' variable." :type '(radio - :extra-offset 8 - :format "%{C Tab Always Indent%}:\n The TAB key:\n%v" - (const :tag "always indents, never inserts TAB" t) - (const :tag "indents in left margin, otherwise inserts TAB" nil) - (other :tag "inserts TAB in literals, otherwise indent" other)) + (const :tag "TAB key always indents, never inserts TAB" t) + (const :tag "TAB key indents in left margin, otherwise inserts TAB" nil) + (other :tag "TAB key inserts TAB in literals, otherwise indents" other)) :group 'c) (defcustom c-insert-tab-function 'insert-tab @@ -223,17 +262,35 @@ (defcustom c-syntactic-indentation t "*Whether the indentation should be controlled by the syntactic context. -If t, the indentation functions indents according to the syntactic +If t, the indentation functions indent according to the syntactic context, using the style settings specified by `c-offsets-alist'. If nil, every line is just indented to the same level as the previous -one, and the \\[c-indent-command] command adjusts the indentation in steps -specified by `c-basic-offset'. The indentation style have no effect -in this mode, nor any of the indentation associated variables, +one, and the \\[c-indent-command] command adjusts the indentation in +steps specified by `c-basic-offset'. The indentation style has no +effect in this mode, nor any of the indentation associated variables, e.g. `c-special-indent-hook'." :type 'boolean :group 'c) +(defcustom c-syntactic-indentation-in-macros t + "*Enable syntactic analysis inside macros. +If this is nil, all lines inside macro definitions are analyzed as +`cpp-macro-cont'. Otherwise they are analyzed syntactically, just +like normal code, and `cpp-define-intro' is used to create the +additional indentation of the bodies of \"#define\" macros. + +Having this enabled simplifies editing of large multiline macros, but +it might complicate editing if CC Mode doesn't recognize the context +of the macro content. The default context inside the macro is the +same as the top level, so if it contains \"bare\" statements they +might be indented wrongly, although there are special cases that +handles this in most cases. If this problem occurs, it's usually +countered easily by surrounding the statements by a block \(or even +better with the \"do { ... } while \(0)\" trick)." + :type 'boolean + :group 'c) + (defcustom-c-stylevar c-comment-only-line-offset 0 "*Extra offset for line which contains only the start of a comment. Can contain an integer or a cons cell of the form: @@ -251,12 +308,90 @@ :type '(choice (integer :tag "Non-anchored offset" 0) (cons :tag "Non-anchored & anchored offset" :value (0 . 0) - :extra-offset 8 (integer :tag "Non-anchored offset") (integer :tag "Anchored offset"))) :group 'c) -(defcustom c-indent-comments-syntactically-p nil +(defcustom-c-stylevar c-indent-comment-alist + '((anchored-comment . (column . 0)) + (end-block . (space . 1)) + (cpp-end-block . (space . 2))) + "*Specifies how \\[indent-for-comment] calculates the comment start column. +This is an association list that contains entries of the form: + + (LINE-TYPE . INDENT-SPEC) + +LINE-TYPE specifies a type of line as described below, and INDENT-SPEC +says what \\[indent-for-comment] should do when used on that type of line. + +The recognized values for LINE-TYPE are: + + empty-line -- The line is empty. + anchored-comment -- The line contains a comment that starts in column 0. + end-block -- The line contains a solitary block closing brace. + cpp-end-block -- The line contains a preprocessor directive that + closes a block, i.e. either \"#endif\" or \"#else\". + other -- The line does not match any other entry + currently on the list. + +An INDENT-SPEC is a cons cell of the form: + + (ACTION . VALUE) + +ACTION says how \\[indent-for-comment] should align the comment, and +VALUE is interpreted depending on ACTION. ACTION can be any of the +following: + + space -- Put VALUE spaces between the end of the line and the start + of the comment. + column -- Start the comment at the column VALUE. If the line is + longer than that, the comment is preceded by a single + space. If VALUE is nil, `comment-column' is used. + align -- Align the comment with one on the previous line, if there + is any. If the line is too long, the comment is preceded + by a single space. If there isn't a comment start on the + previous line, the behavior is specified by VALUE, which + in turn is interpreted as an INDENT-SPEC. + +If a LINE-TYPE is missing, then \\[indent-for-comment] indents the comment +according to `comment-column'. + +Note that a non-nil value on `c-indent-comments-syntactically-p' +overrides this variable, so empty lines are indentented syntactically +in that case, i.e. as if \\[c-indent-command] was used instead." + :type + (let ((space '(cons :tag "space" + :format "%v" + :value (space . 1) + (const :format "space " space) + (integer :format "%v"))) + (column '(cons :tag "column" + :format "%v" + (const :format "column " column) + (c-integer-or-nil :format "%v")))) + `(set ,@(mapcar + (lambda (elt) + `(cons :format "%v" + (c-const-symbol :format "%v: " + :size 20 + :value ,elt) + (choice + :format "%[Choice%] %v" + :value (column . nil) + ,space + ,column + (cons :tag "align" + :format "%v" + (const :format "align " align) + (choice + :format "%[Choice%] %v" + :value (column . nil) + ,space + ,column))))) + '(empty-line anchored-comment end-block cpp-end-block other)))) + :group 'c) + +(defcustom-c-stylevar c-indent-comments-syntactically-p nil "*Specifies how \\[indent-for-comment] should handle comment-only lines. When this variable is non-nil, comment-only lines are indented according to syntactic analysis via `c-offsets-alist'. Otherwise, the @@ -291,11 +426,7 @@ more lines for the first time; otherwise the appropriate prefix is adapted from the comment. This variable is not used for C++ line style comments." - ;; We need to specify a :value to prevent `defcustom-c-stylevar' from - ;; giving it an invalid value. Perhaps `defcustom-c-stylevar' - ;; should evaluate the value first? - ;; Per Abrahamsen <abraham@dina.kvl.dk> 2002-04-06. - :type '(string :value "* ") + :type 'string :group 'c) (defcustom-c-stylevar c-comment-prefix-regexp @@ -319,9 +450,17 @@ which is sometimes inserted by CC Mode inside block comments. It should not match any surrounding whitespace. -Note that CC Mode modifies other variables from this one at mode -initialization, so you will need to do \\[c-mode] (or whatever mode -you're currently using) if you change it in a CC Mode buffer." +Note that CC Mode uses this variable to set many other variables that +handles the paragraph filling. That's done at mode initialization or +when you switch to a style which sets this variable. Thus, if you +change it in some other way, e.g. interactively in a CC Mode buffer, +you will need to do \\[c-mode] (or whatever mode you're currently +using) to reinitialize. + +Note also that when CC Mode starts up, the other variables are +modified before the mode hooks are run. If you change this variable +in a mode hook, you can call `c-setup-paragraph-variables' afterwards +to redo it." :type '(radio (regexp :tag "Regexp for all modes") (list @@ -357,7 +496,6 @@ cpp -- inside a preprocessor directive code -- anywhere else, i.e. in normal code" :type '(set - :extra-offset 8 (const :tag "String literals" string) (const :tag "C style block comments" c) (const :tag "C++ style line comments" c++) @@ -416,7 +554,6 @@ Clean up occurs when the closing parenthesis is typed." :type '(set - :extra-offset 8 (const :tag "Put \"} else {\" on one line" brace-else-brace) (const :tag "Put \"} else if (...) {\" on one line" @@ -484,7 +621,7 @@ :size 20 :value ,elt) (choice :format "%[Choice%] %v" - :value (before after) + :value (before after) (set :menu-tag "Before/after" :format "Newline %v brace\n" (const :format "%v, " before) @@ -547,14 +684,31 @@ :group 'c) (defcustom-c-stylevar c-backslash-column 48 - "*Column to insert backslashes when macroizing a region." + "*Minimum alignment column for line continuation backslashes. +This is used by the functions that automatically insert or align the +line continuation backslashes in multiline macros. If any line in the +macro exceeds this column then the next tab stop from that line is +used as alignment column instead." :type 'integer :group 'c) -(defcustom c-special-indent-hook nil - "*Hook for user defined special indentation adjustments. -This hook gets called after a line is indented by the mode." - :type 'hook +(defcustom-c-stylevar c-backslash-max-column 72 + "*Maximum alignment column for line continuation backslashes. +This is used by the functions that automatically insert or align the +line continuation backslashes in multiline macros. If any line in the +macro exceeds this column then the backslashes for the other lines +will be aligned at this column." + :type 'integer + :group 'c) + +(defcustom c-auto-align-backslashes t + "*Align automatically inserted line continuation backslashes. +When line continuation backslashes are inserted automatically for line +breaks in multiline macros, e.g. by \\[c-context-line-break], they are +aligned with the other backslashes in the same macro if this flag is +set. Otherwise the inserted backslashes are preceded by a single +space." + :type 'boolean :group 'c) (defcustom c-backspace-function 'backward-delete-char-untabify @@ -570,7 +724,13 @@ (defcustom c-electric-pound-behavior nil "*List of behaviors for electric pound insertion. Only currently supported behavior is `alignleft'." - :type '(set :extra-offset 8 (const alignleft)) + :type '(set (const alignleft)) + :group 'c) + +(defcustom c-special-indent-hook nil + "*Hook for user defined special indentation adjustments. +This hook gets called after a line is indented by the mode." + :type 'hook :group 'c) (defcustom-c-stylevar c-label-minimum-indentation 1 @@ -629,18 +789,28 @@ (const :format "Other " other) (string :format "%v")))) :group 'c) -(put 'c-offsets-alist 'c-stylevar-fallback +;; *) At the start of a statement or declaration means in more detail: +;; At the closest preceding statement/declaration that starts at boi +;; and doesn't have a label or comment at that position. If there's +;; no such statement within the same block, then back up to the +;; surrounding block or statement, add the appropriate +;; statement-block-intro, defun-block-intro or substatement syntax +;; symbol and continue searching. +(c-set-stylevar-fallback 'c-offsets-alist '((string . c-lineup-dont-change) ;; Relpos: Beg of previous line. (c . c-lineup-C-comments) ;; Relpos: Beg of the comment. (defun-open . 0) - ;; Relpos: Boi at the func decl start when inside classes, bol - ;; at the func decl start when at top level. + ;; Relpos: When inside a class: Boi at the func decl start. + ;; When at top level: Bol at the func decl start. When inside + ;; a code block (only possible in Pike): At the func decl + ;; start(*). (defun-close . 0) - ;; Relpos: Boi at the func decl start. + ;; Relpos: At the defun block open if it's at boi, otherwise + ;; boi at the func decl start. (defun-block-intro . +) - ;; Relpos: Boi at the block open. + ;; Relpos: At the block open(*). (class-open . 0) ;; Relpos: Boi at the class decl start. (class-close . 0) @@ -649,46 +819,47 @@ ;; Relpos: None for functions (inclass got the relpos then), ;; boi at the lambda start for lambdas. (inline-close . 0) - ;; Relpos: For functions: Boi at the func decl start. For - ;; lambdas: At the block open if it's at boi, at the boi of the - ;; lambda start otherwise. + ;; Relpos: Inexpr functions: At the lambda block open if it's + ;; at boi, else at the statement(*) at boi of the start of the + ;; lambda construct. Otherwise: At the inline block open if + ;; it's at boi, otherwise boi at the func decl start. (func-decl-cont . +) ;; Relpos: Boi at the func decl start. (knr-argdecl-intro . +) - ;; Relpos: Boi at the current line. + ;; Relpos: Boi at the topmost intro line. (knr-argdecl . 0) - ;; Relpos: Boi at the argdecl intro line. + ;; Relpos: At the beginning of the first K&R argdecl. (topmost-intro . 0) ;; Relpos: Bol at the last line of previous construct. - (topmost-intro-cont . 0) + (topmost-intro-cont . c-lineup-topmost-intro-cont) ;; Relpos: Boi at the topmost intro line. (member-init-intro . +) ;; Relpos: Boi at the func decl arglist open. (member-init-cont . c-lineup-multi-inher) ;; Relpos: Beg of the first member init. (inher-intro . +) - ;; Relpos: Java: Boi at the class decl start. Otherwise: Boi - ;; of current line (a bug?), unless it begins with an inher - ;; start colon, in which case boi of previous line is used. + ;; Relpos: Boi at the class decl start. (inher-cont . c-lineup-multi-inher) ;; Relpos: Java: At the implements/extends keyword start. ;; Otherwise: At the inher start colon, or boi at the class ;; decl start if the first inherit clause hangs and it's not a ;; func-local inherit clause (when does that occur?). (block-open . 0) - ;; Relpos: Inexpr statement: Boi at the preceding - ;; paren. Otherwise: None. + ;; Relpos: Inexpr statement: At the statement(*) at boi of the + ;; start of the inexpr construct. Otherwise: None. (block-close . 0) - ;; Relpos: At the open brace if it's at boi. Otherwise boi at - ;; the start of the statement the open brace hangs on, or boi - ;; at the preceding paren for inexpr statements. + ;; Relpos: Inexpr statement: At the inexpr block open if it's + ;; at boi, else at the statement(*) at boi of the start of the + ;; inexpr construct. Block hanging on a case/default label: At + ;; the closest preceding label that starts at boi. Otherwise: + ;; At the block open(*). (brace-list-open . 0) ;; Relpos: Boi at the brace list decl start, but a starting ;; "typedef" token is ignored. (brace-list-close . 0) - ;; Relpos: Boi at the brace list open. + ;; Relpos: At the brace list decl start(*). (brace-list-intro . +) - ;; Relpos: Boi at the brace list open. + ;; Relpos: At the brace list decl start(*). (brace-list-entry . 0) ;; Relpos: At the first non-ws char after the open paren if the ;; first token is on the same line, otherwise boi at that @@ -696,52 +867,50 @@ (brace-entry-open . 0) ;; Relpos: Same as brace-list-entry. (statement . 0) - ;; Relpos: After a ';' in the condition clause of a for + ;; Relpos: After a `;' in the condition clause of a for ;; statement: At the first token after the starting paren. - ;; Otherwise: Boi at the start of the closest non-hanging - ;; previous statement, but after any switch label. + ;; Otherwise: At the preceding statement(*). (statement-cont . +) ;; Relpos: After the first token in the condition clause of a ;; for statement: At the first token after the starting paren. - ;; On the first line in a continued expression that starts with - ;; a stream op and there's no stream op on the previous line: - ;; Boi of previous line. Otherwise: Boi at the beginning of - ;; the statement, but after any type of label. + ;; Otherwise: At the containing statement(*). (statement-block-intro . +) - ;; Relpos: At the block start if it's at boi, otherwise boi at - ;; the start of the statement the open brace hangs on, or boi - ;; at the preceding paren for inexpr statements. + ;; Relpos: In inexpr statement block: At the inexpr block open + ;; if it's at boi, else at the statement(*) at boi of the start + ;; of the inexpr construct. In a block hanging on a + ;; case/default label: At the closest preceding label that + ;; starts at boi. Otherwise: At the start of the containing + ;; block(*). (statement-case-intro . +) - ;; Relpos: At the label keyword (always at boi). + ;; Relpos: At the case/default label(*). (statement-case-open . 0) - ;; Relpos: At the label keyword (always at boi). + ;; Relpos: At the case/default label(*). (substatement . +) - ;; Relpos: Boi at the containing statement or else clause. + ;; Relpos: At the containing statement(*). (substatement-open . +) - ;; Relpos: Boi at the containing statement or else clause. + ;; Relpos: At the containing statement(*). + (substatement-label . 2) + ;; Relpos: At the containing statement(*). (case-label . 0) - ;; Relpos: At the switch block start if it's at boi, otherwise - ;; boi at the start of the switch condition clause. + ;; Relpos: At the start of the switch block(*). (access-label . -) - ;; Relpos: Eol (a bug?). + ;; Relpos: Same as inclass. (label . 2) - ;; Relpos: At the start of the containing block if it's at boi, - ;; otherwise boi at the start of the sexp before the block. + ;; Relpos: At the start of the containing block(*). (do-while-closure . 0) - ;; Relpos: Boi at the corresponding while keyword. + ;; Relpos: At the corresponding while statement(*). (else-clause . 0) - ;; Relpos: Boi at the corresponding if keyword. + ;; Relpos: At the corresponding if statement(*). (catch-clause . 0) - ;; Relpos: Boi at the previous try or catch keyword in the try - ;; statement. - (comment-intro . c-lineup-comment) + ;; Relpos: At the previous try or catch statement clause(*). + (comment-intro . (c-lineup-knr-region-comment c-lineup-comment)) ;; Relpos: None. (arglist-intro . +) ;; Relpos: Boi at the open paren, or at the first non-ws after ;; the open paren of the surrounding sexp, whichever is later. - (arglist-cont . 0) + (arglist-cont . (c-lineup-gcc-asm-reg 0)) ;; Relpos: At the first token after the open paren. - (arglist-cont-nonempty . c-lineup-arglist) + (arglist-cont-nonempty . (c-lineup-gcc-asm-reg c-lineup-arglist)) ;; Relpos: Boi at the open paren, or at the first non-ws after ;; the open paren of the surrounding sexp, whichever is later. (arglist-close . +) @@ -754,8 +923,10 @@ ;; boi at the class decl start. (cpp-macro . [0]) ;; Relpos: None. - (cpp-macro-cont . c-lineup-dont-change) + (cpp-macro-cont . +) ;; Relpos: At the macro start (always at boi). + (cpp-define-intro . (c-lineup-cpp-define +)) + ;; Relpos: None. (friend . 0) ;; Relpos: None. (objc-method-intro . [0]) @@ -779,12 +950,13 @@ ;; Relpos: At the namespace block open brace if it's at boi, ;; otherwise boi at the namespace keyword. (template-args-cont . (c-lineup-template-args +)) - ;; Relpos: Boi at the decl start. + ;; Relpos: Boi at the decl start. This might be changed; the + ;; logical position is clearly the opening '<'. (inlambda . c-lineup-inexpr-block) ;; Relpos: None. (lambda-intro-cont . +) ;; Relpos: Boi at the lambda start. - (inexpr-statement . 0) + (inexpr-statement . +) ;; Relpos: None. (inexpr-class . +) ;; Relpos: None. @@ -844,7 +1016,7 @@ `c-offsets-alist' is a style variable. This means that the offsets on this variable are normally taken from the style system in CC Mode -\(see `c-default-style' and `c-styles-alist'). However, any offsets +\(see `c-default-style' and `c-style-alist'). However, any offsets put explicitly on this list will override the style system when a CC Mode buffer is initialized \(there is a variable `c-old-style-variable-behavior' that changes this, though). @@ -889,12 +1061,13 @@ statement-case-open -- The first line in a case block starting with brace. substatement -- The first line after an if/while/for/do/else. substatement-open -- The brace that opens a substatement block. - case-label -- A `case' or `default' label. + substatement-label -- Labelled line after an if/while/for/do/else. + case-label -- A \"case\" or \"default\" label. access-label -- C++ private/protected/public access label. label -- Any ordinary label. - do-while-closure -- The `while' that ends a do/while construct. - else-clause -- The `else' of an if/else construct. - catch-clause -- The `catch' or `finally' of a try/catch construct. + do-while-closure -- The \"while\" that ends a do/while construct. + else-clause -- The \"else\" of an if/else construct. + catch-clause -- The \"catch\" or \"finally\" of a try/catch construct. comment-intro -- A line containing only a comment introduction. arglist-intro -- The first line in an argument list. arglist-cont -- Subsequent argument list lines when no @@ -908,8 +1081,7 @@ inclass -- The construct is nested inside a class definition. Used together with e.g. `topmost-intro'. cpp-macro -- The start of a C preprocessor macro definition. - cpp-macro-cont -- Subsequent lines in a multi-line C preprocessor - macro definition. + cpp-macro-cont -- Inside a multi-line C preprocessor macro definition. friend -- A C++ friend declaration. objc-method-intro -- The first line of an Objective-C method definition. objc-method-args-cont -- Lines continuing an Objective-C method definition. @@ -1021,14 +1193,16 @@ times for core indentation functions (e.g. `c-parse-state'). For styles that conform to the Emacs recommendation of putting these braces in column zero, this can degrade performance about as much. -This variable only has effect in XEmacs.") +This variable only has effect in XEmacs." + :type 'boolean + :group 'c) -(defcustom c-old-style-variable-behavior nil +(defvar c-old-style-variable-behavior nil "*Enables the old style variable behavior when non-nil. Normally the values of the style variables will override the style settings specified by the variables `c-default-style' and -`c-styles-alist'. However, in CC Mode 5.25 and earlier, it was the +`c-style-alist'. However, in CC Mode 5.25 and earlier, it was the other way around, meaning that changes made to the style variables from e.g. Customize would not take effect unless special precautions were taken. That was confusing, especially for novice users. @@ -1077,6 +1251,20 @@ Set from `c-comment-prefix-regexp' at mode initialization.") (make-variable-buffer-local 'c-current-comment-prefix) +(defvar c-buffer-is-cc-mode nil + "Non-nil for all buffers with a major mode derived from CC Mode. +Otherwise, this variable is nil. I.e. this variable is non-nil for +`c-mode', `c++-mode', `objc-mode', `java-mode', `idl-mode', +`pike-mode', and any other non-CC Mode mode that calls +`c-initialize-cc-mode' (e.g. `awk-mode'). The value is the mode +symbol itself (i.e. `c-mode' etc) of the original CC Mode mode, or +just t if it's not known.") +(make-variable-buffer-local 'c-buffer-is-cc-mode) + +;; Have to make `c-buffer-is-cc-mode' permanently local so that it +;; survives the initialization of the derived mode. +(put 'c-buffer-is-cc-mode 'permanent-local t) + ;; Figure out what features this Emacs has ;;;###autoload