comparison lisp/psgml/psgml-edit.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; psgml-edit.el --- Editing commands for SGML-mode with parsing support
2 ;; $Id: psgml-edit.el,v 1.1.1.1 1996/12/18 03:35:19 steve Exp $
3
4 ;; Copyright (C) 1994, 1995, 1996 Lennart Staflin
5
6 ;; Author: Lennart Staflin <lenst@lysator.liu.se>
7
8 ;; This program is free software; you can redistribute it and/or
9 ;; modify it under the terms of the GNU General Public License
10 ;; as published by the Free Software Foundation; either version 2
11 ;; of the License, or (at your option) any later version.
12 ;;
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
17 ;;
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program; if not, write to the Free Software
20 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22
23 ;;;; Commentary:
24
25 ;; Part of major mode for editing the SGML document-markup language.
26
27
28 ;;;; Code:
29
30 (provide 'psgml-edit)
31 (require 'psgml)
32 (require 'psgml-parse)
33
34
35 ;;;; Variables
36
37 (defvar sgml-split-level nil
38 "Used by sgml-split-element")
39
40
41 ;;;; SGML mode: structure editing
42
43 (defun sgml-last-element ()
44 "Return the element where last command left point.
45 This either uses the save value in `sgml-last-element' or parses the buffer
46 to find current open element."
47 (setq sgml-markup-type nil)
48 (if (and (memq last-command sgml-users-of-last-element)
49 sgml-last-element) ; Don't return nil
50 sgml-last-element
51 (setq sgml-last-element (sgml-find-context-of (point)))) )
52
53 (defun sgml-set-last-element (&optional el)
54 (if el (setq sgml-last-element el))
55 (sgml-show-context sgml-last-element))
56
57 (defun sgml-beginning-of-element ()
58 "Move to after the start-tag of the current element.
59 If the start-tag is implied, move to the start of the element."
60 (interactive)
61 (goto-char (sgml-element-stag-end (sgml-last-element)))
62 (sgml-set-last-element (if (sgml-element-empty sgml-last-element)
63 (sgml-element-parent sgml-last-element))))
64
65 (defun sgml-end-of-element ()
66 "Move to before the end-tag of the current element."
67 (interactive)
68 (goto-char (sgml-element-etag-start (sgml-last-element)))
69 (sgml-set-last-element (if (sgml-element-empty sgml-last-element)
70 (sgml-element-parent sgml-last-element))))
71
72 (defun sgml-backward-up-element ()
73 "Move backward out of this element level.
74 That is move to before the start-tag or where a start-tag is implied."
75 (interactive)
76 (goto-char (sgml-element-start (sgml-last-element)))
77 (sgml-set-last-element (sgml-element-parent sgml-last-element)))
78
79 (defun sgml-up-element ()
80 "Move forward out of this element level.
81 That is move to after the end-tag or where an end-tag is implied."
82 (interactive)
83 (goto-char (sgml-element-end (sgml-last-element)))
84 (sgml-set-last-element (sgml-element-parent sgml-last-element)))
85
86 (defun sgml-forward-element ()
87 "Move forward over next element."
88 (interactive)
89 (let ((next
90 (sgml-find-element-after (point) (sgml-last-element))))
91 (goto-char (sgml-element-end next))
92 (sgml-set-last-element (sgml-element-parent next))))
93
94 (defun sgml-backward-element ()
95 "Move backward over previous element at this level.
96 With implied tags this is ambigous."
97 (interactive)
98 (let ((prev ; previous element
99 (sgml-find-previous-element (point) (sgml-last-element))))
100 (goto-char (sgml-element-start prev))
101 (sgml-set-last-element (sgml-element-parent prev))))
102
103 (defun sgml-down-element ()
104 "Move forward and down one level in the element structure."
105 (interactive)
106 (let ((to
107 (sgml-find-element-after (point) (sgml-last-element))))
108 (goto-char (sgml-element-stag-end to))
109 (sgml-set-last-element (if (sgml-element-empty to)
110 (sgml-element-parent to)
111 to))))
112
113
114 (defun sgml-kill-element ()
115 "Kill the element following the cursor."
116 (interactive "*")
117 (sgml-parse-to-here)
118 (when sgml-markup-type
119 (error "Point is inside markup"))
120 (kill-region (point)
121 (sgml-element-end (sgml-find-element-after (point)))))
122
123 (defun sgml-transpose-element ()
124 "Interchange element before point with element after point, leave point after."
125 (interactive "*")
126 (let ((pre (sgml-find-previous-element (point)))
127 (next (sgml-find-element-after (point)))
128 s1 s2 m2)
129 (goto-char (sgml-element-start next))
130 (setq m2 (point-marker))
131 (setq s2 (buffer-substring (point)
132 (sgml-element-end next)))
133 (delete-region (point) (sgml-element-end next))
134 (goto-char (sgml-element-start pre))
135 (setq s1 (buffer-substring (point) (sgml-element-end pre)))
136 (delete-region (point) (sgml-element-end pre))
137 (insert-before-markers s2)
138 (goto-char m2)
139 (insert s1)
140 (sgml-message "")))
141
142 (defun sgml-mark-element ()
143 "Set mark after next element."
144 (interactive)
145 (push-mark (sgml-element-end (sgml-find-element-after (point))) nil t))
146
147 (defun sgml-mark-current-element ()
148 "Set mark at end of current element, and leave point before current element."
149 (interactive)
150 (let ((el (sgml-find-element-of (point))))
151 (goto-char (sgml-element-start el))
152 (push-mark (sgml-element-end el) nil t)))
153
154
155 (defun sgml-change-element-name (gi)
156 "Replace the name of the current element with a new name.
157 Eventual attributes of the current element will be translated if
158 possible."
159 (interactive
160 (list (let ((el (sgml-find-element-of (point))))
161 (goto-char (sgml-element-start el))
162 (sgml-read-element-name
163 (format "Change %s to: " (sgml-element-name el))))))
164 (when (or (null gi) (equal gi ""))
165 (error "Illegal name"))
166 (let* ((element (sgml-find-element-of (point)))
167 (attspec (sgml-element-attribute-specification-list element))
168 (oldattlist (sgml-element-attlist element)))
169 (unless (sgml-element-empty element)
170 (goto-char (sgml-element-end element))
171 (delete-char (- (sgml-element-etag-len element)))
172 (insert (sgml-end-tag-of gi)))
173 (goto-char (sgml-element-start element))
174 (delete-char (sgml-element-stag-len element))
175 (insert (sgml-start-tag-of gi))
176 (forward-char -1)
177 (let* ((newel (sgml-find-element-of (point)))
178 (newattlist (sgml-element-attlist newel))
179 (newasl (sgml-translate-attribute-specification-list
180 attspec oldattlist newattlist)))
181 (sgml-insert-attributes newasl newattlist))))
182
183 (defun sgml-translate-attribute-specification-list (values from to)
184 "Translate attribute specification from one element type to another.
185 Input attribute values in VALUES using attlist FROM is translated into
186 a list using attlist TO."
187 (let ((new-values nil)
188 (sgml-show-warnings t)
189 tem)
190 (loop for attspec in values
191 as from-decl = (sgml-lookup-attdecl (sgml-attspec-name attspec) from)
192 as to-decl = (sgml-lookup-attdecl (sgml-attspec-name attspec) to)
193 do
194 (cond
195 ;; Special case ID attribute
196 ((and (eq 'id (sgml-attdecl-declared-value from-decl))
197 (setq tem (sgml-attribute-with-declared-value to 'id)))
198 (push
199 (sgml-make-attspec (sgml-attdecl-name tem)
200 (sgml-attspec-attval attspec))
201 new-values))
202 ;; Use attribute with same name if compatible type
203 ((equal (sgml-attdecl-declared-value from-decl)
204 (sgml-attdecl-declared-value to-decl))
205 (push attspec new-values))
206 (to-decl
207 (sgml-log-warning
208 "Attribute %s has new declared-value"
209 (sgml-attspec-name attspec))
210 (push attspec new-values))
211 (t
212 (sgml-log-warning "Can't translate attribute %s = %s"
213 (sgml-attspec-name attspec)
214 (sgml-attspec-attval attspec)))))
215 new-values))
216
217 (defun sgml-untag-element ()
218 "Remove tags from current element."
219 (interactive "*")
220 (let ((el (sgml-find-element-of (point))))
221 (when (or (sgml-strict-epos-p (sgml-element-stag-epos el))
222 (sgml-strict-epos-p (sgml-element-etag-epos el)))
223 (error "Current element has some tag inside an entity reference"))
224 (goto-char (sgml-element-etag-start el))
225 (delete-char (sgml-element-etag-len el))
226 (goto-char (sgml-element-start el))
227 (delete-char (sgml-element-stag-len el))))
228
229 (defun sgml-kill-markup ()
230 "Kill next tag, markup declaration or process instruction."
231 (interactive "*")
232 (let ((start (point)))
233 (sgml-with-parser-syntax
234 (sgml-parse-s)
235 (setq sgml-markup-start (point))
236 (cond ((sgml-parse-markup-declaration 'ignore))
237 ((sgml-parse-processing-instruction))
238 ((sgml-skip-tag)))
239 (kill-region start (point)))))
240
241
242 ;;;; SGML mode: folding
243
244 (defun sgml-fold-region (beg end &optional unhide)
245 "Hide (or if prefixarg unhide) region.
246 If called from a program first two arguments are start and end of
247 region. And optional third argument true unhides."
248 (interactive "r\nP")
249 (let ((mp (buffer-modified-p))
250 (inhibit-read-only t) ;
251 (buffer-read-only nil) ; should not need this, but
252 ; perhaps some old version of
253 ; emacs does not understand
254 ; inhibit-read-only
255 (before-change-function nil)
256 (after-change-function nil))
257 (setq selective-display t)
258 (unwind-protect
259 (subst-char-in-region beg end
260 (if unhide ?\r ?\n)
261 (if unhide ?\n ?\r)
262 'noundo)
263 (when sgml-buggy-subst-char-in-region
264 (set-buffer-modified-p mp)))))
265
266 (defun sgml-fold-element ()
267 "Fold the lines comprising the current element, leaving the first line visible.
268 This uses the selective display feature."
269 (interactive)
270 (sgml-parse-to-here)
271 (cond ((and (eq sgml-current-tree sgml-top-tree) ; outside document element
272 sgml-markup-type)
273 (sgml-fold-region sgml-markup-start
274 (save-excursion
275 (sgml-parse-to (point))
276 (point))))
277 ((and (eq sgml-current-tree sgml-top-tree) ; outside document element
278 (looking-at " *<!"))
279 (sgml-fold-region (point)
280 (save-excursion
281 (skip-chars-forward " \t")
282 (sgml-parse-to (1+ (point)))
283 (point))))
284
285 (t
286 (let ((el (sgml-find-element-of (point))))
287 (when (eq el sgml-top-tree)
288 (error "No element here"))
289 (save-excursion
290 (goto-char (sgml-element-end el))
291 (when (zerop (sgml-element-etag-len el))
292 (skip-chars-backward " \t\n"))
293 (sgml-fold-region (sgml-element-start el)
294 (point)))))))
295
296 (defun sgml-fold-subelement ()
297 "Fold all elements current elements content, leaving the first lines visible.
298 This uses the selective display feature."
299 (interactive)
300 (let* ((el (sgml-find-element-of (point)))
301 (start (sgml-element-start el))
302 (end (sgml-element-end el))
303 (c (sgml-element-content el)))
304 (while c
305 (sgml-fold-region (sgml-element-start c)
306 (sgml-element-end c))
307 (setq c (sgml-element-next c)))))
308
309 (defun sgml-unfold-line ()
310 "Show hidden lines in current line."
311 (interactive)
312 (let ((op (point)))
313 (beginning-of-line)
314 (push-mark)
315 (end-of-line)
316 (exchange-point-and-mark)
317 (sgml-fold-region (point) (mark) 'unhide)
318 (goto-char op)))
319
320 (defun sgml-unfold-element ()
321 "Show all hidden lines in current element."
322 (interactive)
323 (let* ((element (sgml-find-element-of (point))))
324 (sgml-fold-region (sgml-element-start element)
325 (sgml-element-end element)
326 'unfold)))
327
328 (defun sgml-expand-element ()
329 "As sgml-fold-subelement, but unfold first."
330 (interactive)
331 (sgml-unfold-element)
332 (sgml-fold-subelement))
333
334 (defun sgml-unfold-all ()
335 "Show all hidden lines in buffer."
336 (interactive)
337 (sgml-fold-region (point-min)
338 (point-max)
339 'unfold))
340
341 ;;;; SGML mode: indentation and movement
342
343 (defun sgml-indent-line (&optional col element)
344 "Indent line, calling parser to determine level unless COL or ELEMENT
345 is given. If COL is given it should be the column to indent to. If
346 ELEMENT is given it should be a parse tree node, from which the level
347 is determined."
348 (when sgml-indent-step
349 (let ((here (point-marker)))
350 (back-to-indentation)
351 (unless (or col element)
352 ;; Determine element
353 (setq element
354 (let ((sgml-throw-on-error 'parse-error))
355 (catch sgml-throw-on-error
356 (if (eobp)
357 (sgml-find-context-of (point))
358 (sgml-find-element-of (point)))))))
359 (when (eq element sgml-top-tree) ; not in a element at all
360 (setq element nil) ; forget element
361 (goto-char here)) ; insert normal tab insted)
362 (when element
363 (sgml-with-parser-syntax
364 (let ((stag (sgml-is-start-tag))
365 (etag (sgml-is-end-tag)))
366 (when (and
367 (not (member* (sgml-element-gi
368 (if (or stag etag)
369 (sgml-element-parent element)
370 element))
371 sgml-inhibit-indent-tags
372 :test #'equalp))
373 (or sgml-indent-data
374 (not (sgml-element-data-p
375 (if stag
376 (sgml-element-parent element)
377 element)))))
378 (setq col
379 (* sgml-indent-step
380 (+ (if (or stag etag) -1 0)
381 (sgml-element-level element))))))))
382 (when (and col (/= col (current-column)))
383 (beginning-of-line 1)
384 (delete-horizontal-space)
385 (indent-to col))
386 (when (< (point) here)
387 (goto-char here))
388 col)))
389
390 (defun sgml-next-data-field ()
391 "Move forward to next point where data is allowed."
392 (interactive)
393 (when (eobp)
394 (error "End of buffer"))
395 (let ((sgml-throw-on-warning 'next-data)
396 (avoid-el (sgml-last-element)))
397 ;; Avoid stopping in current element, unless point is in the start
398 ;; tag of the element
399 (when (< (point) (sgml-element-stag-end avoid-el))
400 (setq avoid-el nil))
401 (catch sgml-throw-on-warning
402 (while (progn
403 (sgml-parse-to (1+ (point)))
404 (setq sgml-last-element
405 (if (not (eq ?< (following-char)))
406 (sgml-find-element-of (point))
407 sgml-current-tree))
408 (or (eq sgml-last-element avoid-el)
409 (not (sgml-element-data-p sgml-last-element)))))
410 (sgml-set-last-element))))
411
412 (defun sgml-next-trouble-spot ()
413 "Move forward to next point where something is amiss with the structure."
414 (interactive)
415 (push-mark)
416 (sgml-note-change-at (point)) ; Prune the parse tree
417 (sgml-parse-to (point))
418 (let ((sgml-last-trouble-spot (point))
419 (sgml-throw-on-warning 'trouble))
420 (or (catch sgml-throw-on-warning
421 (sgml-parse-until-end-of nil t))
422 (message "Ok"))))
423
424
425
426 ;;;; SGML mode: information display
427
428 (defun sgml-list-valid-tags ()
429 "Display a list of the contextually valid tags."
430 (interactive)
431 (sgml-parse-to-here)
432 (let ((model (sgml-element-model sgml-current-tree)))
433 (with-output-to-temp-buffer "*Tags*"
434 (princ (format "Current element: %s %s\n"
435 (sgml-element-name sgml-current-tree)
436 (if (sgml-eltype-defined
437 (sgml-element-eltype sgml-current-tree))
438 ""
439 "[UNDEFINED]")))
440 (princ (format "Element content: %s %s\n"
441 (cond ((or (sgml-current-mixed-p) (eq model sgml-any))
442 "mixed")
443 ((sgml-model-group-p model)
444 "element")
445 (t
446 model))
447 (if (eq model sgml-any)
448 "[ANY]" "")))
449
450 (cond ((sgml-final-p sgml-current-state)
451 (princ "Valid end-tags : ")
452 (loop for e in (sgml-current-list-of-endable-eltypes)
453 do (princ (sgml-end-tag-of e)) (princ " "))
454 (terpri))
455 (t
456 (princ "Current element can not end here\n")))
457 ;;; (let ((s (sgml-tree-shortmap sgml-current-tree)))
458 ;;; (when s
459 ;;; (princ (format "Current shortref map: %s\n" s))))
460 (princ "Valid start-tags\n")
461 (sgml-print-valid-tags "In current element:"
462 sgml-current-tree sgml-current-state))))
463
464 (defun sgml-print-valid-tags (prompt tree state &optional exclude omitted-stag)
465 (if (not (sgml-model-group-p state))
466 (princ (format "%s (in %s)\n" prompt state))
467 (let* ((req (sgml-required-tokens state))
468 (elems (nconc req
469 (delq sgml-pcdata-token
470 (sgml-optional-tokens state))))
471 (in (sgml-tree-includes tree))
472 (ex (append exclude (sgml-tree-excludes tree))))
473 ;; Modify for exceptions
474 (while in
475 (unless (memq (car in) elems)
476 (setq elems (nconc elems (list (car in)))))
477 (setq in (cdr in)))
478 (while ex
479 (setq elems (delq (car ex) elems))
480 (setq ex (cdr ex)))
481 ;;
482 (setq elems (sort elems (function string-lessp)))
483 (sgml-print-list-of-tags prompt elems)
484 ;; Check for omissable start-tags
485 (when (and req (null (cdr req)))
486 ;; *** Assumes tokens are eltypes
487 (let ((el (sgml-fake-open-element tree (car req))))
488 (when (sgml-element-stag-optional el)
489 (sgml-print-valid-tags
490 (format "If omitting %s:" (sgml-start-tag-of el))
491 el
492 (sgml-element-model el)
493 (append exclude elems)
494 'omitted-stag))))
495 ;; Check for omissable end-tag
496 (when (and (not omitted-stag)
497 (sgml-final-p state)
498 (sgml-element-etag-optional tree))
499 (sgml-print-valid-tags
500 (format "If omitting %s:" (sgml-end-tag-of tree))
501 (sgml-element-parent tree)
502 (sgml-element-pstate tree)
503 (append exclude elems))))))
504
505 (defun sgml-print-list-of-tags (prompt list)
506 (when list
507 (princ prompt)
508 (let ((col (length prompt))
509 (w (1- (frame-width))))
510 (loop for e in list
511 as str = (sgml-start-tag-of e)
512 do
513 (setq col (+ col (length str) 2))
514 (cond ((>= col w)
515 (setq col (+ (length str) 2))
516 (terpri)))
517 (princ " ")
518 (princ str))
519 (terpri))))
520
521 (defun sgml-show-context (&optional element)
522 "Display where the cursor is in the element hierarchy."
523 (interactive)
524 (let* ((el (or element (sgml-last-element)))
525 (model (sgml-element-model el)))
526 (sgml-message "%s %s"
527 (cond
528 ((and (null element) ; Don't trust sgml-markup-type if
529 ; explicit element is given as argument
530 sgml-markup-type))
531 ((sgml-element-mixed el)
532 "#PCDATA")
533 ((not (sgml-model-group-p model))
534 model)
535 (t ""))
536 (if (eq el sgml-top-tree)
537 "in empty context"
538 (sgml-element-context-string el)))))
539
540 (defun sgml-what-element ()
541 "Display what element is under the cursor."
542 (interactive)
543 (let ((el (sgml-find-element-of (point))))
544 (assert (not (null el)))
545 (message "%s %s"
546 (cond ((eq el sgml-top-tree)
547 "outside document element")
548 ((< (point) (sgml-element-stag-end el))
549 "start-tag")
550 ((>= (point) (sgml-element-etag-start el))
551 "end-tag")
552 (t
553 "content"))
554 (sgml-element-context-string el))))
555
556 ;;;; SGML mode: keyboard inserting
557
558 (defun sgml-insert-tag (tag &optional silent no-nl-after)
559 "Insert a tag, reading tag name in minibuffer with completion.
560 If the variable sgml-balanced-tag-edit is t, also inserts the
561 corresponding end tag. If sgml-leave-point-after-insert is t, the point
562 is left after the inserted tag(s), unless the element has som required
563 content. If sgml-leave-point-after-insert is nil the point is left
564 after the first tag inserted."
565 (interactive
566 (list
567 (completing-read "Tag: " (sgml-completion-table) nil t "<" )))
568 (sgml-find-context-of (point))
569 (assert (null sgml-markup-type))
570 ;; Fix white-space before tag
571 (unless (sgml-element-data-p (sgml-parse-to-here))
572 (skip-chars-backward " \t")
573 (cond ((bolp)
574 (if (looking-at "^\\s-*$")
575 (fixup-whitespace)))
576 (t
577 (insert "\n"))))
578 (insert tag)
579 (sgml-indent-line)
580 (unless no-nl-after
581 (save-excursion
582 (unless (sgml-element-data-p (sgml-parse-to-here))
583 (unless (eolp)
584 (save-excursion (insert "\n"))))))
585 (or silent (sgml-show-context)))
586
587 (defvar sgml-new-attribute-list-function
588 (function sgml-default-asl))
589
590 (defun sgml-insert-element (name &optional after silent)
591 "Reads element name from minibuffer and inserts start and end tags."
592 (interactive (list (sgml-read-element-name "Element: ")
593 sgml-leave-point-after-insert))
594 (let (newpos ; position to leave cursor at
595 element ; inserted element
596 (sgml-show-warnings nil))
597 (when (and name (not (equal name "")))
598 (sgml-insert-tag (sgml-start-tag-of name) 'silent)
599 (forward-char -1)
600 (setq element (sgml-find-element-of (point)))
601 (sgml-insert-attributes (funcall sgml-new-attribute-list-function
602 element)
603 (sgml-element-attlist element))
604 (forward-char 1)
605 (when (not (sgml-element-empty element))
606 (when (and sgml-auto-insert-required-elements
607 (sgml-model-group-p sgml-current-state))
608 (let (tem)
609 (while (and (setq tem (sgml-required-tokens sgml-current-state))
610 (null (cdr tem)))
611 (setq tem (sgml-insert-element (car tem) t t))
612 (setq newpos (or newpos tem))
613 (sgml-parse-to-here))
614 (when tem ; more than one req elem
615 (insert "\n")
616 (when sgml-insert-missing-element-comment
617 (insert (format "<!-- one of %s -->" tem))
618 (sgml-indent-line nil element)))))
619 (setq newpos (or newpos (point)))
620 (when sgml-insert-end-tag-on-new-line
621 (insert "\n"))
622 (sgml-insert-tag (sgml-end-tag-of name) 'silent)
623 (unless after
624 (goto-char newpos))
625 (unless silent (sgml-show-context)))
626 newpos)))
627
628 (defun sgml-default-asl (element)
629 (loop for attdecl in (sgml-element-attlist element)
630 when (sgml-default-value-type-p (sgml-attdecl-default-value attdecl)
631 'required)
632 collect
633 (sgml-make-attspec
634 (sgml-attdecl-name attdecl)
635 (sgml-read-attribute-value attdecl nil))))
636
637 (defun sgml-tag-region (element start end)
638 "Reads element name from minibuffer and inserts start and end tags."
639 (interactive
640 (list
641 (save-excursion (goto-char (region-beginning))
642 (sgml-read-element-name "Tag region with element: "))
643 (region-beginning)
644 (region-end)))
645 (save-excursion
646 (when (and element (not (equal element "")))
647 (goto-char end)
648 (insert (sgml-end-tag-of element))
649 (goto-char start)
650 (sgml-insert-tag (sgml-start-tag-of element)))))
651
652 (defun sgml-insert-attributes (avl attlist)
653 "Insert the attributes with values AVL and declarations ATTLIST.
654 AVL should be a assoc list mapping symbols to strings."
655 (let (name val dcl def tem)
656 (loop for attspec in attlist do
657 (setq name (sgml-attspec-name attspec)
658 val (cdr-safe (sgml-lookup-attspec name avl))
659 dcl (sgml-attdecl-declared-value attspec)
660 def (sgml-attdecl-default-value attspec))
661 (unless val ; no value given
662 ;; Supply the default value if a value is needed
663 (cond ((sgml-default-value-type-p 'required def)
664 (setq val ""))
665 ((and (not (or sgml-omittag sgml-shorttag))
666 (consp def))
667 (setq val (sgml-default-value-attval def)))))
668 (cond
669 ((null val)) ; Ignore
670 ;; Ignore attributes with default value
671 ((and (consp def)
672 (eq sgml-minimize-attributes 'max)
673 (or sgml-omittag sgml-shorttag)
674 (equal val (sgml-default-value-attval def))))
675 ;; No attribute name for token groups
676 ((and sgml-minimize-attributes sgml-shorttag
677 (member (sgml-general-case val)
678 (sgml-declared-value-token-group dcl)))
679 (insert " " val))
680 (t
681 (insert " " name "=" (sgml-quote-attribute-value val)))))
682 (when auto-fill-function
683 (funcall auto-fill-function))))
684
685
686 (defun sgml-quote-attribute-value (value)
687 "Add quotes to the string VALUE unless minimization is on."
688 (let ((quote ""))
689 (cond ((and (not sgml-always-quote-attributes)
690 sgml-shorttag
691 (string-match "\\`[.A-Za-z0-9---]+\\'" value))
692 ) ; no need to quote
693 ((not (string-match "\"" value)) ; can use "" quotes
694 (setq quote "\""))
695 (t ; use '' quotes
696 (setq quote "'")))
697 (concat quote value quote)))
698
699 (defun sgml-completion-table (&optional avoid-tags-in-cdata)
700 (sgml-parse-to-here)
701 (when sgml-markup-type
702 (error "No tags allowed"))
703 (cond ((or (sgml-model-group-p sgml-current-state)
704 (eq sgml-current-state sgml-any))
705 (append
706 (mapcar (function (lambda (x) (cons (sgml-end-tag-of x) x)))
707 (sgml-current-list-of-endable-eltypes))
708 (mapcar (function (lambda (x) (cons (sgml-start-tag-of x) x)))
709 (sgml-current-list-of-valid-eltypes))))
710 (t
711 (sgml-message "%s" sgml-current-state)
712 nil)))
713
714 (defun sgml-insert-end-tag ()
715 "Insert end-tag for the current open element."
716 (interactive "*")
717 (sgml-parse-to-here)
718 (cond
719 ((eq sgml-current-tree sgml-top-tree)
720 (sgml-error "No open element"))
721 ((not (sgml-final-p sgml-current-state))
722 (sgml-error "Can`t end element here"))
723 (t
724 (when (and sgml-indent-step
725 (not (sgml-element-data-p sgml-current-tree)))
726 (delete-horizontal-space)
727 (unless (bolp)
728 (insert "\n")))
729 (when (prog1 (bolp)
730 (insert (if (eq t (sgml-element-net-enabled sgml-current-tree))
731 "/"
732 ;; wing change: If there is more than one endable
733 ;; tag, we probably want the outermost one rather
734 ;; than the innermost one. Thus, we end a </ul>
735 ;; even when a </li> is possible.
736 (sgml-end-tag-of
737 (car (last (sgml-current-list-of-endable-eltypes)))))))
738 (sgml-indent-line)))))
739
740 (defun sgml-insert-start-tag (name asl attlist &optional net)
741 (insert "<" name)
742 (sgml-insert-attributes asl attlist)
743 (insert (if net "/" ">")))
744
745 (defun sgml-change-start-tag (element asl)
746 (let ((name (sgml-element-gi element))
747 (attlist (sgml-element-attlist element)))
748 (assert (sgml-bpos-p (sgml-element-stag-epos element)))
749 (goto-char (sgml-element-start element))
750 (delete-char (sgml-element-stag-len element))
751 (sgml-insert-start-tag name asl attlist
752 (eq t (sgml-element-net-enabled element)))))
753
754 (defun sgml-read-attribute-value (attdecl curvalue)
755 "Return the attribute value read from user.
756 ATTDECL is the attribute declaration for the attribute to read.
757 CURVALUE is nil or a string that will be used as default value."
758 (assert attdecl)
759 (let* ((name (sgml-attdecl-name attdecl))
760 (dv (sgml-attdecl-declared-value attdecl))
761 (tokens (sgml-declared-value-token-group dv))
762 (notations (sgml-declared-value-notation dv))
763 (type (cond (tokens "token")
764 (notations "notation")
765 (t (symbol-name dv))))
766 (prompt
767 (format "Value for %s (%s%s): "
768 name type
769 (if curvalue
770 (format " Default: %s" curvalue)
771 "")))
772 value)
773 (setq value
774 (if (or tokens notations)
775 (completing-read prompt
776 (mapcar 'list (or tokens notations))
777 nil t)
778 (read-string prompt)))
779 (if (and curvalue (equal value ""))
780 curvalue value)))
781
782 (defun sgml-non-fixed-attributes (attlist)
783 (loop for attdecl in attlist
784 unless (sgml-default-value-type-p 'fixed
785 (sgml-attdecl-default-value attdecl))
786 collect attdecl))
787
788 (defun sgml-insert-attribute (name value)
789 "Read attribute name and value from minibuffer and insert attribute spec."
790 (interactive
791 (let* ((el (sgml-find-attribute-element))
792 (name
793 (completing-read
794 "Attribute name: "
795 (mapcar (function (lambda (a) (list (sgml-attdecl-name a))))
796 (sgml-non-fixed-attributes (sgml-element-attlist el)))
797 nil t)))
798 (list name
799 (sgml-read-attribute-value
800 (sgml-lookup-attdecl name (sgml-element-attlist el))
801 (sgml-element-attval el name)))))
802 ;; Body
803 (assert (stringp name))
804 (assert (or (null value) (stringp value)))
805 (let* ((el (sgml-find-attribute-element))
806 (asl (cons (sgml-make-attspec name value)
807 (sgml-element-attribute-specification-list el)))
808 (in-tag (< (point) (sgml-element-stag-end el))))
809 (sgml-change-start-tag el asl)
810 (when in-tag (forward-char -1))))
811
812 (defun sgml-split-element ()
813 "Split the current element at point.
814 If repeated, the containing element will be split before the beginning
815 of then current element."
816 (interactive "*")
817 (setq sgml-split-level
818 (if (eq this-command last-command)
819 (1+ sgml-split-level)
820 0))
821 (let ((u (sgml-find-context-of (point)))
822 (start (point-marker))
823 before)
824 (loop repeat sgml-split-level do
825 (goto-char (sgml-element-start u))
826 (setq u (sgml-element-parent u)))
827 ;; Verify that a new element can be started
828 (unless (and (sgml-element-pstate u) ; in case of top element
829 (sgml-get-move (sgml-element-pstate u)
830 (sgml-element-name u)))
831
832 (sgml-error "The %s element can't be split"
833 (sgml-element-name u)))
834 ;; Do the split
835 (sgml-insert-end-tag)
836 (sgml-insert-tag (sgml-start-tag-of u) 'silent)
837 (skip-chars-forward " \t\n")
838 (sgml-indent-line)
839 (when (> sgml-split-level 0)
840 (goto-char start))
841 (or (eq sgml-top-tree
842 (setq u (sgml-element-parent u)))
843 (sgml-message
844 "Repeat the command to split the containing %s element"
845 (sgml-element-name u)))))
846
847 ;;; David Megginson's custom menus for keys
848
849 (defun sgml-custom-dtd (doctype)
850 "Insert a DTD declaration from the sgml-custom-dtd alist."
851 (interactive
852 (list (completing-read "Insert DTD: " sgml-custom-dtd nil t)))
853 (let ((entry (assoc doctype sgml-custom-dtd)))
854 (sgml-doctype-insert (second entry) (cddr entry))))
855
856 (defun sgml-custom-markup (markup)
857 "Insert markup from the sgml-custom-markup alist."
858 (interactive
859 (list (completing-read "Insert Markup: " sgml-custom-markup nil t)))
860 (sgml-insert-markup (cadr (assoc markup sgml-custom-markup))))
861
862
863 ;;;; SGML mode: Menu inserting
864
865 (defun sgml-tags-menu (event)
866 "Pop up a menu with valid tags and insert the choosen tag.
867 If the variable sgml-balanced-tag-edit is t, also inserts the
868 corresponding end tag. If sgml-leave-point-after-insert is t, the point
869 is left after the inserted tag(s), unless the element has som required
870 content. If sgml-leave-point-after-insert is nil the point is left
871 after the first tag inserted."
872 (interactive "*e")
873 (let ((end (sgml-mouse-region)))
874 (sgml-parse-to-here)
875 (cond
876 ((eq sgml-markup-type 'start-tag)
877 (sgml-attrib-menu event))
878 (t
879 (let ((what
880 (sgml-menu-ask event (if (or end sgml-balanced-tag-edit)
881 'element 'tags))))
882 (cond
883 ((null what))
884 (end
885 (sgml-tag-region what (point) end))
886 (sgml-balanced-tag-edit
887 (sgml-insert-element what))
888 (t
889 (sgml-insert-tag what))))))))
890
891 (defun sgml-element-menu (event)
892 "Pop up a menu with valid elements and insert choice.
893 If sgml-leave-point-after-insert is nil the point is left after the first
894 tag inserted."
895 (interactive "*e")
896 (let ((what (sgml-menu-ask event 'element)))
897 (and what (sgml-insert-element what))))
898
899 (defun sgml-start-tag-menu (event)
900 "Pop up a menu with valid start-tags and insert choice."
901 (interactive "*e")
902 (let ((what (sgml-menu-ask event 'start-tag)))
903 (and what (sgml-insert-tag what))))
904
905 (defun sgml-end-tag-menu (event)
906 "Pop up a menu with valid end-tags and insert choice."
907 (interactive "*e")
908 (let ((what (sgml-menu-ask event 'end-tag)))
909 (and what (sgml-insert-tag what))))
910
911 (defun sgml-tag-region-menu (event)
912 "Pop up a menu with valid elements and tag current region with the choice."
913 (interactive "*e")
914 (let ((what (sgml-menu-ask event 'element)))
915 (and what (sgml-tag-region what
916 (region-beginning)
917 (region-end)))))
918
919 (defun sgml-menu-ask (event type)
920 (sgml-parse-to-here)
921 (let (tab
922 (title (capitalize (symbol-name type))))
923 (cond
924 (sgml-markup-type)
925 ((eq type 'element)
926 (setq tab
927 (mapcar (function symbol-name)
928 (sgml-current-list-of-valid-eltypes))))
929 (t
930 (unless (eq type 'start-tag)
931 (setq tab
932 (mapcar (function sgml-end-tag-of)
933 (sgml-current-list-of-endable-eltypes))))
934 (unless (eq type 'end-tag)
935 (setq tab
936 (nconc tab
937 (mapcar (function sgml-start-tag-of)
938 (sgml-current-list-of-valid-eltypes)))))))
939 (or tab
940 (error "No valid %s at this point" type))
941 (or
942 (sgml-popup-menu event
943 title
944 (mapcar (function (lambda (x) (cons x x)))
945 tab))
946 (message nil))))
947
948 (defun sgml-entities-menu (event)
949 (interactive "*e")
950 (sgml-need-dtd)
951 (let ((menu
952 (mapcar (function (lambda (x) (cons x x)))
953 (sort (sgml-map-entities (function sgml-entity-name)
954 (sgml-dtd-entities sgml-dtd-info)
955 t)
956 (function string-lessp))))
957 choice)
958 (unless menu
959 (error "No entities defined"))
960 (setq choice (sgml-popup-menu event "Entities" menu))
961 (when choice
962 (insert "&" choice ";"))))
963
964 (defun sgml-doctype-insert (doctype vars)
965 "Insert string DOCTYPE (ignored if nil) and set variables in &rest VARS.
966 VARS should be a list of variables and values.
967 For backward compatibility a singel string instead of a variable is
968 assigned to sgml-default-dtd-file.
969 All variables are made buffer local and are also added to the
970 buffers local variables list."
971 (when doctype
972 (unless (bolp)
973 (insert "\n"))
974 (unless (eolp)
975 (insert "\n")
976 (forward-char -1))
977 (sgml-insert-markup doctype))
978 (while vars
979 (cond ((stringp (car vars))
980 (sgml-set-local-variable 'sgml-default-dtd-file (car vars))
981 (setq vars (cdr vars)))
982 ((car vars) ; Avoid nil
983 (sgml-set-local-variable (car vars) (cadr vars))
984 (setq vars (cddr vars)))))
985 (setq sgml-top-tree nil))
986
987 (defun sgml-attrib-menu (event)
988 "Pop up a menu of the attributes of the current element
989 \(or the element whith start-tag before point)."
990 (interactive "e")
991 (let* ((el (sgml-find-attribute-element))
992 (attlist (sgml-non-fixed-attributes (sgml-element-attlist el)))
993 tokens menu other)
994 (or attlist
995 (error "No non-fixed attributes for element"))
996 (setq menu
997 (loop for attdecl in attlist
998 for name = (sgml-attdecl-name attdecl)
999 for defval = (sgml-attdecl-default-value attdecl)
1000 for tokens = (or (sgml-declared-value-token-group
1001 (sgml-attdecl-declared-value attdecl))
1002 (sgml-declared-value-notation
1003 (sgml-attdecl-declared-value attdecl)))
1004 collect
1005 (cons
1006 (sgml-attdecl-name attdecl)
1007 (nconc
1008 (if tokens
1009 (loop for val in tokens collect
1010 (list val
1011 (list 'sgml-insert-attribute name val)))
1012 (list
1013 (list "Set attribute value"
1014 (list 'sgml-insert-attribute
1015 (sgml-attdecl-name attdecl)
1016 (list 'sgml-read-attribute-value
1017 (list 'quote attdecl)
1018 (sgml-element-attval el name))))))
1019 (if (sgml-default-value-type-p 'required defval)
1020 nil
1021 (list "--"
1022 (list (if (sgml-default-value-type-p nil defval)
1023 (format "Default: %s"
1024 (sgml-default-value-attval defval))
1025 "#IMPLIED")
1026 (list 'sgml-insert-attribute name nil))))))))
1027 (sgml-popup-multi-menu event "Attributes" menu)))
1028
1029 ;;;; SGML mode: Fill
1030
1031 (defun sgml-fill-element (element)
1032 "Fill bigest enclosing element with mixed content.
1033 If current element has pure element content, recursively fill the
1034 subelements."
1035 (interactive (list (sgml-find-element-of (point))))
1036 ;;
1037 (message "Filling...")
1038 (when (sgml-element-mixed element)
1039 ;; Find bigest enclosing element with mixed content
1040 (while (sgml-element-mixed (sgml-element-parent element))
1041 (setq element (sgml-element-parent element))))
1042 ;;
1043 (sgml-do-fill element)
1044 (sgml-message "Done"))
1045
1046 (defun sgml-do-fill (element)
1047 (when sgml-debug
1048 (goto-char (sgml-element-start element))
1049 (sit-for 0))
1050 (save-excursion
1051 (cond
1052 ((sgml-element-mixed element)
1053 (let (last-pos
1054 (c (sgml-element-content element))
1055 (agenda nil)) ; regions to fill later
1056 (goto-char (sgml-element-stag-end element))
1057 (when (eolp) (forward-char 1))
1058 (setq last-pos (point))
1059 (while c
1060 (cond
1061 ((sgml-element-mixed c))
1062 (t
1063 ;; Put region before element on agenda. Can't fill it now
1064 ;; that would mangel the parse tree that is beeing traversed.
1065 (push (cons last-pos (sgml-element-start c))
1066 agenda)
1067 (goto-char (sgml-element-start c))
1068 (sgml-do-fill c)
1069 ;; Fill may change parse tree, get a fresh
1070 (setq c (sgml-find-element-of (point)))
1071 (setq last-pos (sgml-element-end c))))
1072 (setq c (sgml-element-next c)))
1073 ;; Fill the last region in content of element,
1074 ;; but get a fresh parse tree, if it has change due to other fills.
1075 (sgml-fill-region last-pos
1076 (sgml-element-etag-start
1077 (sgml-find-element-of
1078 (sgml-element-start element))))
1079 (while agenda
1080 (sgml-fill-region (caar agenda) (cdar agenda))
1081 (setq agenda (cdr agenda)))))
1082 (t
1083 ;; If element is not mixed, fill subelements recursively
1084 (let ((c (sgml-element-content element)))
1085 (while c
1086 (goto-char (sgml-element-start c))
1087 (sgml-do-fill c)
1088 (setq c (sgml-element-next (sgml-find-element-of (point))))))))))
1089
1090 (defun sgml-fill-region (start end)
1091 (sgml-message "Filling...")
1092 (save-excursion
1093 (goto-char end)
1094 (skip-chars-backward " \t\n")
1095 (while (progn (beginning-of-line 1)
1096 (< start (point)))
1097 (delete-horizontal-space)
1098 (delete-char -1)
1099 (insert " "))
1100 (end-of-line 1)
1101 (let (give-up prev-column opoint)
1102 (while (and (not give-up) (> (current-column) fill-column))
1103 (setq prev-column (current-column))
1104 (setq opoint (point))
1105 (move-to-column (1+ fill-column))
1106 (skip-chars-backward "^ \t\n")
1107 (if (bolp)
1108 (re-search-forward "[ \t]" opoint t))
1109 (setq opoint (point))
1110 (skip-chars-backward " \t")
1111 (if (bolp)
1112 (setq give-up t)
1113 (delete-region (point) opoint)
1114 (newline)
1115 (sgml-indent-line)
1116 (end-of-line 1)
1117 (setq give-up (>= (current-column) prev-column)))))))
1118
1119 ;;;; SGML mode: Attribute editing
1120
1121 (defvar sgml-start-attributes nil)
1122 (defvar sgml-main-buffer nil)
1123 (defvar sgml-attlist nil)
1124
1125 (defun sgml-edit-attributes ()
1126 "Edit attributes of current element.
1127 Editing is done in a separate window."
1128 (interactive)
1129 (let ((element (sgml-find-attribute-element)))
1130 (unless (sgml-bpos-p (sgml-element-stag-epos element))
1131 (error "Element's start-tag is not in the buffer"))
1132 (push-mark)
1133 (goto-char (sgml-element-start element))
1134 (let* ((start (point-marker))
1135 (asl (sgml-element-attribute-specification-list element))
1136 (cb (current-buffer))
1137 (quote sgml-always-quote-attributes))
1138 (switch-to-buffer-other-window
1139 (sgml-attribute-buffer element asl))
1140 (sgml-edit-attrib-mode)
1141 (make-local-variable 'sgml-attlist)
1142 (setq sgml-attlist (sgml-element-attlist element))
1143 (make-local-variable 'sgml-start-attributes)
1144 (setq sgml-start-attributes start)
1145 (make-local-variable 'sgml-always-quote-attributes)
1146 (setq sgml-always-quote-attributes quote)
1147 (make-local-variable 'sgml-main-buffer)
1148 (setq sgml-main-buffer cb))))
1149
1150 (defun sgml-attribute-buffer (element asl)
1151 (let ((bname "*Edit attributes*")
1152 (buf nil)
1153 (inhibit-read-only t))
1154 (save-excursion
1155 (when (setq buf (get-buffer bname))
1156 (kill-buffer buf))
1157 (setq buf (get-buffer-create bname))
1158 (set-buffer buf)
1159 (erase-buffer)
1160 (sgml-insert '(read-only t rear-nonsticky (read-only))
1161 "<%s -- Edit values and finish with C-c C-c --\n"
1162 (sgml-element-name element))
1163 (loop
1164 for attr in (sgml-element-attlist element) do
1165 ;; Produce text like
1166 ;; name = value
1167 ;; -- declaration : default --
1168 (let* ((aname (sgml-attdecl-name attr))
1169 (dcl-value (sgml-attdecl-declared-value attr))
1170 (def-value (sgml-attdecl-default-value attr))
1171 (cur-value (sgml-lookup-attspec aname asl)))
1172 (sgml-insert ; atribute name
1173 '(read-only t rear-nonsticky (read-only))
1174 " %s = " aname)
1175 (cond ; attribute value
1176 ((sgml-default-value-type-p 'fixed def-value)
1177 (sgml-insert '(read-only t category sgml-fixed
1178 rear-nonsticky (category))
1179 "#FIXED %s"
1180 (sgml-default-value-attval def-value)))
1181 ((and (null cur-value)
1182 (or (memq def-value '(implied conref current))
1183 (sgml-default-value-attval def-value)))
1184 (sgml-insert '(category sgml-default rear-nonsticky (category))
1185 "#DEFAULT"))
1186 ((not (null cur-value))
1187 (sgml-insert nil "%s" (sgml-attspec-attval cur-value))))
1188 (sgml-insert
1189 '(read-only 1)
1190 "\n\t-- %s: %s --\n"
1191 (cond ((sgml-declared-value-token-group dcl-value))
1192 ((sgml-declared-value-notation dcl-value)
1193 (format "NOTATION %s"
1194 (sgml-declared-value-notation dcl-value)))
1195 (t
1196 dcl-value))
1197 (cond ((sgml-default-value-attval def-value))
1198 (t
1199 (concat "#" (upcase (symbol-name def-value))))))))
1200 (sgml-insert '(read-only t) ">")
1201 (goto-char (point-min))
1202 (sgml-edit-attrib-next))
1203 buf))
1204
1205 (defvar sgml-edit-attrib-mode-map (make-sparse-keymap))
1206 (define-key sgml-edit-attrib-mode-map "\C-c\C-c" 'sgml-edit-attrib-finish)
1207 (define-key sgml-edit-attrib-mode-map "\C-c\C-d" 'sgml-edit-attrib-default)
1208 (define-key sgml-edit-attrib-mode-map "\C-c\C-k" 'sgml-edit-attrib-clear)
1209
1210 (define-key sgml-edit-attrib-mode-map "\C-a" 'sgml-edit-attrib-field-start)
1211 (define-key sgml-edit-attrib-mode-map "\C-e" 'sgml-edit-attrib-field-end)
1212 (define-key sgml-edit-attrib-mode-map "\t" 'sgml-edit-attrib-next)
1213
1214 (defun sgml-edit-attrib-mode ()
1215 "Major mode to edit attribute specification list.\\<sgml-edit-attrib-mode-map>
1216 Use \\[sgml-edit-attrib-next] to move between input fields. Use
1217 \\[sgml-edit-attrib-default] to make an attribute have its default
1218 value. To abort edit kill buffer (\\[kill-buffer]) and remove window
1219 (\\[delete-window]). To finsh edit use \\[sgml-edit-attrib-finish].
1220
1221 \\{sgml-edit-attrib-mode-map}"
1222 (kill-all-local-variables)
1223 (setq mode-name "SGML edit attributes"
1224 major-mode 'sgml-edit-attrib-mode)
1225 (use-local-map sgml-edit-attrib-mode-map)
1226 (run-hooks 'text-mode-hook 'sgml-edit-attrib-mode-hook))
1227
1228 (defun sgml-edit-attrib-finish ()
1229 "Finish editing and insert attribute values in original buffer."
1230 (interactive)
1231 (let ((cb (current-buffer))
1232 (asl (sgml-edit-attrib-specification-list))
1233 ;; save buffer local variables
1234 (start sgml-start-attributes))
1235 (when (markerp start)
1236 (delete-windows-on cb)
1237 (switch-to-buffer (marker-buffer start))
1238 (kill-buffer cb)
1239 (goto-char start)
1240 (let ((element (sgml-find-element-of start)))
1241 ;; *** Should the it be verified that this element
1242 ;; is the one edited?
1243 (sgml-change-start-tag element asl)))))
1244
1245
1246 (defun sgml-edit-attrib-specification-list ()
1247 (goto-char (point-min))
1248 (forward-line 1)
1249 (sgml-with-parser-syntax
1250 (let ((asl nil)
1251 (al sgml-attlist))
1252 (while (not (eq ?> (following-char)))
1253 (sgml-parse-s)
1254 (let ((name (sgml-check-nametoken)))
1255 (forward-char 3)
1256 (unless (memq (get-text-property (point) 'category)
1257 '(sgml-default sgml-fixed))
1258 (push
1259 (sgml-make-attspec (sgml-attdecl-name (car al))
1260 (sgml-extract-attribute-value
1261 (sgml-attdecl-declared-value (car al))))
1262 asl))
1263 (while (progn (beginning-of-line 2)
1264 (or (eolp)
1265 (not (get-text-property (point) 'read-only))))))
1266 ; was (eq t)
1267 (forward-line 1)
1268 (setq al (cdr al)))
1269 asl)))
1270
1271
1272 (defun sgml-extract-attribute-value (type)
1273 (save-excursion
1274 (save-restriction
1275 (narrow-to-region (point)
1276 (progn (sgml-edit-attrib-field-end)
1277 (point)))
1278 (unless (eq type 'cdata)
1279 (subst-char-in-region (point-min) (point-max) ?\n ? )
1280 (goto-char (point-min))
1281 (delete-horizontal-space))
1282 (goto-char (point-min))
1283 (when (search-forward "\"" nil t) ; don't allow both " and '
1284 (goto-char (point-min))
1285 (while (search-forward "'" nil t) ; replace ' with char ref
1286 (replace-match "&#39;")))
1287 (buffer-string))))
1288
1289 (defun sgml-edit-attrib-default ()
1290 "Set current attribute value to default."
1291 (interactive)
1292 (sgml-edit-attrib-clear)
1293 (save-excursion
1294 (sgml-insert '(category sgml-default)
1295 "#DEFAULT")))
1296
1297 (defun sgml-edit-attrib-clear ()
1298 "Kill the value of current attribute."
1299 (interactive)
1300 (kill-region
1301 (progn (sgml-edit-attrib-field-start) (point))
1302 (progn (sgml-edit-attrib-field-end) (point))))
1303
1304 (defun sgml-edit-attrib-field-start ()
1305 "Go to the start of the attribute value field."
1306 (interactive)
1307 (let (start)
1308 (beginning-of-line 1)
1309 (while (not (eq t (get-text-property (point) 'read-only)))
1310 (beginning-of-line 0))
1311 (setq start (next-single-property-change (point) 'read-only))
1312 (unless start (error "No attribute value here"))
1313 (assert (number-or-marker-p start))
1314 (goto-char start)))
1315
1316 (defun sgml-edit-attrib-field-end ()
1317 "Go to the end of the attribute value field."
1318 (interactive)
1319 (sgml-edit-attrib-field-start)
1320 (let ((end (if (and (eolp)
1321 (get-text-property (1+ (point)) 'read-only))
1322 (point)
1323 (next-single-property-change (point) 'read-only))))
1324 (assert (number-or-marker-p end))
1325 (goto-char end)))
1326
1327 (defun sgml-edit-attrib-next ()
1328 "Move to next attribute value."
1329 (interactive)
1330 (or (search-forward-regexp "^ *[.A-Za-z0-9---]+ *= ?" nil t)
1331 (goto-char (point-min))))
1332
1333
1334 ;;;; SGML mode: Hiding tags/attributes
1335
1336 (defconst sgml-tag-regexp
1337 "\\(</?>\\|</?[A-Za-z][---A-Za-z0-9.]*\\(\\([^'\"></]\\|'[^']*'\\|\"[^\"]*\"\\)*\\)>?\\)")
1338
1339 (defun sgml-operate-on-tags (action &optional attr-p)
1340 (let ((buffer-modified-p (buffer-modified-p))
1341 (inhibit-read-only t)
1342 (buffer-read-only nil)
1343 (before-change-function nil)
1344 (markup-index ; match-data index in tag regexp
1345 (if attr-p 2 1))
1346 (tagcount ; number tags to give them uniq
1347 ; invisible properties
1348 1))
1349 (unwind-protect
1350 (save-excursion
1351 (goto-char (point-min))
1352 (while (re-search-forward sgml-tag-regexp nil t)
1353 (cond
1354 ((eq action 'hide)
1355 (let ((tag (downcase
1356 (buffer-substring (1+ (match-beginning 0))
1357 (match-beginning 1)))))
1358 (if (or attr-p (not (member tag sgml-exposed-tags)))
1359 (add-text-properties
1360 (match-beginning markup-index) (match-end markup-index)
1361 (list 'invisible tagcount
1362 'rear-nonsticky '(invisible face))))))
1363 ((eq action 'show) ; ignore markup-index
1364 (remove-text-properties (match-beginning 0) (match-end 0)
1365 '(invisible nil)))
1366 (t (error "Invalid action: %s" action)))
1367 (incf tagcount)))
1368 (set-buffer-modified-p buffer-modified-p))))
1369
1370 (defun sgml-hide-tags ()
1371 "Hide all tags in buffer."
1372 (interactive)
1373 (sgml-operate-on-tags 'hide))
1374
1375 (defun sgml-show-tags ()
1376 "Show hidden tags in buffer."
1377 (interactive)
1378 (sgml-operate-on-tags 'show))
1379
1380 (defun sgml-hide-attributes ()
1381 "Hide all attribute specifications in the buffer."
1382 (interactive)
1383 (sgml-operate-on-tags 'hide 'attributes))
1384
1385 (defun sgml-show-attributes ()
1386 "Show all attribute specifications in the buffer."
1387 (interactive)
1388 (sgml-operate-on-tags 'show 'attributes))
1389
1390
1391 ;;;; SGML mode: Normalize (and misc manipulations)
1392
1393 (defun sgml-expand-shortref-to-text (name)
1394 (let (before-change-function
1395 (entity (sgml-lookup-entity name (sgml-dtd-entities sgml-dtd-info))))
1396 (cond
1397 ((null entity) (sgml-error "Undefined entity %s" name))
1398 ((sgml-entity-data-p entity)
1399 (sgml-expand-shortref-to-entity name))
1400 (t
1401 (delete-region sgml-markup-start (point))
1402 (sgml-entity-insert-text entity)
1403 (setq sgml-goal (point-max)) ; May have changed size of buffer
1404 ;; now parse the entity text
1405 (goto-char (setq sgml-rs-ignore-pos sgml-markup-start))))))
1406
1407 (defun sgml-expand-shortref-to-entity (name)
1408 (let ((end (point))
1409 (re-found nil)
1410 before-change-function)
1411 (goto-char sgml-markup-start)
1412 (setq re-found (search-forward "\n" end t))
1413 (delete-region sgml-markup-start end)
1414 (insert "&" name (if re-found "\n" ";"))
1415 (setq sgml-goal (point-max)) ; May have changed size of buffer
1416 (goto-char (setq sgml-rs-ignore-pos sgml-markup-start))))
1417
1418 (defun sgml-expand-all-shortrefs (to-entity)
1419 "Expand all short references in the buffer.
1420 Short references to text entities are expanded to the replacement text
1421 of the entity other short references are expanded into general entity
1422 references. If argument, TO-ENTITY, is non-nil, or if called
1423 interactive with numeric prefix argument, all short references are
1424 replaced by generaly entity references."
1425 (interactive "*P")
1426 (sgml-reparse-buffer
1427 (if to-entity
1428 (function sgml-expand-shortref-to-entity)
1429 (function sgml-expand-shortref-to-text))))
1430
1431 (defun sgml-normalize (to-entity &optional element)
1432 "Normalize buffer by filling in omitted tags and expanding empty tags.
1433 Argument TO-ENTITY controls how short references are expanded as with
1434 `sgml-expand-all-shortrefs'. An optional argument ELEMENT can be the
1435 element to normalize insted of the whole buffer, if used no short
1436 references will be expanded."
1437 (interactive "*P")
1438 (unless element
1439 (sgml-expand-all-shortrefs to-entity))
1440 (let ((only-one (not (null element))))
1441 (setq element (or element (sgml-top-element)))
1442 (goto-char (sgml-element-end element))
1443 (let ((before-change-function nil))
1444 (sgml-normalize-content element only-one)))
1445 (sgml-note-change-at (sgml-element-start element))
1446 (sgml-message "Done"))
1447
1448 (defun sgml-normalize-element ()
1449 (interactive "*")
1450 (sgml-normalize nil (sgml-find-element-of (point))))
1451
1452 (defun sgml-normalize-content (element only-first)
1453 "Normalize all elements in a content where ELEMENT is first element.
1454 If sgml-normalize-trims is non-nil, trim off white space from ends of
1455 elements with omitted end-tags."
1456 (let ((content nil))
1457 (while element ; Build list of content elements
1458 (push element content)
1459 (setq element (if only-first
1460 nil
1461 (sgml-element-next element))))
1462 (while content
1463 (setq element (car content))
1464 ;; Progress report
1465 (sgml-lazy-message "Normalizing %d%% left"
1466 (/ (point) (/ (+ (point-max) 100) 100)))
1467 ;; Fix the end-tag
1468 (sgml-normalize-end-tag element)
1469 ;; Fix tags of content
1470 (sgml-normalize-content (sgml-tree-content element) nil)
1471 ;; Fix the start-tag
1472 (sgml-normalize-start-tag element)
1473 ;; Next content element
1474 (setq content (cdr content)))))
1475
1476 (defun sgml-normalize-start-tag (element)
1477 (when (sgml-bpos-p (sgml-element-stag-epos element))
1478 (goto-char (min (point) (sgml-element-start element)))
1479 (let ((name (sgml-element-gi element))
1480 (attlist (sgml-element-attlist element))
1481 (asl (sgml-element-attribute-specification-list element)))
1482 (save-excursion
1483 (assert (or (zerop (sgml-element-stag-len element))
1484 (= (point) (sgml-element-start element))))
1485 (delete-char (sgml-element-stag-len element))
1486 (sgml-insert-start-tag name asl attlist nil)))))
1487
1488 (defun sgml-normalize-end-tag (element)
1489 (unless (sgml-element-empty element)
1490 (when (sgml-bpos-p (sgml-element-etag-epos element))
1491 (goto-char (min (point) (sgml-element-etag-start element)))
1492 (if (and (zerop (sgml-element-etag-len element))
1493 sgml-normalize-trims)
1494 (skip-chars-backward " \t\n\r"))
1495 (delete-char (sgml-tree-etag-len element))
1496 (save-excursion (insert (sgml-end-tag-of element))))))
1497
1498
1499 (defun sgml-make-character-reference (&optional invert)
1500 "Convert character after point into a character reference.
1501 If called with a numeric argument, convert a character reference back
1502 to a normal character. If called from a program, set optional
1503 argument INVERT to non-nil."
1504 (interactive "*P")
1505 (cond
1506 (invert
1507 (or (looking-at "&#\\([0-9]+\\)[;\n]?")
1508 (error "No character reference after point"))
1509 (let ((c (string-to-int (buffer-substring (match-beginning 1)
1510 (match-end 1)))))
1511 (delete-region (match-beginning 0)
1512 (match-end 0))
1513 (insert c)))
1514 ;; Convert character to &#nn;
1515 (t
1516 (let ((c (following-char)))
1517 (delete-char 1)
1518 (insert (format "&#%d;" c))))))
1519
1520 (defun sgml-expand-entity-reference ()
1521 "Insert the text of the entity referenced at point."
1522 (interactive)
1523 (sgml-with-parser-syntax
1524 (setq sgml-markup-start (point))
1525 (sgml-check-delim "ERO")
1526 (let* ((ename (sgml-check-name t))
1527 (entity (sgml-lookup-entity ename
1528 (sgml-dtd-entities
1529 (sgml-pstate-dtd
1530 sgml-buffer-parse-state)))))
1531 (unless entity
1532 (error "Undefined entity %s" ename))
1533 (or (sgml-parse-delim "REFC")
1534 (sgml-parse-RE))
1535 (delete-region sgml-markup-start (point))
1536 (sgml-entity-insert-text entity))))
1537
1538
1539 ;;;; SGML mode: TAB completion
1540
1541 (defun sgml-complete ()
1542 "Complete the word/tag/entity before point.
1543 If it is a tag (starts with < or </) complete with valid tags.
1544 If it is an entity (starts with &) complete with declared entities.
1545 If it is a markup declaration (starts with <!) complete with markup
1546 declaration names.
1547 If it is something else complete with ispell-complete-word."
1548 (interactive "*")
1549 (let ((tab ; The completion table
1550 nil)
1551 (pattern nil)
1552 (c nil)
1553 (here (point)))
1554 (skip-chars-backward "^ \n\t</!&%")
1555 (setq pattern (buffer-substring (point) here))
1556 (setq c (char-after (1- (point))))
1557 (cond
1558 ;; entitiy
1559 ((eq c ?&)
1560 (sgml-need-dtd)
1561 (setq tab
1562 (sgml-entity-completion-table
1563 (sgml-dtd-entities (sgml-pstate-dtd sgml-buffer-parse-state)))))
1564 ;; start-tag
1565 ((eq c ?<)
1566 (save-excursion
1567 (backward-char 1)
1568 (sgml-parse-to-here)
1569 (setq tab (sgml-eltype-completion-table
1570 (sgml-current-list-of-valid-eltypes)))))
1571 ;; end-tag
1572 ((eq c ?/)
1573 (save-excursion
1574 (backward-char 2)
1575 (sgml-parse-to-here)
1576 (setq tab (sgml-eltype-completion-table
1577 (sgml-current-list-of-endable-eltypes)))))
1578 ;; markup declaration
1579 ((eq c ?!)
1580 (setq tab sgml-markup-declaration-table))
1581 (t
1582 (goto-char here)
1583 (ispell-complete-word)))
1584 (when tab
1585 (let ((completion (try-completion pattern tab)))
1586 (cond ((null completion)
1587 (goto-char here)
1588 (message "Can't find completion for \"%s\"" pattern)
1589 (ding))
1590 ((eq completion t)
1591 (goto-char here)
1592 (message "[Complete]"))
1593 ((not (string= pattern completion))
1594 (delete-char (length pattern))
1595 (insert completion))
1596 (t
1597 (goto-char here)
1598 (message "Making completion list...")
1599 (let ((list (all-completions pattern tab)))
1600 (with-output-to-temp-buffer " *Completions*"
1601 (display-completion-list list)))
1602 (message "Making completion list...%s" "done")))))))
1603
1604
1605 ;;;; SGML mode: Options menu
1606
1607 (defun sgml-file-options-menu (&optional event)
1608 (interactive "e")
1609 (sgml-options-menu event sgml-file-options))
1610
1611 (defun sgml-user-options-menu (&optional event)
1612 (interactive "e")
1613 (sgml-options-menu event sgml-user-options))
1614
1615 (defun sgml-options-menu (event vars)
1616 (let ((var
1617 (let ((maxlen
1618 (loop for var in vars
1619 maximize (length (sgml-variable-description var)))))
1620 (sgml-popup-menu
1621 event "Options"
1622 (loop for var in vars
1623 for desc = (sgml-variable-description var)
1624 collect
1625 (cons
1626 (format "%s%s [%s]"
1627 desc
1628 (make-string (- maxlen (length desc)) ? )
1629 (sgml-option-value-indicator var))
1630 var))))))
1631 (when var
1632 (sgml-do-set-option var event))))
1633
1634 (defun sgml-do-set-option (var &optional event)
1635 (let ((type (sgml-variable-type var))
1636 (val (symbol-value var)))
1637 (cond
1638 ((eq 'toggle type)
1639 (message "%s set to %s" var (not val))
1640 (set var (not val)))
1641 ((eq 'string type)
1642 (describe-variable var)
1643 (setq val (read-string (concat (sgml-variable-description var) ": ")))
1644 (when (stringp val)
1645 (set var val)))
1646 ((consp type)
1647 (let ((val
1648 (sgml-popup-menu event
1649 (sgml-variable-description var)
1650 (loop for c in type collect
1651 (cons
1652 (if (consp c) (car c) (format "%s" c))
1653 (if (consp c) (cdr c) c))))))
1654 (set var val)
1655 (message "%s set to %s" var val)))
1656 (t
1657 (describe-variable var)
1658 (setq val (read-string (concat (sgml-variable-description var)
1659 " (sexp): ")))
1660 (when (stringp val)
1661 (set var (car (read-from-string val)))))))
1662 (force-mode-line-update))
1663
1664 (defun sgml-option-value-indicator (var)
1665 (let ((type (sgml-variable-type var))
1666 (val (symbol-value var)))
1667 (cond
1668 ((eq type 'toggle)
1669 (if val "Yes" "No"))
1670 ((eq type 'string)
1671 (if (stringp val)
1672 (substring val 0 4)
1673 "-"))
1674 ((and (atom type) val)
1675 "...")
1676 ((consp type)
1677 (or (car (rassq val type))
1678 val))
1679 (t
1680 "-"))))
1681
1682 ;;;; NEW
1683
1684 (defun sgml-trim-and-leave-element ()
1685 (interactive)
1686 (goto-char (sgml-element-etag-start (sgml-last-element)))
1687 (while (progn (forward-char -1)
1688 (looking-at "\\s-"))
1689 (delete-char 1))
1690 (sgml-up-element))
1691
1692
1693 ;;; psgml-edit.el ends here