Mercurial > hg > xemacs-beta
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 "'"))) | |
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 |