aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2017-09-03 11:01:21 +0000
committerAlan Mackenzie2017-09-03 11:01:21 +0000
commitc8439abe22f1bb5e717f5c0f3725084c8d738155 (patch)
treeb026c82df2762959bd93cc8a457e166f4cbbc7c3
parentb733a910091c426de0d831f1ce0cda4ae736ab69 (diff)
downloademacs-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.el23
-rw-r--r--lisp/progmodes/cc-mode.el181
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
1191character with value CHAR.
1192LIMIT bounds the search. The value comparison is done with `equal'.
1193PROPERTY must be a constant.
1194
1195Leave point just after the character, and set the match data on
1196this character, and return point. If the search fails, return
1197nil; 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