summaryrefslogtreecommitdiff
path: root/lisp/textmodes/sgml-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/textmodes/sgml-mode.el')
-rw-r--r--lisp/textmodes/sgml-mode.el131
1 files changed, 69 insertions, 62 deletions
diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el
index 50b2077ef4f..9e3be99af14 100644
--- a/lisp/textmodes/sgml-mode.el
+++ b/lisp/textmodes/sgml-mode.el
@@ -46,8 +46,7 @@
(defcustom sgml-basic-offset 2
"Specifies the basic indentation level for `sgml-indent-line'."
- :type 'integer
- :group 'sgml)
+ :type 'integer)
(defcustom sgml-attribute-offset 0
"Specifies a delta for attribute indentation in `sgml-indent-line'.
@@ -65,16 +64,16 @@ When 2, attribute indentation looks like this:
</element>"
:version "25.1"
:type 'integer
- :safe 'integerp
- :group 'sgml)
+ :safe 'integerp)
(defcustom sgml-xml-mode nil
"When non-nil, tag insertion functions will be XML-compliant.
It is set to be buffer-local when the file has
a DOCTYPE or an XML declaration."
:type 'boolean
- :version "22.1"
- :group 'sgml)
+ :version "22.1")
+
+(defvaralias 'sgml-transformation 'sgml-transformation-function)
(defcustom sgml-transformation-function 'identity
"Default value for `skeleton-transformation-function' in SGML mode."
@@ -87,17 +86,14 @@ a DOCTYPE or an XML declaration."
(and (derived-mode-p 'sgml-mode)
(not sgml-xml-mode)
(setq skeleton-transformation-function val))))
- (buffer-list)))
- :group 'sgml)
+ (buffer-list))))
(put 'sgml-transformation-function 'variable-interactive
"aTransformation function: ")
-(defvaralias 'sgml-transformation 'sgml-transformation-function)
(defcustom sgml-mode-hook nil
"Hook run by command `sgml-mode'.
`text-mode-hook' is run first."
- :group 'sgml
:type 'hook)
;; As long as Emacs's syntax can't be complemented with predicates to context
@@ -210,8 +206,7 @@ This takes effect when first loading the `sgml-mode' library.")
(defcustom sgml-name-8bit-mode nil
"When non-nil, insert non-ASCII characters as named entities."
- :type 'boolean
- :group 'sgml)
+ :type 'boolean)
(defvar sgml-char-names
[nil nil nil nil nil nil nil nil
@@ -281,8 +276,7 @@ Currently, only Latin-1 characters are supported.")
The file name of current buffer file name will be appended to this,
separated by a space."
:type 'string
- :version "21.1"
- :group 'sgml)
+ :version "21.1")
(defvar sgml-saved-validate-command nil
"The command last used to validate in this buffer.")
@@ -291,8 +285,7 @@ separated by a space."
;; so use a small distance here.
(defcustom sgml-slash-distance 1000
"If non-nil, is the maximum distance to search for matching `/'."
- :type '(choice (const nil) integer)
- :group 'sgml)
+ :type '(choice (const nil) integer))
(defconst sgml-namespace-re "[_[:alpha:]][-_.[:alnum:]]*")
(defconst sgml-name-re "[_:[:alpha:]][-_.:[:alnum:]]*")
@@ -304,8 +297,7 @@ Any terminating `>' or `/' is not matched.")
(defface sgml-namespace
'((t (:inherit font-lock-builtin-face)))
- "`sgml-mode' face used to highlight the namespace part of identifiers."
- :group 'sgml)
+ "`sgml-mode' face used to highlight the namespace part of identifiers.")
(defvar sgml-namespace-face 'sgml-namespace)
;; internal
@@ -351,12 +343,21 @@ Any terminating `>' or `/' is not matched.")
("--[ \t\n]*\\(>\\)" (1 "> b"))
("\\(<\\)[?!]" (1 (prog1 "|>"
(sgml-syntax-propertize-inside end))))
- ;; Double quotes outside of tags should not introduce strings.
- ;; Be careful to call `syntax-ppss' on a position before the one we're
- ;; going to change, so as not to need to flush the data we just computed.
- ("\"" (0 (if (prog1 (zerop (car (syntax-ppss (match-beginning 0))))
- (goto-char (match-end 0)))
- (string-to-syntax ".")))))))
+ ;; Double quotes outside of tags should not introduce strings which end up
+ ;; hiding tags. We used to test every double quote and mark it as "."
+ ;; if it's outside of tags, but there are too many double quotes and
+ ;; the resulting number of calls to syntax-ppss made it too slow
+ ;; (bug#33887), so we're now careful to leave alone any pair
+ ;; of quotes that doesn't hold a < or > char, which is the vast majority.
+ ("\\(\"\\)[^\"<>]*[<>\"]"
+ (1 (unless (eq ?\" (char-before))
+ ;; Be careful to call `syntax-ppss' on a position before the one
+ ;; we're going to change, so as not to need to flush the data we
+ ;; just computed.
+ (if (prog1 (zerop (car (syntax-ppss (match-beginning 0))))
+ (goto-char (1- (match-end 0))))
+ (string-to-syntax ".")))))
+ )))
(defun sgml-syntax-propertize (start end)
"Syntactic keywords for `sgml-mode'."
@@ -420,8 +421,7 @@ The attribute alist is made up as
ATTRIBUTERULE is a list of optionally t (no value when no input) followed by
an optional alist of possible values."
:type '(repeat (cons (string :tag "Tag Name")
- (repeat :tag "Tag Rule" sexp)))
- :group 'sgml)
+ (repeat :tag "Tag Rule" sexp))))
(put 'sgml-tag-alist 'risky-local-variable t)
(defcustom sgml-tag-help
@@ -433,8 +433,7 @@ an optional alist of possible values."
("!entity" . "Entity (macro) declaration"))
"Alist of tag name and short description."
:type '(repeat (cons (string :tag "Tag Name")
- (string :tag "Description")))
- :group 'sgml)
+ (string :tag "Description"))))
(defvar sgml-empty-tags nil
"List of tags whose !ELEMENT definition says EMPTY.")
@@ -460,7 +459,7 @@ an optional alist of possible values."
nil t)
(string-match "X\\(HT\\)?ML" (match-string 3))))))
-(defvar v2) ; free for skeleton
+(with-no-warnings (defvar v2)) ; free for skeleton
(defun sgml-comment-indent-new-line (&optional soft)
(let ((comment-start "-- ")
@@ -618,7 +617,7 @@ Behaves electrically if `sgml-quick-keys' is non-nil."
(delete-char -1)
(sgml-close-tag))
(t
- (sgml-slash-matching arg))))
+ (insert-char ?/ arg))))
(defun sgml-slash-matching (arg)
"Insert `/' and display any previous matching `/'.
@@ -895,7 +894,7 @@ Return non-nil if we skipped over matched tags."
(condition-case err
(save-excursion
(goto-char end)
- (skip-chars-backward "[:alnum:]-_.:")
+ (skip-chars-backward "-[:alnum:]_.:")
(if (and ;; (<= (point) beg) ; This poses problems for downcase-word.
(or (eq (char-before) ?<)
(and (eq (char-before) ?/)
@@ -903,7 +902,7 @@ Return non-nil if we skipped over matched tags."
(null (get-char-property (point) 'text-clones)))
(let* ((endp (eq (char-before) ?/))
(cl-start (point))
- (cl-end (progn (skip-chars-forward "[:alnum:]-_.:") (point)))
+ (cl-end (progn (skip-chars-forward "-[:alnum:]_.:") (point)))
(match
(if endp
(when (sgml-skip-tag-backward 1) (forward-char 1) t)
@@ -920,7 +919,8 @@ Return non-nil if we skipped over matched tags."
(equal (buffer-substring cl-start cl-end)
(buffer-substring (point)
(save-excursion
- (skip-chars-forward "[:alnum:]-_.:")
+ (skip-chars-forward
+ "-[:alnum:]_.:")
(point))))
(or (not endp) (eq (char-after cl-end) ?>)))
(when clones
@@ -940,9 +940,6 @@ Return non-nil if we skipped over matched tags."
(define-minor-mode sgml-electric-tag-pair-mode
"Toggle SGML Electric Tag Pair mode.
-With a prefix argument ARG, enable the mode if ARG is positive,
-and disable it otherwise. If called from Lisp, enable the mode
-if ARG is omitted or nil.
SGML Electric Tag Pair mode is a buffer-local minor mode for use
with `sgml-mode' and related major modes. When enabled, editing
@@ -1241,8 +1238,11 @@ See `sgml-tag-alist' for info about attribute rules."
(defun sgml-quote (start end &optional unquotep)
"Quote SGML text in region START ... END.
-Only &, < and > are quoted, the rest is left untouched.
-With prefix argument UNQUOTEP, unquote the region."
+Only &, <, >, ' and \" characters are quoted, the rest is left
+untouched. This is sufficient to use quoted text as SGML argument.
+
+With prefix argument UNQUOTEP, unquote the region. All numeric entities,
+\"amp\", \"lt\", \"gt\" and \"quot\" named entities are unquoted."
(interactive "r\nP")
(save-restriction
(narrow-to-region start end)
@@ -1250,14 +1250,23 @@ With prefix argument UNQUOTEP, unquote the region."
(if unquotep
;; FIXME: We should unquote other named character references as well.
(while (re-search-forward
- "\\(&\\(amp\\|\\(l\\|\\(g\\)\\)t\\)\\)[][<>&;\n\t \"%!'(),/=?]"
+ "\\(&\\(amp\\|quot\\|lt\\|gt\\|#\\([0-9]+\\|[xX][0-9a-fA-F]+\\)\\)\\)\\([][<>&;\n\t \"%!'(),/=?]\\|$\\)"
nil t)
- (replace-match (if (match-end 4) ">" (if (match-end 3) "<" "&")) t t
- nil (if (eq (char-before (match-end 0)) ?\;) 0 1)))
- (while (re-search-forward "[&<>]" nil t)
+ (replace-match
+ (string
+ (or (cdr (assq (char-after (match-beginning 2))
+ '((?a . ?&) (?q . ?\") (?l . ?<) (?g . ?>))))
+ (let ((num (match-string 3)))
+ (if (or (eq ?x (aref num 0)) (eq ?X (aref num 0)))
+ (string-to-number (substring num 1) 16)
+ (string-to-number num 10)))))
+ t t nil (if (eq (char-before (match-end 0)) ?\;) 0 1)))
+ (while (re-search-forward "[&<>\"']" nil t)
(replace-match (cdr (assq (char-before) '((?& . "&amp;")
(?< . "&lt;")
- (?> . "&gt;"))))
+ (?> . "&gt;")
+ (?\" . "&#34;")
+ (?' . "&#39;"))))
t t)))))
(defun sgml-pretty-print (beg end)
@@ -1514,12 +1523,12 @@ Depending on context, inserts a matching close-tag, or closes
the current start-tag or the current comment or the current cdata, ..."
(interactive)
(pcase (car (sgml-lexical-context))
- (`comment (insert " -->"))
- (`cdata (insert "]]>"))
- (`pi (insert " ?>"))
- (`jsp (insert " %>"))
- (`tag (insert " />"))
- (`text
+ ('comment (insert " -->"))
+ ('cdata (insert "]]>"))
+ ('pi (insert " ?>"))
+ ('jsp (insert " %>"))
+ ('tag (insert " />"))
+ ('text
(let ((context (save-excursion (sgml-get-context))))
(if context
(progn
@@ -1552,7 +1561,7 @@ LCON is the lexical context, if any."
(pcase (car lcon)
- (`string
+ ('string
;; Go back to previous non-empty line.
(while (and (> (point) (cdr lcon))
(zerop (forward-line -1))
@@ -1563,7 +1572,7 @@ LCON is the lexical context, if any."
(goto-char (cdr lcon))
(1+ (current-column))))
- (`comment
+ ('comment
(let ((mark (looking-at "--")))
;; Go back to previous non-empty line.
(while (and (> (point) (cdr lcon))
@@ -1582,11 +1591,11 @@ LCON is the lexical context, if any."
(current-column)))
;; We don't know how to indent it. Let's be honest about it.
- (`cdata nil)
+ ('cdata nil)
;; We don't know how to indent it. Let's be honest about it.
- (`pi nil)
+ ('pi nil)
- (`tag
+ ('tag
(goto-char (+ (cdr lcon) sgml-attribute-offset))
(skip-chars-forward "^ \t\n") ;Skip tag name.
(skip-chars-forward " \t")
@@ -1596,7 +1605,7 @@ LCON is the lexical context, if any."
(goto-char (+ (cdr lcon) sgml-attribute-offset))
(+ (current-column) sgml-basic-offset)))
- (`text
+ ('text
(while (looking-at "</")
(sgml-forward-sexp 1)
(skip-chars-forward " \t"))
@@ -1712,7 +1721,6 @@ Currently just returns (EMPTY-TAGS UNCLOSED-TAGS)."
(defcustom html-mode-hook nil
"Hook run by command `html-mode'.
`text-mode-hook' and `sgml-mode-hook' are run first."
- :group 'sgml
:type 'hook
:options '(html-autoview-mode))
@@ -2232,6 +2240,9 @@ buffer's tick counter (as produced by `buffer-modified-tick'),
and the CDR is the list of class names found in the buffer.")
(make-variable-buffer-local 'html--buffer-ids-cache)
+(declare-function libxml-parse-html-region "xml.c"
+ (start end &optional base-url discard-comments))
+
(defun html-current-buffer-classes ()
"Return a list of class names used in the current buffer.
The result is cached in `html--buffer-classes-cache'."
@@ -2363,18 +2374,14 @@ The third `match-string' will be the used in the menu.")
(define-minor-mode html-autoview-mode
"Toggle viewing of HTML files on save (HTML Autoview mode).
-With a prefix argument ARG, enable HTML Autoview mode if ARG is
-positive, and disable it otherwise. If called from Lisp, enable
-the mode if ARG is omitted or nil.
HTML Autoview mode is a buffer-local minor mode for use with
`html-mode'. If enabled, saving the file automatically runs
`browse-url-of-buffer' to view it."
nil nil nil
- :group 'sgml
(if html-autoview-mode
- (add-hook 'after-save-hook 'browse-url-of-buffer nil t)
- (remove-hook 'after-save-hook 'browse-url-of-buffer t)))
+ (add-hook 'after-save-hook #'browse-url-of-buffer nil t)
+ (remove-hook 'after-save-hook #'browse-url-of-buffer t)))
(define-skeleton html-href-anchor