comparison lisp/textmodes/sgml-mode.el @ 44244:31f1fc31fd45

(sgml-lexical-context): Return (text . START) instead of nil when point is outside of any tag. (sgml-beginning-of-tag): Adjust to the change. (sgml-calculate-indent): Use the new info returned by sgml-lexical-context. Try to handle unclosed tags.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Fri, 29 Mar 2002 22:20:15 +0000
parents 600b7e53cf18
children 1d7ee8515c45
comparison
equal deleted inserted replaced
44243:c3ee131a3ab1 44244:31f1fc31fd45
844 844
845 845
846 (defun sgml-lexical-context (&optional limit) 846 (defun sgml-lexical-context (&optional limit)
847 "Return the lexical context at point as (TYPE . START). 847 "Return the lexical context at point as (TYPE . START).
848 START is the location of the start of the lexical element. 848 START is the location of the start of the lexical element.
849 TYPE is one of `string', `comment', `tag', `cdata', .... 849 TYPE is one of `string', `comment', `tag', or `text'.
850 Return nil if we are inside text (i.e. outside of any kind of tag).
851 850
852 If non-nil LIMIT is a nearby position before point outside of any tag." 851 If non-nil LIMIT is a nearby position before point outside of any tag."
853 ;; As usual, it's difficult to get a reliable answer without parsing the 852 ;; As usual, it's difficult to get a reliable answer without parsing the
854 ;; whole buffer. We'll assume that a tag at indentation is outside of 853 ;; whole buffer. We'll assume that a tag at indentation is outside of
855 ;; any string or tag or comment or ... 854 ;; any string or tag or comment or ...
856 (save-excursion 855 (save-excursion
857 (let ((pos (point)) 856 (let ((pos (point))
858 (state nil)) 857 (state nil)
858 textstart)
859 (if limit (goto-char limit) 859 (if limit (goto-char limit)
860 ;; Hopefully this regexp will match something that's not inside 860 ;; Hopefully this regexp will match something that's not inside
861 ;; a tag and also hopefully the match is nearby. 861 ;; a tag and also hopefully the match is nearby.
862 (re-search-backward "^[ \t]*<[_:[:alpha:]/%!?#]" nil 'move)) 862 (re-search-backward "^[ \t]*<[_:[:alpha:]/%!?#]" nil 'move))
863 (setq textstart (point))
863 (with-syntax-table sgml-tag-syntax-table 864 (with-syntax-table sgml-tag-syntax-table
864 (while (< (point) pos) 865 (while (< (point) pos)
865 ;; When entering this loop we're inside text. 866 ;; When entering this loop we're inside text.
867 (setq textstart (point))
866 (skip-chars-forward "^<" pos) 868 (skip-chars-forward "^<" pos)
867 ;; We skipped text and reached a tag. Parse it. 869 ;; We skipped text and reached a tag. Parse it.
868 ;; FIXME: this does not handle CDATA and funny stuff yet. 870 ;; FIXME: Handle net-enabling start-tags and <![CDATA[ ...]]>.
869 (setq state (parse-partial-sexp (point) pos 0))) 871 (setq state (parse-partial-sexp (point) pos 0)))
870 (cond 872 (cond
871 ((nth 3 state) (cons 'string (nth 8 state))) 873 ((nth 3 state) (cons 'string (nth 8 state)))
872 ((nth 4 state) (cons 'comment (nth 8 state))) 874 ((nth 4 state) (cons 'comment (nth 8 state)))
873 ((and state (> (nth 0 state) 0)) (cons 'tag (nth 1 state))) 875 ((and state (> (nth 0 state) 0)) (cons 'tag (nth 1 state)))
874 (t nil)))))) 876 (t (cons 'text textstart)))))))
875 877
876 (defun sgml-beginning-of-tag (&optional top-level) 878 (defun sgml-beginning-of-tag (&optional top-level)
877 "Skip to beginning of tag and return its name. 879 "Skip to beginning of tag and return its name.
878 If this can't be done, return nil." 880 If this can't be done, return nil."
879 (let ((context (sgml-lexical-context))) 881 (let ((context (sgml-lexical-context)))
881 (progn 883 (progn
882 (goto-char (cdr context)) 884 (goto-char (cdr context))
883 (when (looking-at sgml-tag-name-re) 885 (when (looking-at sgml-tag-name-re)
884 (match-string-no-properties 1))) 886 (match-string-no-properties 1)))
885 (if top-level nil 887 (if top-level nil
886 (when context 888 (when (not (eq (car context) 'text))
887 (goto-char (cdr context)) 889 (goto-char (cdr context))
888 (sgml-beginning-of-tag t)))))) 890 (sgml-beginning-of-tag t))))))
889 891
890 (defun sgml-value (alist) 892 (defun sgml-value (alist)
891 "Interactively insert value taken from attributerule ALIST. 893 "Interactively insert value taken from attributerule ALIST.
966 (current-column) 968 (current-column)
967 ;; This is the first attribute: indent. 969 ;; This is the first attribute: indent.
968 (goto-char (1+ (cdr lcon))) 970 (goto-char (1+ (cdr lcon)))
969 (+ (current-column) sgml-basic-offset))) 971 (+ (current-column) sgml-basic-offset)))
970 972
971 (t 973 (t ;; text
972 (while (looking-at "</") 974 (while (looking-at "</")
973 (forward-sexp 1) 975 (forward-sexp 1)
974 (skip-chars-forward " \t")) 976 (skip-chars-forward " \t"))
975 (let ((context (xml-lite-get-context))) 977 (let* ((here (point))
976 (cond 978 (unclosed (and ;; (not sgml-xml-mode)
977 ((null context) 0) ; no context 979 (looking-at sgml-tag-name-re)
978 (t 980 (member-ignore-case (match-string 1)
979 (let ((here (point))) 981 sgml-unclosed-tags)
980 (goto-char (xml-lite-tag-end (car context))) 982 (match-string 1)))
981 (skip-chars-forward " \t\n") 983 (context
982 (if (and (< (point) here) (xml-lite-at-indentation-p)) 984 ;; If possible, align on the previous non-empty text line.
983 (current-column) 985 ;; Otherwise, do a more serious parsing to find the
984 (goto-char (xml-lite-tag-start (car context))) 986 ;; tag(s) relative to which we should be indenting.
985 (+ (current-column) 987 (if (and (not unclosed) (skip-chars-backward " \t")
986 (* sgml-basic-offset (length context)))))))))))) 988 (< (skip-chars-backward " \t\n") 0)
989 (back-to-indentation)
990 (> (point) (cdr lcon)))
991 nil
992 (goto-char here)
993 (nreverse (xml-lite-get-context (if unclosed nil 'empty)))))
994 (there (point)))
995 ;; Ignore previous unclosed start-tag in context.
996 (while (and context unclosed
997 (eq t (compare-strings
998 (xml-lite-tag-name (car context)) nil nil
999 unclosed nil nil t)))
1000 (setq context (cdr context)))
1001 ;; Indent to reflect nesting.
1002 (if (and context
1003 (goto-char (xml-lite-tag-end (car context)))
1004 (skip-chars-forward " \t\n")
1005 (< (point) here) (xml-lite-at-indentation-p))
1006 (current-column)
1007 (goto-char there)
1008 (+ (current-column)
1009 (* sgml-basic-offset (length context)))))))))
987 1010
988 (defun sgml-indent-line () 1011 (defun sgml-indent-line ()
989 "Indent the current line as SGML." 1012 "Indent the current line as SGML."
990 (interactive) 1013 (interactive)
991 (let* ((savep (point)) 1014 (let* ((savep (point))