diff options
| author | Alan Mackenzie | 2019-07-02 12:33:01 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2019-07-02 12:33:01 +0000 |
| commit | b25d58c956a9fcd2b81b804699573ea851bd8fde (patch) | |
| tree | 75567cf91b5108b6257e2f83ae89a73448ce4581 | |
| parent | 22b64f7bac8d015f3d0e6a42e9d764a61656e7a1 (diff) | |
| download | emacs-b25d58c956a9fcd2b81b804699573ea851bd8fde.tar.gz emacs-b25d58c956a9fcd2b81b804699573ea851bd8fde.zip | |
CC Mode: Improve handling of unbalanced strings
* lisp/progmodes/cc-fonts.el (c-before-font-lock-functions): Add function
c-after-change-escape-NL-in-string into value for most languages.
* lisp/progmodes/cc-mode.el (c-after-change-escape-NL-in-string): New
function.
(c-before-change-check-unbalanced-strings): Handle the making and breaking of
escaped newlines, by removal or addition of text.
| -rw-r--r-- | lisp/progmodes/cc-langs.el | 6 | ||||
| -rw-r--r-- | lisp/progmodes/cc-mode.el | 78 |
2 files changed, 78 insertions, 6 deletions
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 2fcd6acf51f..153d3fc2608 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el | |||
| @@ -478,7 +478,7 @@ so that all identifiers are recognized as words.") | |||
| 478 | (list fs))) | 478 | (list fs))) |
| 479 | "If non-nil, a list of functions called from c-before-change-hook. | 479 | "If non-nil, a list of functions called from c-before-change-hook. |
| 480 | Typically these will record enough state to allow | 480 | Typically these will record enough state to allow |
| 481 | `c-before-font-lock-function' to extend the region to fontify, | 481 | `c-before-font-lock-functions' to extend the region to fontify, |
| 482 | and may do such things as removing text-properties which must be | 482 | and may do such things as removing text-properties which must be |
| 483 | recalculated. | 483 | recalculated. |
| 484 | 484 | ||
| @@ -497,15 +497,18 @@ parameters \(point-min) and \(point-max).") | |||
| 497 | ;; For documentation see the following c-lang-defvar of the same name. | 497 | ;; For documentation see the following c-lang-defvar of the same name. |
| 498 | ;; The value here may be a list of functions or a single function. | 498 | ;; The value here may be a list of functions or a single function. |
| 499 | t '(c-depropertize-new-text | 499 | t '(c-depropertize-new-text |
| 500 | c-after-change-escape-NL-in-string | ||
| 500 | c-after-change-mark-abnormal-strings | 501 | c-after-change-mark-abnormal-strings |
| 501 | c-change-expand-fl-region) | 502 | c-change-expand-fl-region) |
| 502 | (c objc) '(c-depropertize-new-text | 503 | (c objc) '(c-depropertize-new-text |
| 504 | c-after-change-escape-NL-in-string | ||
| 503 | c-parse-quotes-after-change | 505 | c-parse-quotes-after-change |
| 504 | c-after-change-mark-abnormal-strings | 506 | c-after-change-mark-abnormal-strings |
| 505 | c-extend-font-lock-region-for-macros | 507 | c-extend-font-lock-region-for-macros |
| 506 | c-neutralize-syntax-in-CPP | 508 | c-neutralize-syntax-in-CPP |
| 507 | c-change-expand-fl-region) | 509 | c-change-expand-fl-region) |
| 508 | c++ '(c-depropertize-new-text | 510 | c++ '(c-depropertize-new-text |
| 511 | c-after-change-escape-NL-in-string | ||
| 509 | c-after-change-unmark-raw-strings | 512 | c-after-change-unmark-raw-strings |
| 510 | c-parse-quotes-after-change | 513 | c-parse-quotes-after-change |
| 511 | c-after-change-mark-abnormal-strings | 514 | c-after-change-mark-abnormal-strings |
| @@ -514,6 +517,7 @@ parameters \(point-min) and \(point-max).") | |||
| 514 | c-restore-<>-properties | 517 | c-restore-<>-properties |
| 515 | c-change-expand-fl-region) | 518 | c-change-expand-fl-region) |
| 516 | java '(c-depropertize-new-text | 519 | java '(c-depropertize-new-text |
| 520 | c-after-change-escape-NL-in-string | ||
| 517 | c-parse-quotes-after-change | 521 | c-parse-quotes-after-change |
| 518 | c-after-change-mark-abnormal-strings | 522 | c-after-change-mark-abnormal-strings |
| 519 | c-restore-<>-properties | 523 | c-restore-<>-properties |
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 5c18879712c..8f4bb341acb 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el | |||
| @@ -1262,11 +1262,31 @@ Note that the style variables are always made local to the buffer." | |||
| 1262 | (setq c-new-BEG (min (car beg-limits) c-new-BEG)))) | 1262 | (setq c-new-BEG (min (car beg-limits) c-new-BEG)))) |
| 1263 | 1263 | ||
| 1264 | ((< end (point-max)) | 1264 | ((< end (point-max)) |
| 1265 | (goto-char (1+ end)) ; might be a newline. | 1265 | ;; Have we just escaped a newline by deleting characters? |
| 1266 | ;; In the following regexp, the initial \n caters for a newline getting | 1266 | (if (and (eq end-literal-type 'string) |
| 1267 | ;; joined to a preceding \ by the removal of what comes between. | 1267 | (memq (char-after end) '(?\n ?\r))) |
| 1268 | (re-search-forward "[\n\r]?\\(\\\\\\(.\\|\n\\)\\|[^\\\n\r]\\)*" | 1268 | (cond |
| 1269 | nil t) | 1269 | ;; Are we escaping a newline by deleting stuff between \ and \n? |
| 1270 | ((and (> end beg) | ||
| 1271 | (progn | ||
| 1272 | (goto-char end) | ||
| 1273 | (eq (logand (skip-chars-backward "\\\\" beg) 1) 1))) | ||
| 1274 | (c-clear-char-property end 'syntax-table) | ||
| 1275 | (c-truncate-lit-pos-cache end) | ||
| 1276 | (goto-char (1+ end))) | ||
| 1277 | ;; Are we unescaping a newline by inserting stuff between \ and \n? | ||
| 1278 | ((and (eq end beg) | ||
| 1279 | (progn | ||
| 1280 | (goto-char end) | ||
| 1281 | (eq (logand (skip-chars-backward "\\\\") 1) 1))) | ||
| 1282 | (goto-char (1+ end))) ; To after the NL which is being unescaped. | ||
| 1283 | (t | ||
| 1284 | (goto-char end))) | ||
| 1285 | (goto-char end)) | ||
| 1286 | |||
| 1287 | ;; Move to end of logical line (as it will be after the change, or as it | ||
| 1288 | ;; was before unescaping a NL.) | ||
| 1289 | (re-search-forward "\\(\\\\\\(.\\|\n\\|\r\\)\\|[^\\\n\r]\\)*" nil t) | ||
| 1270 | ;; We're at an EOLL or point-max. | 1290 | ;; We're at an EOLL or point-max. |
| 1271 | (if (equal (c-get-char-property (point) 'syntax-table) '(15)) | 1291 | (if (equal (c-get-char-property (point) 'syntax-table) '(15)) |
| 1272 | (if (memq (char-after) '(?\n ?\r)) | 1292 | (if (memq (char-after) '(?\n ?\r)) |
| @@ -1426,6 +1446,54 @@ Note that the style variables are always made local to the buffer." | |||
| 1426 | (goto-char (min (1+ (match-end 0)) (point-max)))) | 1446 | (goto-char (min (1+ (match-end 0)) (point-max)))) |
| 1427 | (setq s nil))))) | 1447 | (setq s nil))))) |
| 1428 | 1448 | ||
| 1449 | (defun c-after-change-escape-NL-in-string (beg end _old_len) | ||
| 1450 | ;; If a backslash has just been inserted into a string, and this quotes an | ||
| 1451 | ;; existing newline, remove the string fence syntax-table text properties | ||
| 1452 | ;; on what has become the tail of the string. | ||
| 1453 | ;; | ||
| 1454 | ;; POINT is undefined both at entry to and exit from this function, the | ||
| 1455 | ;; buffer will have been widened, and match data will have been saved. | ||
| 1456 | ;; | ||
| 1457 | ;; This function is called exclusively as an after-change function via | ||
| 1458 | ;; `c-before-font-lock-functions'. In C++ Mode, it should come before | ||
| 1459 | ;; `c-after-change-unmark-raw-strings' in that lang variable. | ||
| 1460 | (let (lit-start) ; Don't calculate this till we have to. | ||
| 1461 | (when | ||
| 1462 | (and (> end beg) | ||
| 1463 | (memq (char-after end) '(?\n ?\r)) | ||
| 1464 | (progn (goto-char end) | ||
| 1465 | (eq (logand (skip-chars-backward "\\\\") 1) 1)) | ||
| 1466 | (progn (goto-char end) | ||
| 1467 | (setq lit-start (c-literal-start))) | ||
| 1468 | (memq (char-after lit-start) c-string-delims) | ||
| 1469 | (or (not (c-major-mode-is 'c++-mode)) | ||
| 1470 | (progn | ||
| 1471 | (goto-char lit-start) | ||
| 1472 | (and (not (and (eq (char-before) ?R) | ||
| 1473 | (looking-at c-c++-raw-string-opener-1-re))) | ||
| 1474 | (not (and (eq (char-after) ?\() | ||
| 1475 | (equal (c-get-char-property | ||
| 1476 | (point) 'syntax-table) | ||
| 1477 | '(15)))))) | ||
| 1478 | (save-excursion | ||
| 1479 | (c-beginning-of-macro)))) | ||
| 1480 | (goto-char (1+ end)) ; After the \ | ||
| 1481 | ;; Search forward for a closing ". | ||
| 1482 | (when (and (re-search-forward "\\(\\\\\\(.\\|\n\\)\\|[^\"\\\n\r]\\)*" | ||
| 1483 | nil t) | ||
| 1484 | (eq (char-after) ?\") | ||
| 1485 | (equal (c-get-char-property (point) 'syntax-table) '(15))) | ||
| 1486 | (c-clear-char-property end 'syntax-table) | ||
| 1487 | (c-truncate-lit-pos-cache end) | ||
| 1488 | (c-clear-char-property (point) 'syntax-table) | ||
| 1489 | (forward-char) ; to after the " | ||
| 1490 | (when | ||
| 1491 | (and | ||
| 1492 | ;; Search forward for an end of logical line. | ||
| 1493 | (re-search-forward "\\(\\\\\\(.\\|\n\\)\\|[^\\\n\r]\\)*" nil t) | ||
| 1494 | (memq (char-after) '(?\n ?\r))) | ||
| 1495 | (c-clear-char-property (point) 'syntax-table)))))) | ||
| 1496 | |||
| 1429 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 1497 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 1430 | ;; Parsing of quotes. | 1498 | ;; Parsing of quotes. |
| 1431 | ;; | 1499 | ;; |