Mercurial > emacs
comparison lisp/textmodes/xml-lite.el @ 44242:84ff52bf6d2f
(xml-lite-get-context): Allow stopping even with an empty context.
Don't save excursion any more. Ignore end-tags in sgml-empty-tags.
Don't complain about unmatched start-tags in sgml-unclosed-tags.
(xml-lite-get-context, xml-lite-calculate-indent)
(xml-lite-insert-end-tag): Save excursion around xml-lite-get-context.
(xml-lite-indent-line): Use back-to-indentation.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Fri, 29 Mar 2002 20:10:46 +0000 |
parents | 2eeb8d7f1161 |
children | c3ee131a3ab1 |
comparison
equal
deleted
inserted
replaced
44241:600b7e53cf18 | 44242:84ff52bf6d2f |
---|---|
203 (or (null end) | 203 (or (null end) |
204 (> end point)))) | 204 (> end point)))) |
205 | 205 |
206 (defun xml-lite-get-context (&optional full) | 206 (defun xml-lite-get-context (&optional full) |
207 "Determine the context of the current position. | 207 "Determine the context of the current position. |
208 If FULL is `empty', return even if the context is empty (i.e. | |
209 we just skipped over some element and got to a beginning of line). | |
208 If FULL is non-nil, parse back to the beginning of the buffer, otherwise | 210 If FULL is non-nil, parse back to the beginning of the buffer, otherwise |
209 parse until we find a start-tag as the first thing on a line. | 211 parse until we find a start-tag as the first thing on a line. |
210 | 212 |
211 The context is a list of tag-info structures. The last one is the tag | 213 The context is a list of tag-info structures. The last one is the tag |
212 immediately enclosing the current position." | 214 immediately enclosing the current position." |
213 (let ((here (point)) | 215 (let ((here (point)) |
214 (ignore nil) | 216 (ignore nil) |
215 tag-info context) | 217 (context nil) |
218 tag-info) | |
216 ;; CONTEXT keeps track of the tag-stack | 219 ;; CONTEXT keeps track of the tag-stack |
217 ;; IGNORE keeps track of the nesting level of point relative to the | 220 ;; IGNORE keeps track of the nesting level of point relative to the |
218 ;; first (outermost) tag on the context. This is the list of | 221 ;; first (outermost) tag on the context. This is the list of |
219 ;; enclosing start-tags we'll have to ignore. | 222 ;; enclosing start-tags we'll have to ignore. |
220 (save-excursion | 223 (skip-chars-backward " \t\n") ; Make sure we're not at indentation. |
221 | 224 (while |
222 (while | 225 (and (or ignore (not (if full (eq full 'empty) context)) |
223 (and (or (not context) | 226 (not (xml-lite-at-indentation-p))) |
224 ignore | 227 (setq tag-info (xml-lite-parse-tag-backward))) |
225 full | 228 |
226 (not (xml-lite-at-indentation-p))) | 229 ;; This tag may enclose things we thought were tags. If so, |
227 (setq tag-info (xml-lite-parse-tag-backward))) | 230 ;; discard them. |
228 | 231 (while (and context |
229 ;; This tag may enclose things we thought were tags. If so, | 232 (> (xml-lite-tag-end tag-info) |
230 ;; discard them. | 233 (xml-lite-tag-end (car context)))) |
231 (while (and context | 234 (setq context (cdr context))) |
232 (> (xml-lite-tag-end tag-info) | |
233 (xml-lite-tag-end (car context)))) | |
234 (setq context (cdr context))) | |
235 | 235 |
236 (cond | 236 (cond |
237 | 237 |
238 ;; inside a tag ... | 238 ;; inside a tag ... |
239 ((xml-lite-inside-tag-p tag-info here) | 239 ((xml-lite-inside-tag-p tag-info here) |
240 (push tag-info context)) | 240 (push tag-info context)) |
241 | 241 |
242 ;; start-tag | 242 ;; start-tag |
243 ((eq (xml-lite-tag-type tag-info) 'open) | 243 ((eq (xml-lite-tag-type tag-info) 'open) |
244 (cond | 244 (cond |
245 ((null ignore) (push tag-info context)) | 245 ((null ignore) (push tag-info context)) |
246 ((eq t (compare-strings (xml-lite-tag-name tag-info) nil nil | 246 ((eq t (compare-strings (xml-lite-tag-name tag-info) nil nil |
247 (car ignore) nil nil t)) | 247 (car ignore) nil nil t)) |
248 (setq ignore (cdr ignore))) | 248 (setq ignore (cdr ignore))) |
249 (t | 249 (t |
250 ;; The open and close tags don't match. | 250 ;; The open and close tags don't match. |
251 (if (not sgml-xml-mode) | 251 (if (not sgml-xml-mode) |
252 ;; Assume the open tag is simply not closed. | 252 ;; Assume the open tag is simply not closed. |
253 (message "Unclosed tag <%s>" (xml-lite-tag-name tag-info)) | 253 (unless (member-ignore-case (xml-lite-tag-name tag-info) |
254 (message "Unmatched tags <%s> and </%s>" | 254 sgml-unclosed-tags) |
255 (xml-lite-tag-name tag-info) (pop ignore)))))) | 255 (message "Unclosed tag <%s>" (xml-lite-tag-name tag-info))) |
256 | 256 (message "Unmatched tags <%s> and </%s>" |
257 ;; end-tag | 257 (xml-lite-tag-name tag-info) (pop ignore)))))) |
258 ((eq (xml-lite-tag-type tag-info) 'close) | 258 |
259 (push (xml-lite-tag-name tag-info) ignore)) | 259 ;; end-tag |
260 | 260 ((eq (xml-lite-tag-type tag-info) 'close) |
261 ))) | 261 (if (and (not sgml-xml-mode) |
262 (member-ignore-case (xml-lite-tag-name tag-info) | |
263 sgml-empty-tags)) | |
264 (message "Spurious </%s>: empty tag" (xml-lite-tag-name tag-info)) | |
265 (push (xml-lite-tag-name tag-info) ignore))) | |
266 )) | |
262 | 267 |
263 ;; return context | 268 ;; return context |
264 context | 269 context)) |
265 )) | |
266 | 270 |
267 (defun xml-lite-show-context (&optional full) | 271 (defun xml-lite-show-context (&optional full) |
268 "Display the current context. | 272 "Display the current context. |
269 If FULL is non-nil, parse back to the beginning of the buffer." | 273 If FULL is non-nil, parse back to the beginning of the buffer." |
270 (interactive "P") | 274 (interactive "P") |
271 (with-output-to-temp-buffer "*XML Context*" | 275 (with-output-to-temp-buffer "*XML Context*" |
272 (pp (xml-lite-get-context full)))) | 276 (pp (save-excursion (xml-lite-get-context full))))) |
273 | 277 |
274 | 278 |
275 ;; Indenting | 279 ;; Indenting |
276 | 280 |
277 (defun xml-lite-calculate-indent () | 281 (defun xml-lite-calculate-indent () |
278 "Calculate the column to which this line should be indented." | 282 "Calculate the column to which this line should be indented." |
279 (let* ((here (point)) | 283 (let* ((here (point)) |
280 (context (xml-lite-get-context)) | 284 (context (save-excursion (xml-lite-get-context))) |
281 (ref-tag-info (car context)) | 285 (ref-tag-info (car context)) |
282 (last-tag-info (car (last context)))) | 286 (last-tag-info (car (last context)))) |
283 | 287 |
284 (save-excursion | 288 (save-excursion |
285 (cond | 289 (cond |
336 "Indent the current line as XML." | 340 "Indent the current line as XML." |
337 (interactive) | 341 (interactive) |
338 (let* ((savep (point)) | 342 (let* ((savep (point)) |
339 (indent-col | 343 (indent-col |
340 (save-excursion | 344 (save-excursion |
341 (beginning-of-line) | 345 (back-to-indentation) |
342 (skip-chars-forward " \t") | |
343 (if (>= (point) savep) (setq savep nil)) | 346 (if (>= (point) savep) (setq savep nil)) |
344 ;; calculate basic indent | |
345 (xml-lite-calculate-indent)))) | 347 (xml-lite-calculate-indent)))) |
346 (if savep | 348 (if savep |
347 (save-excursion (indent-line-to indent-col)) | 349 (save-excursion (indent-line-to indent-col)) |
348 (indent-line-to indent-col)))) | 350 (indent-line-to indent-col)))) |
349 | 351 |
351 ;; Editing shortcuts | 353 ;; Editing shortcuts |
352 | 354 |
353 (defun xml-lite-insert-end-tag () | 355 (defun xml-lite-insert-end-tag () |
354 "Insert an end-tag for the current element." | 356 "Insert an end-tag for the current element." |
355 (interactive) | 357 (interactive) |
356 (let* ((context (xml-lite-get-context)) | 358 (let* ((context (save-excursion (xml-lite-get-context))) |
357 (tag-info (car (last context))) | 359 (tag-info (car (last context))) |
358 (type (and tag-info (xml-lite-tag-type tag-info)))) | 360 (type (and tag-info (xml-lite-tag-type tag-info)))) |
359 | 361 |
360 (cond | 362 (cond |
361 | 363 |