Mercurial > emacs
changeset 51478:cc38ef483a77
(sgml-parse-tag-backward): Try and detect
when we're starting from within a tag.
(sgml-get-context): When called from inside a tag, do something useful.
Rename the arg now that it's never used for `full' context anymore.
(sgml-calculate-indent): Make `lcon' an argument.
Return nil when we don't know what to do.
If the initial lcon turns out to be wrong, try again.
(sgml-indent-line): If sgml-calculate-indent returns nil, don't indent.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Thu, 05 Jun 2003 01:14:23 +0000 |
parents | 3ee34a66739e |
children | 4f9ddb5b4715 |
files | lisp/textmodes/sgml-mode.el |
diffstat | 1 files changed, 123 insertions(+), 94 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/textmodes/sgml-mode.el Thu Jun 05 00:36:28 2003 +0000 +++ b/lisp/textmodes/sgml-mode.el Thu Jun 05 01:14:23 2003 +0000 @@ -368,8 +368,8 @@ (looking-at "\\s-*<\\?xml") (when (re-search-forward (eval-when-compile - (mapconcat 'identity - '("<!DOCTYPE" "\\(\\w+\\)" "\\(\\w+\\)" + (mapconcat 'identity + '("<!DOCTYPE" "\\(\\w+\\)" "\\(\\w+\\)" "\"\\([^\"]+\\)\"" "\"\\([^\"]+\\)\"") "\\s-+")) nil t) @@ -1045,8 +1045,14 @@ Assume that parsing starts from within a textual context. Leave point at the beginning of the tag." (let (tag-type tag-start tag-end name) - (or (search-backward ">" limit 'move) + (or (re-search-backward "[<>]" limit 'move) (error "No tag found")) + (when (eq (char-after) ?<) + ;; Oops!! Looks like we were not in a textual context after all!. + ;; Let's try to recover. + (with-syntax-table sgml-tag-syntax-table + (forward-sexp) + (forward-char -1))) (setq tag-end (1+ (point))) (cond ((sgml-looking-back-at "--") ; comment @@ -1082,15 +1088,17 @@ (goto-char tag-start) (sgml-make-tag tag-type tag-start tag-end name))) -(defun sgml-get-context (&optional full) +(defun sgml-get-context (&optional until) "Determine the context of the current position. -If FULL is `empty', return even if the context is empty (i.e. +By default, parse until we find a start-tag as the first thing on a line. +If UNTIL is `empty', return even if the context is empty (i.e. we just skipped over some element and got to a beginning of line). -If FULL is non-nil, parse back to the beginning of the buffer, otherwise -parse until we find a start-tag as the first thing on a line. The context is a list of tag-info structures. The last one is the tag -immediately enclosing the current position." +immediately enclosing the current position. + +Point is assumed to be outside of any tag. If we discover that it's +not the case, the first tag returned is the one inside which we are." (let ((here (point)) (ignore nil) (context nil) @@ -1101,12 +1109,13 @@ ;; enclosing start-tags we'll have to ignore. (skip-chars-backward " \t\n") ; Make sure we're not at indentation. (while - (and (or ignore - (not (if full (eq full 'empty) context)) + (and (not (eq until 'now)) + (or ignore + (not (if until (eq until 'empty) context)) (not (sgml-at-indentation-p)) (and context (/= (point) (sgml-tag-start (car context))) - (sgml-unclosed-tag-p (sgml-tag-name (car context))))) + (sgml-unclosed-tag-p (sgml-tag-name (car context))))) (setq tag-info (ignore-errors (sgml-parse-tag-backward)))) ;; This tag may enclose things we thought were tags. If so, @@ -1117,6 +1126,10 @@ (setq context (cdr context))) (cond + ((> (sgml-tag-end tag-info) here) + ;; Oops!! Looks like we were not outside of any tag, after all. + (push tag-info context) + (setq until 'now)) ;; start-tag ((eq (sgml-tag-type tag-info) 'open) @@ -1207,99 +1220,113 @@ (and (not sgml-xml-mode) (member-ignore-case tag-name sgml-unclosed-tags))) -(defun sgml-calculate-indent () - "Calculate the column to which this line should be indented." - (let ((lcon (sgml-lexical-context))) +(defun sgml-calculate-indent (&optional lcon) + "Calculate the column to which this line should be indented. +LCON is the lexical context, if any." + (unless lcon (setq lcon (sgml-lexical-context))) + + ;; Indent comment-start markers inside <!-- just like comment-end markers. + (if (and (eq (car lcon) 'tag) + (looking-at "--") + (save-excursion (goto-char (cdr lcon)) (looking-at "<!--"))) + (setq lcon (cons 'comment (+ (cdr lcon) 2)))) + + (case (car lcon) - ;; Indent comment-start markers inside <!-- just like comment-end markers. - (if (and (eq (car lcon) 'tag) - (looking-at "--") - (save-excursion (goto-char (cdr lcon)) (looking-at "<!--"))) - (setq lcon (cons 'comment (+ (cdr lcon) 2)))) + (string + ;; Go back to previous non-empty line. + (while (and (> (point) (cdr lcon)) + (zerop (forward-line -1)) + (looking-at "[ \t]*$"))) + (if (> (point) (cdr lcon)) + ;; Previous line is inside the string. + (current-indentation) + (goto-char (cdr lcon)) + (1+ (current-column)))) - (case (car lcon) - - (string + (comment + (let ((mark (looking-at "--"))) ;; Go back to previous non-empty line. (while (and (> (point) (cdr lcon)) (zerop (forward-line -1)) - (looking-at "[ \t]*$"))) + (or (looking-at "[ \t]*$") + (if mark (not (looking-at "[ \t]*--")))))) (if (> (point) (cdr lcon)) - ;; Previous line is inside the string. - (current-indentation) + ;; Previous line is inside the comment. + (skip-chars-forward " \t") (goto-char (cdr lcon)) - (1+ (current-column)))) + ;; Skip `<!' to get to the `--' with which we want to align. + (search-forward "--") + (goto-char (match-beginning 0))) + (when (and (not mark) (looking-at "--")) + (forward-char 2) (skip-chars-forward " \t")) + (current-column))) - (comment - (let ((mark (looking-at "--"))) - ;; Go back to previous non-empty line. - (while (and (> (point) (cdr lcon)) - (zerop (forward-line -1)) - (or (looking-at "[ \t]*$") - (if mark (not (looking-at "[ \t]*--")))))) - (if (> (point) (cdr lcon)) - ;; Previous line is inside the comment. - (skip-chars-forward " \t") - (goto-char (cdr lcon))) - (when (and (not mark) (looking-at "--")) - (forward-char 2) (skip-chars-forward " \t")) - (current-column))) + ;; We don't know how to indent it. Let's be honest about it. + (cdata nil) - (cdata - (current-column)) - - (tag + (tag + (goto-char (1+ (cdr lcon))) + (skip-chars-forward "^ \t\n") ;Skip tag name. + (skip-chars-forward " \t") + (if (not (eolp)) + (current-column) + ;; This is the first attribute: indent. (goto-char (1+ (cdr lcon))) - (skip-chars-forward "^ \t\n") ;Skip tag name. - (skip-chars-forward " \t") - (if (not (eolp)) - (current-column) - ;; This is the first attribute: indent. - (goto-char (1+ (cdr lcon))) - (+ (current-column) sgml-basic-offset))) + (+ (current-column) sgml-basic-offset))) - (text - (while (looking-at "</") - (forward-sexp 1) - (skip-chars-forward " \t")) - (let* ((here (point)) - (unclosed (and ;; (not sgml-xml-mode) - (looking-at sgml-tag-name-re) - (member-ignore-case (match-string 1) - sgml-unclosed-tags) - (match-string 1))) - (context - ;; If possible, align on the previous non-empty text line. - ;; Otherwise, do a more serious parsing to find the - ;; tag(s) relative to which we should be indenting. - (if (and (not unclosed) (skip-chars-backward " \t") - (< (skip-chars-backward " \t\n") 0) - (back-to-indentation) - (> (point) (cdr lcon))) - nil - (goto-char here) - (nreverse (sgml-get-context (if unclosed nil 'empty))))) - (there (point))) - ;; Ignore previous unclosed start-tag in context. - (while (and context unclosed - (eq t (compare-strings - (sgml-tag-name (car context)) nil nil - unclosed nil nil t))) - (setq context (cdr context))) - ;; Indent to reflect nesting. - (if (and context - (goto-char (sgml-tag-end (car context))) - (skip-chars-forward " \t\n") - (< (point) here) (sgml-at-indentation-p)) - (current-column) - (goto-char there) - (+ (current-column) - (* sgml-basic-offset (length context)))))) + (text + (while (looking-at "</") + (forward-sexp 1) + (skip-chars-forward " \t")) + (let* ((here (point)) + (unclosed (and ;; (not sgml-xml-mode) + (looking-at sgml-tag-name-re) + (member-ignore-case (match-string 1) + sgml-unclosed-tags) + (match-string 1))) + (context + ;; If possible, align on the previous non-empty text line. + ;; Otherwise, do a more serious parsing to find the + ;; tag(s) relative to which we should be indenting. + (if (and (not unclosed) (skip-chars-backward " \t") + (< (skip-chars-backward " \t\n") 0) + (back-to-indentation) + (> (point) (cdr lcon))) + nil + (goto-char here) + (nreverse (sgml-get-context (if unclosed nil 'empty))))) + (there (point))) + ;; Ignore previous unclosed start-tag in context. + (while (and context unclosed + (eq t (compare-strings + (sgml-tag-name (car context)) nil nil + unclosed nil nil t))) + (setq context (cdr context))) + ;; Indent to reflect nesting. + (cond + ;; If we were not in a text context after all, let's try again. + ((and context (> (sgml-tag-end (car context)) here)) + (goto-char here) + (sgml-calculate-indent + (cons (if (memq (sgml-tag-type (car context)) '(comment cdata)) + (sgml-tag-type (car context)) 'tag) + (sgml-tag-start (car context))))) + ;; Align on the first element after the nearest open-tag, if any. + ((and context + (goto-char (sgml-tag-end (car context))) + (skip-chars-forward " \t\n") + (< (point) here) (sgml-at-indentation-p)) + (current-column)) + (t + (goto-char there) + (+ (current-column) + (* sgml-basic-offset (length context))))))) - (otherwise - (error "Unrecognised context %s" (car lcon))) + (otherwise + (error "Unrecognised context %s" (car lcon))) - ))) + )) (defun sgml-indent-line () "Indent the current line as SGML." @@ -1310,9 +1337,11 @@ (back-to-indentation) (if (>= (point) savep) (setq savep nil)) (sgml-calculate-indent)))) - (if savep - (save-excursion (indent-line-to indent-col)) - (indent-line-to indent-col)))) + (if (null indent-col) + 'noindent + (if savep + (save-excursion (indent-line-to indent-col)) + (indent-line-to indent-col))))) (defun sgml-guess-indent () "Guess an appropriate value for `sgml-basic-offset'.