Mercurial > emacs
comparison lisp/textmodes/sgml-mode.el @ 14159:93175ed23e01
Also load for .sgm and .dtd files.
(sgml-specials, sgml-name-8bit-mode, sgml-char-names)
(sgml-font-lock-keywords, sgml-face-tag-alist, sgml-tag-face-alist)
(sgml-display-text, sgml-tag-alist, sgml-tag-help)
(sgml-auto-attributes): New variables.
(sgml-mode-common): New function.
(sgml-mode): Most code moved to it.
(sgml-name-char, sgml-name-self, sgml-maybe-name-self)
(sgml-name-8bit-mode, sgml-tag, sgml-attributes, sgml-auto-attributes)
(sgml-tag-help, sgml-maybe-end-tag, sgml-skip-tag-backward)
(sgml-skip-tag-forward, sgml-tags-invisible): New commands.
(sgml-beginning-of-tag, sgml-value): New functions.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Fri, 12 Jan 1996 21:14:51 +0000 |
parents | ac7375e60931 |
children | 313ea10ec42c |
comparison
equal
deleted
inserted
replaced
14158:9d42246240c3 | 14159:93175ed23e01 |
---|---|
1 ;;; sgml-mode.el --- SGML-editing mode | 1 ;;; sgml-mode.el --- SGML- and HTML-editing modes |
2 | 2 |
3 ;; Copyright (C) 1992 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: James Clark <jjc@clark.com> | 5 ;; Author: James Clark <jjc@clark.com> |
6 ;; Adapted-By: ESR | 6 ;; Adapted-By: ESR; Daniel.Pfeiffer@Informatik.START.dbp.de |
7 ;; Keywords: wp | 7 ;; Keywords: wp, hypermedia, comm, languages |
8 | 8 |
9 ;; This file is part of GNU Emacs. | 9 ;; This file is part of GNU Emacs. |
10 | 10 |
11 ;; GNU Emacs is free software; you can redistribute it and/or modify | 11 ;; GNU Emacs is free software; you can redistribute it and/or modify |
12 ;; it under the terms of the GNU General Public License as published by | 12 ;; it under the terms of the GNU General Public License as published by |
22 ;; along with GNU Emacs; see the file COPYING. If not, write to | 22 ;; along with GNU Emacs; see the file COPYING. If not, write to |
23 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 23 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | 24 |
25 ;;; Commentary: | 25 ;;; Commentary: |
26 | 26 |
27 ;; Major mode for editing the SGML document-markup language. | 27 ;; Configurable major mode for editing document in the SGML standard general |
28 ;; markup language. As an example contains a mode for editing the derived | |
29 ;; HTML hypertext markup language. | |
28 | 30 |
29 ;;; Code: | 31 ;;; Code: |
30 | 32 |
31 (provide 'sgml-mode) | 33 ;;;###autoload |
32 (require 'compile) | 34 (or (rassq 'sgml-mode auto-mode-alist) |
33 | 35 (setq auto-mode-alist `(("\\.sgml?\\'" . sgml-mode) |
34 ;;; sgmls is a free SGML parser available from | 36 ("\\.dtd\\'" . sgml-mode) |
35 ;;; ftp.uu.net:pub/text-processing/sgml | 37 ,@auto-mode-alist))) |
36 ;;; Its error messages can be parsed by next-error. | 38 |
37 ;;; The -s option suppresses output. | 39 |
38 | 40 ;; As long as Emacs' syntax can't be complemented with predicates to context |
39 (defconst sgml-validate-command | 41 ;; sensitively confirm the syntax of characters, we have to live with this |
40 "sgmls -s" | 42 ;; kludgy kind of tradeoff. |
43 (defvar sgml-specials '(?\" ?-) | |
44 "List of characters that have a special meaning for sgml-mode. | |
45 This list is used when first loading the sgml-mode library. | |
46 The supported characters and potential disadvantages are: | |
47 | |
48 ?\\\" Makes \" in text start a string. | |
49 ?' Makes ' in text start a string. | |
50 ?- Makes -- in text start a comment. | |
51 | |
52 When only one of ?\\\" or ?' are included, \"'\" or '\"' as it can be found in | |
53 DTDs, start a string. To partially avoid this problem this also makes these | |
54 self insert as named entities. <!----> must contain an even multiple of two | |
55 (4, 8, ...) minuses, or Emacs' syntax mechanism won't recognize a comment.") | |
56 | |
57 | |
58 (defvar sgml-mode-map | |
59 (let ((map (list 'keymap (make-vector 256 nil))) | |
60 (menu-map (make-sparse-keymap "SGML"))) | |
61 (define-key map "\t" 'indent-relative-maybe) | |
62 (define-key map "\C-c\C-i" 'sgml-tags-invisible) | |
63 (define-key map "/" 'sgml-slash) | |
64 (define-key map "&" 'sgml-name-char) | |
65 (define-key map "<" 'sgml-tag) | |
66 (define-key map "\C-c\C-a" 'sgml-attributes) | |
67 (define-key map "\C-c\C-b" 'sgml-skip-tag-backward) | |
68 (define-key map [?\C-c left] 'sgml-skip-tag-backward) | |
69 (define-key map "\C-c\C-f" 'sgml-skip-tag-forward) | |
70 (define-key map [?\C-c right] 'sgml-skip-tag-forward) | |
71 (define-key map "\C-c\C-d" 'sgml-delete-tag) | |
72 (define-key map "\C-c\^?" 'sgml-delete-tag) | |
73 (define-key map "\C-c?" 'sgml-tag-help) | |
74 (define-key map " " 'sgml-auto-attributes) | |
75 (define-key map ">" 'sgml-maybe-end-tag) | |
76 (if (memq ?\" sgml-specials) | |
77 (define-key map "\"" 'sgml-name-self)) | |
78 (if (memq ?' sgml-specials) | |
79 (define-key map "'" 'sgml-name-self)) | |
80 (define-key map "\C-c8" 'sgml-name-8bit-mode) | |
81 (define-key map "\C-c\C-v" 'sgml-validate) | |
82 (let ((c 127) | |
83 (map (nth 1 map))) | |
84 (while (< (setq c (1+ c)) 256) | |
85 (aset map c 'sgml-maybe-name-self))) | |
86 (define-key map [menu-bar sgml] (cons "SGML" menu-map)) | |
87 (define-key menu-map [sgml-validate] '("Validate" . sgml-validate)) | |
88 (define-key menu-map [sgml-name-8bit-mode] | |
89 '("Toggle 8 Bit Insertion" . sgml-name-8bit-mode)) | |
90 (define-key menu-map [sgml-tags-invisible] | |
91 '("Toggle Tag Visibility" . sgml-tags-invisible)) | |
92 (define-key menu-map [sgml-tag-help] | |
93 '("Describe Tag" . sgml-tag-help)) | |
94 (define-key menu-map [sgml-delete-tag] | |
95 '("Delete Tag" . sgml-delete-tag)) | |
96 (define-key menu-map [sgml-skip-tag-forward] | |
97 '("Forward Tag" . sgml-skip-tag-forward)) | |
98 (define-key menu-map [sgml-skip-tag-backward] | |
99 '("Backward Tag" . sgml-skip-tag-backward)) | |
100 (define-key menu-map [sgml-attributes] | |
101 '("Insert Attributes" . sgml-attributes)) | |
102 (define-key menu-map [sgml-tag] '("Insert Tag" . sgml-tag)) | |
103 map) | |
104 "Keymap for SGML mode. See also `sgml-specials'.") | |
105 | |
106 | |
107 (defvar sgml-mode-syntax-table | |
108 (let ((table (copy-syntax-table text-mode-syntax-table))) | |
109 (modify-syntax-entry ?< "(>" table) | |
110 (modify-syntax-entry ?> ")<" table) | |
111 (if (memq ?- sgml-specials) | |
112 (modify-syntax-entry ?- "_ 1234" table)) | |
113 (if (memq ?\" sgml-specials) | |
114 (modify-syntax-entry ?\" "\"\"" table)) | |
115 (if (memq ?' sgml-specials) | |
116 (modify-syntax-entry ?\' "\"'" table)) | |
117 table) | |
118 "Syntax table used in SGML mode. See also `sgml-specials'.") | |
119 | |
120 | |
121 (defvar sgml-name-8bit-mode nil | |
122 "*When non-`nil' insert 8 bit characters with their names.") | |
123 | |
124 (defvar sgml-char-names | |
125 [nil nil nil nil nil nil nil nil | |
126 nil nil nil nil nil nil nil nil | |
127 nil nil nil nil nil nil nil nil | |
128 nil nil nil nil nil nil nil nil | |
129 "ensp" "excl" "quot" "num" "dollar" "percnt" "amp" "apos" | |
130 "lpar" "rpar" "ast" "plus" "comma" "hyphen" "period" "sol" | |
131 nil nil nil nil nil nil nil nil | |
132 nil nil "colon" "semi" "lt" "eq" "gt" "quest" | |
133 "commat" nil nil nil nil nil nil nil | |
134 nil nil nil nil nil nil nil nil | |
135 nil nil nil nil nil nil nil nil | |
136 nil nil nil "lsqb" nil "rsqb" "uarr" "lowbar" | |
137 "lsquo" nil nil nil nil nil nil nil | |
138 nil nil nil nil nil nil nil nil | |
139 nil nil nil nil nil nil nil nil | |
140 nil nil nil "lcub" "verbar" "rcub" "tilde" nil | |
141 nil nil nil nil nil nil nil nil | |
142 nil nil nil nil nil nil nil nil | |
143 nil nil nil nil nil nil nil nil | |
144 nil nil nil nil nil nil nil nil | |
145 "nbsp" "iexcl" "cent" "pound" "curren" "yen" "brvbar" "sect" | |
146 "uml" "copy" "ordf" "laquo" "not" "shy" "reg" "macr" | |
147 "ring" "plusmn" "sup2" "sup3" "acute" "micro" "para" "middot" | |
148 "cedil" "sup1" "ordm" "raquo" "frac14" "half" "frac34" "iquest" | |
149 "Agrave" "Aacute" "Acirc" "Atilde" "Auml" "Aring" "AElig" "Ccedil" | |
150 "Egrave" "Eacute" "Ecirc" "Euml" "Igrave" "Iacute" "Icirc" "Iuml" | |
151 "ETH" "Ntilde" "Ograve" "Oacute" "Ocirc" "Otilde" "Ouml" nil | |
152 "Oslash" "Ugrave" "Uacute" "Ucirc" "Uuml" "Yacute" "THORN" "szlig" | |
153 "agrave" "aacute" "acirc" "atilde" "auml" "aring" "aelig" "ccedil" | |
154 "egrave" "eacute" "ecirc" "euml" "igrave" "iacute" "icirc" "iuml" | |
155 "eth" "ntilde" "ograve" "oacute" "ocirc" "otilde" "ouml" "divide" | |
156 "oslash" "ugrave" "uacute" "ucirc" "uuml" "yacute" "thorn" "yuml"] | |
157 "Vector of symbolic character names without `&' and `;'.") | |
158 | |
159 | |
160 ;; sgmls is a free SGML parser available from | |
161 ;; ftp.uu.net:pub/text-processing/sgml | |
162 ;; Its error messages can be parsed by next-error. | |
163 ;; The -s option suppresses output. | |
164 | |
165 (defvar sgml-validate-command "sgmls -s" | |
41 "*The command to validate an SGML document. | 166 "*The command to validate an SGML document. |
42 The file name of current buffer file name will be appended to this, | 167 The file name of current buffer file name will be appended to this, |
43 separated by a space.") | 168 separated by a space.") |
44 | 169 |
45 (defvar sgml-saved-validate-command nil | 170 (defvar sgml-saved-validate-command nil |
46 "The command last used to validate in this buffer.") | 171 "The command last used to validate in this buffer.") |
47 | 172 |
48 (defvar sgml-mode-map nil "Keymap for SGML mode") | 173 |
49 | 174 ;;; I doubt that null end tags are used much for large elements, |
50 (if sgml-mode-map | 175 ;;; so use a small distance here. |
51 () | 176 (defconst sgml-slash-distance 1000 |
52 (setq sgml-mode-map (make-sparse-keymap)) | 177 "*If non-nil, is the maximum distance to search for matching /.") |
53 (define-key sgml-mode-map ">" 'sgml-close-angle) | 178 |
54 (define-key sgml-mode-map "/" 'sgml-slash) | 179 (defconst sgml-start-tag-regex |
55 (define-key sgml-mode-map "\C-c\C-v" 'sgml-validate)) | 180 "<[A-Za-z]\\([-.A-Za-z0-9= \n\t]\\|\"[^\"]*\"\\|'[^']*'\\)*" |
56 | 181 "Regular expression that matches a non-empty start tag. |
57 ;;;###autoload | 182 Any terminating > or / is not matched.") |
58 (defun sgml-mode () | 183 |
59 "Major mode for editing SGML. | 184 |
60 Makes > display the matching <. Makes / display matching /. | 185 (defvar sgml-font-lock-keywords |
61 Use \\[sgml-validate] to validate your document with an SGML parser." | 186 '(("<\\([!?][a-z0-9]+\\)" 1 font-lock-keyword-face) |
62 (interactive) | 187 ("<\\(/?[a-z0-9]+\\)" 1 font-lock-function-name-face) |
188 ("[&%][-.A-Za-z0-9]+;?" . font-lock-variable-name-face)) | |
189 "*Rules for highlighting SGML code. See also `sgml-tag-face-alist'.") | |
190 | |
191 ;; internal | |
192 (defvar sgml-font-lock-keywords-1 ()) | |
193 | |
194 (defvar sgml-face-tag-alist () | |
195 "Alist of face and tag name for facemenu.") | |
196 | |
197 (defvar sgml-tag-face-alist () | |
198 "Tag names and face or list of faces to fontify with when invisible. | |
199 When `font-lock-maximum-decoration' is 1 this is always used for fontifying. | |
200 When more these are fontified together with `sgml-font-lock-keywords'.") | |
201 | |
202 | |
203 (defvar sgml-display-text () | |
204 "Tag names as lowercase symbols, and display string when invisible.") | |
205 | |
206 ;; internal | |
207 (defvar sgml-tags-invisible nil) | |
208 | |
209 | |
210 (defvar sgml-tag-alist | |
211 '(("!attlist") | |
212 ("!doctype") | |
213 ("!element") | |
214 ("!entity")) | |
215 "*Alist of tag names for completing read and insertion rules. | |
216 This alist is made up as | |
217 | |
218 ((\"tag\" . TAGRULE) | |
219 ...) | |
220 | |
221 TAGRULE is a list of optionally `t' (no endtag) or `\\n' (separate endtag by | |
222 newlines) or a skeleton with `nil', `t' or `\\n' in place of the interactor | |
223 followed by an ATTRIBUTERULE (for an always present attribute) or an | |
224 attribute alist. | |
225 | |
226 The attribute alist is made up as | |
227 | |
228 ((\"attribute\" . ATTRIBUTERULE) | |
229 ...) | |
230 | |
231 ATTRIBUTERULE is a list of optionally `t' (no value when no input) followed by | |
232 an optional alist of possible values.") | |
233 | |
234 (defvar sgml-tag-help | |
235 '(("!" . "Empty declaration for comment") | |
236 ("![" . "Embed declarations with parser directive") | |
237 ("!attlist" . "Tag attributes declaration") | |
238 ("!doctype" . "Document type (DTD) declaration") | |
239 ("!element" . "Tag declaration") | |
240 ("!entity" . "Entity (macro) declaration")) | |
241 "*Alist of tag name and short description.") | |
242 | |
243 | |
244 ;; put read-only last to enable setting this even when read-only enabled | |
245 (or (get 'sgml-tag 'invisible) | |
246 (setplist 'sgml-tag | |
247 (append '(invisible t | |
248 rear-nonsticky t | |
249 point-entered sgml-point-entered | |
250 read-only t) | |
251 (symbol-plist 'sgml-tag)))) | |
252 | |
253 | |
254 (defvar sgml-auto-attributes t | |
255 "*When non-`nil' SPC at top level of tag prompts for attributes.") | |
256 | |
257 | |
258 | |
259 (defun sgml-mode-common (sgml-tag-face-alist sgml-display-text) | |
260 "Common code for setting up `sgml-mode' and derived modes. | |
261 SGML-TAG-FACE-ALIST is used for calculating `sgml-font-lock-keywords-1'. | |
262 SGML-DISPLAY-TEXT sets up alternate text for when tags are invisible (see | |
263 varables of same name)." | |
63 (kill-all-local-variables) | 264 (kill-all-local-variables) |
64 (setq local-abbrev-table text-mode-abbrev-table) | 265 (setq local-abbrev-table text-mode-abbrev-table) |
266 (set-syntax-table sgml-mode-syntax-table) | |
267 (make-local-variable 'indent-line-function) | |
268 (make-local-variable 'paragraph-start) | |
269 (make-local-variable 'paragraph-separate) | |
270 (make-local-variable 'sgml-saved-validate-command) | |
271 (make-local-variable 'comment-start) | |
272 (make-local-variable 'comment-end) | |
273 (make-local-variable 'comment-indent-function) | |
274 (make-local-variable 'comment-start-skip) | |
275 (make-local-variable 'comment-indent-function) | |
276 (make-local-variable 'sgml-tags-invisible) | |
277 (make-local-variable 'skeleton-transformation) | |
278 (make-local-variable 'skeleton-further-elements) | |
279 (make-local-variable 'skeleton-end-hook) | |
280 (make-local-variable 'font-lock-defaults) | |
281 (make-local-variable 'sgml-font-lock-keywords-1) | |
282 (make-local-variable 'facemenu-add-face-function) | |
283 (make-local-variable 'facemenu-end-add-face) | |
284 ;;(make-local-variable 'facemenu-remove-face-function) | |
285 (and sgml-tag-face-alist | |
286 (not (assq 1 sgml-tag-face-alist)) | |
287 (nconc sgml-tag-face-alist | |
288 `((1 (,(concat "<\\(" | |
289 (mapconcat 'car sgml-tag-face-alist "\\|") | |
290 "\\)\\([ \t].+\\)?>\\(.+\\)</\\1>") | |
291 3 (cdr (assoc (match-string 1) ',sgml-tag-face-alist))))))) | |
292 (setq indent-line-function 'indent-relative-maybe | |
293 ;; A start or end tag by itself on a line separates a paragraph. | |
294 ;; This is desirable because SGML discards a newline that appears | |
295 ;; immediately after a start tag or immediately before an end tag. | |
296 paragraph-start "^[ \t\n]\\|\ | |
297 \\(</?\\([A-Za-z]\\([-.A-Za-z0-9= \t\n]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?>$\\)" | |
298 paragraph-separate "^[ \t\n]*$\\|\ | |
299 ^</?\\([A-Za-z]\\([-.A-Za-z0-9= \t\n]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?>$" | |
300 comment-start "<!-- " | |
301 comment-end " -->" | |
302 comment-indent-function 'sgml-comment-indent | |
303 ;; This will allow existing comments within declarations to be | |
304 ;; recognized. | |
305 comment-start-skip "--[ \t]*" | |
306 skeleton-transformation 'identity | |
307 skeleton-further-elements '((completion-ignore-case t)) | |
308 skeleton-end-hook (lambda () | |
309 (or (eolp) | |
310 (not (or (eq v2 '\n) | |
311 (eq (car-safe v2) '\n))) | |
312 (newline-and-indent))) | |
313 sgml-font-lock-keywords-1 (cdr (assq 1 sgml-tag-face-alist)) | |
314 font-lock-defaults '((sgml-font-lock-keywords | |
315 sgml-font-lock-keywords-1) | |
316 nil | |
317 t) | |
318 facemenu-add-face-function | |
319 (lambda (face end) | |
320 (if (setq face (cdr (assq face sgml-face-tag-alist))) | |
321 (progn | |
322 (setq facemenu-end-add-face (concat "</" face ">")) | |
323 (concat "<" face ">")) | |
324 (error "Face not configured for %s mode." mode-name)))) | |
325 (while sgml-display-text | |
326 (put (car (car sgml-display-text)) 'before-string | |
327 (cdr (car sgml-display-text))) | |
328 (setq sgml-display-text (cdr sgml-display-text))) | |
329 (run-hooks 'text-mode-hook 'sgml-mode-hook)) | |
330 | |
331 | |
332 ;;;###autoload | |
333 (defun sgml-mode (&optional function) | |
334 "Major mode for editing SGML documents. | |
335 Makes > match <. Makes / blink matching /. | |
336 | |
337 Do \\[describe-variable] sgml- SPC to see available variables. | |
338 | |
339 Use \\[sgml-validate] to validate your document with an SGML parser. | |
340 \\{sgml-mode-map}" | |
341 (interactive) | |
342 (sgml-mode-common sgml-tag-face-alist sgml-display-text) | |
65 (use-local-map sgml-mode-map) | 343 (use-local-map sgml-mode-map) |
66 (setq mode-name "SGML") | 344 (setq mode-name "SGML" |
67 (setq major-mode 'sgml-mode) | 345 major-mode 'sgml-mode)) |
68 (make-local-variable 'paragraph-start) | 346 |
69 ;; A start or end tag by itself on a line separates a paragraph. | 347 |
70 ;; This is desirable because SGML discards a newline that appears | |
71 ;; immediately after a start tag or immediately before an end tag. | |
72 (setq paragraph-start | |
73 "^[ \t\n]\\|\ | |
74 \\(</?\\([A-Za-z]\\([-.A-Za-z0-9= \t\n]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?>$\\)") | |
75 (make-local-variable 'paragraph-separate) | |
76 (setq paragraph-separate | |
77 "^[ \t\n]*$\\|\ | |
78 ^</?\\([A-Za-z]\\([-.A-Za-z0-9= \t\n]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?>$") | |
79 (make-local-variable 'sgml-saved-validate-command) | |
80 (set-syntax-table text-mode-syntax-table) | |
81 (make-local-variable 'comment-start) | |
82 (setq comment-start "<!-- ") | |
83 (make-local-variable 'comment-end) | |
84 (setq comment-end " -->") | |
85 (make-local-variable 'comment-indent-function) | |
86 (setq comment-indent-function 'sgml-comment-indent) | |
87 (make-local-variable 'comment-start-skip) | |
88 ;; This will allow existing comments within declarations to be | |
89 ;; recognized. | |
90 (setq comment-start-skip "--[ \t]*") | |
91 (run-hooks 'text-mode-hook 'sgml-mode-hook)) | |
92 | 348 |
93 (defun sgml-comment-indent () | 349 (defun sgml-comment-indent () |
94 (if (and (looking-at "--") | 350 (if (and (looking-at "--") |
95 (not (and (eq (char-after (1- (point))) ?!) | 351 (not (and (eq (preceding-char) ?!) |
96 (eq (char-after (- (point) 2)) ?<)))) | 352 (eq (char-after (- (point) 2)) ?<)))) |
97 (progn | 353 (progn |
98 (skip-chars-backward " \t") | 354 (skip-chars-backward " \t") |
99 (max comment-column (1+ (current-column)))) | 355 (max comment-column (1+ (current-column)))) |
100 0)) | 356 0)) |
101 | 357 |
102 (defconst sgml-start-tag-regex | 358 |
103 "<[A-Za-z]\\([-.A-Za-z0-9= \n\t]\\|\"[^\"]*\"\\|'[^']*'\\)*" | |
104 "Regular expression that matches a non-empty start tag. | |
105 Any terminating > or / is not matched.") | |
106 | |
107 (defvar sgml-mode-markup-syntax-table nil | |
108 "Syntax table used for scanning SGML markup.") | |
109 | |
110 (if sgml-mode-markup-syntax-table | |
111 () | |
112 (setq sgml-mode-markup-syntax-table (make-syntax-table)) | |
113 (modify-syntax-entry ?< "(>" sgml-mode-markup-syntax-table) | |
114 (modify-syntax-entry ?> ")<" sgml-mode-markup-syntax-table) | |
115 (modify-syntax-entry ?- "_ 1234" sgml-mode-markup-syntax-table) | |
116 (modify-syntax-entry ?\' "\"" sgml-mode-markup-syntax-table)) | |
117 | |
118 (defconst sgml-angle-distance 4000 | |
119 "*If non-nil, is the maximum distance to search for matching <.") | |
120 | |
121 (defun sgml-close-angle (arg) | |
122 "Insert > and display matching <." | |
123 (interactive "p") | |
124 (insert-char ?> arg) | |
125 (if (> arg 0) | |
126 (let ((oldpos (point)) | |
127 (blinkpos)) | |
128 (save-excursion | |
129 (save-restriction | |
130 (if sgml-angle-distance | |
131 (narrow-to-region (max (point-min) | |
132 (- (point) sgml-angle-distance)) | |
133 oldpos)) | |
134 ;; See if it's the end of a marked section. | |
135 (and (> (- (point) (point-min)) 3) | |
136 (eq (char-after (- (point) 2)) ?\]) | |
137 (eq (char-after (- (point) 3)) ?\]) | |
138 (re-search-backward "<!\\[\\(-?[A-Za-z0-9. \t\n&;]\\|\ | |
139 --\\([^-]\\|-[^-]\\)*--\\)*\\[" | |
140 (point-min) | |
141 t) | |
142 (let ((msspos (point))) | |
143 (if (and (search-forward "]]>" oldpos t) | |
144 (eq (point) oldpos)) | |
145 (setq blinkpos msspos)))) | |
146 ;; This handles cases where the > ends one of the following: | |
147 ;; markup declaration starting with <! (possibly including a | |
148 ;; declaration subset); start tag; end tag; SGML declaration. | |
149 (if blinkpos | |
150 () | |
151 (goto-char oldpos) | |
152 (condition-case () | |
153 (let ((oldtable (syntax-table)) | |
154 (parse-sexp-ignore-comments t)) | |
155 (unwind-protect | |
156 (progn | |
157 (set-syntax-table sgml-mode-markup-syntax-table) | |
158 (setq blinkpos (scan-sexps oldpos -1))) | |
159 (set-syntax-table oldtable))) | |
160 (error nil)) | |
161 (and blinkpos | |
162 (goto-char blinkpos) | |
163 (or | |
164 ;; Check that it's a valid delimiter in context. | |
165 (not (looking-at | |
166 "<\\(\\?\\|/?[A-Za-z>]\\|!\\([[A-Za-z]\\|--\\)\\)")) | |
167 ;; Check that it's not a net-enabling start tag | |
168 ;; nor an unclosed start-tag. | |
169 (looking-at (concat sgml-start-tag-regex "[/<]")) | |
170 ;; Nor an unclosed end-tag. | |
171 (looking-at "</[A-Za-z][-.A-Za-z0-9]*[ \t]*<")) | |
172 (setq blinkpos nil))) | |
173 (if blinkpos | |
174 () | |
175 ;; See if it's the end of a processing instruction. | |
176 (goto-char oldpos) | |
177 (if (search-backward "<?" (point-min) t) | |
178 (let ((pipos (point))) | |
179 (if (and (search-forward ">" oldpos t) | |
180 (eq (point) oldpos)) | |
181 (setq blinkpos pipos)))))) | |
182 (if blinkpos | |
183 (progn | |
184 (goto-char blinkpos) | |
185 (if (pos-visible-in-window-p) | |
186 (sit-for 1) | |
187 (message "Matches %s" | |
188 (buffer-substring blinkpos | |
189 (progn (end-of-line) | |
190 (point))))))))))) | |
191 | |
192 ;;; I doubt that null end tags are used much for large elements, | |
193 ;;; so use a small distance here. | |
194 (defconst sgml-slash-distance 1000 | |
195 "*If non-nil, is the maximum distance to search for matching /.") | |
196 | 359 |
197 (defun sgml-slash (arg) | 360 (defun sgml-slash (arg) |
198 "Insert / and display any previous matching /. | 361 "Insert / and display any previous matching /. |
199 Two /s are treated as matching if the first / ends a net-enabling | 362 Two /s are treated as matching if the first / ends a net-enabling |
200 start tag, and the second / is the corresponding null end tag." | 363 start tag, and the second / is the corresponding null end tag." |
235 (buffer-substring (progn | 398 (buffer-substring (progn |
236 (beginning-of-line) | 399 (beginning-of-line) |
237 (point)) | 400 (point)) |
238 (1+ blinkpos)))))))))) | 401 (1+ blinkpos)))))))))) |
239 | 402 |
403 | |
404 (defun sgml-name-char (&optional char) | |
405 "Insert a symbolic character name according to `sgml-char-names'. | |
406 8 bit chars may be inserted with the meta key as in M-SPC for no break space, | |
407 or M-- for a soft hyphen." | |
408 (interactive "*") | |
409 (insert ?&) | |
410 (or char | |
411 (setq char (read-quoted-char))) | |
412 (delete-backward-char 1) | |
413 (insert char) | |
414 (undo-boundary) | |
415 (delete-backward-char 1) | |
416 (insert ?& | |
417 (or (aref sgml-char-names char) | |
418 (format "#%d" char)) | |
419 ?\;)) | |
420 | |
421 | |
422 (defun sgml-name-self () | |
423 "Insert a symbolic character name according to `sgml-char-names'." | |
424 (interactive "*") | |
425 (sgml-name-char last-command-char)) | |
426 | |
427 | |
428 (defun sgml-maybe-name-self () | |
429 "Insert a symbolic character name according to `sgml-char-names'." | |
430 (interactive "*") | |
431 (if sgml-name-8bit-mode | |
432 (sgml-name-char last-command-char) | |
433 (self-insert-command 1))) | |
434 | |
435 | |
436 (defun sgml-name-8bit-mode () | |
437 "Toggle insertion of 8 bit characters." | |
438 (interactive) | |
439 (setq sgml-name-8bit-mode (not sgml-name-8bit-mode))) | |
440 | |
441 | |
442 | |
443 (define-skeleton sgml-tag | |
444 "Insert a tag you are prompted for, optionally with attributes. | |
445 Completion and configuration is according to `sgml-tag-alist'. | |
446 If you like tags and attributes in uppercase set `skeleton-transformation' | |
447 to `upcase'." | |
448 (funcall skeleton-transformation | |
449 (completing-read "Tag: " sgml-tag-alist)) | |
450 ?< (setq v1 (eval str)) | | |
451 (("") -1 '(undo-boundary) "<") | | |
452 (("") '(setq v2 (sgml-attributes v1 t)) ?> | |
453 (if (or (eq v2 t) | |
454 (string-match "^[/!?]" v1)) | |
455 () | |
456 (if (symbolp v2) | |
457 '(("") v2 _ v2 "</" v1 ?>) | |
458 (if (eq (car v2) t) | |
459 (cons '("") (cdr v2)) | |
460 (append '(("") (car v2)) | |
461 (cdr v2) | |
462 '(resume: (car v2) _ "</" v1 ?>))))))) | |
463 | |
464 (autoload 'skeleton-read "skeleton") | |
465 | |
466 (defun sgml-attributes (alist &optional quiet) | |
467 "When at toplevel of a tag, interactively insert attributes." | |
468 (interactive (list (save-excursion (sgml-beginning-of-tag t)))) | |
469 (or (stringp alist) (error "Wrong context for adding attribute")) | |
470 (if alist | |
471 (let ((completion-ignore-case t) | |
472 car attribute i) | |
473 (setq alist (cdr (assoc (downcase alist) sgml-tag-alist))) | |
474 (if (or (symbolp (car alist)) | |
475 (symbolp (car (car alist)))) | |
476 (setq car (car alist) | |
477 alist (cdr alist))) | |
478 (or quiet | |
479 (message "No attributes configured.")) | |
480 (if (stringp (car alist)) | |
481 (progn | |
482 (insert (if (eq (preceding-char) ? ) "" ? ) (car alist)) | |
483 (sgml-value alist)) | |
484 (setq i (length alist)) | |
485 (while (> i 0) | |
486 (insert ? ) | |
487 (insert (funcall skeleton-transformation | |
488 (setq attribute | |
489 (skeleton-read '(completing-read | |
490 "[Attribute]: " | |
491 alist))))) | |
492 (if (string= "" attribute) | |
493 (setq i 0) | |
494 (sgml-value (assoc attribute alist)) | |
495 (setq i (1- i)))) | |
496 (if (eq (preceding-char) ? ) | |
497 (delete-backward-char 1))) | |
498 car))) | |
499 | |
500 (defun sgml-auto-attributes (arg) | |
501 "Self insert, except, when at top level of tag, prompt for attributes. | |
502 With prefix ARG, or if `sgml-auto-attributes' is `nil' only self insert." | |
503 (interactive "*P") | |
504 (let ((point (point)) | |
505 tag) | |
506 (if (or arg | |
507 (not sgml-auto-attributes) | |
508 (not sgml-tag-alist) ; no message when nothing configured | |
509 (symbolp (setq tag (save-excursion (sgml-beginning-of-tag t)))) | |
510 (eq (aref tag 0) ?/)) | |
511 (self-insert-command (prefix-numeric-value arg)) | |
512 (sgml-attributes tag) | |
513 (setq last-command-char ? ) | |
514 (or (> (point) point) | |
515 (self-insert-command 1))))) | |
516 | |
517 | |
518 (defun sgml-tag-help (&optional tag) | |
519 "Display description of optional TAG or tag at point." | |
520 (interactive) | |
521 (or tag | |
522 (save-excursion | |
523 (if (eq (following-char) ?<) | |
524 (forward-char)) | |
525 (setq tag (sgml-beginning-of-tag)))) | |
526 (or (stringp tag) | |
527 (error "No tag selected")) | |
528 (setq tag (downcase tag)) | |
529 (message (or (cdr (assoc tag sgml-tag-help)) | |
530 (and (eq (aref tag 0) ?/) | |
531 (cdr (assoc (substring tag 1) sgml-tag-help))) | |
532 "No description available"))) | |
533 | |
534 | |
535 (defun sgml-maybe-end-tag () | |
536 "Name self unless in position to end a tag." | |
537 (interactive) | |
538 (or (condition-case nil | |
539 (save-excursion (up-list -1)) | |
540 (error | |
541 (sgml-name-self) | |
542 t)) | |
543 (condition-case nil | |
544 (progn | |
545 (save-excursion (up-list 1)) | |
546 (sgml-name-self)) | |
547 (error (self-insert-command 1))))) | |
548 | |
549 | |
550 (defun sgml-skip-tag-backward (arg) | |
551 "Skip to beginning of tag or matching opening tag if present. | |
552 With prefix ARG, repeat that many times." | |
553 (interactive "p") | |
554 (while (>= arg 1) | |
555 (search-backward "<" nil t) | |
556 (if (looking-at "</\\([^ \n\t>]+\\)") | |
557 ;; end tag, skip any nested pairs | |
558 (let ((case-fold-search t) | |
559 (re (concat "</?" (regexp-quote (match-string 1))))) | |
560 (while (and (re-search-backward re nil t) | |
561 (eq (char-after (1+ (point))) ?/)) | |
562 (forward-char 1) | |
563 (sgml-skip-tag-backward 1)))) | |
564 (setq arg (1- arg)))) | |
565 | |
566 (defun sgml-skip-tag-forward (arg &optional return) | |
567 "Skip to end of tag or matching closing tag if present. | |
568 With prefix ARG, repeat that many times. | |
569 Return t iff after a closing tag." | |
570 (interactive "p") | |
571 (setq return t) | |
572 (while (>= arg 1) | |
573 (skip-chars-forward "^<>") | |
574 (if (eq (following-char) ?>) | |
575 (up-list -1)) | |
576 (if (looking-at "<\\([^/ \n\t>]+\\)") | |
577 ;; start tag, skip any nested same pairs _and_ closing tag | |
578 (let ((case-fold-search t) | |
579 (re (concat "</?" (regexp-quote (match-string 1)))) | |
580 point close) | |
581 (forward-list 1) | |
582 (setq point (point)) | |
583 (while (and (re-search-forward re nil t) | |
584 (not (setq close | |
585 (eq (char-after (1+ (match-beginning 0))) ?/))) | |
586 (not (up-list -1)) | |
587 (sgml-skip-tag-forward 1)) | |
588 (setq close nil)) | |
589 (if close | |
590 (up-list 1) | |
591 (goto-char point) | |
592 (setq return))) | |
593 (forward-list 1)) | |
594 (setq arg (1- arg))) | |
595 return) | |
596 | |
597 (defun sgml-delete-tag (arg) | |
598 "Delete tag on or after cursor, and matching closing or opening tag. | |
599 With prefix ARG, repeat that many times." | |
600 (interactive "p") | |
601 (while (>= arg 1) | |
602 (save-excursion | |
603 (let* (close open) | |
604 (if (looking-at "[ \t]*<") | |
605 ;; just before tag | |
606 (if (eq (char-after (match-end 0)) ?/) | |
607 ;; closing tag | |
608 (progn | |
609 (setq close (point)) | |
610 (goto-char (match-end 0)))) | |
611 ;; on tag? | |
612 (or (save-excursion (setq close (sgml-beginning-of-tag) | |
613 close (and (stringp close) | |
614 (eq (aref close 0) ?/) | |
615 (point)))) | |
616 ;; not on closing tag | |
617 (let ((point (point))) | |
618 (sgml-skip-tag-backward 1) | |
619 (if (or (not (eq (following-char) ?<)) | |
620 (save-excursion | |
621 (forward-list 1) | |
622 (<= (point) point))) | |
623 (error "Not on or before tag"))))) | |
624 (if close | |
625 (progn | |
626 (sgml-skip-tag-backward 1) | |
627 (setq open (point)) | |
628 (goto-char close) | |
629 (kill-sexp 1)) | |
630 (setq open (point)) | |
631 (sgml-skip-tag-forward 1) | |
632 (backward-list) | |
633 (forward-char) | |
634 (if (eq (aref (sgml-beginning-of-tag) 0) ?/) | |
635 (kill-sexp 1))) | |
636 (goto-char open) | |
637 (kill-sexp 1))) | |
638 (setq arg (1- arg)))) | |
639 | |
640 | |
641 | |
642 (defun sgml-tags-invisible (arg) | |
643 "Toggle visibility of existing tags." | |
644 (interactive "P") | |
645 (let ((modified (buffer-modified-p)) | |
646 (inhibit-read-only t) | |
647 (point (point-min)) | |
648 symbol) | |
649 (save-excursion | |
650 (goto-char point) | |
651 (if (setq sgml-tags-invisible | |
652 (if arg | |
653 (>= (prefix-numeric-value arg) 0) | |
654 (not sgml-tags-invisible))) | |
655 (while (re-search-forward "<\\([!/?A-Za-z][-A-Za-z0-9]*\\)" | |
656 nil t) | |
657 (setq symbol (intern-soft (downcase (match-string 1)))) | |
658 (goto-char (match-beginning 0)) | |
659 (and (get symbol 'before-string) | |
660 (not (overlays-at (point))) | |
661 (overlay-put (make-overlay (point) | |
662 (match-beginning 1)) | |
663 'category symbol)) | |
664 (put-text-property (setq point (point)) (forward-list) | |
665 'intangible (point)) | |
666 (put-text-property point (point) | |
667 'category 'sgml-tag)) | |
668 (while (< (setq point (next-overlay-change point)) (point-max)) | |
669 (delete-overlay (car (overlays-at point)))) | |
670 (remove-text-properties (point-min) (point-max) | |
671 '(category sgml-tag intangible t)))) | |
672 (set-buffer-modified-p modified) | |
673 (run-hooks 'sgml-tags-invisible-hook) | |
674 (message ""))) | |
675 | |
676 (defun sgml-point-entered (x y) | |
677 ;; Show preceding or following hidden tag, depending of cursor direction. | |
678 (let ((inhibit-point-motion-hooks t)) | |
679 (save-excursion | |
680 (message "Invisible tag: %s" | |
681 (buffer-substring | |
682 (point) | |
683 (if (or (and (> x y) | |
684 (not (eq (following-char) ?<))) | |
685 (and (< x y) | |
686 (eq (preceding-char) ?>))) | |
687 (backward-list) | |
688 (forward-list))))))) | |
689 | |
690 | |
691 (autoload 'compile-internal "compile") | |
692 | |
240 (defun sgml-validate (command) | 693 (defun sgml-validate (command) |
241 "Validate an SGML document. | 694 "Validate an SGML document. |
242 Runs COMMAND, a shell command, in a separate process asynchronously | 695 Runs COMMAND, a shell command, in a separate process asynchronously |
243 with output going to the buffer *compilation*. | 696 with output going to the buffer *compilation*. |
244 You can then use the command \\[next-error] to find the next error message | 697 You can then use the command \\[next-error] to find the next error message |
252 (and name | 705 (and name |
253 (file-name-nondirectory name)))))))) | 706 (file-name-nondirectory name)))))))) |
254 (setq sgml-saved-validate-command command) | 707 (setq sgml-saved-validate-command command) |
255 (compile-internal command "No more errors")) | 708 (compile-internal command "No more errors")) |
256 | 709 |
710 | |
711 (defun sgml-beginning-of-tag (&optional top-level) | |
712 "Skip to beginning of tag and return its name. | |
713 Else `t'." | |
714 (or (if top-level | |
715 (condition-case nil | |
716 (up-list -1) | |
717 (error t)) | |
718 (>= (point) | |
719 (if (search-backward "<" nil t) | |
720 (save-excursion | |
721 (forward-list) | |
722 (point)) | |
723 0))) | |
724 (if (looking-at "<[!?/]?[[A-Za-z][A-Za-z0-9]*") | |
725 (buffer-substring-no-properties | |
726 (1+ (point)) | |
727 (match-end 0)) | |
728 t))) | |
729 | |
730 (defun sgml-value (alist) | |
731 (setq alist (cdr alist)) | |
732 (if (stringp (car alist)) | |
733 (insert "=\"" (car alist) ?\") | |
734 (if (eq (car alist) t) | |
735 (if (cdr alist) | |
736 (progn | |
737 (insert "=\"") | |
738 (setq alist (skeleton-read '(completing-read | |
739 "[Value]: " (cdr alist)))) | |
740 (if (string< "" alist) | |
741 (insert (funcall skeleton-transformation alist) ?\") | |
742 (delete-backward-char 2)))) | |
743 (insert "=\"") | |
744 (if alist | |
745 (insert (funcall skeleton-transformation | |
746 (skeleton-read '(completing-read "Value: " alist))))) | |
747 (insert ?\")))) | |
748 | |
749 (provide 'sgml-mode) | |
750 | |
751 ;;;###autoload | |
752 (or (rassq 'html-mode auto-mode-alist) | |
753 (setq auto-mode-alist `(("\\.s?html?\\'" . html-mode) | |
754 ,@auto-mode-alist))) | |
755 | |
756 (defvar html-quick-keys t | |
757 "Use C-c <x> combinations for quick insertion of frequent tags when non-nil. | |
758 This takes effect when first loading the library.") | |
759 | |
760 (defvar html-mode-map | |
761 (let ((map (nconc (make-sparse-keymap) sgml-mode-map)) | |
762 (menu-map (make-sparse-keymap "HTML"))) | |
763 (if html-quick-keys | |
764 (progn | |
765 (define-key map "\C-c1" 'html-headline) | |
766 (define-key map "\C-c2" 'html-headline) | |
767 (define-key map "\C-c3" 'html-headline) | |
768 (define-key map "\C-c4" 'html-headline) | |
769 (define-key map "\C-c5" 'html-headline) | |
770 (define-key map "\C-c6" 'html-headline) | |
771 (define-key map "\C-c-" 'html-horizontal-rule) | |
772 (define-key map "\C-c\r" 'html-paragraph) | |
773 (define-key map "\C-c\n" 'html-line) | |
774 (define-key map "\C-co" 'html-list) | |
775 (define-key map "\C-cu" 'html-list) | |
776 (define-key map "\C-cr" 'html-radio-buttons) | |
777 (define-key map "\C-cl" 'html-list-item) | |
778 (define-key map "\C-ch" 'html-href-anchor) | |
779 (define-key map "\C-cn" 'html-name-anchor) | |
780 (define-key map "\C-ci" 'html-image))) | |
781 (define-key map "\C-c\C-s" 'html-autoview-mode) | |
782 (define-key map "\C-c\C-v" 'browse-url-of-buffer) | |
783 (define-key map [menu-bar html] (cons "HTML" menu-map)) | |
784 (define-key menu-map [html-autoview-mode] | |
785 '("Toggle Autoviewing" . html-autoview-mode)) | |
786 (define-key menu-map [browse-url-of-buffer] | |
787 '("View Buffer Contents" . browse-url-of-buffer)) | |
788 (define-key menu-map [nil] '("--")) | |
789 ;;(define-key menu-map "6" '("Heading 6" . html-headline)) | |
790 ;;(define-key menu-map "5" '("Heading 5" . html-headline)) | |
791 ;;(define-key menu-map "4" '("Heading 4" . html-headline)) | |
792 (define-key menu-map "3" '("Heading 3" . html-headline)) | |
793 (define-key menu-map "2" '("Heading 2" . html-headline)) | |
794 (define-key menu-map "1" '("Heading 1" . html-headline)) | |
795 (define-key menu-map "l" '("Radio Buttons" . html-radio-buttons)) | |
796 (define-key menu-map "l" '("List Item" . html-list-item)) | |
797 (define-key menu-map "u" '("Unordered List" . html-list)) | |
798 (define-key menu-map "o" '("Ordered List" . html-list)) | |
799 (define-key menu-map "-" '("Horizontal rule" . html-horizontal-rule)) | |
800 (define-key menu-map "\n" '("Line Break" . html-line)) | |
801 (define-key menu-map "\r" '("Paragraph" . html-paragraph)) | |
802 (define-key menu-map "i" '("Image" . html-image)) | |
803 (define-key menu-map "h" '("Href Anchor" . html-href-anchor)) | |
804 (define-key menu-map "n" '("Name Anchor" . html-name-anchor)) | |
805 map) | |
806 "Keymap for commands for use in HTML mode.") | |
807 | |
808 | |
809 (defvar html-face-tag-alist | |
810 '((bold . "b") | |
811 (italic . "i") | |
812 (underline . "u") | |
813 (modeline . "rev")) | |
814 "Value of `sgml-face-tag-alist' for HTML mode.") | |
815 | |
816 (defvar html-tag-face-alist | |
817 '(("b" . bold) | |
818 ("big" . bold) | |
819 ("blink" . highlight) | |
820 ("cite" . italic) | |
821 ("em" . italic) | |
822 ("h1" bold underline) | |
823 ("h2" bold-italic underline) | |
824 ("h3" italic underline) | |
825 ("h4" . underline) | |
826 ("h5" . underline) | |
827 ("h6" . underline) | |
828 ("i" . italic) | |
829 ("rev" . modeline) | |
830 ("s" . underline) | |
831 ("small" . default) | |
832 ("strong" . bold) | |
833 ("title" bold underline) | |
834 ("tt" . default) | |
835 ("u" . underline) | |
836 ("var" . italic)) | |
837 "Value of `sgml-tag-face-alist' for HTML mode.") | |
838 | |
839 | |
840 (defvar html-display-text | |
841 '((img . "[/]") | |
842 (hr . "----------") | |
843 (li . "o ")) | |
844 "Value of `sgml-display-text' for HTML mode.") | |
845 | |
846 | |
847 ; should code exactly HTML 3 here when that is finished | |
848 (defvar html-tag-alist | |
849 (let* ((1-9 '(("8") ("9") | |
850 ("1") ("2") ("3") ("4") ("5") ("6") ("7"))) | |
851 (align '(("align" ("left") ("center") ("right")))) | |
852 (valign '(("top") ("middle") ("bottom") ("baseline"))) | |
853 (rel '(("next") ("previous") ("parent") ("subdocument") ("made"))) | |
854 (href '("href" ("ftp:") ("file:") ("finger:") ("gopher:") ("http:") | |
855 ("mailto:") ("news:") ("rlogin:") ("telnet:") ("tn3270:") | |
856 ("wais:"))) | |
857 (name '("name")) | |
858 (link `(,href | |
859 ("rel" ,@rel) | |
860 ("rev" ,@rel) | |
861 ("title"))) | |
862 (list '((nil \n | |
863 ( "List item: " | |
864 "<li>" str \n)) | |
865 ("type" ("A") ("a") ("I") ("i") ("1")))) | |
866 (cell `(t | |
867 ,align | |
868 ("valign" ,@valign) | |
869 ("colspan" ,@1-9) | |
870 ("rowspan" ,@1-9) | |
871 ("nowrap" t)))) | |
872 ;; put ,-expressions first, else byte-compile chokes (as of V19.29) | |
873 ;; and like this it's more efficient anyway | |
874 `(("a" ,name ,@link) | |
875 ("base" t ,@href) | |
876 ("dir" ,@list) | |
877 ("font" "size" ("-1") ("+1") ("-2") ("+2") ,@(cdr (cdr 1-9))) | |
878 ("form" \n ("action" ,@(cdr href)) ("method" ("get") ("post"))) | |
879 ("h1" ,@align) | |
880 ("h2" ,@align) | |
881 ("h3" ,@align) | |
882 ("h4" ,@align) | |
883 ("h5" ,@align) | |
884 ("h6" ,@align) | |
885 ("hr" t ("size" ,@1-9) ("width") ("noshade" t) ,@align) | |
886 ("img" t ("align" ,@valign ("texttop") ("absmiddle") ("absbottom")) | |
887 ("src") ("alt") ("width" "1") ("height" "1") | |
888 ("border" "1") ("vspace" "1") ("hspace" "1") ("ismap" t)) | |
889 ("input" t ("size" ,@1-9) ("maxlength" ,@1-9) ("checked" t) ,name | |
890 ("type" ("text") ("password") ("checkbox") ("radio") ("sbmit") ("reset")) | |
891 ("value")) | |
892 ("link" t ,@link) | |
893 ("menu" ,@list) | |
894 ("ol" ,@list) | |
895 ("p" t ,@align) | |
896 ("select" (nil \n | |
897 ("Text: " | |
898 "<option>" str \n)) | |
899 ,name ("size" ,@1-9) ("multiple" t)) | |
900 ("table" (nil \n | |
901 ((completing-read "Cell kind: " '(("td") ("th")) | |
902 nil t "t") | |
903 "<tr><" str ?> _ \n)) | |
904 ("border" t ,@1-9) ("width" "10") ("cellpadding")) | |
905 ("td" ,@cell) | |
906 ("textarea" ,name ("rows" ,@1-9) ("cols" ,@1-9)) | |
907 ("th" ,@cell) | |
908 ("ul" ,@list) | |
909 | |
910 ,@sgml-tag-alist | |
911 | |
912 ("abbrev") | |
913 ("acronym") | |
914 ("address") | |
915 ("array" (nil \n | |
916 ("Item: " "<item>" str \n)) | |
917 "align") | |
918 ("au") | |
919 ("b") | |
920 ("big") | |
921 ("blink") | |
922 ("blockquote" \n) | |
923 ("body" \n ("background" ".gif") ("bgcolor" "#") ("text" "#") | |
924 ("link" "#") ("alink" "#") ("vlink" "#")) | |
925 ("box" (nil _ "<over>" _)) | |
926 ("br" t ("clear" ("left") ("right"))) | |
927 ("caption" ("valign" ("top") ("bottom"))) | |
928 ("center" \n) | |
929 ("cite") | |
930 ("code" \n) | |
931 ("dd" t) | |
932 ("del") | |
933 ("dfn") | |
934 ("dl" (nil \n | |
935 ( "Term: " | |
936 "<dt>" str "<dd>" _ \n))) | |
937 ("dt" (t _ "<dd>")) | |
938 ("em") | |
939 ("fn" "id" "fn") | |
940 ("head" \n) | |
941 ("html" (\n | |
942 "<head>\n" | |
943 "<title>" (setq str (read-input "Title: ")) "</title>\n" | |
944 "<body>\n<h1>" str "</h1>\n" _ | |
945 "\n<address>\n<a href=\"mailto:" | |
946 (user-login-name) ?@ (system-name) | |
947 "\">" (user-full-name) "</a>\n</address>")) | |
948 ("i") | |
949 ("ins") | |
950 ("isindex" t ("action") ("prompt")) | |
951 ("kbd") | |
952 ("lang") | |
953 ("li" t) | |
954 ("math" \n) | |
955 ("nobr") | |
956 ("option" t ("value") ("label") ("selected" t)) | |
957 ("over" t) | |
958 ("person") | |
959 ("pre" \n) | |
960 ("q") | |
961 ("rev") | |
962 ("s") | |
963 ("samp") | |
964 ("small") | |
965 ("strong") | |
966 ("sub") | |
967 ("sup") | |
968 ("title") | |
969 ("tr" t) | |
970 ("tt") | |
971 ("u") | |
972 ("var") | |
973 ("wbr" t))) | |
974 "*Value of `sgml-tag-alist' for HTML mode.") | |
975 | |
976 (defvar html-tag-help | |
977 `(,@sgml-tag-help | |
978 ("a" . "Anchor of point or link elsewhere") | |
979 ("abbrev" . "?") | |
980 ("acronym" . "?") | |
981 ("address" . "Formatted mail address") | |
982 ("array" . "Math array") | |
983 ("au" . "?") | |
984 ("b" . "Bold face") | |
985 ("base" . "Base address for URLs") | |
986 ("big" . "Font size") | |
987 ("blink" . "Blinking text") | |
988 ("blockquote" . "Indented quotation") | |
989 ("body" . "Document body") | |
990 ("box" . "Math fraction") | |
991 ("br" . "Line break") | |
992 ("caption" . "Table caption") | |
993 ("center" . "Centered text") | |
994 ("changed" . "Change bars") | |
995 ("cite" . "Citation of a document") | |
996 ("code" . "Formatted source code") | |
997 ("dd" . "Definition of term") | |
998 ("del" . "?") | |
999 ("dfn" . "?") | |
1000 ("dir" . "Directory list (obsolete)") | |
1001 ("dl" . "Definition list") | |
1002 ("dt" . "Term to be definined") | |
1003 ("em" . "Emphasised") | |
1004 ("embed" . "Embedded data in foreign format") | |
1005 ("fig" . "Figure") | |
1006 ("figa" . "Figure anchor") | |
1007 ("figd" . "Figure description") | |
1008 ("figt" . "Figure text") | |
1009 ("fn" . "?") | |
1010 ("font" . "Font size") | |
1011 ("form" . "Form with input fields") | |
1012 ("group" . "Document grouping") | |
1013 ("h1" . "Most important section headline") | |
1014 ("h2" . "Important section headline") | |
1015 ("h3" . "Section headline") | |
1016 ("h4" . "Minor section headline") | |
1017 ("h5" . "Unimportant section headline") | |
1018 ("h6" . "Least important section headline") | |
1019 ("head" . "Document header") | |
1020 ("hr" . "Horizontal rule") | |
1021 ("html" . "HTML Document") | |
1022 ("i" . "Italic face") | |
1023 ("img" . "Graphic image") | |
1024 ("input" . "Form input field") | |
1025 ("ins" . "?") | |
1026 ("isindex" . "Input field for index search") | |
1027 ("kbd" . "Keybard example face") | |
1028 ("lang" . "Natural language") | |
1029 ("li" . "List item") | |
1030 ("link" . "Link relationship") | |
1031 ("math" . "Math formula") | |
1032 ("menu" . "Menu list (obsolete)") | |
1033 ("mh" . "Form mail header") | |
1034 ("nextid" . "Allocate new id") | |
1035 ("nobr" . "Text without line break") | |
1036 ("ol" . "Ordered list") | |
1037 ("option" . "Selection list item") | |
1038 ("over" . "Math fraction rule") | |
1039 ("p" . "Paragraph start") | |
1040 ("panel" . "Floating panel") | |
1041 ("person" . "?") | |
1042 ("pre" . "Preformatted fixed width text") | |
1043 ("q" . "?") | |
1044 ("rev" . "Reverse video") | |
1045 ("s" . "?") | |
1046 ("samp" . "Sample text") | |
1047 ("select" . "Selection list") | |
1048 ("small" . "Font size") | |
1049 ("sp" . "Nobreak space") | |
1050 ("strong" . "Standout text") | |
1051 ("sub" . "Subscript") | |
1052 ("sup" . "Superscript") | |
1053 ("table" . "Table with rows and columns") | |
1054 ("tb" . "Table vertical break") | |
1055 ("td" . "Table data cell") | |
1056 ("textarea" . "Form multiline edit area") | |
1057 ("th" . "Table header cell") | |
1058 ("title" . "Document title") | |
1059 ("tr" . "Table row separator") | |
1060 ("tt" . "Typewriter face") | |
1061 ("u" . "Underlined text") | |
1062 ("ul" . "Unordered list") | |
1063 ("var" . "Math variable face") | |
1064 ("wbr" . "Enable <br> within <nobr>")) | |
1065 "*Value of `sgml-tag-help' for HTML mode.") | |
1066 | |
1067 | |
1068 | |
1069 ;;;###autoload | |
1070 (defun html-mode () | |
1071 "Major mode based on SGML mode for editing HTML documents. | |
1072 This allows inserting skeleton costructs used in hypertext documents via | |
1073 the command `<' with completion. See below for an introduction to HTML. | |
1074 Use \\[browse-url-of-buffer] to see how this comes out. | |
1075 See also `sgml-mode' on which this is based. | |
1076 | |
1077 Do \\[describe-variable] html- SPC to see available variables. | |
1078 | |
1079 To write fairly well formatted pages you only need to know few things. Most | |
1080 browsers have a function to read the source code of the page being seen, so | |
1081 you can imitate various tricks. Here's a very short HTML primer which you | |
1082 can also view with a browser to see what happens: | |
1083 | |
1084 <title>A Title Describing Contents</title> should be on every page. Pages can | |
1085 have <h1>Very Major Headlines</h1> through <h6>Very Minor Headlines</h6> | |
1086 <hr> Parts can be separated with horizontal rules. | |
1087 | |
1088 <p>Paragraphs only need an opening tag. Line breaks and multiple spaces are | |
1089 ignored unless the text is <pre>preformatted.</pre> Text can be marked as | |
1090 <b>bold</b>, <i>italic</i> or <u>underlined</u> using the normal M-g or | |
1091 Edit/Text Properties/Face commands. | |
1092 | |
1093 Pages can have <a name=\"SOMENAME\">named points</a> and can link other points | |
1094 to them with <a href=\"#SOMENAME\">see also somename</a>. In the same way <a | |
1095 href=\"URL\">see also URL</a> where URL is a filename relative to current | |
1096 directory or something like http://www.cs.indiana.edu/elisp/w3/docs.html. | |
1097 | |
1098 Images in many formats can be inlined with <img src=\"URL\">. | |
1099 | |
1100 If you mainly create your own documents, `sgml-specials' might be interesting. | |
1101 But note that some HTML 2 browsers can't handle '. To work around that | |
1102 do: | |
1103 | |
1104 \(eval-after-load \"sgml-mode\" '(aset sgml-char-names ?' nil)) | |
1105 \\{html-mode-map}" | |
1106 (interactive) | |
1107 (sgml-mode-common html-tag-face-alist html-display-text) | |
1108 (use-local-map html-mode-map) | |
1109 (make-local-variable 'sgml-tag-alist) | |
1110 (make-local-variable 'sgml-face-tag-alist) | |
1111 (make-local-variable 'sgml-tag-help) | |
1112 (make-local-variable 'outline-regexp) | |
1113 (make-local-variable 'outline-heading-end-regexp) | |
1114 (make-local-variable 'outline-level) | |
1115 (setq mode-name "HTML" | |
1116 major-mode 'html-mode | |
1117 sgml-tag-alist html-tag-alist | |
1118 sgml-face-tag-alist html-face-tag-alist | |
1119 sgml-tag-help html-tag-help | |
1120 outline-regexp "^.*<[Hh][1-6]\\>" | |
1121 outline-heading-end-regexp "</[Hh][1-6]>" | |
1122 outline-level (lambda () | |
1123 (char-after (1- (match-end 0))))) | |
1124 (run-hooks 'html-mode-hook)) | |
1125 | |
1126 | |
1127 (define-skeleton html-href-anchor | |
1128 "HTML anchor tag with href attribute." | |
1129 nil | |
1130 "<a href=\"http:" _ "\"></a>") | |
1131 | |
1132 (define-skeleton html-name-anchor | |
1133 "HTML anchor tag with name attribute." | |
1134 nil | |
1135 "<a name=\"" _ "\"></a>") | |
1136 | |
1137 (define-skeleton html-headline | |
1138 "HTML headline tags." | |
1139 last-command-char | |
1140 "<h" str ?> _ "</h" str ?>) | |
1141 | |
1142 (define-skeleton html-horizontal-rule | |
1143 "HTML horizontal rule tag." | |
1144 nil | |
1145 "<hr>" \n) | |
1146 | |
1147 (define-skeleton html-image | |
1148 "HTML image tag." | |
1149 nil | |
1150 "<img src=\"http:" _ "\">") | |
1151 | |
1152 (define-skeleton html-line | |
1153 "HTML line break tag." | |
1154 nil | |
1155 "<br>" \n) | |
1156 | |
1157 (define-skeleton html-list | |
1158 "HTML unordered/ordered list tags." | |
1159 last-command-char | |
1160 ?< str "l>" \n | |
1161 "<li>" _ \n | |
1162 "</" str "l>") | |
1163 | |
1164 (define-skeleton html-list-item | |
1165 "HTML list item tag." | |
1166 nil | |
1167 (if (bolp) nil '\n) | |
1168 "<li>") | |
1169 | |
1170 (define-skeleton html-paragraph | |
1171 "HTML paragraph tag." | |
1172 nil | |
1173 (if (bolp) nil ?\n) | |
1174 \n "<p>") | |
1175 | |
1176 (define-skeleton html-radio-buttons | |
1177 "Group of connected radio button inputs." | |
1178 nil | |
1179 '(setq v1 (eval str)) ; allow passing name as argument | |
1180 ("Value & Text: " | |
1181 "<input type=\"radio\" name=\"" | |
1182 (or v1 (setq v1 (skeleton-read "Name: "))) | |
1183 "\" value=\"" str ?\" | |
1184 (if v2 "" " checked") ?> str | |
1185 (or v2 (setq v2 (if (y-or-n-p "Newline? ") "<br>" ""))) \n)) | |
1186 | |
1187 | |
1188 (defun html-autoview-mode (&optional arg) | |
1189 "Toggle automatic viewing via `html-viewer' upon saving buffer. | |
1190 With positive prefix ARG always turns viewing on, with negative ARG always off. | |
1191 Can be used as a value for `html-mode-hook'." | |
1192 (interactive "P") | |
1193 (if (setq arg (if arg | |
1194 (< (prefix-numeric-value arg) 0) | |
1195 (and (boundp 'after-save-hook) | |
1196 (memq 'browse-url-of-buffer after-save-hook)))) | |
1197 (setq after-save-hook (delq 'browse-url-of-buffer after-save-hook)) | |
1198 (make-local-hook 'after-save-hook) | |
1199 (add-hook 'after-save-hook 'browse-url-of-buffer nil t)) | |
1200 (message "Autoviewing turned %s." | |
1201 (if arg "off" "on"))) | |
1202 | |
257 ;;; sgml-mode.el ends here | 1203 ;;; sgml-mode.el ends here |