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