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) '((?& . "&amp;")
861 (?< . "&lt;")
862 (?> . "&gt;"))))))))
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 `&apos;'. 1252 interesting. But note that some HTML 2 browsers can't handle `&apos;'.
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.