1 ;;; psgml-edit.el --- Editing commands for SGML-mode with parsing support
3 ;; $Id: psgml-edit.el,v 2.73 2005/03/02 19:46:31 lenst Exp $
5 ;; Copyright (C) 1994, 1995, 1996 Lennart Staflin
7 ;; Author: Lennart Staflin <lenst@lysator.liu.se>
9 ;; This program is free software; you can redistribute it and/or
10 ;; modify it under the terms of the GNU General Public License
11 ;; as published by the Free Software Foundation; either version 2
12 ;; of the License, or (at your option) any later version.
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program; if not, write to the Free Software
21 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 ;; Part of major mode for editing the SGML document-markup language.
33 (require 'psgml-parse)
35 (require 'tempo) ;; XEmacs change
36 (eval-when-compile (require 'cl))
39 ;; (setq byte-compile-warnings '(free-vars unresolved callargs redefine)))
44 (defvar sgml-split-level nil
45 "Used by sgml-split-element")
48 ;;;; SGML mode: structure editing
50 (defun sgml-last-element ()
51 "Return the element where last command left point.
52 This either uses the save value in `sgml-last-element' or parses the buffer
53 to find current open element."
54 (setq sgml-markup-type nil)
55 (if (and (not sgml-xml-p)
56 (memq last-command sgml-users-of-last-element)
57 sgml-last-element) ; Don't return nil
59 (setq sgml-last-element (sgml-find-context-of (point)))) )
61 (defun sgml-set-last-element (&optional el)
62 (if el (setq sgml-last-element el))
63 (sgml-show-context sgml-last-element))
65 (defun sgml-beginning-of-element ()
66 "Move to after the start-tag of the current element.
67 If the start-tag is implied, move to the start of the element."
69 (goto-char (sgml-element-stag-end (sgml-last-element)))
70 (sgml-set-last-element (if (sgml-element-empty sgml-last-element)
71 (sgml-element-parent sgml-last-element))))
73 (defun sgml-end-of-element ()
74 "Move to before the end-tag of the current element."
76 (goto-char (sgml-element-etag-start (sgml-last-element)))
77 (sgml-set-last-element (if (sgml-element-empty sgml-last-element)
78 (sgml-element-parent sgml-last-element))))
80 (defun sgml-backward-up-element ()
81 "Move backward out of this element level.
82 That is move to before the start-tag or where a start-tag is implied."
84 (goto-char (sgml-element-start (sgml-last-element)))
85 (sgml-set-last-element (sgml-element-parent sgml-last-element)))
87 (defun sgml-up-element ()
88 "Move forward out of this element level.
89 That is move to after the end-tag or where an end-tag is implied."
91 (goto-char (sgml-element-end (sgml-last-element)))
92 (sgml-set-last-element (sgml-element-parent sgml-last-element)))
94 (defun sgml-forward-element ()
95 "Move forward over next element."
98 (sgml-find-element-after (point) (sgml-last-element))))
99 (goto-char (sgml-element-end next))
100 (sgml-set-last-element (sgml-element-parent next))))
102 (defun sgml-backward-element ()
103 "Move backward over previous element at this level.
104 With implied tags this is ambiguous."
106 (let ((prev ; previous element
107 (sgml-find-previous-element (point) (sgml-last-element))))
108 (goto-char (sgml-element-start prev))
109 (sgml-set-last-element (sgml-element-parent prev))))
111 (defun sgml-down-element ()
112 "Move forward and down one level in the element structure."
115 (sgml-find-element-after (point) (sgml-last-element))))
116 (when (sgml-strict-epos-p (sgml-element-stag-epos to))
117 (error "Sub-element in other entity"))
118 (goto-char (sgml-element-stag-end to))
119 (sgml-set-last-element (if (sgml-element-empty to)
120 (sgml-element-parent to)
123 (defun sgml-kill-element ()
124 "Kill the element following the cursor."
127 (when sgml-markup-type
128 (error "Point is inside markup"))
130 (sgml-element-end (sgml-find-element-after (point)))))
132 (defun sgml-transpose-element ()
133 "Interchange element before point with element after point, leave point after."
135 (let ((pre (sgml-find-previous-element (point)))
136 (next (sgml-find-element-after (point)))
138 (goto-char (sgml-element-start next))
139 (setq m2 (point-marker))
140 (setq s2 (buffer-substring (point)
141 (sgml-element-end next)))
142 (delete-region (point) (sgml-element-end next))
143 (goto-char (sgml-element-start pre))
144 (setq s1 (buffer-substring (point) (sgml-element-end pre)))
145 (delete-region (point) (sgml-element-end pre))
146 (insert-before-markers s2)
151 (defun sgml-mark-element ()
152 "Set mark after next element."
154 (push-mark (sgml-element-end (sgml-find-element-after (point))) nil t))
156 (defun sgml-mark-current-element ()
157 "Set mark at end of current element, and leave point before current element."
159 (let ((el (sgml-find-element-of (point))))
160 (goto-char (sgml-element-start el))
161 (push-mark (sgml-element-end el) nil t)))
164 (defun sgml-change-element-name (gi)
165 "Replace the name of the current element with a new name.
166 Eventual attributes of the current element will be translated if
169 (list (let ((el (sgml-find-element-of (point))))
170 (goto-char (sgml-element-start el))
171 (sgml-read-element-name
172 (format "Change %s to: " (sgml-element-name el))))))
173 (when (or (null gi) (equal gi ""))
174 (error "Illegal name"))
175 (let* ((element (sgml-find-element-of (point)))
176 (attspec (sgml-element-attribute-specification-list element))
177 (oldattlist (sgml-element-attlist element))
178 (tagc (if (and sgml-xml-p (sgml-element-empty element))
179 (sgml-delim "XML-TAGCE")
180 (sgml-delim "TAGC")))
181 (tagc-len (length tagc)))
182 (goto-char (sgml-element-end element))
183 (unless (sgml-element-empty element)
184 (delete-char (- (sgml-element-etag-len element))))
185 ;; XEmacs change: use tempo
186 (tempo-process-and-insert-string (sgml-end-tag-of gi))
187 (goto-char (sgml-element-start element))
188 (delete-char (sgml-element-stag-len element))
189 ;; XEmacs change: use tempo
190 (tempo-process-and-insert-string (concat (sgml-delim "STAGO")
191 (sgml-general-insert-case gi)
193 (let* ((newel (sgml-find-context-of (point)))
194 (newattlist (sgml-element-attlist newel))
195 (newasl (sgml-translate-attribute-specification-list
196 attspec oldattlist newattlist)))
197 (backward-char tagc-len)
198 (sgml-insert-attributes newasl newattlist)
199 (forward-char tagc-len))))
202 (defun sgml-translate-attribute-specification-list (values from to)
203 "Translate attribute specification from one element type to another.
204 Input attribute values in VALUES using attlist FROM is translated into
205 a list using attlist TO."
206 (let ((new-values nil)
207 (sgml-show-warnings t)
209 (loop for attspec in values
210 as from-decl = (sgml-lookup-attdecl (sgml-attspec-name attspec) from)
211 as to-decl = (sgml-lookup-attdecl (sgml-attspec-name attspec) to)
214 ;; Special case ID attribute
215 ((and (eq 'ID (sgml-attdecl-declared-value from-decl))
216 (setq tem (sgml-attribute-with-declared-value to 'ID)))
218 (sgml-make-attspec (sgml-attdecl-name tem)
219 (sgml-attspec-attval attspec))
221 ;; Use attribute with same name if compatible type
222 ((equal (sgml-attdecl-declared-value from-decl)
223 (sgml-attdecl-declared-value to-decl))
224 (push attspec new-values))
227 "Attribute %s has new declared-value"
228 (sgml-attspec-name attspec))
229 (push attspec new-values))
231 (sgml-log-warning "Can't translate attribute %s = %s"
232 (sgml-attspec-name attspec)
233 (sgml-attspec-attval attspec)))))
236 (defun sgml-untag-element ()
237 "Remove tags from current element."
239 (let ((el (sgml-find-element-of (point))))
240 (when (or (sgml-strict-epos-p (sgml-element-stag-epos el))
241 (sgml-strict-epos-p (sgml-element-etag-epos el)))
242 (error "Current element has some tag inside an entity reference"))
243 (goto-char (sgml-element-etag-start el))
244 (delete-char (sgml-element-etag-len el))
245 (goto-char (sgml-element-start el))
246 (delete-char (sgml-element-stag-len el))))
248 (defun sgml-kill-markup ()
249 "Kill next tag, markup declaration or process instruction."
251 (let ((start (point)))
252 (sgml-with-parser-syntax
254 (setq sgml-markup-start (point))
255 (cond ((sgml-parse-markup-declaration 'ignore))
256 ((sgml-parse-processing-instruction))
258 (kill-region start (point)))))
261 ;;;; SGML mode: folding
263 (defun sgml-fold-region (beg end &optional unhide)
264 "Hide (or if prefixarg unhide) region.
265 If called from a program first two arguments are start and end of
266 region. And optional third argument true unhides."
268 (setq selective-display t)
269 (let ((mp (buffer-modified-p))
270 (inhibit-read-only t)
271 (before-change-functions nil)
272 (after-change-functions nil))
274 (subst-char-in-region beg end
278 (when sgml-buggy-subst-char-in-region
279 (set-buffer-modified-p mp)))))
281 (defun sgml-fold-element ()
282 "Fold the lines comprising the current element, leaving the first line visible.
283 This uses the selective display feature."
286 (cond ((and (eq sgml-current-tree sgml-top-tree) ; outside document element
288 (sgml-fold-region sgml-markup-start
290 (sgml-parse-to (point))
292 ((and (eq sgml-current-tree sgml-top-tree) ; outside document element
294 (sgml-fold-region (point)
296 (skip-chars-forward " \t")
297 (sgml-parse-to (1+ (point)))
301 (let ((el (sgml-find-element-of (point))))
302 (when (eq el sgml-top-tree)
303 (error "No element here"))
305 (goto-char (sgml-element-end el))
306 (when (zerop (sgml-element-etag-len el))
307 (skip-chars-backward " \t\n"))
308 (sgml-fold-region (sgml-element-start el)
311 (defun sgml-fold-subelement ()
312 "Fold all elements current elements content, leaving the first lines visible.
313 This uses the selective display feature."
315 (let* ((el (sgml-find-element-of (point)))
316 (c (sgml-element-content el)))
318 (sgml-fold-region (sgml-element-start c)
319 (sgml-element-end c))
320 (setq c (sgml-element-next c)))))
322 (defun sgml-unfold-line ()
323 "Show hidden lines in current line."
329 (exchange-point-and-mark)
330 (sgml-fold-region (point) (mark) 'unhide)
333 (defun sgml-unfold-element ()
334 "Show all hidden lines in current element."
336 (let* ((element (sgml-find-element-of (point))))
337 (sgml-fold-region (sgml-element-start element)
338 (sgml-element-end element)
341 (defun sgml-expand-element ()
342 "As sgml-fold-subelement, but unfold first."
344 (sgml-unfold-element)
345 (sgml-fold-subelement))
347 (defun sgml-unfold-all ()
348 "Show all hidden lines in buffer."
350 (sgml-fold-region (point-min)
354 ;;;; SGML mode: indentation and movement
357 (defun sgml-indent-according-to-level (element)
359 (sgml-element-level element)))
361 (defun sgml-indent-according-to-stag (element)
363 (goto-char (sgml-element-start element))
364 (+ (current-column) sgml-indent-step)))
366 (defun sgml-indent-according-to-stag-end (element)
368 (goto-char (sgml-element-start element))
371 (length (sgml-element-gi element))
375 ;;(setq sgml-content-indent-function 'sgml-indent-according-to-stag)
377 (defun sgml-indent-line (&optional col element)
378 "Indent line, calling parser to determine level unless COL or ELEMENT
379 is given. If COL is given it should be the column to indent to. If
380 ELEMENT is given it should be a parse tree node, from which the level
383 (sgml-debug "-> sgml-indent-line %s %s"
384 col (if element (sgml-element-gi element)))
385 (when sgml-indent-step
386 (let ((here (point-marker))
387 ;; Where the indentation goes, i.e., will this be data
389 ;; Where we compute indentation, where the thing we indent is.
390 ;; Can be different from above if end-tag is omitted.
392 (back-to-indentation)
396 (let ((sgml-throw-on-error 'parse-error))
397 (catch sgml-throw-on-error
398 ;; This used to be (sgml-find-element-of (point))
399 ;; Why? Possibly to handle omitted end-tags
400 (sgml-debug "-- sgml-indent-line find context")
401 (sgml-find-context-of (point)))))
402 (setq element-level element-insert)
403 (when (and (not (eobp)) element-level)
404 (setq element-level (sgml-find-element-of (point)))
405 ;; It would be good if sgml-find-element-of would also tell
406 ;; us if the character is in the start-tag/end-tag or
408 (when (or (= (point) (sgml-element-start element-level))
409 (sgml-with-parser-syntax (sgml-is-end-tag)))
410 (setq element-level (sgml-element-parent element-level)))))
411 (when (eq element-level sgml-top-tree) ; not in a element at all
412 (setq element-level nil) ; forget element
413 (goto-char here)) ; insert normal tab instead
415 (cond ((and (> (point) (sgml-element-start element-insert))
416 (< (point) (sgml-element-stag-end element-insert))
417 (not (sgml-element-data-p
418 (sgml-element-parent element-insert))))
420 (funcall sgml-attribute-indent-function element-insert)))
422 ;; Wing change, adapted by James
423 (not (member* (sgml-element-gi
424 (if (or (sgml-is-start-tag) (sgml-is-end-tag))
425 (sgml-element-parent element-level)
427 sgml-inhibit-indent-tags :test #'equalp))
429 (not (sgml-element-data-p element-insert))))
431 (funcall sgml-content-indent-function element-level)))))
432 (when (and col (/= col (current-column)))
433 (beginning-of-line 1)
434 (delete-horizontal-space)
436 (when (< (point) here)
441 (defun sgml-next-data-field ()
442 "Move forward to next point where data is allowed."
445 (error "End of buffer"))
446 (let ((sgml-throw-on-warning 'next-data)
447 (avoid-el (sgml-last-element)))
448 ;; Avoid stopping in current element, unless point is in the start
449 ;; tag of the element
450 (when (< (point) (sgml-element-stag-end avoid-el))
452 (catch sgml-throw-on-warning
454 (sgml-parse-to (1+ (point)))
455 (setq sgml-last-element
456 (if (not (eq ?< (following-char)))
457 (sgml-find-element-of (point))
459 (or (eq sgml-last-element avoid-el)
460 (not (sgml-element-data-p sgml-last-element)))))
461 (sgml-set-last-element))))
464 (defun sgml-next-trouble-spot ()
465 "Move forward to next point where something is amiss with the structure."
468 (sgml-note-change-at (point)) ; Prune the parse tree
469 (sgml-parse-to (point))
470 (let ((sgml-throw-on-warning 'trouble))
471 (or (catch sgml-throw-on-warning
472 (sgml-parse-until-end-of nil t))
477 ;;;; SGML mode: information display
479 (defun sgml-list-valid-tags ()
480 "Display a list of the contextually valid tags."
483 (let ((model (sgml-element-model sgml-current-tree))
484 (smap-name (sgml-lookup-shortref-name
485 (sgml-dtd-shortmaps sgml-dtd-info)
486 sgml-current-shortmap)))
487 (with-output-to-temp-buffer "*Tags*"
488 (princ (format "Current element: %s %s\n"
489 (sgml-element-name sgml-current-tree)
490 (if (sgml-eltype-defined
491 (sgml-element-eltype sgml-current-tree))
494 (princ (format "Element content: %s %s\n"
495 (cond ((or (sgml-current-mixed-p) (eq model sgml-any))
497 ((sgml-model-group-p model)
501 (if (eq model sgml-any)
505 (princ (format "Current short reference map: %s\n" smap-name)))
507 (cond ((sgml-final-p sgml-current-state)
508 (princ "Valid end-tags : ")
509 (loop for e in (sgml-current-list-of-endable-eltypes)
510 do (princ (sgml-end-tag-of e)) (princ " "))
513 (princ "Current element can not end here\n")))
514 ;;; (let ((s (sgml-tree-shortmap sgml-current-tree)))
516 ;;; (princ (format "Current shortref map: %s\n" s))))
517 (princ "Valid start-tags\n")
518 (sgml-print-valid-tags "In current element:"
519 sgml-current-tree sgml-current-state))))
521 (defun sgml-print-valid-tags (prompt tree state &optional exclude omitted-stag)
522 (if (not (sgml-model-group-p state))
523 (princ (format "%s (in %s)\n" prompt state))
524 (let* ((req (sgml-required-tokens state))
526 (delq sgml-pcdata-token
527 (sgml-optional-tokens state))))
528 (in (sgml-tree-includes tree))
529 (ex (append exclude (sgml-tree-excludes tree))))
530 ;; Modify for exceptions
532 (unless (memq (car in) elems)
533 (setq elems (nconc elems (list (car in)))))
536 (setq elems (delq (car ex) elems))
539 (setq elems (sort elems (function string-lessp)))
540 (sgml-print-list-of-tags prompt elems)
541 ;; Check for omissable start-tags
542 (when (and req (null (cdr req)))
543 ;; *** Assumes tokens are eltypes
544 (let ((el (sgml-fake-open-element tree (car req))))
545 (when (sgml-element-stag-optional el)
546 (sgml-print-valid-tags
547 (format "If omitting %s:" (sgml-start-tag-of el))
549 (sgml-element-model el)
550 (append exclude elems)
552 ;; Check for omissable end-tag
553 (when (and (not omitted-stag)
555 (sgml-element-etag-optional tree))
556 (sgml-print-valid-tags
557 (format "If omitting %s:" (sgml-end-tag-of tree))
558 (sgml-element-parent tree)
559 (sgml-element-pstate tree)
560 (append exclude elems))))))
562 (defun sgml-print-list-of-tags (prompt list)
565 (let ((col (length prompt))
566 (w (1- (frame-width))))
568 as str = (sgml-start-tag-of e)
570 (setq col (+ col (length str) 2))
572 (setq col (+ (length str) 2))
579 (defun sgml-show-context-standard (el &optional markup-type)
580 (let* ((model (sgml-element-model el)))
582 (cond (markup-type (format "%s" markup-type))
583 ((sgml-element-mixed el)
585 ((not (sgml-model-group-p model))
588 (if (eq el sgml-top-tree)
590 (sgml-element-context-string el)))))
593 (defun sgml-show-context-backslash (el &optional markup-type)
595 (while (not (sgml-off-top-p el))
596 (push (sgml-element-gi el) gis)
597 (setq el (sgml-element-parent el)))
598 (mapconcat #'sgml-general-insert-case gis "\\")))
601 (defun sgml-show-context (&optional element)
602 "Display where the cursor is in the element hierarchy."
604 (message "%s" (funcall sgml-show-context-function
605 (or element (sgml-last-element))
606 (if element nil sgml-markup-type))))
609 (defun sgml-what-element ()
610 "Display what element is under the cursor."
613 (nobol (eq (point) sgml-rs-ignore-pos))
614 (sref (and sgml-current-shortmap
615 (sgml-deref-shortmap sgml-current-shortmap nobol)))
618 (setq el (sgml-find-element-of pos))
619 (assert (not (null el)))
621 (cond ((eq el sgml-top-tree)
622 "outside document element")
623 ((< (point) (sgml-element-stag-end el))
625 ((>= (point) (sgml-element-etag-start el))
631 (sgml-element-context-string el))))
633 ;;;; SGML mode: keyboard inserting
635 (defun sgml-coerce-element-type (obj)
637 (setq obj (sgml-lookup-eltype (sgml-general-case obj))))
638 (when nil ;FIXME: need predicate
639 (setq obj (sgml-tree-eltype obj)))
642 (defun sgml-break-brefore-stag-p (element)
643 (sgml-eltype-appdata (sgml-coerce-element-type element)
644 'break-brefore-stag))
646 (defun sgml-break-after-stag-p (element)
647 (sgml-eltype-appdata (sgml-coerce-element-type element)
650 (defun sgml-insert-break ()
651 (skip-chars-backward " \t")
653 (if (looking-at "^\\s-*$")
656 ;; FIXME: fixup-whitespace ??
660 (defun sgml-insert-tag (tag &optional silent no-nl-after)
661 "Insert a tag, reading tag name in minibuffer with completion.
662 If the variable `sgml-balanced-tag-edit' is t, also inserts the
663 corresponding end tag. If `sgml-leave-point-after-insert' is t, the point
664 is left after the inserted tag(s), unless the element has some required
665 content. If `sgml-leave-point-after-insert' is nil, the point is left
666 after the first tag inserted."
669 (let ((completion-ignore-case sgml-namecase-general))
670 (completing-read "Tag: " (sgml-completion-table) nil t "<" ))))
671 (sgml-find-context-of (point))
672 (assert (null sgml-markup-type))
673 ;; Fix white-space before tag
674 (unless (sgml-element-data-p (sgml-parse-to-here))
675 (skip-chars-backward " \t")
677 (if (looking-at "^\\s-*$")
681 ;; XEmacs change: use tempo
682 (tempo-process-and-insert-string tag)
686 (unless (sgml-element-data-p (sgml-parse-to-here))
688 (save-excursion (insert "\n"))))))
689 (or silent (sgml-show-context)))
691 (defvar sgml-new-attribute-list-function
692 (function sgml-default-asl))
694 (defun sgml-insert-element (name &optional after silent)
695 "Reads element name from minibuffer and inserts start and end tags.
696 If sgml-leave-point-after-insert is t, the point
697 is left after the inserted tag(s), unless the element has some required
698 content. If sgml-leave-point-after-insert is nil the point is left
699 after the first tag inserted."
700 (interactive (list (sgml-read-element-name "Element: ")
701 sgml-leave-point-after-insert))
702 (let (newpos ; position to leave cursor at
703 element ; inserted element
704 (sgml-show-warnings nil))
705 (when (and name (not (equal name "")))
706 (when (sgml-break-brefore-stag-p name)
708 (sgml-insert-tag (sgml-start-tag-of name) 'silent)
709 (if (and sgml-xml-p (sgml-check-empty name))
712 (setq element (sgml-find-element-of (point)))
713 (sgml-insert-attributes (funcall sgml-new-attribute-list-function
715 (sgml-element-attlist element))
716 ;; Get element with new attributes
717 (setq element (sgml-find-context-of (point)))
718 (if (and sgml-xml-p (sgml-check-empty name))
721 (when (sgml-break-after-stag-p name)
723 (when (not (sgml-element-empty element))
724 (when (and sgml-auto-insert-required-elements
725 (sgml-model-group-p sgml-current-state))
727 (while (and (setq tem (sgml-required-tokens sgml-current-state))
729 (setq tem (sgml-insert-element (car tem) t t))
730 (setq newpos (or newpos tem))
731 (sgml-parse-to-here))
732 (when tem ; more than one req elem
734 (when sgml-insert-missing-element-comment
735 (insert (format "<!-- one of %s -->" tem))
736 (sgml-indent-line)))))
737 (setq newpos (or newpos (point)))
738 (when sgml-insert-end-tag-on-new-line
740 (sgml-insert-tag (sgml-end-tag-of name) 'silent)
743 (unless silent (sgml-show-context)))
746 (defun sgml-default-asl (element)
747 (loop for attdecl in (sgml-element-attlist element)
748 when (sgml-default-value-type-p (sgml-attdecl-default-value attdecl)
752 (sgml-attdecl-name attdecl)
753 (sgml-read-attribute-value attdecl (sgml-element-name element) nil))))
755 (defun sgml-tag-region (element start end)
756 "Reads element name from minibuffer and inserts start and end tags."
759 (save-excursion (goto-char (region-beginning))
760 (sgml-read-element-name "Tag region with element: "))
764 (when (and element (not (equal element "")))
766 ;; XEmacs change: use tempo
767 (tempo-process-and-insert-string (sgml-end-tag-of element))
769 (sgml-insert-tag (sgml-start-tag-of element)))))
771 (defun sgml-insert-attributes (avl attlist)
772 "Insert the attributes with values AVL and declarations ATTLIST.
773 AVL should be a assoc list mapping symbols to strings."
774 (let (name val dcl def)
775 (loop for attspec in attlist do
776 (setq name (sgml-attspec-name attspec)
777 val (cdr-safe (sgml-lookup-attspec name avl))
778 dcl (sgml-attdecl-declared-value attspec)
779 def (sgml-attdecl-default-value attspec))
780 (setq name (sgml-general-insert-case name))
781 (unless val ; no value given
782 ;; Supply the default value if a value is needed
783 (cond ((sgml-default-value-type-p 'REQUIRED def)
785 ((and (or (not (or sgml-xml-p sgml-omittag sgml-shorttag))
786 sgml-insert-defaulted-attributes)
788 (setq val (sgml-default-value-attval def)))))
790 (cond ((eq dcl 'CDATA))
791 ((eq dcl 'ENTITY) (setq val (sgml-entity-insert-case val)))
792 (t (setq val (sgml-general-insert-case val)))))
794 ((null val)) ; Ignore
795 ;; Ignore attributes with default value
797 (eq sgml-minimize-attributes 'max)
798 (or sgml-omittag sgml-shorttag)
799 (equal val (sgml-default-value-attval def))))
800 ;; No attribute name for token groups
801 ((and sgml-minimize-attributes sgml-shorttag
802 (member (sgml-general-case val)
803 (sgml-declared-value-token-group dcl)))
804 ;; XEmacs change: use tempo
805 (tempo-process-and-insert-string (concat " " val)))
807 ;; XEmacs change: use tempo
808 (tempo-process-and-insert-string (concat " " name "="))
809 (insert (sgml-quote-attribute-value val)))))
810 (when auto-fill-function
811 (funcall auto-fill-function))))
814 (defun sgml-quote-attribute-value (value)
815 "Add quotes to the string VALUE unless minimization is on."
817 (cond ((and (not sgml-always-quote-attributes)
819 (string-match "\\`[-.A-Za-z0-9]+\\'" value))
821 ((not (string-match "\"" value)) ; can use "" quotes
825 (concat quote value quote)))
827 (defun sgml-completion-table (&optional avoid-tags-in-cdata)
829 (when sgml-markup-type
830 (error "No tags allowed"))
831 (cond ((or (sgml-model-group-p sgml-current-state)
832 (eq sgml-current-state sgml-any))
834 (mapcar (function (lambda (x) (cons (sgml-end-tag-of x) x)))
835 (sgml-current-list-of-endable-eltypes))
836 (mapcar (function (lambda (x) (cons (sgml-start-tag-of x) x)))
837 (sgml-current-list-of-valid-eltypes))))
839 (sgml-message "%s" sgml-current-state)
842 (defun sgml-element-endable-p ()
844 (and (not (eq sgml-current-tree sgml-top-tree))
845 (sgml-final-p sgml-current-state)))
847 (defun sgml-insert-end-tag ()
848 "Insert end-tag for the current open element."
852 ((eq sgml-current-tree sgml-top-tree)
853 (sgml-error "No open element"))
854 ((not (sgml-final-p sgml-current-state))
855 (sgml-error "Can`t end element here"))
857 (when (and sgml-indent-step
858 (not (sgml-element-data-p sgml-current-tree)))
859 (delete-horizontal-space)
863 ;; XEmacs change: use tempo
864 (tempo-process-and-insert-string
865 (if (eq t (sgml-element-net-enabled sgml-current-tree))
867 (sgml-end-tag-of sgml-current-tree))))
868 (sgml-indent-line)))))
870 (defun sgml-insert-start-tag (name asl attlist &optional net)
871 ;; Insert a start-tag with attributes
872 ;; if NET is true end with NESTC unless XML then end with NESTC NET
874 ;; XEmacs change: use tempo
875 (tempo-process-and-insert-string (concat (sgml-delim "STAGO")
876 (sgml-general-insert-case name)))
877 (sgml-insert-attributes asl attlist)
878 ;; In XML, force net if element is always empty
879 (when (and sgml-xml-p (sgml-check-empty name))
881 ;; XEmacs change: use tempo
882 (tempo-process-and-insert-string
883 (if net (if sgml-xml-p
884 (sgml-delim "XML-TAGCE")
885 (sgml-delim "NESTC"))
886 (sgml-delim "TAGC"))))
888 (defun sgml-change-start-tag (element asl)
889 (let ((name (sgml-element-gi element))
890 (attlist (sgml-element-attlist element)))
891 ;; Concoct an attribute specification list using the names of the
892 ;; existing attributes and those ot be changed.
893 (when (and (not attlist) sgml-dtd-less)
894 (dolist (elt (mapcar 'car asl))
895 (unless (assoc elt attlist) ; avoid duplicates
896 (push (sgml-make-attdecl elt 'CDATA 'REQUIRED) attlist)))
897 (setq attlist (nreverse attlist)))
898 (assert (sgml-bpos-p (sgml-element-stag-epos element)))
899 (goto-char (sgml-element-start element))
900 (delete-char (sgml-element-stag-len element))
901 (sgml-insert-start-tag name asl attlist
903 (sgml-element-empty element)
904 (eq t (sgml-element-net-enabled element))))))
906 (defun sgml-read-attribute-value (attdecl element curvalue)
907 "Return the attribute value read from user.
908 ATTDECL is the attribute declaration for the attribute to read.
909 CURVALUE is nil or a string that will be used as default value."
911 (let* ((name (sgml-attdecl-name attdecl))
912 (dv (sgml-attdecl-declared-value attdecl))
913 (tokens (sgml-declared-value-token-group dv))
914 (notations (sgml-declared-value-notation dv))
916 (ids (and (memq dv '(IDREF IDREFS)) (sgml-id-list)))
917 (type (cond (tokens "token")
918 (notations "NOTATION")
919 (t (symbol-name dv))))
921 (format "Value for %s in %s (%s%s): "
923 (if (and curvalue (not (eq dv 'IDREFS)))
924 (format " Default: %s" curvalue)
928 (cond ((or tokens notations)
929 (let ((completion-ignore-case sgml-namecase-general))
930 (completing-read prompt
931 (mapcar 'list (or tokens notations))
934 (let ((completion-ignore-case sgml-namecase-general)
935 (minibuffer-local-completion-map sgml-edit-idrefs-map))
936 (completing-read prompt
937 'sgml-idrefs-completer
940 (cons curvalue (length curvalue))))))
942 (read-string prompt))))
943 (if (and curvalue (equal value ""))
946 (defun sgml-idrefs-completer (fullstring pred action)
947 (let* ((start (string-match "\\(\\(:?-\\|\\w\\)*\\)$" fullstring))
948 (string (match-string 0 fullstring))
949 (prefix (substring fullstring 0 start)))
950 ;(message "prefix: %s string: %s" prefix string)
952 (let ((completion (try-completion string (sgml-id-alist) pred)))
953 (if (eq completion t)
955 (concat prefix completion))))
957 (all-completions string (sgml-id-alist) pred))
959 (member string (sgml-id-alist))))))
961 (defun sgml-non-fixed-attributes (attlist)
962 (loop for attdecl in attlist
963 unless (sgml-default-value-type-p 'FIXED
964 (sgml-attdecl-default-value attdecl))
967 (defun sgml-insert-attribute (name value)
968 "Read attribute name and value from minibuffer and insert attribute spec."
970 (let* ((el (sgml-find-attribute-element))
973 (let ((completion-ignore-case sgml-namecase-general))
977 (function (lambda (a) (list (sgml-attdecl-name a))))
980 (sgml-non-fixed-attributes (sgml-element-attlist el))))
981 nil (not sgml-dtd-less))))))
983 (sgml-read-attribute-value
986 (sgml-lookup-attdecl name (sgml-element-attlist el)))
987 (sgml-element-name el)
988 (sgml-element-attval el name)))))
990 (assert (stringp name))
991 (assert (or (null value) (stringp value)))
992 (let* ((el (sgml-find-attribute-element))
993 (asl (cons (sgml-make-attspec name value)
994 (sgml-element-attribute-specification-list el)))
995 (in-tag (< (point) (sgml-element-stag-end el))))
996 (sgml-change-start-tag el asl)
997 (when in-tag (forward-char -1))))
999 (defun sgml-split-element ()
1000 "Split the current element at point.
1001 If repeated, the containing element will be split before the beginning
1002 of then current element."
1004 (setq sgml-split-level
1005 (if (eq this-command last-command)
1006 (1+ sgml-split-level)
1008 (let ((u (sgml-find-context-of (point)))
1009 (start (point-marker)))
1010 (loop repeat sgml-split-level do
1011 (goto-char (sgml-element-start u))
1012 (setq u (sgml-element-parent u)))
1013 ;; Verify that a new element can be started
1014 (unless (and (sgml-element-pstate u) ; in case of top element
1015 (sgml-get-move (sgml-element-pstate u)
1016 (sgml-element-name u)))
1018 (sgml-error "The %s element can't be split"
1019 (sgml-element-name u)))
1021 (sgml-insert-end-tag)
1023 (sgml-insert-tag (sgml-start-tag-of u) 'silent)
1024 (skip-chars-forward " \t\n")
1026 (when (> sgml-split-level 0)
1028 (or (eq sgml-top-tree
1029 (setq u (sgml-element-parent u)))
1031 "Repeat the command to split the containing %s element"
1032 (sgml-element-name u)))))
1034 ;;; David Megginson's custom menus for keys
1036 (defun sgml-custom-dtd (doctype)
1037 "Insert a DTD declaration from the sgml-custom-dtd alist."
1039 (list (completing-read "Insert DTD: " sgml-custom-dtd nil t)))
1040 (let ((entry (assoc doctype sgml-custom-dtd)))
1041 (sgml-doctype-insert (second entry) (cddr entry))))
1043 (defun sgml-custom-markup (markup)
1044 "Insert markup from the sgml-custom-markup alist."
1046 (let ((completion-ignore-case sgml-namecase-general))
1047 (list (completing-read "Insert Markup: " sgml-custom-markup nil t))))
1048 (sgml-insert-markup (cadr (assoc markup sgml-custom-markup))))
1051 ;;;; SGML mode: Menu inserting
1053 (defun sgml-tags-menu (event)
1054 "Pop up a menu with valid tags and insert the chosen tag.
1055 If the variable sgml-balanced-tag-edit is t, also inserts the
1056 corresponding end tag. If sgml-leave-point-after-insert is t, the point
1057 is left after the inserted tag(s), unless the element has some required
1058 content. If sgml-leave-point-after-insert is nil the point is left
1059 after the first tag inserted."
1061 (let ((end (sgml-mouse-region)))
1062 (sgml-parse-to-here)
1064 ((eq sgml-markup-type 'start-tag)
1065 (sgml-attrib-menu event))
1068 (sgml-menu-ask event (if (or end sgml-balanced-tag-edit)
1073 (sgml-tag-region what (point) end))
1074 (sgml-balanced-tag-edit
1075 (sgml-insert-element what))
1077 (sgml-insert-tag what))))))))
1079 (defun sgml-element-menu (event)
1080 "Pop up a menu with valid elements and insert choice.
1081 If sgml-leave-point-after-insert is nil the point is left after the first
1084 (let ((what (sgml-menu-ask event 'element)))
1085 (and what (sgml-insert-element what))))
1087 (defun sgml-add-element-menu (event)
1089 (let ((what (sgml-menu-ask event 'add-element)))
1090 (and what (sgml-add-element-to-element what nil))))
1092 (defun sgml-start-tag-menu (event)
1093 "Pop up a menu with valid start-tags and insert choice."
1095 (let ((what (sgml-menu-ask event 'start-tag)))
1096 (and what (sgml-insert-tag what))))
1098 (defun sgml-end-tag-menu (event)
1099 "Pop up a menu with valid end-tags and insert choice."
1101 (let ((what (sgml-menu-ask event 'end-tag)))
1102 (and what (sgml-insert-tag what))))
1104 (defun sgml-tag-region-menu (event)
1105 "Pop up a menu with valid elements and tag current region with the choice."
1107 (let ((what (sgml-menu-ask event 'element)))
1108 (and what (sgml-tag-region what
1112 (defun sgml-menu-ask (event type)
1113 (sgml-parse-to-here)
1115 (title (capitalize (symbol-name type))))
1117 ((eq type 'add-element)
1119 (mapcar #'sgml-eltype-name
1120 (sgml--all-possible-elements
1121 (sgml-find-context-of (point))))))
1125 (mapcar (function symbol-name)
1126 (sgml-current-list-of-valid-eltypes))))
1128 (unless (eq type 'start-tag)
1130 (mapcar (function sgml-end-tag-of)
1131 (sgml-current-list-of-endable-eltypes))))
1132 (unless (eq type 'end-tag)
1135 (mapcar (function sgml-start-tag-of)
1136 (sgml-current-list-of-valid-eltypes)))))))
1138 ;; The best we can do is assemble a list of elements we've
1140 (dolist (n (append (sgml-dtd-eltypes sgml-dtd-info) '())
1141 ;; Space avoids possible clash with valid element.
1142 (setq tab (cons "Any " (cons "--" tab))))
1143 (when (and (symbolp n) (not (memq n tab)))
1144 (push (symbol-name n) tab))))
1146 (error "No valid %s at this point" type))
1147 (let ((elt (sgml-popup-menu event
1149 (mapcar (function (lambda (x) (cons x x)))
1151 (if (equal elt "Any ")
1152 (setq elt (sgml-read-element-name "Element: ")))
1153 (or elt (message nil)))))
1155 (defun sgml-entities-menu (event)
1159 (mapcar (function (lambda (x) (cons x x)))
1160 (sort (sgml-map-entities (function sgml-entity-name)
1161 (sgml-dtd-entities sgml-dtd-info)
1163 (function string-lessp))))
1166 (error "No entities defined"))
1167 (setq choice (sgml-popup-menu event "Entities" menu))
1169 (insert "&" choice ";"))))
1171 (defun sgml-doctype-insert (doctype vars)
1172 "Insert string DOCTYPE (ignored if nil) and set variables in &rest VARS.
1173 VARS should be a list of variables and values.
1174 For backward compatibility a single string instead of a variable is
1175 assigned to sgml-default-dtd-file.
1176 All variables are made buffer local and are also added to the
1177 buffers local variables list."
1184 (sgml-insert-markup doctype))
1186 (cond ((stringp (car vars))
1187 (sgml-set-local-variable 'sgml-default-dtd-file (car vars))
1188 (setq vars (cdr vars)))
1189 ((car vars) ; Avoid nil
1190 (sgml-set-local-variable (car vars) (cadr vars))
1191 (setq vars (cddr vars)))
1193 (setq vars (cddr vars)))))
1194 (setq sgml-top-tree nil))
1196 (defun sgml-attrib-menu (event)
1197 "Pop up a menu of the attributes of the current element
1198 \(or the element with start-tag before point)."
1200 (let ((menu (sgml-make-attrib-menu (sgml-find-attribute-element))))
1201 (sgml-popup-multi-menu event "Attributes" menu)))
1203 (defun sgml-make-attrib-menu (el)
1204 (let ((attlist (sgml-non-fixed-attributes (sgml-element-attlist el))))
1205 (if (and (not attlist) sgml-dtd-less)
1208 (let ((completion-ignore-case sgml-namecase-general))
1212 (lambda (a) (list (sgml-attdecl-name a)))
1215 (sgml-non-fixed-attributes (sgml-element-attlist el))))
1216 nil (not sgml-dtd-less))))))
1218 (setq attlist (list (sgml-make-attdecl name 'CDATA nil))))))
1220 (error "No non-fixed attributes for element"))
1221 (loop for attdecl in attlist
1222 for name = (sgml-attdecl-name attdecl)
1223 for defval = (sgml-attdecl-default-value attdecl)
1224 for tokens = (or (sgml-declared-value-token-group
1225 (sgml-attdecl-declared-value attdecl))
1226 (sgml-declared-value-notation
1227 (sgml-attdecl-declared-value attdecl)))
1230 (sgml-attdecl-name attdecl)
1233 (loop for val in tokens collect
1235 (list 'sgml-insert-attribute name val)))
1237 (list "Set attribute value"
1238 (list 'sgml-insert-attribute
1239 (sgml-attdecl-name attdecl)
1240 (list 'sgml-read-attribute-value
1241 (list 'quote attdecl)
1242 (list 'quote (sgml-element-name el))
1243 (sgml-element-attval el name))))))
1244 (if (sgml-default-value-type-p 'REQUIRED defval)
1247 (list (if (sgml-default-value-type-p nil defval)
1248 (format "Default: %s"
1249 (sgml-default-value-attval defval))
1251 (list 'sgml-insert-attribute name nil)))))))))
1254 ;;;; New Right Button Menu
1256 (defun sgml-right-menu (event)
1257 "Pop up a menu with valid tags and insert the choosen tag.
1258 If the variable sgml-balanced-tag-edit is t, also inserts the
1259 corresponding end tag. If sgml-leave-point-after-insert is t, the point
1260 is left after the inserted tag(s), unless the element has som required
1261 content. If sgml-leave-point-after-insert is nil the point is left
1262 after the first tag inserted."
1264 (let ((end (sgml-mouse-region)))
1265 (sgml-parse-to-here)
1267 ((eq sgml-markup-type 'start-tag)
1268 (sgml-right-stag-menu event))
1271 (sgml-menu-ask event (if (or end sgml-balanced-tag-edit)
1276 (sgml-tag-region what (point) end))
1277 (sgml-balanced-tag-edit
1278 (sgml-insert-element what))
1280 (sgml-insert-tag what))))))))
1283 (defun sgml-right-stag-menu (event)
1284 (let* ((el (sgml-find-attribute-element))
1285 (attrib-menu (ignore-errors (sgml-make-attrib-menu el))))
1287 (let* ((alt-gi (mapcar (function sgml-eltype-name)
1289 (sgml-find-context-of (sgml-element-start el))
1290 (sgml-current-list-of-valid-eltypes))))
1293 (loop for gi in alt-gi
1294 collect `(,gi (sgml-change-element-name ,gi))))))
1295 (sgml-popup-multi-menu
1298 ("Edit attributes" (sgml-edit-attributes))
1299 ("Normalize" (sgml-normalize-element))
1300 ("Fill" (sgml-fill-element
1301 (sgml-find-context-of (point))))
1302 ("Splice" (sgml-untag-element))
1303 ("Fold" (sgml-fold-element)))
1310 ;;;; SGML mode: Fill
1312 (defun sgml-element-fillable (element)
1313 (and (sgml-element-mixed element)
1314 (not (sgml-element-appdata element 'nofill))))
1316 (defun sgml-fill-element (element)
1317 "Fill biggest enclosing element with mixed content.
1318 If current element has pure element content, recursively fill the
1320 (interactive (list (sgml-find-element-of (point))))
1322 (message "Filling...")
1323 (when (sgml-element-fillable element)
1324 ;; Find biggest enclosing fillable element
1325 (while (sgml-element-fillable (sgml-element-parent element))
1326 (setq element (sgml-element-parent element))))
1328 (sgml-do-fill element)
1329 (sgml-message "Done"))
1331 (defun sgml-do-fill (element)
1333 (goto-char (sgml-element-start element))
1337 ((sgml-element-fillable element)
1339 (c (sgml-element-content element))
1340 (agenda nil)) ; regions to fill later
1341 (goto-char (sgml-element-stag-end element))
1342 (when (eolp) (forward-char 1))
1343 (setq last-pos (point))
1346 ((sgml-element-fillable c))
1348 ;; Put region before element on agenda. Can't fill it now
1349 ;; that would mangle the parse tree that is being traversed.
1350 (push (cons last-pos (sgml-element-start c))
1352 (goto-char (sgml-element-start c))
1354 ;; Fill may change parse tree, get a fresh
1355 (setq c (sgml-find-element-of (point)))
1356 (setq last-pos (sgml-element-end c))))
1357 (setq c (sgml-element-next c)))
1358 ;; Fill the last region in content of element,
1359 ;; but get a fresh parse tree, if it has change due to other fills.
1360 (goto-char last-pos)
1361 (when (bolp) (sgml-indent-line))
1362 (sgml-fill-region last-pos
1363 (sgml-element-etag-start
1364 (sgml-find-element-of
1365 (sgml-element-start element))))
1367 (sgml-fill-region (caar agenda) (cdar agenda))
1368 (setq agenda (cdr agenda)))))
1370 ;; If element is not mixed, fill subelements recursively
1371 (let ((c (sgml-element-content element)))
1373 (goto-char (sgml-element-etag-start c))
1375 (goto-char (sgml-element-start c))
1377 (setq c (sgml-find-element-of (point)))
1379 (setq c (sgml-element-next (sgml-find-element-of (point))))))))))
1381 (defun sgml-fill-region (start end)
1382 (sgml-message "Filling...")
1385 (skip-chars-backward " \t\n")
1386 (while (progn (beginning-of-line 1)
1389 (delete-horizontal-space)
1392 (let (give-up prev-column opoint oopoint)
1393 (while (and (not give-up) (> (current-column) fill-column))
1394 (setq prev-column (current-column))
1395 (setq oopoint (point))
1396 (move-to-column (1+ fill-column))
1397 (skip-chars-backward "^ \t\n")
1398 (setq opoint (point))
1399 (skip-chars-backward " \t")
1403 (if (re-search-forward "[ \t]" oopoint t)
1405 (skip-chars-forward " \t")
1406 (setq opoint (point)))
1410 (delete-region (point) opoint)
1414 (setq give-up (>= (current-column) prev-column))))))))
1416 ;;;; SGML mode: Attribute editing
1418 (defvar sgml-start-attributes nil)
1419 (defvar sgml-main-buffer nil)
1420 (defvar sgml-attlist nil)
1422 (defun sgml-edit-attributes ()
1423 "Edit attributes of current element.
1424 Editing is done in a separate window."
1426 (let ((element (sgml-find-attribute-element)))
1427 (unless (sgml-bpos-p (sgml-element-stag-epos element))
1428 (error "Element's start-tag is not in the buffer"))
1430 (goto-char (sgml-element-start element))
1431 (let* ((start (point-marker))
1432 (asl (sgml-element-attribute-specification-list element))
1433 (cb (current-buffer))
1434 (quote sgml-always-quote-attributes)
1436 (switch-to-buffer-other-window
1437 (sgml-attribute-buffer element asl))
1438 (make-local-variable 'sgml-start-attributes)
1439 (setq sgml-start-attributes start)
1440 (make-local-variable 'sgml-always-quote-attributes)
1441 (setq sgml-always-quote-attributes quote)
1442 (make-local-variable 'sgml-main-buffer)
1443 (setq sgml-main-buffer cb)
1444 (make-local-variable 'sgml-xml-p)
1445 (setq sgml-xml-p xml-p))))
1448 (defun sgml-effective-attlist (eltype)
1449 (let ((effective-attlist nil)
1450 (attlist (sgml-eltype-attlist eltype))
1451 (attnames (or (sgml-eltype-appdata eltype 'attnames)
1453 (while (and attnames (not (eq '* (car attnames))))
1454 (let ((attdecl (sgml-lookup-attdecl (car attnames) attlist)))
1456 (push attdecl effective-attlist)
1457 (message "Attnames specefication error: no %s attribute in %s"
1458 (car attnames) eltype)))
1459 (setq attnames (cdr attnames)))
1460 (when (eq '* (car attnames))
1462 (let ((attdecl (sgml-lookup-attdecl (sgml-attdecl-name (car attlist))
1463 effective-attlist)))
1465 (push (car attlist) effective-attlist)))
1466 (setq attlist (cdr attlist))))
1467 (nreverse effective-attlist)))
1470 (defun sgml-attribute-buffer (element asl)
1471 (let ((bname "*Edit attributes*")
1473 (inhibit-read-only t))
1475 (when (setq buf (get-buffer bname))
1477 (setq buf (get-buffer-create bname))
1480 (sgml-edit-attrib-mode)
1481 (make-local-variable 'sgml-attlist)
1482 (setq sgml-attlist (sgml-effective-attlist
1483 (sgml-element-eltype element)))
1484 (sgml-insert '(read-only t)
1485 (substitute-command-keys
1486 "<%s -- Edit values and finish with \
1487 \\[sgml-edit-attrib-finish], abort with \\[sgml-edit-attrib-abort] --\n")
1488 (sgml-element-name element))
1490 for attr in sgml-attlist do
1491 ;; Produce text like
1493 ;; -- declaration : default --
1494 (let* ((aname (sgml-attdecl-name attr))
1495 (dcl-value (sgml-attdecl-declared-value attr))
1496 (def-value (sgml-attdecl-default-value attr))
1497 (cur-value (sgml-lookup-attspec aname asl)))
1498 (sgml-insert ; atribute name
1499 '(read-only t category sgml-form) " %s =" aname)
1500 (cond ; attribute value
1501 ((sgml-default-value-type-p 'FIXED def-value)
1502 (sgml-insert '(read-only t category sgml-fixed)
1504 (sgml-default-value-attval def-value)))
1505 ((and (null cur-value)
1506 (or (memq def-value '(IMPLIED CONREF CURRENT))
1507 (sgml-default-value-attval def-value)))
1508 (sgml-insert '(read-only t category sgml-form
1509 rear-nonsticky (read-only category))
1511 (sgml-insert '(category sgml-default rear-nonsticky (category))
1514 (sgml-insert '(read-only t category sgml-form
1515 rear-nonsticky (read-only category))
1517 (when (not (null cur-value))
1518 (sgml-insert nil "%s" (sgml-attspec-attval cur-value)))))
1521 "\n\t-- %s: %s --\n"
1522 (cond ((sgml-declared-value-token-group dcl-value))
1523 ((sgml-declared-value-notation dcl-value)
1524 (format "NOTATION %s"
1525 (sgml-declared-value-notation dcl-value)))
1528 (cond ((sgml-default-value-attval def-value))
1530 (concat "#" (upcase (symbol-name def-value))))))))
1531 (sgml-insert '(read-only t) ">")
1532 (goto-char (point-min))
1533 (sgml-edit-attrib-next))
1537 (defvar sgml-edit-attrib-mode-map (make-sparse-keymap))
1539 ;; used as only for #DEFAULT in attribute editing. Binds all normally inserting
1540 ;; keys to a command that will clear the #DEFAULT before doing self-insert.
1541 (defvar sgml-attr-default-keymap
1542 (let ((map (make-sparse-keymap)))
1543 (set-keymap-parent map sgml-edit-attrib-mode-map)
1544 (substitute-key-definition 'self-insert-command
1545 'sgml-attr-clean-and-insert
1548 (put 'sgml-default 'local-map map)))
1550 (define-key sgml-edit-attrib-mode-map "\C-c\C-c" 'sgml-edit-attrib-finish)
1551 (define-key sgml-edit-attrib-mode-map "\C-c\C-d" 'sgml-edit-attrib-default)
1552 (define-key sgml-edit-attrib-mode-map "\C-c\C-k" 'sgml-edit-attrib-abort)
1554 (define-key sgml-edit-attrib-mode-map "\C-a" 'sgml-edit-attrib-field-start)
1555 (define-key sgml-edit-attrib-mode-map "\C-e" 'sgml-edit-attrib-field-end)
1556 (define-key sgml-edit-attrib-mode-map "\t" 'sgml-edit-attrib-next)
1558 (defun sgml-edit-attrib-mode ()
1559 "Major mode to edit attribute specification list.\\<sgml-edit-attrib-mode-map>
1560 Use \\[sgml-edit-attrib-next] to move between input fields. Use
1561 \\[sgml-edit-attrib-default] to make an attribute have its default
1562 value. To abort edit kill buffer (\\[kill-buffer]) and remove window
1563 \(\\[delete-window]). To finish edit use \\[sgml-edit-attrib-finish].
1565 \\{sgml-edit-attrib-mode-map}"
1566 (setq mode-name "SGML edit attributes"
1567 major-mode 'sgml-edit-attrib-mode)
1568 (use-local-map sgml-edit-attrib-mode-map)
1569 (run-hooks 'text-mode-hook 'sgml-edit-attrib-mode-hook))
1571 (defun sgml-edit-attrib-abort ()
1572 "Abort the attribute editor, removing the window."
1574 (let ((cb (current-buffer))
1575 (start sgml-start-attributes))
1576 (delete-windows-on cb)
1578 (when (markerp start)
1579 (switch-to-buffer (marker-buffer start))
1580 (goto-char start))))
1582 (defun sgml-edit-attrib-finish ()
1583 "Finish editing and insert attribute values in original buffer."
1585 (let ((cb (current-buffer))
1586 (asl (sgml-edit-attrib-specification-list))
1587 ;; save buffer local variables
1588 (start sgml-start-attributes))
1589 (when (markerp start)
1590 (delete-windows-on cb)
1591 (switch-to-buffer (marker-buffer start))
1594 (let ((element (sgml-find-element-of start)))
1595 ;; *** Should the it be verified that this element
1596 ;; is the one edited?
1597 (sgml-change-start-tag element asl)))))
1600 (defun sgml-edit-attrib-specification-list ()
1601 (goto-char (point-min))
1603 (sgml-with-parser-syntax
1606 (while (not (eq ?> (following-char)))
1608 (sgml-check-nametoken) ; attribute name, should match head of al
1610 (unless (memq (get-text-property (point) 'category)
1611 '(sgml-default sgml-fixed))
1613 (sgml-make-attspec (sgml-attdecl-name (car al))
1614 (sgml-extract-attribute-value
1615 (sgml-attdecl-declared-value (car al))))
1617 (while (progn (beginning-of-line 2)
1619 (not (get-text-property (point) 'read-only)))))
1626 (defun sgml-extract-attribute-value (type)
1629 (narrow-to-region (point)
1630 (progn (sgml-edit-attrib-field-end)
1632 (goto-char (point-min))
1634 (if (eq 'sgml-default (get-text-property (point) 'category))
1637 (unless (eq type 'CDATA)
1638 (subst-char-in-region (point-min) (point-max) ?\n ? )
1639 (goto-char (point-min))
1640 (delete-horizontal-space))
1641 (goto-char (point-min))
1642 (when (search-forward "\"" nil t) ; don't allow both " and '
1643 (goto-char (point-min))
1644 (while (search-forward "'" nil t) ; replace ' with char ref
1645 (replace-match "'")))
1648 (defun sgml-edit-attrib-default ()
1649 "Set current attribute value to default."
1651 (sgml-edit-attrib-clear)
1653 (sgml-insert '(category sgml-default rear-nonsticky (category))
1656 (defun sgml-edit-attrib-clear ()
1657 "Kill the value of current attribute."
1659 (let ((inhibit-read-only '(sgml-default)))
1660 (sgml-edit-attrib-field-start)
1661 (let ((end (save-excursion (sgml-edit-attrib-field-end) (point))))
1662 (put-text-property (point) end 'read-only nil)
1663 (let ((inhibit-read-only t))
1664 (put-text-property (1- (point)) (point)
1665 'rear-nonsticky '(read-only category)))
1666 (kill-region (point) end))))
1669 (defun sgml-attr-clean-and-insert (n)
1670 "Insert the character you type, after clearing the current attribute."
1672 (sgml-edit-attrib-clear)
1673 (self-insert-command n))
1676 (defun sgml-edit-attrib-field-start ()
1677 "Go to the start of the attribute value field."
1680 (beginning-of-line 1)
1681 (while (not (eq t (get-text-property (point) 'read-only)))
1682 (beginning-of-line 0))
1683 (while (eq 'sgml-form (get-text-property (point) 'category))
1684 (setq start (next-single-property-change (point) 'category))
1685 (unless start (error "No attribute value here"))
1686 (assert (number-or-marker-p start))
1687 (goto-char start))))
1689 (defun sgml-edit-attrib-field-end ()
1690 "Go to the end of the attribute value field."
1692 (sgml-edit-attrib-field-start)
1693 (let ((end (if (and (eolp)
1694 (get-text-property (1+ (point)) 'read-only))
1696 (next-single-property-change (point) 'read-only))))
1697 (assert (number-or-marker-p end))
1700 (defun sgml-edit-attrib-next ()
1701 "Move to next attribute value."
1703 (if (eq t (get-text-property (point) 'read-only))
1704 (beginning-of-line 1))
1705 (or (search-forward-regexp (if sgml-have-re-char-clases
1706 "^ *[-_.:[:alnum:]]+ *= ?"
1707 "^ *[-_.:A-Za-z0-9]+ *= ?") nil t)
1708 (goto-char (point-min))))
1711 ;;;; SGML mode: Hiding tags/attributes
1713 (defconst sgml-tag-regexp
1714 (if sgml-have-re-char-clases
1715 "\\(</?>\\|</?[_[:alpha:]][-_:[:alnum:].]*\\(\\([^'\"></]\\|'[^']*'\\|\"[^\"]*\"\\)*\\)/?>?\\)"
1716 "\\(</?>\\|</?[_A-Za-z][-_:A-Za-z0-9.]*\\(\\([^'\"></]\\|'[^']*'\\|\"[^\"]*\"\\)*\\)/?>?\\)"))
1718 (defun sgml-operate-on-tags (action &optional attr-p)
1719 (let ((buffer-modified-p (buffer-modified-p))
1720 (inhibit-read-only t)
1721 (buffer-read-only nil)
1722 (before-change-functions nil)
1723 (markup-index ; match-data index in tag regexp
1725 (tagcount ; number tags to give them uniq
1726 ; invisible properties
1730 (goto-char (point-min))
1731 (while (re-search-forward sgml-tag-regexp nil t)
1734 (let ((tag (downcase
1735 (buffer-substring-no-properties
1736 (1+ (match-beginning 0))
1737 (match-beginning 2)))))
1738 (if (or attr-p (not (member tag sgml-exposed-tags)))
1739 (add-text-properties
1740 (match-beginning markup-index) (match-end markup-index)
1741 (list 'invisible tagcount
1742 'rear-nonsticky '(invisible face))))))
1743 ((eq action 'show) ; ignore markup-index
1744 (remove-text-properties (match-beginning 0) (match-end 0)
1746 (t (error "Invalid action: %s" action)))
1748 (sgml-restore-buffer-modified-p buffer-modified-p))))
1750 (defun sgml-hide-tags ()
1751 "Hide all tags in buffer."
1753 (sgml-operate-on-tags 'hide))
1755 (defun sgml-show-tags ()
1756 "Show hidden tags in buffer."
1758 (sgml-operate-on-tags 'show))
1760 (defun sgml-hide-attributes ()
1761 "Hide all attribute specifications in the buffer."
1763 (sgml-operate-on-tags 'hide 'attributes))
1765 (defun sgml-show-attributes ()
1766 "Show all attribute specifications in the buffer."
1768 (sgml-operate-on-tags 'show 'attributes))
1771 ;;;; SGML mode: Normalize (and misc manipulations)
1773 (defun sgml-expand-shortref-to-text (name)
1774 (let (before-change-functions
1775 (entity (sgml-lookup-entity name (sgml-dtd-entities sgml-dtd-info))))
1777 ((null entity) (sgml-error "Undefined entity %s" name))
1778 ((sgml-entity-data-p entity)
1779 (sgml-expand-shortref-to-entity name))
1781 (delete-region sgml-markup-start (point))
1782 (sgml-entity-insert-text entity)
1783 (setq sgml-goal (point-max)) ; May have changed size of buffer
1784 ;; now parse the entity text
1785 (setq sgml-rs-ignore-pos sgml-markup-start)
1786 (goto-char sgml-markup-start)))))
1788 (defun sgml-expand-shortref-to-entity (name)
1791 before-change-functions)
1792 (goto-char sgml-markup-start)
1793 (setq re-found (search-forward "\n" end t))
1794 (delete-region sgml-markup-start end)
1795 (insert "&" name (if re-found "\n" ";"))
1796 (setq sgml-goal (point-max)) ; May have changed size of buffer
1797 (goto-char (setq sgml-rs-ignore-pos sgml-markup-start))))
1799 (defun sgml-expand-all-shortrefs (to-entity)
1800 "Expand all short references in the buffer.
1801 Short references to text entities are expanded to the replacement text
1802 of the entity; other short references are expanded into general entity
1803 references. If argument TO-ENTITY is non-nil, or if called
1804 interactively with a numeric prefix argument, all short references are
1805 replaced by general entity references."
1807 (sgml-reparse-buffer
1809 (function sgml-expand-shortref-to-entity)
1810 (function sgml-expand-shortref-to-text))))
1812 (defun sgml-normalize (to-entity &optional element)
1813 "Normalize buffer by filling in omitted tags and expanding empty tags.
1814 Argument TO-ENTITY controls how short references are expanded as with
1815 `sgml-expand-all-shortrefs'. An optional argument ELEMENT can be the
1816 element to normalize instead of the whole buffer, if used no short
1817 references will be expanded."
1820 (sgml-expand-all-shortrefs to-entity))
1821 (let ((only-one (not (null element))))
1822 (setq element (or element (sgml-top-element)))
1823 (goto-char (sgml-element-end element))
1824 ;; FIXME: actually the sgml-note-change-at called by the
1825 ;; before-change-functions need to be delayed to after the normalize
1826 ;; to avoid destroying the tree wile traversing it.
1827 (let ((before-change-functions nil))
1828 (sgml-normalize-content element only-one)))
1829 (sgml-note-change-at (sgml-element-start element))
1830 (sgml-message "Done"))
1832 (defun sgml-normalize-element ()
1834 (sgml-normalize nil (sgml-find-element-of (point))))
1836 (defun sgml-normalize-content (element only-first)
1837 "Normalize all elements in a content where ELEMENT is first element.
1838 If sgml-normalize-trims is non-nil, trim off white space from ends of
1839 elements with omitted end-tags."
1840 (let ((content nil))
1841 (while element ; Build list of content elements
1842 (push element content)
1843 (setq element (if only-first
1845 (sgml-element-next element))))
1847 (setq element (car content))
1849 (sgml-lazy-message "Normalizing %d%% left"
1850 (/ (point) (/ (+ (point-max) 100) 100)))
1852 (sgml-normalize-end-tag element)
1853 ;; Fix tags of content
1854 (sgml-normalize-content (sgml-tree-content element) nil)
1855 ;; Fix the start-tag
1856 (sgml-normalize-start-tag element)
1857 ;; Next content element
1858 (setq content (cdr content)))))
1860 (defun sgml-normalize-start-tag (element)
1861 (when (sgml-bpos-p (sgml-element-stag-epos element))
1862 (goto-char (min (point) (sgml-element-start element)))
1863 (let ((name (sgml-element-gi element))
1864 (attlist (sgml-element-attlist element))
1865 (asl (sgml-element-attribute-specification-list element)))
1867 (assert (or (zerop (sgml-element-stag-len element))
1868 (= (point) (sgml-element-start element))))
1869 (delete-char (sgml-element-stag-len element))
1870 (sgml-insert-start-tag name asl attlist nil)))))
1872 (defun sgml-normalize-end-tag (element)
1873 (unless (sgml-element-empty element)
1874 (when (sgml-bpos-p (sgml-element-etag-epos element))
1875 (goto-char (min (point) (sgml-element-etag-start element)))
1876 (if (and (zerop (sgml-element-etag-len element))
1877 sgml-normalize-trims)
1878 (skip-chars-backward " \t\n\r"))
1879 (delete-char (sgml-tree-etag-len element))
1880 ;; XEmacs change: use tempo
1881 (save-excursion (tempo-process-and-insert-string (sgml-end-tag-of element))))))
1884 (defun sgml-make-character-reference (&optional invert)
1885 "Convert character after point into a character reference.
1886 If called with a numeric argument, convert a character reference back
1887 to a normal character. If called from a program, set optional
1888 argument INVERT to non-nil. If the function `decode-char' is defined,
1889 convert to and from Unicode. Otherwise will only work for ASCII or 8-bit
1890 characters in the current coding system."
1894 (or (looking-at "&#\\([0-9]+\\)[;\n]?")
1895 (error "No character reference after point"))
1896 (let ((c (string-to-int (buffer-substring (match-beginning 1)
1898 (delete-region (match-beginning 0)
1900 (if (fboundp 'decode-char) ; Emacs 21, Mule-UCS
1901 (setq c (decode-char 'ucs c))
1902 ;; Else have to assume 8-bit character.
1903 (if (fboundp 'unibyte-char-to-multibyte) ; Emacs 20
1904 (setq c (unibyte-char-to-multibyte c))))
1906 ;; Convert character to &#nn;
1908 (let ((c (following-char)))
1910 (if (fboundp 'encode-char)
1911 (setq c (encode-char c 'ucs))
1912 (if (fboundp 'multibyte-char-to-unibyte)
1913 (setq c (multibyte-char-to-unibyte c))))
1914 (insert (format "&#%d;" c))))))
1916 (defun sgml-expand-entity-reference ()
1917 "Insert the text of the entity referenced at point."
1920 (sgml-with-parser-syntax
1921 (setq sgml-markup-start (point))
1922 (or (sgml-parse-delim "ERO")
1924 (skip-syntax-backward "w_")
1925 (forward-char -1) ; @@ Really length of ERO
1926 (setq sgml-markup-start (point))
1927 (sgml-check-delim "ERO")))
1928 (let* ((ename (sgml-check-name t))
1929 (entity (sgml-lookup-entity ename
1932 sgml-buffer-parse-state)))))
1934 (error "Undefined entity %s" ename))
1935 (or (sgml-parse-delim "REFC")
1937 (delete-region sgml-markup-start (point))
1938 (sgml-entity-insert-text entity)))))
1942 (defun sgml-trim-and-leave-element ()
1943 "Remove blanks at end of current element and move point to after element."
1945 (goto-char (sgml-element-etag-start (sgml-last-element)))
1946 (while (progn (forward-char -1)
1947 (looking-at "\\s-"))
1952 (defvar sgml-notation-handlers
1955 "*An alist mapping notations to programs handling them")
1957 ;; Function contributed by Matthias Clasen <clasen@netzservice.de>
1958 (defun sgml-edit-external-entity ()
1959 "Open a new window and display the external entity at the point."
1963 (sgml-with-parser-syntax
1964 (setq sgml-markup-start (point))
1965 (unless (sgml-parse-delim "ERO")
1966 (search-backward-regexp "[&>;]")
1967 (setq sgml-markup-start (point))
1968 (sgml-check-delim "ERO"))
1969 (sgml-parse-to-here) ; get an up-to-date parse tree
1970 (let* ( (parent (buffer-file-name)) ; used to be (sgml-file)
1971 (ename (sgml-check-name t))
1972 (entity (sgml-lookup-entity ename
1975 sgml-buffer-parse-state))))
1979 (error "Undefined entity %s" ename))
1981 (let* ((type (sgml-entity-type entity))
1982 (notation (sgml-entity-notation entity))
1983 (handler (cdr (assoc notation sgml-notation-handlers))))
1988 (message (format "Using '%s' to handle notation '%s'."
1991 (set-buffer (get-buffer-create "*SGML background*"))
1993 (let* ((file (sgml-external-file
1994 (sgml-entity-text entity)
1996 (sgml-entity-name entity)))
1997 (process (start-process
1998 (format "%s background" handler)
2000 (process-kill-without-query process))))
2001 (error "Don't know how to handle notation '%s'." notation)))
2004 ;; here I try to construct a useful value for
2005 ;; `sgml-parent-element'.
2007 ;; find sensible values for the HAS-SEEN-ELEMENT part
2009 (child (sgml-tree-content sgml-current-tree)))
2011 (sgml-tree-etag-epos child)
2012 (<= (sgml-tree-end child) (point)))
2013 (push (sgml-element-gi child) seen)
2014 (setq child (sgml-tree-next child)))
2015 (push (nreverse seen) ppos))
2018 (let ((rover sgml-current-tree))
2019 (while (not (eq rover sgml-top-tree))
2020 (push (sgml-element-gi rover) ppos)
2021 (setq rover (sgml-tree-parent rover))))
2023 (find-file-other-window
2024 (sgml-external-file (sgml-entity-text entity)
2025 (sgml-entity-type entity)
2026 (sgml-entity-name entity)))
2027 (goto-char (point-min))
2029 (setq sgml-parent-document (cons parent ppos))
2030 ;; update the live element indicator of the new window
2031 (sgml-parse-to-here)))
2032 (t (error "Can't edit entities of type '%s'." type))))))))
2034 ;;;; SGML mode: TAB completion
2036 (defun sgml-complete ()
2037 "Complete the word/tag/entity before point.
2038 If it is a tag (starts with < or </) complete with valid tags.
2039 If it is an entity (starts with &) complete with declared entities.
2040 If it is a markup declaration (starts with <!) complete with markup
2041 declaration names. If it is a reserved word starting with # complete
2043 If it is something else complete with ispell-complete-word."
2045 (let ((tab ; The completion table
2047 (ignore-case ; If ignore case in matching completion
2048 sgml-namecase-general)
2050 'sgml-general-insert-case)
2054 (skip-chars-backward "^ \n\t</!&%#")
2055 (setq pattern (buffer-substring (point) here))
2056 (setq c (char-after (1- (point))))
2061 (setq insert-case 'sgml-entity-insert-case)
2063 (sgml-entity-completion-table
2064 (sgml-dtd-entities (sgml-pstate-dtd sgml-buffer-parse-state)))))
2069 (sgml-parse-to-here)
2070 (setq tab (sgml-eltype-completion-table
2071 (sgml-current-list-of-valid-eltypes)))))
2076 (sgml-parse-to-here)
2077 (setq tab (sgml-eltype-completion-table
2078 (sgml-current-list-of-endable-eltypes)))))
2079 ;; markup declaration
2081 (setq tab sgml-markup-declaration-table
2083 ;; Reserved words with '#' prefix
2085 (setq tab '(("PCDATA") ("NOTATION") ("IMPLIED") ("REQUIRED")
2086 ("FIXED") ("EMPTY"))
2090 (ispell-complete-word)))
2092 (let* ((completion-ignore-case ignore-case)
2093 (completion (try-completion pattern tab)))
2094 (cond ((null completion)
2096 (message "Can't find completion for \"%s\"" pattern)
2100 (message "[Complete]"))
2101 ((not (string= pattern completion))
2102 (delete-char (length pattern))
2103 (insert (funcall insert-case completion)))
2106 (message "Making completion list...")
2107 (let ((list (all-completions pattern tab)))
2108 (with-output-to-temp-buffer " *Completions*"
2109 (display-completion-list list)))
2110 (message "Making completion list...%s" "done")))))))
2113 ;;;; SGML mode: Options menu
2115 (defun sgml-file-options-menu (&optional event)
2117 (sgml-options-menu event sgml-file-options))
2119 (defun sgml-user-options-menu (&optional event)
2121 (sgml-options-menu event sgml-user-options))
2123 (defun sgml-options-menu (event vars)
2126 (loop for var in vars
2127 maximize (length (sgml-variable-description var)))))
2130 (loop for var in vars
2131 for desc = (sgml-variable-description var)
2136 (make-string (- maxlen (length desc)) ? )
2137 (sgml-option-value-indicator var))
2140 (sgml-do-set-option var event))))
2142 ;; Fixme: Use Customize for this.
2143 (defun sgml-do-set-option (var &optional event)
2144 (let ((type (sgml-variable-type var))
2145 (val (symbol-value var)))
2148 (message "%s set to %s" var (not val))
2149 (set var (not val)))
2151 (describe-variable var)
2152 (setq val (read-string (concat (sgml-variable-description var) ": ")))
2155 ((eq 'file-list type)
2156 (describe-variable var)
2157 (sgml-append-to-help-buffer "\
2158 Enter as many filenames as you want. Entering a directory
2159 or non-existing filename will exit the loop.")
2164 (concat (sgml-variable-description var) ": ")
2166 (if (and (file-exists-p next) (not (file-directory-p next)))
2167 (setq val (cons next val)))))
2169 ((eq 'file-or-nil type)
2170 (describe-variable var)
2171 (sgml-append-to-help-buffer "\
2172 Entering a directory or non-existing filename here
2173 will reset the variable.")
2174 (setq val (expand-file-name
2176 (concat (sgml-variable-description var) ": ")
2177 nil (if (stringp val) (file-name-nondirectory val))
2178 nil (if (stringp val) (file-name-nondirectory val)) )))
2179 (if (and (file-exists-p val) (not (file-directory-p val)))
2184 (sgml-popup-menu event
2185 (sgml-variable-description var)
2186 (loop for c in type collect
2188 (if (consp c) (car c) (format "%s" c))
2189 (if (consp c) (cdr c) c))))))
2191 (message "%s set to %s" var val)))
2193 (describe-variable var)
2194 (setq val (read-string (concat (sgml-variable-description var)
2197 (set var (car (read-from-string val)))))))
2198 (force-mode-line-update))
2200 (defun sgml-append-to-help-buffer (string)
2202 (set-buffer "*Help*")
2203 (let ((inhibit-read-only t))
2204 (goto-char (point-max))
2205 (insert "\n" string))))
2207 ;;;; SGML mode: insert element where valid
2209 (defun sgml--add-before-p (tok state child)
2210 ;; Can TOK be added in STATE followed by CHILD
2211 (let ((snext (sgml-get-move state tok))
2215 (setq snext (sgml-get-move snext
2217 (sgml-element-eltype c))))
2218 (setq c (and snext (sgml-element-next c)))))
2219 ;; If snext is still non nill it can be inserted
2222 (defun sgml--all-possible-elements (el)
2223 (let ((c (sgml-element-content el))
2224 (s (sgml-element-model el))
2227 ;; Fixme: this test avoids an error when DTD-less, but it's
2228 ;; probably an inappropriate kludge. -- fx
2229 (when (not (eq s 'ANY))
2230 (dolist (tok (nconc (sgml-optional-tokens s)
2231 (sgml-required-tokens s)))
2232 (unless (memq tok found)
2233 ;; tok is optional here and not already found -- check that
2234 ;; it would not make the content invalid
2235 (when (sgml--add-before-p tok s c)
2236 (push tok found)))))
2238 (setq s (sgml-element-pstate c))
2239 (setq c (sgml-element-next c)))
2240 (mapcar #'sgml-token-eltype found)))
2243 (defun sgml-add-element-to-element (gi first)
2244 "Add an element of type GI to the current element.
2245 The element will be added at the last legal position if FIRST is `nil',
2246 otherwise it will be added at the first legal position."
2249 (mapcar (lambda (et) (cons (sgml-eltype-name et) nil))
2250 (sgml--all-possible-elements
2251 (sgml-find-context-of (point))))))
2253 (error "No element possible"))
2255 (let ((completion-ignore-case sgml-namecase-general))
2256 (list (completing-read "Element: " tab nil t
2257 (and (null (cdr tab)) (caar tab)))
2258 current-prefix-arg))))))
2259 (let ((el (sgml-find-context-of (point)))
2260 (et (sgml-lookup-eltype (sgml-general-case gi))))
2261 ;; First expand empty tag
2262 (when (and sgml-xml-p (sgml-element-empty el))
2264 (goto-char (sgml-element-stag-end el))
2266 (insert ">\n" (sgml-end-tag-of sgml-current-tree))
2268 (setq el (sgml-find-context-of (point))))
2269 (let ((c (sgml-element-content el))
2270 (s (sgml-element-model el))
2271 (tok (sgml-eltype-token et))
2273 ;; Find legal position for new element
2274 (while (and (not (cond
2275 ((sgml--add-before-p tok s c)
2276 (setq last (if c (sgml-element-start c)
2277 (sgml-element-etag-start el)))
2280 (c (setq s (sgml-element-pstate c))
2281 (setq c (sgml-element-next c))
2285 (sgml-insert-element gi))
2287 (error "A %s element is not valid in current element" gi))))))
2289 ;;;; Show current element type
2290 ;; Candidate for C-c C-t
2292 (autoload 'sgml-princ-names "psgml-info")
2293 (autoload 'sgml-eltype-refrenced-elements "psgml-info")
2295 (defun sgml-show-current-element-type ()
2296 "Show information about the current element and its type."
2298 (let* ((el (sgml-find-context-of (point)))
2299 (et (sgml-element-eltype el)))
2300 (with-output-to-temp-buffer "*Current Element Type*"
2301 (princ (format "ELEMENT: %s%s\n" (sgml-eltype-name et)
2302 (let ((help-text (sgml-eltype-appdata et 'help-text)))
2304 (format " -- %s" help-text)
2307 (princ (format "\n Start-tag is %s.\n End-tag is %s.\n"
2308 (if (sgml-eltype-stag-optional et)
2309 "optional" "required")
2310 (if (sgml-eltype-etag-optional et)
2311 "optional" "required"))))
2313 (princ "\nCONTENT: ")
2314 (cond ((symbolp (sgml-eltype-model et)) (princ (sgml-eltype-model et)))
2316 (princ (if (sgml-eltype-mixed et)
2319 (sgml-print-position-in-model el et (point) sgml-current-state)
2322 (mapcar #'symbol-name (sgml-eltype-refrenced-elements et))
2324 (let ((incl (sgml-eltype-includes et))
2325 (excl (sgml-eltype-excludes et)))
2326 (when (or incl excl)
2327 (princ "\n\nEXCEPTIONS:"))
2330 (sgml-princ-names (mapcar #'symbol-name incl)))
2333 (sgml-princ-names (mapcar #'symbol-name excl))))
2335 (princ "\n\nATTRIBUTES:\n")
2336 (sgml-print-attlist et)
2338 (let ((s (sgml-eltype-shortmap et)))
2340 (princ (format "\nUSEMAP: %s\n" s))))
2342 (princ "\nOCCURS IN:\n")
2343 (let ((occurs-in ()))
2345 (function (lambda (cand)
2346 (when (memq et (sgml-eltype-refrenced-elements cand))
2347 (push cand occurs-in))))
2348 (sgml-pstate-dtd sgml-buffer-parse-state))
2349 (sgml-princ-names (mapcar 'sgml-eltype-name
2350 (sort occurs-in (function string-lessp))))))))
2352 (defun sgml-print-attlist (et)
2353 (let ((ob (current-buffer)))
2354 (set-buffer standard-output)
2357 for attdecl in (sgml-eltype-attlist et) do
2359 (princ (sgml-attdecl-name attdecl))
2360 (let ((dval (sgml-attdecl-declared-value attdecl))
2361 (defl (sgml-attdecl-default-value attdecl)))
2363 (setq dval (concat (if (eq (first dval)
2366 (mapconcat (function identity)
2372 (cond ((sgml-default-value-type-p 'FIXED defl)
2373 (setq defl (format "#FIXED '%s'"
2374 (sgml-default-value-attval defl))))
2376 (setq defl (upcase (format "#%s" defl))))
2378 (setq defl (format "'%s'"
2379 (sgml-default-value-attval defl)))))
2387 (defun sgml-print-position-in-model (element element-type buffer-pos parse-state)
2388 (let ((u (sgml-element-content element))
2390 (while (and u (>= buffer-pos (sgml-element-end u)))
2391 (push (sgml-element-gi u) names)
2392 (setq u (sgml-element-next u)))
2394 (sgml-princ-names (nreverse names) " " ", ")
2397 (let* ((state parse-state)
2398 (required-seq ; the seq of req el following point
2399 (loop for required = (sgml-required-tokens state)
2400 while (and required (null (cdr required)))
2401 collect (sgml-eltype-name (car required))
2402 do (setq state (sgml-get-move state (car required)))))
2404 (mapcar 'sgml-eltype-name
2405 (append (sgml-optional-tokens state)
2406 (sgml-required-tokens state)))))
2412 (mapconcat (lambda (x) x)
2414 (if (sgml-final state)
2416 (sgml-princ-names required-seq " " ", "))
2419 (sgml-princ-names last-alt " (" " | ")
2421 (when (sgml-final state)
2425 ;;;; Structure Viewing and Navigating
2428 (defun sgml-show-structure ()
2429 "Show the document structure in a separate buffer."
2431 (let ((source (current-buffer))
2432 (result (get-buffer-create "*Document structure*")))
2439 (sgml-structure-elements (sgml-top-element)))))
2440 (sgml-show-structure-insert structure))
2441 (goto-char (point-min))
2442 (display-buffer result)))
2445 (defun sgml-show-structure-insert (structure)
2446 (loop for (gi level marker title) in structure do
2447 (let ((start (point)))
2448 (insert (make-string (* 2 level) ? ))
2449 (sgml-insert `(face match mouse-face highlight) gi)
2450 (sgml-insert `(mouse-face highlight) " %s" title)
2452 (add-text-properties
2454 `(occur-target ,marker help-echo "mouse-2: go to this occurrence")))))
2457 (defun sgml-show-struct-element-p (element)
2458 (let ((configured (sgml-element-appdata element 'structure)))
2459 (unless (eql configured 'ignore)
2461 (and (not (sgml-element-data-p element))
2462 (not (sgml-element-empty element)))))))
2465 (defun sgml-structure-elements (element)
2466 (when (sgml-show-struct-element-p element)
2467 (let ((gi (sgml-element-gi element))
2468 (level (sgml-element-level element))
2469 (child1 (sgml-element-content element))
2472 (goto-char (sgml-element-start element))
2473 (setq marker (copy-marker (point-marker)))
2475 (not (sgml-show-struct-element-p child1))
2476 (sgml-element-data-p child1))
2477 (let ((start-epos (sgml-element-stag-epos child1))
2478 (end-epos (sgml-element-etag-epos child1)))
2479 (when (and (sgml-bpos-p start-epos)
2480 (sgml-bpos-p end-epos))
2481 (goto-char start-epos)
2482 (forward-char (sgml-element-stag-len child1))
2483 (when (looking-at "\\s-*$")
2485 (when (< (point) end-epos)
2487 (buffer-substring (point)
2488 ;; XEmacs: point-at-eol for < 21.4.20
2491 (cons (list (sgml-general-insert-case gi)
2493 (loop for child = child1 then (sgml-element-next child)
2495 nconc (sgml-structure-elements child))))))
2498 ;;; psgml-edit.el ends here