Mercurial > emacs
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)) |