diff options
| author | Alan Mackenzie | 2018-06-08 16:42:18 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2018-06-08 16:42:18 +0000 |
| commit | fe06f643b2808b198bb58bda04a8c863e55a2a56 (patch) | |
| tree | 6b6cefea3df9647cea1a3315f59c7936d56965e3 | |
| parent | db353b8649cdae54146308e4c875e53d02b0aaee (diff) | |
| download | emacs-fe06f643b2808b198bb58bda04a8c863e55a2a56.tar.gz emacs-fe06f643b2808b198bb58bda04a8c863e55a2a56.zip | |
CC Mode: Fontify unbalanced quotes in unconstrained multiline strings, etc.
("Unconstrained" meaning that every string is multiline, without needing such
special marking as used by Pike Mode.)
* lisp/progmodes/cc-mode.el (c-pps-to-string-delim): Don't process the char
before BOB.
(c-multiline-string-check-final-quote): New function.
(c-bc-changed-stringiness): New variable.
(c-before-change-check-unbalanced-strings): Add handling for unconstrained
multiline strings.
(c-after-change-re-mark-unbalanced-strings): Add handling for unconstrained
multiline strings. Handle escaped double quotes more accurately.
| -rw-r--r-- | lisp/progmodes/cc-mode.el | 214 |
1 files changed, 147 insertions, 67 deletions
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index a1411ad5ea2..e619fac43f2 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el | |||
| @@ -1110,13 +1110,56 @@ Note that the style variables are always made local to the buffer." | |||
| 1110 | (goto-char start) | 1110 | (goto-char start) |
| 1111 | (while (progn | 1111 | (while (progn |
| 1112 | (parse-partial-sexp (point) end nil nil st-s 'syntax-table) | 1112 | (parse-partial-sexp (point) end nil nil st-s 'syntax-table) |
| 1113 | (c-clear-char-property (1- (point)) 'syntax-table) | 1113 | (unless (bobp) |
| 1114 | (c-clear-char-property (1- (point)) 'syntax-table)) | ||
| 1114 | (setq st-pos (point)) | 1115 | (setq st-pos (point)) |
| 1115 | (and (< (point) end) | 1116 | (and (< (point) end) |
| 1116 | (not (eq (char-before) ?\"))))) | 1117 | (not (eq (char-before) ?\"))))) |
| 1117 | (goto-char (min no-st-pos st-pos)) | 1118 | (goto-char (min no-st-pos st-pos)) |
| 1118 | nil)) | 1119 | nil)) |
| 1119 | 1120 | ||
| 1121 | (defun c-multiline-string-check-final-quote () | ||
| 1122 | ;; Check that the final quote in the buffer is correctly marked or not with | ||
| 1123 | ;; a string-fence syntax-table text propery. The return value has no | ||
| 1124 | ;; significance. | ||
| 1125 | (let (pos-ll pos-lt) | ||
| 1126 | (save-excursion | ||
| 1127 | (goto-char (point-max)) | ||
| 1128 | (skip-chars-backward "^\"") | ||
| 1129 | (while | ||
| 1130 | (and | ||
| 1131 | (not (bobp)) | ||
| 1132 | (cond | ||
| 1133 | ((progn | ||
| 1134 | (setq pos-ll (c-literal-limits) | ||
| 1135 | pos-lt (c-literal-type pos-ll)) | ||
| 1136 | (memq pos-lt '(c c++))) | ||
| 1137 | ;; In a comment. | ||
| 1138 | (goto-char (car pos-ll))) | ||
| 1139 | ((save-excursion | ||
| 1140 | (backward-char) ; over " | ||
| 1141 | (eq (logand (skip-chars-backward "\\\\") 1) 1)) | ||
| 1142 | ;; At an escaped string. | ||
| 1143 | (backward-char) | ||
| 1144 | t) | ||
| 1145 | (t | ||
| 1146 | ;; At a significant " | ||
| 1147 | (c-clear-char-property (1- (point)) 'syntax-table) | ||
| 1148 | (setq pos-ll (c-literal-limits) | ||
| 1149 | pos-lt (c-literal-type pos-ll)) | ||
| 1150 | nil))) | ||
| 1151 | (skip-chars-backward "^\"")) | ||
| 1152 | (cond | ||
| 1153 | ((bobp)) | ||
| 1154 | ((eq pos-lt 'string) | ||
| 1155 | (c-put-char-property (1- (point)) 'syntax-table '(15))) | ||
| 1156 | (t nil))))) | ||
| 1157 | |||
| 1158 | (defvar c-bc-changed-stringiness nil) | ||
| 1159 | ;; Non-nil when, in a before-change function, the deletion of a range of text | ||
| 1160 | ;; will change the "stringiness" of the subsequent text. Only used when | ||
| 1161 | ;; `c-multiline-sting-start-char' is a non-nil value which isn't a character. | ||
| 1162 | |||
| 1120 | (defun c-before-change-check-unbalanced-strings (beg end) | 1163 | (defun c-before-change-check-unbalanced-strings (beg end) |
| 1121 | ;; If BEG or END is inside an unbalanced string, remove the syntax-table | 1164 | ;; If BEG or END is inside an unbalanced string, remove the syntax-table |
| 1122 | ;; text property from respectively the start or end of the string. Also | 1165 | ;; text property from respectively the start or end of the string. Also |
| @@ -1175,6 +1218,18 @@ Note that the style variables are always made local to the buffer." | |||
| 1175 | (< (point) (point-max)))))) | 1218 | (< (point) (point-max)))))) |
| 1176 | (setq c-new-END (max (point) c-new-END))) | 1219 | (setq c-new-END (max (point) c-new-END))) |
| 1177 | 1220 | ||
| 1221 | (c-multiline-string-start-char | ||
| 1222 | (setq c-bc-changed-stringiness | ||
| 1223 | (not (eq (eq end-literal-type 'string) | ||
| 1224 | (eq beg-literal-type 'string)))) | ||
| 1225 | ;; Deal with deletion of backslashes before "s. | ||
| 1226 | (goto-char end) | ||
| 1227 | (if (and (looking-at "\\\\*\"") | ||
| 1228 | (eq (logand (skip-chars-backward "\\\\" beg) 1) 1)) | ||
| 1229 | (setq c-bc-changed-stringiness (not c-bc-changed-stringiness))) | ||
| 1230 | (if (eq beg-literal-type 'string) | ||
| 1231 | (setq c-new-BEG (min (car beg-limits) c-new-BEG)))) | ||
| 1232 | |||
| 1178 | ((< c-new-END (point-max)) | 1233 | ((< c-new-END (point-max)) |
| 1179 | (goto-char (1+ c-new-END)) ; might be a newline. | 1234 | (goto-char (1+ c-new-END)) ; might be a newline. |
| 1180 | ;; In the following regexp, the initial \n caters for a newline getting | 1235 | ;; In the following regexp, the initial \n caters for a newline getting |
| @@ -1183,7 +1238,6 @@ Note that the style variables are always made local to the buffer." | |||
| 1183 | nil t) | 1238 | nil t) |
| 1184 | ;; We're at an EOLL or point-max. | 1239 | ;; We're at an EOLL or point-max. |
| 1185 | (setq c-new-END (min (1+ (point)) (point-max))) | 1240 | (setq c-new-END (min (1+ (point)) (point-max))) |
| 1186 | ;; FIXME!!! Write a clever comment here. | ||
| 1187 | (goto-char c-new-END) | 1241 | (goto-char c-new-END) |
| 1188 | (if (equal (c-get-char-property (1- (point)) 'syntax-table) '(15)) | 1242 | (if (equal (c-get-char-property (1- (point)) 'syntax-table) '(15)) |
| 1189 | (if (memq (char-before) '(?\n ?\r)) | 1243 | (if (memq (char-before) '(?\n ?\r)) |
| @@ -1202,14 +1256,16 @@ Note that the style variables are always made local to the buffer." | |||
| 1202 | (if (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) | 1256 | (if (c-search-backward-char-property 'syntax-table '(15) c-new-BEG) |
| 1203 | (c-clear-char-property (point) 'syntax-table)))) | 1257 | (c-clear-char-property (point) 'syntax-table)))) |
| 1204 | 1258 | ||
| 1205 | (when (eq end-literal-type 'string) | 1259 | (unless (and c-multiline-string-start-char |
| 1206 | (c-clear-char-property (1- (cdr end-limits)) 'syntax-table)) | 1260 | (not (c-characterp c-multiline-string-start-char))) |
| 1261 | (when (eq end-literal-type 'string) | ||
| 1262 | (c-clear-char-property (1- (cdr end-limits)) 'syntax-table)) | ||
| 1207 | 1263 | ||
| 1208 | (when (eq beg-literal-type 'string) | 1264 | (when (eq beg-literal-type 'string) |
| 1209 | (setq c-new-BEG (min c-new-BEG (car beg-limits))) | 1265 | (setq c-new-BEG (min c-new-BEG (car beg-limits))) |
| 1210 | (c-clear-char-property (car beg-limits) 'syntax-table)))) | 1266 | (c-clear-char-property (car beg-limits) 'syntax-table))))) |
| 1211 | 1267 | ||
| 1212 | (defun c-after-change-re-mark-unbalanced-strings (beg _end _old-len) | 1268 | (defun c-after-change-re-mark-unbalanced-strings (beg end _old-len) |
| 1213 | ;; Mark any unbalanced strings in the region (c-new-BEG c-new-END) with | 1269 | ;; Mark any unbalanced strings in the region (c-new-BEG c-new-END) with |
| 1214 | ;; string fence syntax-table text properties. | 1270 | ;; string fence syntax-table text properties. |
| 1215 | ;; | 1271 | ;; |
| @@ -1218,66 +1274,90 @@ Note that the style variables are always made local to the buffer." | |||
| 1218 | ;; | 1274 | ;; |
| 1219 | ;; This function is called exclusively as an after-change function via | 1275 | ;; This function is called exclusively as an after-change function via |
| 1220 | ;; `c-before-font-lock-functions'. | 1276 | ;; `c-before-font-lock-functions'. |
| 1221 | (c-save-buffer-state | 1277 | (if (and c-multiline-string-start-char |
| 1222 | ((cll (progn (goto-char c-new-BEG) | 1278 | (not (c-characterp c-multiline-string-start-char))) |
| 1223 | (c-literal-limits))) | 1279 | ;; Only the last " might need to be marked. |
| 1224 | (beg-literal-type (and cll (c-literal-type cll))) | 1280 | (c-save-buffer-state |
| 1225 | (beg-limits | 1281 | ((beg-literal-limits |
| 1226 | (cond | 1282 | (progn (goto-char beg) (c-literal-limits))) |
| 1227 | ((and (eq beg-literal-type 'string) | 1283 | (beg-literal-type (c-literal-type beg-literal-limits)) |
| 1228 | (c-unescaped-nls-in-string-p (car cll))) | 1284 | end-literal-limits end-literal-type) |
| 1229 | (cons | 1285 | (when (and (eq beg-literal-type 'string) |
| 1230 | (car cll) | 1286 | (c-get-char-property (car beg-literal-limits) 'syntax-table)) |
| 1287 | (c-clear-char-property (car beg-literal-limits) 'syntax-table) | ||
| 1288 | (setq c-bc-changed-stringiness (not c-bc-changed-stringiness))) | ||
| 1289 | (setq end-literal-limits (progn (goto-char end) (c-literal-limits)) | ||
| 1290 | end-literal-type (c-literal-type end-literal-limits)) | ||
| 1291 | ;; Deal with the insertion of backslashes before a ". | ||
| 1292 | (goto-char end) | ||
| 1293 | (if (and (looking-at "\\\\*\"") | ||
| 1294 | (eq (logand (skip-chars-backward "\\\\" beg) 1) 1)) | ||
| 1295 | (setq c-bc-changed-stringiness (not c-bc-changed-stringiness))) | ||
| 1296 | (when (eq (eq (eq beg-literal-type 'string) | ||
| 1297 | (eq end-literal-type 'string)) | ||
| 1298 | c-bc-changed-stringiness) | ||
| 1299 | (c-multiline-string-check-final-quote))) | ||
| 1300 | ;; There could be several "s needing marking. | ||
| 1301 | (c-save-buffer-state | ||
| 1302 | ((cll (progn (goto-char c-new-BEG) | ||
| 1303 | (c-literal-limits))) | ||
| 1304 | (beg-literal-type (and cll (c-literal-type cll))) | ||
| 1305 | (beg-limits | ||
| 1306 | (cond | ||
| 1307 | ((and (eq beg-literal-type 'string) | ||
| 1308 | (c-unescaped-nls-in-string-p (car cll))) | ||
| 1309 | (cons | ||
| 1310 | (car cll) | ||
| 1311 | (progn | ||
| 1312 | (goto-char (1+ (car cll))) | ||
| 1313 | (search-forward-regexp | ||
| 1314 | (cdr (assq (char-after (car cll)) c-string-innards-re-alist)) | ||
| 1315 | nil t) | ||
| 1316 | (min (1+ (point)) (point-max))))) | ||
| 1317 | ((and (null beg-literal-type) | ||
| 1318 | (goto-char beg) | ||
| 1319 | (eq (char-before) c-multiline-string-start-char) | ||
| 1320 | (memq (char-after) c-string-delims)) | ||
| 1321 | (cons (point) | ||
| 1322 | (progn | ||
| 1323 | (forward-char) | ||
| 1324 | (search-forward-regexp | ||
| 1325 | (cdr (assq (char-before) c-string-innards-re-alist)) nil t) | ||
| 1326 | (1+ (point))))) | ||
| 1327 | (cll))) | ||
| 1328 | s) | ||
| 1329 | (goto-char | ||
| 1330 | (cond ((null beg-literal-type) | ||
| 1331 | c-new-BEG) | ||
| 1332 | ((eq beg-literal-type 'string) | ||
| 1333 | (car beg-limits)) | ||
| 1334 | (t ; comment | ||
| 1335 | (cdr beg-limits)))) | ||
| 1336 | (while | ||
| 1337 | (and | ||
| 1338 | (< (point) c-new-END) | ||
| 1231 | (progn | 1339 | (progn |
| 1232 | (goto-char (1+ (car cll))) | 1340 | ;; Skip over any comments before the next string. |
| 1233 | (search-forward-regexp | 1341 | (while (progn |
| 1234 | (cdr (assq (char-after (car cll)) c-string-innards-re-alist)) | 1342 | (setq s (parse-partial-sexp (point) c-new-END nil |
| 1235 | nil t) | 1343 | nil s 'syntax-table)) |
| 1236 | (min (1+ (point)) (point-max))))) | 1344 | (and (not (nth 3 s)) |
| 1237 | ((and (null beg-literal-type) | 1345 | (< (point) c-new-END) |
| 1238 | (goto-char beg) | 1346 | (not (memq (char-before) c-string-delims))))) |
| 1239 | (eq (char-before) c-multiline-string-start-char) | 1347 | ;; We're at the start of a string. |
| 1240 | (memq (char-after) c-string-delims)) | 1348 | (memq (char-before) c-string-delims))) |
| 1241 | (cons (point) | 1349 | (if (c-unescaped-nls-in-string-p (1- (point))) |
| 1242 | (progn | 1350 | (looking-at "\\(\\\\\\(.\\|\n|\\\r\\)\\|[^\"]\\)*") |
| 1243 | (forward-char) | 1351 | (looking-at (cdr (assq (char-before) c-string-innards-re-alist)))) |
| 1244 | (search-forward-regexp | 1352 | (cond |
| 1245 | (cdr (assq (char-before) c-string-innards-re-alist)) nil t) | 1353 | ((memq (char-after (match-end 0)) '(?\n ?\r)) |
| 1246 | (1+ (point))))) | 1354 | (c-put-char-property (1- (point)) 'syntax-table '(15)) |
| 1247 | (cll))) | 1355 | (c-put-char-property (match-end 0) 'syntax-table '(15))) |
| 1248 | s) | 1356 | ((or (eq (match-end 0) (point-max)) |
| 1249 | (goto-char | 1357 | (eq (char-after (match-end 0)) ?\\)) ; \ at EOB |
| 1250 | (cond ((null beg-literal-type) | 1358 | (c-put-char-property (1- (point)) 'syntax-table '(15)))) |
| 1251 | c-new-BEG) | 1359 | (goto-char (min (1+ (match-end 0)) (point-max))) |
| 1252 | ((eq beg-literal-type 'string) | 1360 | (setq s nil))))) |
| 1253 | (car beg-limits)) | ||
| 1254 | (t ; comment | ||
| 1255 | (cdr beg-limits)))) | ||
| 1256 | (while | ||
| 1257 | (and | ||
| 1258 | (< (point) c-new-END) | ||
| 1259 | (progn | ||
| 1260 | ;; Skip over any comments before the next string. | ||
| 1261 | (while (progn | ||
| 1262 | (setq s (parse-partial-sexp (point) c-new-END nil | ||
| 1263 | nil s 'syntax-table)) | ||
| 1264 | (and (not (nth 3 s)) | ||
| 1265 | (< (point) c-new-END) | ||
| 1266 | (not (memq (char-before) c-string-delims))))) | ||
| 1267 | ;; We're at the start of a string. | ||
| 1268 | (memq (char-before) c-string-delims))) | ||
| 1269 | (if (c-unescaped-nls-in-string-p (1- (point))) | ||
| 1270 | (looking-at "[^\"]*") | ||
| 1271 | (looking-at (cdr (assq (char-before) c-string-innards-re-alist)))) | ||
| 1272 | (cond | ||
| 1273 | ((memq (char-after (match-end 0)) '(?\n ?\r)) | ||
| 1274 | (c-put-char-property (1- (point)) 'syntax-table '(15)) | ||
| 1275 | (c-put-char-property (match-end 0) 'syntax-table '(15))) | ||
| 1276 | ((or (eq (match-end 0) (point-max)) | ||
| 1277 | (eq (char-after (match-end 0)) ?\\)) ; \ at EOB | ||
| 1278 | (c-put-char-property (1- (point)) 'syntax-table '(15)))) | ||
| 1279 | (goto-char (min (1+ (match-end 0)) (point-max))) | ||
| 1280 | (setq s nil)))) | ||
| 1281 | 1361 | ||
| 1282 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 1362 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 1283 | ;; Parsing of quotes. | 1363 | ;; Parsing of quotes. |