Mercurial > emacs
comparison lisp/textmodes/sgml-mode.el @ 40320:66ba1d523634
(sgml-font-lock-keywords-1): Ignore comments.
(sgml-font-lock-keywords-2): Use `eval'. Moved from sgml-mode-common.
(sgml-font-lock-syntactic-keywords): New var.
(sgml-mode-common): Drop the two args.
Don't make buffer-local variables that aren't used.
Don't set sgml-font-lock-keywords-2 now that it uses `eval instead.
Don't set `before-string' props from sgml-display-text.
(sgml-mode): Use define-derived-mode.
(sgml-tags-invisible): Use sgml-display-text.
(sgml-quote): New command.
(html-tag-alist): Add args for `span'.
(html-mode): Use define-derived-mode.
Set sgml-display-text and sgml-tag-face-alist.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Thu, 25 Oct 2001 22:25:30 +0000 |
parents | 744190a4880c |
children | 25129ef47b45 |
comparison
equal
deleted
inserted
replaced
40319:52af99ad587f | 40320:66ba1d523634 |
---|---|
232 | 232 |
233 ;; internal | 233 ;; internal |
234 (defconst sgml-font-lock-keywords-1 | 234 (defconst sgml-font-lock-keywords-1 |
235 '(("<\\([!?][a-z][-.a-z0-9]*\\)" 1 font-lock-keyword-face) | 235 '(("<\\([!?][a-z][-.a-z0-9]*\\)" 1 font-lock-keyword-face) |
236 ("<\\(/?[a-z][-.a-z0-9]*\\)" 1 font-lock-function-name-face) | 236 ("<\\(/?[a-z][-.a-z0-9]*\\)" 1 font-lock-function-name-face) |
237 ("[&%][a-z][-.a-z0-9]*;?" . font-lock-variable-name-face) | 237 ("[&%][a-z][-.a-z0-9]*;?" . font-lock-variable-name-face))) |
238 ("<! *--.*-- *>" . font-lock-comment-face))) | 238 |
239 | 239 (defconst sgml-font-lock-keywords-2 |
240 (defconst sgml-font-lock-keywords-2 ()) | 240 (append |
241 sgml-font-lock-keywords-1 | |
242 '((eval | |
243 . (cons (concat "<" | |
244 (regexp-opt (mapcar 'car sgml-tag-face-alist) t) | |
245 "\\([ \t][^>]*\\)?>\\([^<]+\\)</\\1>") | |
246 '(3 (cdr (assoc (downcase (match-string 1)) | |
247 sgml-tag-face-alist)))))))) | |
241 | 248 |
242 ;; for font-lock, but must be defvar'ed after | 249 ;; for font-lock, but must be defvar'ed after |
243 ;; sgml-font-lock-keywords-1 and sgml-font-lock-keywords-2 above | 250 ;; sgml-font-lock-keywords-1 and sgml-font-lock-keywords-2 above |
244 (defvar sgml-font-lock-keywords sgml-font-lock-keywords-1 | 251 (defvar sgml-font-lock-keywords sgml-font-lock-keywords-1 |
245 "*Rules for highlighting SGML code. See also `sgml-tag-face-alist'.") | 252 "*Rules for highlighting SGML code. See also `sgml-tag-face-alist'.") |
253 | |
254 (defvar sgml-font-lock-syntactic-keywords | |
255 ;; Use the `b' style of comments to avoid interference with the -- ... -- | |
256 ;; comments recognized when `sgml-specials' includes ?-. | |
257 ;; FIXME: beware of <!--> blabla <!--> !! | |
258 '(("\\(<\\)!--" (1 "< b")) | |
259 ("--[ \t\n]*\\(>\\)" (1 "> b"))) | |
260 "Syntactic keywords for `sgml-mode'.") | |
246 | 261 |
247 ;; internal | 262 ;; internal |
248 (defvar sgml-face-tag-alist () | 263 (defvar sgml-face-tag-alist () |
249 "Alist of face and tag name for facemenu.") | 264 "Alist of face and tag name for facemenu.") |
250 | 265 |
301 (string :tag "Description"))) | 316 (string :tag "Description"))) |
302 :group 'sgml) | 317 :group 'sgml) |
303 | 318 |
304 (defvar v2) ; free for skeleton | 319 (defvar v2) ; free for skeleton |
305 | 320 |
306 (defun sgml-mode-common (sgml-tag-face-alist sgml-display-text) | 321 (defun sgml-mode-common () |
307 "Common code for setting up `sgml-mode' and derived modes. | 322 "Common code for setting up `sgml-mode' and derived modes." |
308 SGML-TAG-FACE-ALIST is used for calculating `sgml-font-lock-keywords-2'. | |
309 SGML-DISPLAY-TEXT sets up alternate text for when tags are invisible (see | |
310 varables of same name)." | |
311 (setq local-abbrev-table text-mode-abbrev-table) | |
312 (set-syntax-table sgml-mode-syntax-table) | |
313 (make-local-variable 'indent-line-function) | 323 (make-local-variable 'indent-line-function) |
314 (make-local-variable 'paragraph-start) | 324 (make-local-variable 'paragraph-start) |
315 (make-local-variable 'paragraph-separate) | 325 (make-local-variable 'paragraph-separate) |
316 (make-local-variable 'adaptive-fill-regexp) | 326 (make-local-variable 'adaptive-fill-regexp) |
317 (make-local-variable 'sgml-saved-validate-command) | 327 (make-local-variable 'sgml-saved-validate-command) |
318 (make-local-variable 'comment-start) | 328 (make-local-variable 'comment-start) |
319 (make-local-variable 'comment-end) | 329 (make-local-variable 'comment-end) |
320 (make-local-variable 'comment-indent-function) | 330 (make-local-variable 'comment-indent-function) |
321 (make-local-variable 'comment-indent-function) | |
322 (make-local-variable 'sgml-tags-invisible) | |
323 (make-local-variable 'skeleton-transformation) | 331 (make-local-variable 'skeleton-transformation) |
324 (make-local-variable 'skeleton-further-elements) | 332 (make-local-variable 'skeleton-further-elements) |
325 (make-local-variable 'skeleton-end-hook) | 333 (make-local-variable 'skeleton-end-hook) |
326 (make-local-variable 'font-lock-defaults) | 334 (make-local-variable 'font-lock-defaults) |
327 (make-local-variable 'sgml-font-lock-keywords-1) | |
328 (make-local-variable 'sgml-font-lock-keywords-2) | |
329 (make-local-variable 'facemenu-add-face-function) | 335 (make-local-variable 'facemenu-add-face-function) |
330 (make-local-variable 'facemenu-end-add-face) | 336 (make-local-variable 'facemenu-end-add-face) |
331 ;;(make-local-variable 'facemenu-remove-face-function) | 337 ;;(make-local-variable 'facemenu-remove-face-function) |
332 (and sgml-tag-face-alist | |
333 (not (assq 1 sgml-tag-face-alist)) | |
334 (nconc sgml-tag-face-alist | |
335 `((1 (,(concat "<\\(" | |
336 (mapconcat 'car sgml-tag-face-alist "\\|") | |
337 "\\)\\([ \t].+\\)?>\\(.+\\)</\\1>") | |
338 3 (cdr (assoc (downcase (match-string 1)) | |
339 ',sgml-tag-face-alist))))))) | |
340 (setq indent-line-function 'indent-relative-maybe | 338 (setq indent-line-function 'indent-relative-maybe |
341 ;; A start or end tag by itself on a line separates a paragraph. | 339 ;; A start or end tag by itself on a line separates a paragraph. |
342 ;; This is desirable because SGML discards a newline that appears | 340 ;; This is desirable because SGML discards a newline that appears |
343 ;; immediately after a start tag or immediately before an end tag. | 341 ;; immediately after a start tag or immediately before an end tag. |
344 paragraph-separate "[ \t]*$\\|\ | 342 paragraph-separate "[ \t]*$\\|\ |
354 skeleton-end-hook (lambda () | 352 skeleton-end-hook (lambda () |
355 (or (eolp) | 353 (or (eolp) |
356 (not (or (eq v2 '\n) | 354 (not (or (eq v2 '\n) |
357 (eq (car-safe v2) '\n))) | 355 (eq (car-safe v2) '\n))) |
358 (newline-and-indent))) | 356 (newline-and-indent))) |
359 sgml-font-lock-keywords-2 (append | |
360 sgml-font-lock-keywords-1 | |
361 (cdr (assq 1 sgml-tag-face-alist))) | |
362 font-lock-defaults '((sgml-font-lock-keywords | 357 font-lock-defaults '((sgml-font-lock-keywords |
363 sgml-font-lock-keywords-1 | 358 sgml-font-lock-keywords-1 |
364 sgml-font-lock-keywords-2) | 359 sgml-font-lock-keywords-2) |
365 nil | 360 nil t nil nil |
366 t) | 361 (font-lock-syntactic-keywords |
362 . sgml-font-lock-syntactic-keywords)) | |
367 facemenu-add-face-function 'sgml-mode-facemenu-add-face-function) | 363 facemenu-add-face-function 'sgml-mode-facemenu-add-face-function) |
368 ;; This will allow existing comments within declarations to be | 364 ;; This will allow existing comments within declarations to be |
369 ;; recognized. | 365 ;; recognized. |
370 (set (make-local-variable 'comment-start-skip) "\\(?:<!\\)?--[ \t]*") | 366 (set (make-local-variable 'comment-start-skip) "\\(?:<!\\)?--[ \t]*") |
371 (set (make-local-variable 'comment-end-skip) "[ \t]*--\\([ \t\n]*>\\)?") | 367 (set (make-local-variable 'comment-end-skip) "[ \t]*--\\([ \t\n]*>\\)?")) |
372 (dolist (pair sgml-display-text) | |
373 (put (car pair) 'before-string (cdr pair)))) | |
374 | 368 |
375 | 369 |
376 (defun sgml-mode-facemenu-add-face-function (face end) | 370 (defun sgml-mode-facemenu-add-face-function (face end) |
377 (if (setq face (cdr (assq face sgml-face-tag-alist))) | 371 (if (setq face (cdr (assq face sgml-face-tag-alist))) |
378 (progn | 372 (progn |
381 (concat "<" face ">")) | 375 (concat "<" face ">")) |
382 (error "Face not configured for %s mode" mode-name))) | 376 (error "Face not configured for %s mode" mode-name))) |
383 | 377 |
384 | 378 |
385 ;;;###autoload | 379 ;;;###autoload |
386 (defun sgml-mode () | 380 (define-derived-mode sgml-mode text-mode "SGML" |
387 "Major mode for editing SGML documents. | 381 "Major mode for editing SGML documents. |
388 Makes > match <. Makes / blink matching /. | 382 Makes > match <. Makes / blink matching /. |
389 Keys <, &, SPC within <>, \" and ' can be electric depending on | 383 Keys <, &, SPC within <>, \" and ' can be electric depending on |
390 `sgml-quick-keys'. | 384 `sgml-quick-keys'. |
391 | 385 |
399 Use \\[sgml-validate] to validate your document with an SGML parser. | 393 Use \\[sgml-validate] to validate your document with an SGML parser. |
400 | 394 |
401 Do \\[describe-variable] sgml- SPC to see available variables. | 395 Do \\[describe-variable] sgml- SPC to see available variables. |
402 Do \\[describe-key] on the following bindings to discover what they do. | 396 Do \\[describe-key] on the following bindings to discover what they do. |
403 \\{sgml-mode-map}" | 397 \\{sgml-mode-map}" |
404 (interactive) | 398 (sgml-mode-common) |
405 (kill-all-local-variables) | |
406 (setq mode-name "SGML" | |
407 major-mode 'sgml-mode) | |
408 (sgml-mode-common sgml-tag-face-alist sgml-display-text) | |
409 ;; Set imenu-generic-expression here, rather than in sgml-mode-common, | 399 ;; Set imenu-generic-expression here, rather than in sgml-mode-common, |
410 ;; because this definition probably is not useful in HTML mode. | 400 ;; because this definition probably is not useful in HTML mode. |
411 (make-local-variable 'imenu-generic-expression) | 401 (make-local-variable 'imenu-generic-expression) |
412 (setq imenu-generic-expression | 402 (setq imenu-generic-expression |
413 "<!\\(element\\|entity\\)[ \t\n]+%?[ \t\n]*\\([A-Za-z][-A-Za-z.0-9]*\\)") | 403 "<!\\(element\\|entity\\)[ \t\n]+%?[ \t\n]*\\([A-Za-z][-A-Za-z.0-9]*\\)")) |
414 (use-local-map sgml-mode-map) | |
415 (run-hooks 'text-mode-hook 'sgml-mode-hook)) | |
416 | 404 |
417 | 405 |
418 (defun sgml-comment-indent () | 406 (defun sgml-comment-indent () |
419 (if (looking-at "--") comment-column 0)) | 407 (if (looking-at "--") comment-column 0)) |
420 | 408 |
745 (inhibit-modification-hooks t) | 733 (inhibit-modification-hooks t) |
746 ;; Avoid spurious the `file-locked' checks. | 734 ;; Avoid spurious the `file-locked' checks. |
747 (buffer-file-name nil) | 735 (buffer-file-name nil) |
748 ;; This is needed in case font lock gets called, | 736 ;; This is needed in case font lock gets called, |
749 ;; since it moves point and might call sgml-point-entered. | 737 ;; since it moves point and might call sgml-point-entered. |
738 ;; How could it get called? -stef | |
750 (inhibit-point-motion-hooks t) | 739 (inhibit-point-motion-hooks t) |
751 symbol) | 740 string) |
752 (unwind-protect | 741 (unwind-protect |
753 (save-excursion | 742 (save-excursion |
754 (goto-char (point-min)) | 743 (goto-char (point-min)) |
755 (if (setq sgml-tags-invisible | 744 (if (setq sgml-tags-invisible |
756 (if arg | 745 (if arg |
757 (>= (prefix-numeric-value arg) 0) | 746 (>= (prefix-numeric-value arg) 0) |
758 (not sgml-tags-invisible))) | 747 (not sgml-tags-invisible))) |
759 (while (re-search-forward "<\\([!/?A-Za-z][-A-Za-z0-9]*\\)" | 748 (while (re-search-forward "<\\([!/?A-Za-z][-A-Za-z0-9]*\\)" |
760 nil t) | 749 nil t) |
761 (setq symbol (intern-soft (downcase (match-string 1)))) | 750 (setq string |
751 (cdr (assq (intern-soft (downcase (match-string 1))) | |
752 sgml-display-text))) | |
762 (goto-char (match-beginning 0)) | 753 (goto-char (match-beginning 0)) |
763 (and (get symbol 'before-string) | 754 (and (stringp string) |
764 (not (overlays-at (point))) | 755 (not (overlays-at (point))) |
765 (overlay-put (make-overlay (point) | 756 (overlay-put (make-overlay (point) |
766 (match-beginning 1)) | 757 (match-beginning 1)) |
767 'category symbol)) | 758 'before-string string)) |
768 (put-text-property (point) | 759 (put-text-property (point) |
769 (progn (forward-list) (point)) | 760 (progn (forward-list) (point)) |
770 'category 'sgml-tag)) | 761 'category 'sgml-tag)) |
771 (let ((pos (point))) | 762 (let ((pos (point-min))) |
772 (while (< (setq pos (next-overlay-change pos)) (point-max)) | 763 (while (< (setq pos (next-overlay-change pos)) (point-max)) |
773 (delete-overlay (car (overlays-at pos))))) | 764 (delete-overlay (car (overlays-at pos))))) |
774 (remove-text-properties (point-min) (point-max) | 765 (remove-text-properties (point-min) (point-max) '(category nil)))) |
775 '(category sgml-tag intangible t)))) | |
776 (restore-buffer-modified-p modified)) | 766 (restore-buffer-modified-p modified)) |
777 (run-hooks 'sgml-tags-invisible-hook) | 767 (run-hooks 'sgml-tags-invisible-hook) |
778 (message ""))) | 768 (message ""))) |
779 | 769 |
780 (defun sgml-point-entered (x y) | 770 (defun sgml-point-entered (x y) |
852 (delete-backward-char 2)))) | 842 (delete-backward-char 2)))) |
853 (insert "=\"") | 843 (insert "=\"") |
854 (if alist | 844 (if alist |
855 (insert (skeleton-read '(completing-read "Value: " alist)))) | 845 (insert (skeleton-read '(completing-read "Value: " alist)))) |
856 (insert ?\")))) | 846 (insert ?\")))) |
847 | |
848 (defun sgml-quote (start end &optional unquotep) | |
849 "Quote SGML text in region. | |
850 With prefix argument, unquote the region." | |
851 (interactive "r\np") | |
852 (if (< start end) | |
853 (goto-char start) | |
854 (goto-char end) | |
855 (setq end start)) | |
856 (if unquotep | |
857 (while (re-search-forward "&\\(amp\\|\\(l\\|\\(g\\)\\)t\\);" end t) | |
858 (replace-match (if (match-end 3) ">" (if (match-end 2) "<" "&")))) | |
859 (while (re-search-forward "[&<>]" end t) | |
860 (replace-match (cdr (assq (char-before) '((?& . "&") | |
861 (?< . "<") | |
862 (?> . ">")))))))) | |
857 | 863 |
858 | 864 |
859 ;;; HTML mode | 865 ;;; HTML mode |
860 | 866 |
861 (defcustom html-mode-hook nil | 867 (defcustom html-mode-hook nil |
1096 ("q") | 1102 ("q") |
1097 ("rev") | 1103 ("rev") |
1098 ("s") | 1104 ("s") |
1099 ("samp") | 1105 ("samp") |
1100 ("small") | 1106 ("small") |
1101 ("span") | 1107 ("span" nil |
1108 ("class" | |
1109 ("builtin") | |
1110 ("comment") | |
1111 ("constant") | |
1112 ("function-name") | |
1113 ("keyword") | |
1114 ("string") | |
1115 ("type") | |
1116 ("variable-name") | |
1117 ("warning"))) | |
1102 ("strong") | 1118 ("strong") |
1103 ("sub") | 1119 ("sub") |
1104 ("sup") | 1120 ("sup") |
1105 ("title") | 1121 ("title") |
1106 ("tr" t) | 1122 ("tr" t) |
1200 ("var" . "Math variable face") | 1216 ("var" . "Math variable face") |
1201 ("wbr" . "Enable <br> within <nobr>")) | 1217 ("wbr" . "Enable <br> within <nobr>")) |
1202 "*Value of `sgml-tag-help' for HTML mode.") | 1218 "*Value of `sgml-tag-help' for HTML mode.") |
1203 | 1219 |
1204 ;;;###autoload | 1220 ;;;###autoload |
1205 (defun html-mode () | 1221 (define-derived-mode html-mode sgml-mode "HTML" |
1206 "Major mode based on SGML mode for editing HTML documents. | 1222 "Major mode based on SGML mode for editing HTML documents. |
1207 This allows inserting skeleton constructs used in hypertext documents with | 1223 This allows inserting skeleton constructs used in hypertext documents with |
1208 completion. See below for an introduction to HTML. Use | 1224 completion. See below for an introduction to HTML. Use |
1209 \\[browse-url-of-buffer] to see how this comes out. See also `sgml-mode' on | 1225 \\[browse-url-of-buffer] to see how this comes out. See also `sgml-mode' on |
1210 which this is based. | 1226 which this is based. |
1236 interesting. But note that some HTML 2 browsers can't handle `''. | 1252 interesting. But note that some HTML 2 browsers can't handle `''. |
1237 To work around that, do: | 1253 To work around that, do: |
1238 (eval-after-load \"sgml-mode\" '(aset sgml-char-names ?' nil)) | 1254 (eval-after-load \"sgml-mode\" '(aset sgml-char-names ?' nil)) |
1239 | 1255 |
1240 \\{html-mode-map}" | 1256 \\{html-mode-map}" |
1241 (interactive) | 1257 (set (make-local-variable 'sgml-display-text) html-display-text) |
1242 (kill-all-local-variables) | 1258 (set (make-local-variable 'sgml-tag-face-alist) html-tag-face-alist) |
1243 (setq mode-name "HTML" | |
1244 major-mode 'html-mode) | |
1245 (sgml-mode-common html-tag-face-alist html-display-text) | |
1246 (use-local-map html-mode-map) | |
1247 (make-local-variable 'sgml-tag-alist) | 1259 (make-local-variable 'sgml-tag-alist) |
1248 (make-local-variable 'sgml-face-tag-alist) | 1260 (make-local-variable 'sgml-face-tag-alist) |
1249 (make-local-variable 'sgml-tag-help) | 1261 (make-local-variable 'sgml-tag-help) |
1250 (make-local-variable 'outline-regexp) | 1262 (make-local-variable 'outline-regexp) |
1251 (make-local-variable 'outline-heading-end-regexp) | 1263 (make-local-variable 'outline-heading-end-regexp) |
1252 (make-local-variable 'outline-level) | 1264 (make-local-variable 'outline-level) |
1253 (make-local-variable 'sentence-end) | 1265 (make-local-variable 'sentence-end) |
1254 (setq sentence-end | 1266 (setq sentence-end |
1255 (if sentence-end-double-space | 1267 (if sentence-end-double-space |
1256 "[.?!][]\"')}]*\\(<[^>]*>\\)*\\($\\| $\\|\t\\| \\)[ \t\n]*" | 1268 "[.?!][]\"')}]*\\(<[^>]*>\\)*\\($\\| $\\|\t\\| \\)[ \t\n]*" |
1257 | 1269 "[.?!][]\"')}]*\\(<[^>]*>\\)*\\($\\|[ \t]\\)[ \t\n]*")) |
1258 "[.?!][]\"')}]*\\(<[^>]*>\\)*\\($\\| \\|\t\\)[ \t\n]*")) | |
1259 (setq sgml-tag-alist html-tag-alist | 1270 (setq sgml-tag-alist html-tag-alist |
1260 sgml-face-tag-alist html-face-tag-alist | 1271 sgml-face-tag-alist html-face-tag-alist |
1261 sgml-tag-help html-tag-help | 1272 sgml-tag-help html-tag-help |
1262 outline-regexp "^.*<[Hh][1-6]\\>" | 1273 outline-regexp "^.*<[Hh][1-6]\\>" |
1263 outline-heading-end-regexp "</[Hh][1-6]>" | 1274 outline-heading-end-regexp "</[Hh][1-6]>" |
1265 (char-after (1- (match-end 0))))) | 1276 (char-after (1- (match-end 0))))) |
1266 (setq imenu-create-index-function 'html-imenu-index) | 1277 (setq imenu-create-index-function 'html-imenu-index) |
1267 ;; It's for the user to decide if it defeats it or not -stef | 1278 ;; It's for the user to decide if it defeats it or not -stef |
1268 ;; (make-local-variable 'imenu-sort-function) | 1279 ;; (make-local-variable 'imenu-sort-function) |
1269 ;; (setq imenu-sort-function nil) ; sorting the menu defeats the purpose | 1280 ;; (setq imenu-sort-function nil) ; sorting the menu defeats the purpose |
1270 (run-hooks 'text-mode-hook 'sgml-mode-hook 'html-mode-hook)) | 1281 ) |
1271 | 1282 |
1272 (defvar html-imenu-regexp | 1283 (defvar html-imenu-regexp |
1273 "\\s-*<h\\([1-9]\\)[^\n<>]*>\\(<[^\n<>]*>\\)*\\s-*\\([^\n<>]*\\)" | 1284 "\\s-*<h\\([1-9]\\)[^\n<>]*>\\(<[^\n<>]*>\\)*\\s-*\\([^\n<>]*\\)" |
1274 "*A regular expression matching a head line to be added to the menu. | 1285 "*A regular expression matching a head line to be added to the menu. |
1275 The first `match-string' should be a number from 1-9. | 1286 The first `match-string' should be a number from 1-9. |