diff options
| author | Alan Mackenzie | 2017-09-03 11:01:21 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2017-09-03 11:01:21 +0000 |
| commit | c8439abe22f1bb5e717f5c0f3725084c8d738155 (patch) | |
| tree | b026c82df2762959bd93cc8a457e166f4cbbc7c3 | |
| parent | b733a910091c426de0d831f1ce0cda4ae736ab69 (diff) | |
| download | emacs-c8439abe22f1bb5e717f5c0f3725084c8d738155.tar.gz emacs-c8439abe22f1bb5e717f5c0f3725084c8d738155.zip | |
Correct the fontification of quote marks after buffer changes in CC Mode.
* lisp/progmodes/cc-defs.el
(c-search-forward-char-property-with-value-on-char): New macro.
* lisp/progmodes/cc-mode.el (c-parse-quotes-before-change)
(c-parse-quotes-after-change): Rewrite the functions, simplifying
considerably, and removing unnecessary optimisations. Invalidate two caches
after manipulating text properties.
| -rw-r--r-- | lisp/progmodes/cc-defs.el | 23 | ||||
| -rw-r--r-- | lisp/progmodes/cc-mode.el | 181 |
2 files changed, 121 insertions, 83 deletions
diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index ab910ab7dec..dda343d72e0 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el | |||
| @@ -1185,6 +1185,29 @@ been put there by c-put-char-property. POINT remains unchanged." | |||
| 1185 | ;; GNU Emacs | 1185 | ;; GNU Emacs |
| 1186 | `(c-clear-char-property-with-value-function ,from ,to ,property ,value))) | 1186 | `(c-clear-char-property-with-value-function ,from ,to ,property ,value))) |
| 1187 | 1187 | ||
| 1188 | (defmacro c-search-forward-char-property-with-value-on-char | ||
| 1189 | (property value char &optional limit) | ||
| 1190 | "Search forward for a text-property PROPERTY having value VALUE on a | ||
| 1191 | character with value CHAR. | ||
| 1192 | LIMIT bounds the search. The value comparison is done with `equal'. | ||
| 1193 | PROPERTY must be a constant. | ||
| 1194 | |||
| 1195 | Leave point just after the character, and set the match data on | ||
| 1196 | this character, and return point. If the search fails, return | ||
| 1197 | nil; point is then left undefined." | ||
| 1198 | `(let ((char-skip (concat "^" (char-to-string ,char))) | ||
| 1199 | (-limit- ,limit) | ||
| 1200 | (-value- ,value)) | ||
| 1201 | (while | ||
| 1202 | (and | ||
| 1203 | (progn (skip-chars-forward char-skip -limit-) | ||
| 1204 | (< (point) -limit-)) | ||
| 1205 | (not (equal (c-get-char-property (point) ,property) -value-))) | ||
| 1206 | (forward-char)) | ||
| 1207 | (when (< (point) -limit-) | ||
| 1208 | (search-forward-regexp ".") ; to set the match-data. | ||
| 1209 | (point)))) | ||
| 1210 | |||
| 1188 | (defun c-clear-char-property-with-value-on-char-function (from to property | 1211 | (defun c-clear-char-property-with-value-on-char-function (from to property |
| 1189 | value char) | 1212 | value char) |
| 1190 | "Remove all text-properties PROPERTY with value VALUE on | 1213 | "Remove all text-properties PROPERTY with value VALUE on |
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 48a6619bd1e..663a51ca72a 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el | |||
| @@ -1197,76 +1197,82 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") | |||
| 1197 | ;; | 1197 | ;; |
| 1198 | ;; This function is called exclusively as a before-change function via the | 1198 | ;; This function is called exclusively as a before-change function via the |
| 1199 | ;; variable `c-get-state-before-change-functions'. | 1199 | ;; variable `c-get-state-before-change-functions'. |
| 1200 | (c-save-buffer-state (p-limit found) | 1200 | (c-save-buffer-state () |
| 1201 | ;; Special consideration for deleting \ from '\''. | ||
| 1202 | (if (and (> end beg) | ||
| 1203 | (eq (char-before end) ?\\) | ||
| 1204 | (<= c-new-END end)) | ||
| 1205 | (setq c-new-END (min (1+ end) (point-max)))) | ||
| 1206 | |||
| 1207 | ;; Do we have a ' (or something like ',',',',',') within range of | ||
| 1208 | ;; c-new-BEG? | ||
| 1209 | (goto-char c-new-BEG) | 1201 | (goto-char c-new-BEG) |
| 1210 | (setq p-limit (max (- (point) 2) (point-min))) | 1202 | ;; We need to scan for 's from the BO (logical) line. |
| 1211 | (while (and (skip-chars-backward "^\\\\'" p-limit) | ||
| 1212 | (> (point) p-limit)) | ||
| 1213 | (when (eq (char-before) ?\\) | ||
| 1214 | (setq p-limit (max (1- p-limit) (point-min)))) | ||
| 1215 | (backward-char) | ||
| 1216 | (setq c-new-BEG (point))) | ||
| 1217 | (beginning-of-line) | 1203 | (beginning-of-line) |
| 1218 | (while (and | 1204 | (while (eq (char-before (1- (point))) ?\\) |
| 1219 | (setq found (search-forward-regexp "\\('\\([^'\\]\\|\\\\.\\)\\)*'" | 1205 | (beginning-of-line 0)) |
| 1220 | c-new-BEG 'limit)) | 1206 | (while (and (< (point) c-new-BEG) |
| 1221 | (< (point) (1- c-new-BEG)))) | 1207 | (search-forward "'" c-new-BEG t)) |
| 1222 | (if found | 1208 | (cond |
| 1223 | (setq c-new-BEG | 1209 | ((c-quoted-number-straddling-point) |
| 1224 | (if (and (eq (point) (1- c-new-BEG)) | 1210 | (goto-char (match-end 0)) |
| 1225 | (eq (char-after) ?')) ; "''" before c-new-BEG. | 1211 | (if (> (match-end 0) c-new-BEG) |
| 1226 | (1- c-new-BEG) | 1212 | (setq c-new-BEG (match-beginning 0)))) |
| 1227 | (match-beginning 0)))) | 1213 | ((c-quoted-number-head-before-point) |
| 1228 | 1214 | (if (>= (point) c-new-BEG) | |
| 1229 | ;; Check for a number with quote separators straddling c-new-BEG | 1215 | (setq c-new-BEG (match-beginning 0)))) |
| 1230 | (when c-has-quoted-numbers | 1216 | ((looking-at "\\([^'\\]\\|\\\\.\\)'") |
| 1231 | (goto-char c-new-BEG) | 1217 | (goto-char (match-end 0)) |
| 1232 | (when ;; (c-quoted-number-straddling-point) | 1218 | (if (> (match-end 0) c-new-BEG) |
| 1233 | (c-quoted-number-head-before-point) | 1219 | (setq c-new-BEG (1- (match-beginning 0))))) |
| 1234 | (setq c-new-BEG (match-beginning 0)))) | 1220 | ((or (>= (point) (1- c-new-BEG)) |
| 1221 | (and (eq (point) (- c-new-BEG 2)) | ||
| 1222 | (eq (char-after) ?\\))) | ||
| 1223 | (setq c-new-BEG (1- (point)))) | ||
| 1224 | (t nil))) | ||
| 1235 | 1225 | ||
| 1236 | ;; Do we have a ' (or something like ',',',',...,',') within range of | ||
| 1237 | ;; c-new-END? | ||
| 1238 | (goto-char c-new-END) | 1226 | (goto-char c-new-END) |
| 1239 | (setq p-limit (min (+ (point) 2) (point-max))) | 1227 | ;; We will scan from the BO (logical) line. |
| 1240 | (while (and (skip-chars-forward "^\\\\'" p-limit) | 1228 | (beginning-of-line) |
| 1241 | (< (point) p-limit)) | 1229 | (while (eq (char-before (1- (point))) ?\\) |
| 1242 | (when (eq (char-after) ?\\) | 1230 | (beginning-of-line 0)) |
| 1243 | (setq p-limit (min (1+ p-limit) (point-max)))) | 1231 | (while (and (< (point) c-new-END) |
| 1244 | (forward-char) | 1232 | (search-forward "'" c-new-END t)) |
| 1245 | (setq c-new-END (point))) | 1233 | (cond |
| 1246 | (if (looking-at "[^']?\\('\\([^'\\]\\|\\\\.\\)\\)*'") | 1234 | ((c-quoted-number-straddling-point) |
| 1247 | (setq c-new-END (match-end 0))) | 1235 | (goto-char (match-end 0)) |
| 1248 | 1236 | (if (> (match-end 0) c-new-END) | |
| 1249 | ;; Check for a number with quote separators straddling c-new-END. | 1237 | (setq c-new-END (match-end 0)))) |
| 1250 | (when c-has-quoted-numbers | 1238 | ((c-quoted-number-tail-after-point) |
| 1251 | (goto-char c-new-END) | 1239 | (goto-char (match-end 0)) |
| 1252 | (when ;; (c-quoted-number-straddling-point) | 1240 | (if (> (match-end 0) c-new-END) |
| 1253 | (c-quoted-number-tail-after-point) | 1241 | (setq c-new-END (match-end 0)))) |
| 1254 | (setq c-new-END (match-end 0)))) | 1242 | ((looking-at "\\([^'\\]\\|\\\\.\\)'") |
| 1255 | 1243 | (goto-char (match-end 0)) | |
| 1256 | ;; Remove the '(1) syntax-table property from all "'"s within (c-new-BEG | 1244 | (if (> (match-end 0) c-new-END) |
| 1245 | (setq c-new-END (match-end 0)))) | ||
| 1246 | (t nil))) | ||
| 1247 | ;; Having reached c-new-END, handle any 's after it whose context may be | ||
| 1248 | ;; changed by the current buffer change. | ||
| 1249 | (goto-char c-new-END) | ||
| 1250 | (cond | ||
| 1251 | ((c-quoted-number-tail-after-point) | ||
| 1252 | (setq c-new-END (match-end 0))) | ||
| 1253 | ((looking-at | ||
| 1254 | "\\(\\\\.\\|.\\)?\\('\\([^'\\]\\|\\\\.\\)\\)*'") | ||
| 1255 | (setq c-new-END (match-end 0)))) | ||
| 1256 | |||
| 1257 | ;; Remove the '(1) syntax-table property from any "'"s within (c-new-BEG | ||
| 1257 | ;; c-new-END). | 1258 | ;; c-new-END). |
| 1258 | (c-clear-char-property-with-value-on-char | 1259 | (goto-char c-new-BEG) |
| 1259 | c-new-BEG c-new-END | 1260 | (when (c-search-forward-char-property-with-value-on-char |
| 1260 | 'syntax-table '(1) | 1261 | 'syntax-table '(1) ?\' c-new-END) |
| 1261 | ?') | 1262 | (c-invalidate-state-cache (1- (point))) |
| 1262 | ;; Remove the c-digit-separator text property from the same "'"s. | 1263 | (c-truncate-semi-nonlit-pos-cache (1- (point))) |
| 1263 | (when c-has-quoted-numbers | ||
| 1264 | (c-clear-char-property-with-value-on-char | 1264 | (c-clear-char-property-with-value-on-char |
| 1265 | c-new-BEG c-new-END | 1265 | (1- (point)) c-new-END |
| 1266 | 'c-digit-separator t | 1266 | 'syntax-table '(1) |
| 1267 | ?')))) | 1267 | ?') |
| 1268 | 1268 | ;; Remove the c-digit-separator text property from the same "'"s. | |
| 1269 | (defun c-parse-quotes-after-change (_beg _end _old-len) | 1269 | (when c-has-quoted-numbers |
| 1270 | (c-clear-char-property-with-value-on-char | ||
| 1271 | (1- (point)) c-new-END | ||
| 1272 | 'c-digit-separator t | ||
| 1273 | ?'))))) | ||
| 1274 | |||
| 1275 | (defun c-parse-quotes-after-change (beg end old-len) | ||
| 1270 | ;; This function applies syntax-table properties (value '(1)) and | 1276 | ;; This function applies syntax-table properties (value '(1)) and |
| 1271 | ;; c-digit-separator properties as needed to 's within the range (c-new-BEG | 1277 | ;; c-digit-separator properties as needed to 's within the range (c-new-BEG |
| 1272 | ;; c-new-END). This operation is performed even within strings and | 1278 | ;; c-new-END). This operation is performed even within strings and |
| @@ -1277,25 +1283,34 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") | |||
| 1277 | (c-save-buffer-state (num-beg num-end) | 1283 | (c-save-buffer-state (num-beg num-end) |
| 1278 | ;; Apply the needed syntax-table and c-digit-separator text properties to | 1284 | ;; Apply the needed syntax-table and c-digit-separator text properties to |
| 1279 | ;; quotes. | 1285 | ;; quotes. |
| 1280 | (goto-char c-new-BEG) | 1286 | (save-restriction |
| 1281 | (while (and (< (point) c-new-END) | 1287 | (goto-char c-new-BEG) |
| 1282 | (search-forward "'" c-new-END 'limit)) | 1288 | (while (and (< (point) c-new-END) |
| 1283 | (cond ((and (eq (char-before (1- (point))) ?\\) | 1289 | (search-forward "'" c-new-END 'limit)) |
| 1284 | ;; Check we've got an odd number of \s, here. | 1290 | (cond ((and (eq (char-before (1- (point))) ?\\) |
| 1285 | (save-excursion | 1291 | ;; Check we've got an odd number of \s, here. |
| 1286 | (backward-char) | 1292 | (save-excursion |
| 1287 | (eq (logand (skip-chars-backward "\\\\") 1) 1)))) ; not a real '. | 1293 | (backward-char) |
| 1288 | ((c-quoted-number-straddling-point) | 1294 | (eq (logand (skip-chars-backward "\\\\") 1) 1)))) ; not a real '. |
| 1289 | (setq num-beg (match-beginning 0) | 1295 | ((c-quoted-number-straddling-point) |
| 1290 | num-end (match-end 0)) | 1296 | (setq num-beg (match-beginning 0) |
| 1291 | (c-put-char-properties-on-char num-beg num-end | 1297 | num-end (match-end 0)) |
| 1292 | 'syntax-table '(1) ?') | 1298 | (c-invalidate-state-cache num-beg) |
| 1293 | (c-put-char-properties-on-char num-beg num-end | 1299 | (c-truncate-semi-nonlit-pos-cache num-beg) |
| 1294 | 'c-digit-separator t ?') | 1300 | (c-put-char-properties-on-char num-beg num-end |
| 1295 | (goto-char num-end)) | 1301 | 'syntax-table '(1) ?') |
| 1296 | ((looking-at "\\([^\\']\\|\\\\.\\)'") ; balanced quoted expression. | 1302 | (c-put-char-properties-on-char num-beg num-end |
| 1297 | (goto-char (match-end 0))) | 1303 | 'c-digit-separator t ?') |
| 1298 | (t (c-put-char-property (1- (point)) 'syntax-table '(1))))))) | 1304 | (goto-char num-end)) |
| 1305 | ((looking-at "\\([^\\']\\|\\\\.\\)'") ; balanced quoted expression. | ||
| 1306 | (goto-char (match-end 0))) | ||
| 1307 | (t | ||
| 1308 | (c-invalidate-state-cache (1- (point))) | ||
| 1309 | (c-truncate-semi-nonlit-pos-cache (1- (point))) | ||
| 1310 | (c-put-char-property (1- (point)) 'syntax-table '(1)))) | ||
| 1311 | ;; Prevent the next `c-quoted-number-straddling-point' getting | ||
| 1312 | ;; confused by already processed single quotes. | ||
| 1313 | (narrow-to-region (point) (point-max)))))) | ||
| 1299 | 1314 | ||
| 1300 | (defun c-before-change (beg end) | 1315 | (defun c-before-change (beg end) |
| 1301 | ;; Function to be put on `before-change-functions'. Primarily, this calls | 1316 | ;; Function to be put on `before-change-functions'. Primarily, this calls |