-;;; sgml-mode.el --- SGML- and HTML-editing modes -*- coding: iso-2022-7bit -*-
+;;; sgml-mode.el --- SGML- and HTML-editing modes -*- coding: utf-8 -*-
;; Copyright (C) 1992, 1995, 1996, 1998, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
;; Author: James Clark <jjc@jclark.com>
;; Maintainer: FSF
(define-key map "\C-c\C-d" 'sgml-delete-tag)
(define-key map "\C-c\^?" 'sgml-delete-tag)
(define-key map "\C-c?" 'sgml-tag-help)
+ (define-key map "\C-c]" 'sgml-close-tag)
(define-key map "\C-c/" 'sgml-close-tag)
+
+ ;; Redundant keybindings, for consistency with TeX mode.
+ (define-key map "\C-c\C-o" 'sgml-tag)
+ (define-key map "\C-c\C-e" 'sgml-close-tag)
+
(define-key map "\C-c8" 'sgml-name-8bit-mode)
(define-key map "\C-c\C-v" 'sgml-validate)
(when sgml-quick-keys
(let ((table (sgml-make-syntax-table sgml-specials)))
(dolist (char '(?\( ?\) ?\{ ?\} ?\[ ?\] ?$ ?% ?& ?* ?+ ?/))
(modify-syntax-entry char "." table))
+ (unless (memq ?' sgml-specials)
+ ;; Avoid that skipping a tag backwards skips any "'" prefixing it.
+ (modify-syntax-entry ?' "w" table))
table)
"Syntax table used to parse SGML tags.")
(defvar sgml-font-lock-keywords sgml-font-lock-keywords-1
"*Rules for highlighting SGML code. See also `sgml-tag-face-alist'.")
-(defvar sgml-font-lock-syntactic-keywords
+(defconst sgml-syntax-propertize-function
+ (syntax-propertize-rules
;; Use the `b' style of comments to avoid interference with the -- ... --
;; comments recognized when `sgml-specials' includes ?-.
;; FIXME: beware of <!--> blabla <!--> !!
- '(("\\(<\\)!--" (1 "< b"))
+ ("\\(<\\)!--" (1 "< b"))
("--[ \t\n]*\\(>\\)" (1 "> b"))
;; Double quotes outside of tags should not introduce strings.
;; Be careful to call `syntax-ppss' on a position before the one we're
(comment-indent-new-line soft)))
(defun sgml-mode-facemenu-add-face-function (face end)
- (if (setq face (cdr (assq face sgml-face-tag-alist)))
- (progn
- (setq face (funcall skeleton-transformation-function face))
- (setq facemenu-end-add-face (concat "</" face ">"))
- (concat "<" face ">"))
- (error "Face not configured for %s mode" (format-mode-line mode-name))))
+ (let ((tag-face (cdr (assq face sgml-face-tag-alist))))
+ (cond (tag-face
+ (setq tag-face (funcall skeleton-transformation-function tag-face))
+ (setq facemenu-end-add-face (concat "</" tag-face ">"))
+ (concat "<" tag-face ">"))
+ ((and (consp face)
+ (consp (car face))
+ (null (cdr face))
+ (memq (caar face) '(:foreground :background)))
+ (setq facemenu-end-add-face "</span>")
+ (format "<span style=\"%s:%s\">"
+ (if (eq (caar face) :foreground)
+ "color"
+ "background-color")
+ (cadr (car face))))
+ (t
+ (error "Face not configured for %s mode"
+ (format-mode-line mode-name))))))
(defun sgml-fill-nobreak ()
;; Don't break between a tag name and its first argument.
'((sgml-font-lock-keywords
sgml-font-lock-keywords-1
sgml-font-lock-keywords-2)
- nil t nil nil
- (font-lock-syntactic-keywords
- . sgml-font-lock-syntactic-keywords)))
+ nil t))
+ (set (make-local-variable 'syntax-propertize-function)
+ sgml-syntax-propertize-function)
(set (make-local-variable 'facemenu-add-face-function)
'sgml-mode-facemenu-add-face-function)
(set (make-local-variable 'sgml-xml-mode) (sgml-xml-guess))
"\\)\\(" sgml-name-re "\\)\\1")
2))))
-;; Some programs (such as Glade 2) generate XML which has
-;; -*- mode: xml -*-.
-;;;###autoload
-(defalias 'xml-mode 'sgml-mode)
-
(defun sgml-comment-indent ()
(if (looking-at "--") comment-column 0))
(insert-char ?/ 1)
(indent-according-to-mode))
((eq sgml-quick-keys 'close)
- (delete-backward-char 1)
+ (delete-char -1)
(sgml-close-tag))
(t
(sgml-slash-matching arg))))
(insert ?&)
(or char
(setq char (read-quoted-char "Enter char or octal number")))
- (delete-backward-char 1)
+ (delete-char -1)
(insert char)
(undo-boundary)
(sgml-namify-char))
((encode-char char 'ucs)))))
(if (not name)
(error "Don't know the name of `%c'" char)
- (delete-backward-char 1)
+ (delete-char -1)
(insert (format (if (numberp name) "&#%d;" "&%s;") name)))))
(defun sgml-name-self ()
"Insert a symbolic character name according to `sgml-char-names'."
(interactive "*")
- (sgml-name-char last-command-char))
+ (sgml-name-char last-command-event))
(defun sgml-maybe-name-self ()
"Insert a symbolic character name according to `sgml-char-names'."
(interactive "*")
(if sgml-name-8bit-mode
- (let ((mc last-command-char))
- (if (< mc 256)
- (setq mc (unibyte-char-to-multibyte mc)))
- (or mc (setq mc last-command-char))
- (sgml-name-char mc))
+ (sgml-name-char last-command-event)
(self-insert-command 1)))
(defun sgml-name-8bit-mode ()
(sgml-value (assoc (downcase attribute) alist))
(setq i (1- i))))
(if (eq (preceding-char) ?\s)
- (delete-backward-char 1)))
+ (delete-char -1)))
car)))
(defun sgml-auto-attributes (arg)
(eq (aref tag 0) ?/))
(self-insert-command (prefix-numeric-value arg))
(sgml-attributes tag)
- (setq last-command-char ?\s)
+ (setq last-command-event ?\s)
(or (> (point) point)
(self-insert-command 1)))))
(defun sgml-tag-help (&optional tag)
"Display description of tag TAG. If TAG is omitted, use the tag at point."
- (interactive)
- (or tag
+ (interactive
+ (list (let ((def (save-excursion
+ (if (eq (following-char) ?<) (forward-char))
+ (sgml-beginning-of-tag))))
+ (completing-read (if def
+ (format "Tag (default %s): " def)
+ "Tag: ")
+ sgml-tag-alist nil nil nil
+ 'sgml-tag-history def))))
+ (or (and tag (> (length tag) 0))
(save-excursion
(if (eq (following-char) ?<)
(forward-char))
(setq arg (1- arg)))
return)))
+(defsubst sgml-looking-back-at (str)
+ "Return t if the test before point matches STR."
+ (let ((start (- (point) (length str))))
+ (and (>= start (point-min))
+ (equal str (buffer-substring-no-properties start (point))))))
+
(defun sgml-delete-tag (arg)
;; FIXME: Should be called sgml-kill-tag or should not touch the kill-ring.
"Delete tag on or after cursor, and matching closing or opening tag.
(kill-sexp 1))
(setq open (point))
(when (and (sgml-skip-tag-forward 1)
- (not (looking-back "/>")))
+ (not (sgml-looking-back-at "/>")))
(kill-sexp -1)))
;; Delete any resulting empty line. If we didn't kill-sexp,
;; this *should* do nothing, because we're right after the tag.
(let ((cdata-start (point)))
(unless (search-forward "]]>" pos 'move)
(list 0 nil nil 'cdata nil nil nil nil cdata-start))))
+ ((looking-at comment-start-skip)
+ ;; parse-partial-sexp doesn't handle <!-- comments -->,
+ ;; or only if ?- is in sgml-specials, so match explicitly
+ (let ((start (point)))
+ (unless (re-search-forward comment-end-skip pos 'move)
+ (list 0 nil nil nil t nil nil nil start))))
((and sgml-xml-mode (looking-at "<\\?"))
;; Processing Instructions.
;; In SGML, it's basically a normal tag of the form
(setq alist (skeleton-read '(completing-read "Value: " (cdr alist))))
(if (string< "" alist)
(insert alist ?\")
- (delete-backward-char 2)))
+ (delete-char -2)))
(insert "=\"")
(if (cdr alist)
(insert (skeleton-read '(completing-read "Value: " alist)))
(buffer-substring-no-properties
(point) (progn (skip-syntax-forward "w_") (point))))
-(defsubst sgml-looking-back-at (str)
- "Return t if the test before point matches STR."
- (let ((start (- (point) (length str))))
- (and (>= start (point-min))
- (equal str (buffer-substring-no-properties start (point))))))
-
(defun sgml-tag-text-p (start end)
"Return non-nil if text between START and END is a tag.
Checks among other things that the tag does not contain spurious
("dt" (t _ (if sgml-xml-mode "</dt>")
"<dd>" (if sgml-xml-mode "</dd>") \n))
("em")
- ;("fn" "id" "fn") ; ???
+ ("fn" "id" "fn") ;; Footnotes were deprecated in HTML 3.2
("head" \n)
("html" (\n
"<head>\n"
("nobr")
("option" t ("value") ("label") ("selected" t))
("over" t)
- ("person")
+ ("person") ;; Tag for person's name tag deprecated in HTML 3.2
("pre" \n)
("q")
("rev")
(defvar html-tag-help
`(,@sgml-tag-help
("a" . "Anchor of point or link elsewhere")
- ("abbrev" . "?")
- ("acronym" . "?")
+ ("abbrev" . "Abbreviation")
+ ("acronym" . "Acronym")
("address" . "Formatted mail address")
("array" . "Math array")
- ("au" . "?")
+ ("au" . "Author")
("b" . "Bold face")
("base" . "Base address for URLs")
("big" . "Font size")
("cite" . "Citation of a document")
("code" . "Formatted source code")
("dd" . "Definition of term")
- ("del" . "?")
- ("dfn" . "?")
+ ("del" . "Deleted text")
+ ("dfn" . "Defining instance of a term")
("dir" . "Directory list (obsolete)")
+ ("div" . "Generic block-level container")
("dl" . "Definition list")
("dt" . "Term to be definined")
("em" . "Emphasized")
("figa" . "Figure anchor")
("figd" . "Figure description")
("figt" . "Figure text")
- ;("fn" . "?") ; ???
+ ("fn" . "Footnote") ;; No one supports special footnote rendering.
("font" . "Font size")
("form" . "Form with input fields")
("group" . "Document grouping")
("i" . "Italic face")
("img" . "Graphic image")
("input" . "Form input field")
- ("ins" . "?")
+ ("ins" . "Inserted text")
("isindex" . "Input field for index search")
("kbd" . "Keybard example face")
("lang" . "Natural language")
("over" . "Math fraction rule")
("p" . "Paragraph start")
("panel" . "Floating panel")
- ("person" . "?")
+ ("person" . "Person's name")
("pre" . "Preformatted fixed width text")
- ("q" . "?")
+ ("q" . "Quotation")
("rev" . "Reverse video")
- ("s" . "?")
+ ("s" . "Strikeout")
("samp" . "Sample text")
("select" . "Selection list")
("small" . "Font size")
("sp" . "Nobreak space")
+ ("span" . "Generic inline container")
("strong" . "Standout text")
("sub" . "Subscript")
("sup" . "Superscript")
(make-local-variable 'outline-heading-end-regexp)
(make-local-variable 'outline-level)
(make-local-variable 'sentence-end-base)
- (setq sentence-end-base "[.?!][]\"'\e$B!I\e$,1r}\e(B)}]*\\(<[^>]*>\\)*"
+ (setq sentence-end-base "[.?!][]\"'”)}]*\\(<[^>]*>\\)*"
sgml-tag-alist html-tag-alist
sgml-face-tag-alist html-face-tag-alist
sgml-tag-help html-tag-help