aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2003-07-16 15:40:25 +0000
committerStefan Monnier2003-07-16 15:40:25 +0000
commitdb14504a96c36a10605c0595913f196ebfe24115 (patch)
tree11d465a22010406c141c7ca32d57632f3a27fac5
parent9c5b265345e7ff4a4ee41d096e4765910c83ca66 (diff)
downloademacs-db14504a96c36a10605c0595913f196ebfe24115.tar.gz
emacs-db14504a96c36a10605c0595913f196ebfe24115.zip
(syntax-ppss): Catch the case where the buffer is narrowed.
-rw-r--r--lisp/emacs-lisp/syntax.el275
1 files changed, 142 insertions, 133 deletions
diff --git a/lisp/emacs-lisp/syntax.el b/lisp/emacs-lisp/syntax.el
index b5b8ec251a7..7bd8378ab86 100644
--- a/lisp/emacs-lisp/syntax.el
+++ b/lisp/emacs-lisp/syntax.el
@@ -39,7 +39,6 @@
39;; - new functions `syntax-state', ... to replace uses of parse-partial-state 39;; - new functions `syntax-state', ... to replace uses of parse-partial-state
40;; with something higher-level (similar to syntax-ppss-context). 40;; with something higher-level (similar to syntax-ppss-context).
41;; - interaction with mmm-mode. 41;; - interaction with mmm-mode.
42;; - what to do when the buffer is narrowed ?
43 42
44;;; Code: 43;;; Code:
45 44
@@ -118,141 +117,151 @@ Point is at POS when this function returns."
118 (pt-min (point-min))) 117 (pt-min (point-min)))
119 (if (and old-pos (> old-pos pos)) (setq old-pos nil)) 118 (if (and old-pos (> old-pos pos)) (setq old-pos nil))
120 ;; Use the OLD-POS if usable and close. Don't update the `last' cache. 119 ;; Use the OLD-POS if usable and close. Don't update the `last' cache.
121 (if (and old-pos (< (- pos old-pos) 120 (condition-case nil
122 ;; The time to find PPSS using syntax-begin-function 121 (if (and old-pos (< (- pos old-pos)
123 ;; is assumed to be about 2 * distance. 122 ;; The time to use syntax-begin-function and
124 (* 2 (/ (cdr (aref syntax-ppss-stats 5)) 123 ;; find PPSS is assumed to be about 2 * distance.
125 (1+ (car (aref syntax-ppss-stats 5))))))) 124 (* 2 (/ (cdr (aref syntax-ppss-stats 5))
126 (progn 125 (1+ (car (aref syntax-ppss-stats 5)))))))
127 (incf (car (aref syntax-ppss-stats 0))) 126 (progn
128 (incf (cdr (aref syntax-ppss-stats 0)) (- pos old-pos)) 127 (incf (car (aref syntax-ppss-stats 0)))
129 (parse-partial-sexp old-pos pos nil nil old-ppss)) 128 (incf (cdr (aref syntax-ppss-stats 0)) (- pos old-pos))
130 129 (parse-partial-sexp old-pos pos nil nil old-ppss))
131 (cond
132 ;; Use OLD-PPSS if possible and close enough.
133 ((and (not old-pos) old-ppss
134 ;; BEWARE! We rely on the undocumented 9th field.
135 ;; The 9th field currently contains the list of positions
136 ;; of open-parens of the enclosing parens. I.e. those positions
137 ;; are outside of any string/comment and the first of those is
138 ;; outside of any paren (i.e. corresponds to a nil ppss).
139 ;; If this list is empty but we are in a string or comment,
140 ;; then the 8th field contains a similar "toplevel" position.
141 ;; If `pt-min' is too far from `pos', we could try to use
142 ;; other positions in (nth 9 old-ppss), but that doesn't seem
143 ;; to happen in practice and it would complicate this code
144 ;; (and the after-change-function code even more). But maybe it
145 ;; would be useful in "degenerate" cases such as when the whole
146 ;; file is wrapped in a set of parenthesis.
147 (setq pt-min (or (car (nth 9 old-ppss))
148 (nth 8 old-ppss)
149 (nth 2 old-ppss)))
150 (<= pt-min pos) (< (- pos pt-min) syntax-ppss-max-span))
151 (incf (car (aref syntax-ppss-stats 1)))
152 (incf (cdr (aref syntax-ppss-stats 1)) (- pos pt-min))
153 (setq ppss (parse-partial-sexp pt-min pos)))
154 ;; The OLD-* data can't be used. Consult the cache.
155 (t
156 (let ((cache-pred nil)
157 (cache syntax-ppss-cache)
158 (pt-min (point-min))
159 ;; I differentiate between PT-MIN and PT-BEST because I feel
160 ;; like it might be important to ensure that the cache is only
161 ;; filled with 100% sure data (whereas syntax-begin-function
162 ;; might return incorrect data). Maybe that's just stupid.
163 (pt-best (point-min))
164 (ppss-best nil))
165 ;; look for a usable cache entry.
166 (while (and cache (< pos (caar cache)))
167 (setq cache-pred cache)
168 (setq cache (cdr cache)))
169 (if cache (setq pt-min (caar cache) ppss (cdar cache)))
170
171 ;; Setup the after-change function if necessary.
172 (unless (or syntax-ppss-cache syntax-ppss-last)
173 (add-hook 'after-change-functions 'syntax-ppss-flush-cache nil t))
174
175 ;; Use the best of OLD-POS and CACHE.
176 (if (or (not old-pos) (< old-pos pt-min))
177 (setq pt-best pt-min ppss-best ppss)
178 (incf (car (aref syntax-ppss-stats 4)))
179 (incf (cdr (aref syntax-ppss-stats 4)) (- pos old-pos))
180 (setq pt-best old-pos ppss-best old-ppss))
181
182 ;; Use the `syntax-begin-function' if available.
183 ;; We could try using that function earlier, but:
184 ;; - The result might not be 100% reliable, so it's better to use
185 ;; the cache if available.
186 ;; - The function might be slow.
187 ;; - If this function almost always finds a safe nearby spot,
188 ;; the cache won't be populated, so consulting it is cheap.
189 (unless (or syntax-begin-function
190 (not (boundp 'font-lock-beginning-of-syntax-function))
191 (not font-lock-beginning-of-syntax-function))
192 (set (make-local-variable 'syntax-begin-function)
193 font-lock-beginning-of-syntax-function))
194 (when (and syntax-begin-function
195 (progn (goto-char pos)
196 (funcall syntax-begin-function)
197 ;; Make sure it's better.
198 (> (point) pt-best))
199 ;; Simple sanity check.
200 (not (memq (get-text-property (point) 'face)
201 '(font-lock-string-face font-lock-comment-face
202 font-lock-doc-face))))
203 (incf (car (aref syntax-ppss-stats 5)))
204 (incf (cdr (aref syntax-ppss-stats 5)) (- pos (point)))
205 (setq pt-best (point) ppss-best nil))
206 130
207 (cond 131 (cond
208 ;; Quick case when we found a nearby pos. 132 ;; Use OLD-PPSS if possible and close enough.
209 ((< (- pos pt-best) syntax-ppss-max-span) 133 ((and (not old-pos) old-ppss
210 (incf (car (aref syntax-ppss-stats 2))) 134 ;; BEWARE! We rely on the undocumented 9th field. The 9th
211 (incf (cdr (aref syntax-ppss-stats 2)) (- pos pt-best)) 135 ;; field currently contains the list of positions of
212 (setq ppss (parse-partial-sexp pt-best pos nil nil ppss-best))) 136 ;; open-parens of the enclosing parens. I.e. those
213 ;; Slow case: compute the state from some known position and 137 ;; positions are outside of any string/comment
214 ;; populate the cache so we won't need to do it again soon. 138 ;; and the first of those is outside of any paren
139 ;; (i.e. corresponds to a nil ppss). If this list is empty
140 ;; but we are in a string or comment, then the 8th field
141 ;; contains a similar "toplevel" position. If `pt-min' is
142 ;; too far from `pos', we could try to use other positions
143 ;; in (nth 9 old-ppss), but that doesn't seem to happen in
144 ;; practice and it would complicate this code (and the
145 ;; after-change-function code even more). But maybe it
146 ;; would be useful in "degenerate" cases such as when the
147 ;; whole file is wrapped in a set of parenthesis.
148 (setq pt-min (or (car (nth 9 old-ppss))
149 (nth 8 old-ppss)
150 (nth 2 old-ppss)))
151 (<= pt-min pos) (< (- pos pt-min) syntax-ppss-max-span))
152 (incf (car (aref syntax-ppss-stats 1)))
153 (incf (cdr (aref syntax-ppss-stats 1)) (- pos pt-min))
154 (setq ppss (parse-partial-sexp pt-min pos)))
155 ;; The OLD-* data can't be used. Consult the cache.
215 (t 156 (t
216 (incf (car (aref syntax-ppss-stats 3))) 157 (let ((cache-pred nil)
217 (incf (cdr (aref syntax-ppss-stats 3)) (- pos pt-min)) 158 (cache syntax-ppss-cache)
218 159 (pt-min (point-min))
219 ;; If `pt-min' is too far, add a few intermediate entries. 160 ;; I differentiate between PT-MIN and PT-BEST because
220 (while (> (- pos pt-min) (* 2 syntax-ppss-max-span)) 161 ;; I feel like it might be important to ensure that the
221 (setq ppss (parse-partial-sexp 162 ;; cache is only filled with 100% sure data (whereas
222 pt-min (setq pt-min (/ (+ pt-min pos) 2)) 163 ;; syntax-begin-function might return incorrect data).
223 nil nil ppss)) 164 ;; Maybe that's just stupid.
224 (let ((pair (cons pt-min ppss))) 165 (pt-best (point-min))
225 (if cache-pred 166 (ppss-best nil))
226 (push pair (cdr cache-pred)) 167 ;; look for a usable cache entry.
227 (push pair syntax-ppss-cache)))) 168 (while (and cache (< pos (caar cache)))
228 169 (setq cache-pred cache)
229 ;; Compute the actual return value. 170 (setq cache (cdr cache)))
230 (setq ppss (parse-partial-sexp pt-min pos nil nil ppss)) 171 (if cache (setq pt-min (caar cache) ppss (cdar cache)))
231 172
232 ;; Debugging check. 173 ;; Setup the after-change function if necessary.
233 ;; (let ((real-ppss (parse-partial-sexp (point-min) pos))) 174 (unless (or syntax-ppss-cache syntax-ppss-last)
234 ;; (setcar (last ppss 4) 0) 175 (add-hook 'after-change-functions
235 ;; (setcar (last real-ppss 4) 0) 176 'syntax-ppss-flush-cache nil t))
236 ;; (setcar (last ppss 8) nil) 177
237 ;; (setcar (last real-ppss 8) nil) 178 ;; Use the best of OLD-POS and CACHE.
238 ;; (unless (equal ppss real-ppss) 179 (if (or (not old-pos) (< old-pos pt-min))
239 ;; (message "!!Syntax: %s != %s" ppss real-ppss) 180 (setq pt-best pt-min ppss-best ppss)
240 ;; (setq ppss real-ppss))) 181 (incf (car (aref syntax-ppss-stats 4)))
241 182 (incf (cdr (aref syntax-ppss-stats 4)) (- pos old-pos))
242 ;; Store it in the cache. 183 (setq pt-best old-pos ppss-best old-ppss))
243 (let ((pair (cons pos ppss))) 184
244 (if cache-pred 185 ;; Use the `syntax-begin-function' if available.
245 (if (> (- (caar cache-pred) pos) syntax-ppss-max-span) 186 ;; We could try using that function earlier, but:
246 (push pair (cdr cache-pred)) 187 ;; - The result might not be 100% reliable, so it's better to use
247 (setcar cache-pred pair)) 188 ;; the cache if available.
248 (if (or (null syntax-ppss-cache) 189 ;; - The function might be slow.
249 (> (- (caar syntax-ppss-cache) pos) 190 ;; - If this function almost always finds a safe nearby spot,
250 syntax-ppss-max-span)) 191 ;; the cache won't be populated, so consulting it is cheap.
251 (push pair syntax-ppss-cache) 192 (when (and (not syntax-begin-function)
252 (setcar syntax-ppss-cache pair))))))))) 193 (boundp 'font-lock-beginning-of-syntax-function)
253 194 font-lock-beginning-of-syntax-function)
254 (setq syntax-ppss-last (cons pos ppss)) 195 (set (make-local-variable 'syntax-begin-function)
255 ppss))) 196 font-lock-beginning-of-syntax-function))
197 (when (and syntax-begin-function
198 (progn (goto-char pos)
199 (funcall syntax-begin-function)
200 ;; Make sure it's better.
201 (> (point) pt-best))
202 ;; Simple sanity check.
203 (not (memq (get-text-property (point) 'face)
204 '(font-lock-string-face font-lock-doc-face
205 font-lock-comment-face))))
206 (incf (car (aref syntax-ppss-stats 5)))
207 (incf (cdr (aref syntax-ppss-stats 5)) (- pos (point)))
208 (setq pt-best (point) ppss-best nil))
209
210 (cond
211 ;; Quick case when we found a nearby pos.
212 ((< (- pos pt-best) syntax-ppss-max-span)
213 (incf (car (aref syntax-ppss-stats 2)))
214 (incf (cdr (aref syntax-ppss-stats 2)) (- pos pt-best))
215 (setq ppss (parse-partial-sexp pt-best pos nil nil ppss-best)))
216 ;; Slow case: compute the state from some known position and
217 ;; populate the cache so we won't need to do it again soon.
218 (t
219 (incf (car (aref syntax-ppss-stats 3)))
220 (incf (cdr (aref syntax-ppss-stats 3)) (- pos pt-min))
221
222 ;; If `pt-min' is too far, add a few intermediate entries.
223 (while (> (- pos pt-min) (* 2 syntax-ppss-max-span))
224 (setq ppss (parse-partial-sexp
225 pt-min (setq pt-min (/ (+ pt-min pos) 2))
226 nil nil ppss))
227 (let ((pair (cons pt-min ppss)))
228 (if cache-pred
229 (push pair (cdr cache-pred))
230 (push pair syntax-ppss-cache))))
231
232 ;; Compute the actual return value.
233 (setq ppss (parse-partial-sexp pt-min pos nil nil ppss))
234
235 ;; Debugging check.
236 ;; (let ((real-ppss (parse-partial-sexp (point-min) pos)))
237 ;; (setcar (last ppss 4) 0)
238 ;; (setcar (last real-ppss 4) 0)
239 ;; (setcar (last ppss 8) nil)
240 ;; (setcar (last real-ppss 8) nil)
241 ;; (unless (equal ppss real-ppss)
242 ;; (message "!!Syntax: %s != %s" ppss real-ppss)
243 ;; (setq ppss real-ppss)))
244
245 ;; Store it in the cache.
246 (let ((pair (cons pos ppss)))
247 (if cache-pred
248 (if (> (- (caar cache-pred) pos) syntax-ppss-max-span)
249 (push pair (cdr cache-pred))
250 (setcar cache-pred pair))
251 (if (or (null syntax-ppss-cache)
252 (> (- (caar syntax-ppss-cache) pos)
253 syntax-ppss-max-span))
254 (push pair syntax-ppss-cache)
255 (setcar syntax-ppss-cache pair)))))))))
256
257 (setq syntax-ppss-last (cons pos ppss))
258 ppss)
259 (args-out-of-range
260 ;; If the buffer is more narrowed than when we built the cache,
261 ;; we may end up calling parse-partial-sexp with a position before
262 ;; point-min. In that case, just parse from point-min assuming
263 ;; a nil state.
264 (parse-partial-sexp (point-min) pos)))))
256 265
257;; Debugging functions 266;; Debugging functions
258 267