Mercurial > emacs
annotate lisp/textmodes/xml-lite.el @ 44180:e7a365c909ff
Don't require `custom'.
(xml-lite-parse-tag-name): Properly treat non-ASCII chars.
(xml-lite-parse-tag-backward): Obey sgml-empty-tags.
(xml-lite-get-context): Drop nested tags not just for comments.
(xml-lite-indent-line): Be more careful about moving point.
(xml-lite-insert-end-tag, xml-lite-slash):
Use indent-according-to-mode instead of xml-lite-indent-line.
(xml-lite-mode): Make xml-lite-orig-indent-line-function buffer-local.
Set sgml-xml-mode. Don't call force-mode-line-update.
(xml-lite-mode-map): Don't bind TAB.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Wed, 27 Mar 2002 18:02:36 +0000 |
parents | 68fd324f9f0f |
children | 65437de0940f |
rev | line source |
---|---|
43687 | 1 ;;; xml-lite.el --- an indentation-engine for XML |
2 | |
3 ;; Copyright (C) 2001 Mike Williams <mdub@bigfoot.com> | |
4 | |
5 ;; Author: Mike Williams <mdub@bigfoot.com> | |
6 ;; Created: February 2001 | |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
7 ;; Version: $Revision: 1.2 $ |
43687 | 8 ;; Keywords: xml |
9 | |
10 ;; This file is part of GNU Emacs. | |
11 | |
12 ;; This program is free software; you can redistribute it and/or modify | |
13 ;; it under the terms of the GNU General Public License as published by | |
14 ;; the Free Software Foundation; either version 2 of the License, or | |
15 ;; (at your option) any later version. | |
16 ;; | |
17 ;; This program is distributed in the hope that it will be useful, | |
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 ;; GNU General Public License for more details. | |
21 ;; | |
22 ;; You should have received a copy of the GNU General Public License | |
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
25 ;; Boston, MA 02111-1307, USA. | |
26 | |
27 ;;; Commentary: | |
28 ;; | |
29 ;; This package provides a simple indentation engine for XML. It is | |
30 ;; intended for use in situations where the full power of the popular PSGML | |
31 ;; package (DTD parsing, syntax checking) is not required. | |
32 ;; | |
33 ;; xml-lite is designed to be used in conjunction with the default GNU | |
34 ;; Emacs sgml-mode, to provide a lightweight XML-editing environment. | |
35 ;; | |
36 ;; Updates will be made available at: | |
37 ;; http://www.bigfoot.com/~mdub/software/xml-lite.el | |
38 ;; | |
39 ;; Note: the font-lock support that was in this package has been removed. | |
40 | |
41 ;;; Thanks: | |
42 ;; | |
43 ;; Jens Schmidt <Jens.Schmidt@oracle.com> | |
44 ;; for his feedback and suggestions | |
45 | |
46 ;;; Code: | |
47 | |
48 (eval-when-compile (require 'cl)) | |
49 (require 'sgml-mode) | |
50 | |
51 | |
52 ;; Variables | |
53 | |
54 (defgroup xml-lite nil | |
55 "Customizable variables for XML-Lite mode." | |
56 :group 'languages | |
57 ) | |
58 | |
59 (defcustom xml-lite-indent-offset 4 | |
60 "*Specifies the default indentation level for `xml-lite-indent-line'." | |
61 :type 'integer | |
62 :group 'xml-lite | |
63 ) | |
64 | |
65 (defcustom xml-lite-indent-comment-offset 5 | |
66 "*Specifies the indentation level for XML comments." | |
67 :type 'integer | |
68 :group 'xml-lite | |
69 ) | |
70 | |
71 (defcustom xml-lite-electric-slash 'close | |
72 "*If non-nil, inserting a '/' after a '<' behaves electrically. | |
73 If set to `indent', typing '</' just triggers reindentation. | |
74 If set to `close', typing '</' inserts an end-tag for the | |
75 enclosing XML element." | |
76 :type '(choice (const :tag "Indent" indent) | |
77 | |
78 (const :tag "Close" close) | |
79 (const :tag "No" nil)) | |
80 | |
81 :group 'xml-lite | |
82 ) | |
83 | |
84 (defcustom xml-lite-mode-line-string " XML" | |
85 "*String to display in the modeline when `xml-lite-mode' is active. | |
86 Set this to nil if you don't want a modeline indicator for xml-lite-mode." | |
87 :type 'string | |
88 :group 'xml-lite) | |
89 | |
90 (defcustom xml-lite-mode-hook nil | |
91 "*Hook called by `xml-lite-mode'." | |
92 :type 'hook | |
93 :group 'xml-lite) | |
94 | |
95 ;;;###autoload | |
96 (defvar xml-lite-mode nil | |
97 "Non-nil if `xml-lite-mode' is enabled.") | |
98 (make-variable-buffer-local 'xml-lite-mode) | |
99 | |
100 | |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
101 ;; Syntax analysis |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
102 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
103 (defsubst xml-lite-at-indentation-p () |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
104 "Return true if point is at the first non-whitespace character on the line." |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
105 (save-excursion |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
106 (skip-chars-backward " \t") |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
107 (bolp))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
108 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
109 (defun xml-lite-in-string-p (&optional limit) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
110 "Determine whether point is inside a string." |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
111 (let (syntax-info) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
112 (or limit |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
113 (setq limit (or (save-excursion |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
114 (re-search-backward "^[ \t]*<" nil t)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
115 (point-min)))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
116 (setq syntax-info (parse-partial-sexp limit (point))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
117 (if (nth 3 syntax-info) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
118 (list (nth 3 syntax-info) (nth 8 syntax-info))))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
119 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
120 |
43687 | 121 ;; Parsing |
122 | |
123 (defstruct (xml-lite-tag | |
124 (:constructor xml-lite-make-tag (type start end name name-end))) | |
125 type start end name name-end) | |
126 | |
127 (defsubst xml-lite-parse-tag-name () | |
128 "Skip past a tag-name, and return the name." | |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
129 (buffer-substring-no-properties |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
130 (point) (progn (skip-syntax-forward "w_") (point)))) |
43687 | 131 |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
132 (defsubst xml-lite-looking-back-at (s) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
133 (let ((limit (max (- (point) (length s)) (point-min)))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
134 (equal s (buffer-substring-no-properties limit (point))))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
135 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
136 (defsubst xml-lite-looking-at (s) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
137 (let ((limit (min (+ (point) (length s))))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
138 (equal s (buffer-substring-no-properties (point) limit)))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
139 |
43687 | 140 (defun xml-lite-parse-tag-backward () |
141 "Get information about the parent tag." | |
142 (let ((limit (point)) | |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
143 tag-type tag-start tag-end name name-end) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
144 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
145 (cond |
43687 | 146 |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
147 ((null (re-search-backward "[<>]" nil t))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
148 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
149 ((= ?> (char-after)) ;--- found tag-end --- |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
150 (setq tag-end (1+ (point))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
151 (goto-char tag-end) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
152 (cond |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
153 ((xml-lite-looking-back-at "--") ; comment |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
154 (setq tag-type 'comment |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
155 tag-start (search-backward "<!--" nil t))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
156 ((xml-lite-looking-back-at "]]>") ; cdata |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
157 (setq tag-type 'cdata |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
158 tag-start (search-backward "![CDATA[" nil t))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
159 (t |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
160 (setq tag-start |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
161 (ignore-errors (backward-sexp) (point)))))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
162 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
163 ((= ?< (char-after)) ;--- found tag-start --- |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
164 (setq tag-start (point)) |
43687 | 165 (goto-char (1+ tag-start)) |
166 (cond | |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
167 ((xml-lite-looking-at "!--") ; comment |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
168 (setq tag-type 'comment |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
169 tag-end (search-forward "-->" nil t))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
170 ((xml-lite-looking-at "![CDATA[") ; cdata |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
171 (setq tag-type 'cdata |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
172 tag-end (search-forward "]]>" nil t))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
173 (t |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
174 (goto-char tag-start) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
175 (setq tag-end |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
176 (ignore-errors (forward-sexp) (point)))))) |
43687 | 177 |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
178 ) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
179 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
180 (cond |
43687 | 181 |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
182 ((or tag-type (null tag-start))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
183 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
184 ((= ?! (char-after (1+ tag-start))) ; declaration |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
185 (setq tag-type 'decl)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
186 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
187 ((= ?? (char-after (1+ tag-start))) ; processing-instruction |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
188 (setq tag-type 'pi)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
189 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
190 ((= ?/ (char-after (1+ tag-start))) ; close-tag |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
191 (goto-char (+ 2 tag-start)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
192 (setq tag-type 'close |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
193 name (xml-lite-parse-tag-name) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
194 name-end (point))) |
43687 | 195 |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
196 ((member ; JSP tags etc |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
197 (char-after (1+ tag-start)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
198 '(?% ?#)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
199 (setq tag-type 'unknown)) |
43687 | 200 |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
201 (t |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
202 (goto-char (1+ tag-start)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
203 (setq tag-type 'open |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
204 name (xml-lite-parse-tag-name) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
205 name-end (point)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
206 ;; check whether it's an empty tag |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
207 (if (or (and tag-end (eq ?/ (char-before (- tag-end 1)))) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
208 (and (not sgml-xml-mode) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
209 (member-ignore-case name sgml-empty-tags))) |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
210 (setq tag-type 'empty)))) |
43687 | 211 |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
212 (cond |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
213 (tag-start |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
214 (goto-char tag-start) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
215 (xml-lite-make-tag tag-type tag-start tag-end name name-end))))) |
43687 | 216 |
217 (defsubst xml-lite-inside-tag-p (tag-info &optional point) | |
218 "Return true if TAG-INFO contains the POINT." | |
219 (let ((end (xml-lite-tag-end tag-info)) | |
220 (point (or point (point)))) | |
221 (or (null end) | |
222 (> end point)))) | |
223 | |
224 (defun xml-lite-get-context (&optional full) | |
225 "Determine the context of the current position. | |
226 If FULL is non-nil, parse back to the beginning of the buffer, otherwise | |
227 parse until we find a start-tag as the first thing on a line. | |
228 | |
229 The context is a list of tag-info structures. The last one is the tag | |
230 immediately enclosing the current position." | |
231 (let ((here (point)) | |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
232 (ignore-depth 0) |
43687 | 233 tag-info context) |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
234 ;; CONTEXT keeps track of the tag-stack |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
235 ;; IGNORE-DEPTH keeps track of the nesting level of point relative to the |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
236 ;; first (outermost) tag on the context. This is the number of |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
237 ;; enclosing start-tags we'll have to ignore. |
43687 | 238 (save-excursion |
239 | |
240 (while | |
241 (and (or (not context) | |
242 full | |
243 (not (xml-lite-at-indentation-p))) | |
244 (setq tag-info (xml-lite-parse-tag-backward))) | |
245 | |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
246 ;; This tag may enclose things we thought were tags. If so, |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
247 ;; discard them. |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
248 (while (and context |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
249 (> (xml-lite-tag-end tag-info) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
250 (xml-lite-tag-end (car context)))) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
251 (setq context (cdr context))) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
252 |
43687 | 253 (cond |
254 | |
255 ;; inside a tag ... | |
256 ((xml-lite-inside-tag-p tag-info here) | |
257 (setq context (cons tag-info context))) | |
258 | |
259 ;; start-tag | |
260 ((eq (xml-lite-tag-type tag-info) 'open) | |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
261 (setq ignore-depth (1- ignore-depth)) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
262 (when (= ignore-depth -1) |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
263 (push tag-info context) |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
264 (setq ignore-depth 0))) |
43687 | 265 |
266 ;; end-tag | |
267 ((eq (xml-lite-tag-type tag-info) 'close) | |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
268 (setq ignore-depth (1+ ignore-depth))) |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
269 |
43687 | 270 ))) |
271 | |
272 ;; return context | |
273 context | |
274 )) | |
275 | |
276 (defun xml-lite-show-context (&optional full) | |
277 "Display the current context. | |
278 If FULL is non-nil, parse back to the beginning of the buffer." | |
279 (interactive "P") | |
280 (with-output-to-temp-buffer "*XML Context*" | |
281 (pp (xml-lite-get-context full)))) | |
282 | |
283 | |
284 ;; Indenting | |
285 | |
286 (defun xml-lite-calculate-indent () | |
287 "Calculate the column to which this line should be indented." | |
288 (let* ((here (point)) | |
289 (context (xml-lite-get-context)) | |
290 (ref-tag-info (car context)) | |
291 (last-tag-info (car (last context)))) | |
292 | |
293 (save-excursion | |
294 (cond | |
295 | |
296 ;; no context | |
297 ((null context) | |
298 0) | |
299 | |
300 ;; inside a comment | |
301 ((eq 'comment (xml-lite-tag-type last-tag-info)) | |
302 (goto-char (xml-lite-tag-start last-tag-info)) | |
303 (+ (current-column) xml-lite-indent-comment-offset)) | |
304 | |
305 ;; inside a tag | |
306 ((xml-lite-inside-tag-p last-tag-info here) | |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
307 |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
308 (let ((in-string |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
309 (xml-lite-in-string-p (xml-lite-tag-start last-tag-info)))) |
43687 | 310 (cond |
311 ;; inside a string | |
44168
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
312 (in-string |
68fd324f9f0f
(xml-lite-at-indentation-p): Move.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
43687
diff
changeset
|
313 (goto-char (nth 1 in-string)) |
43687 | 314 (1+ (current-column))) |
315 ;; if we have a tag-name, base indent on that | |
316 ((and (xml-lite-tag-name-end last-tag-info) | |
317 (progn | |
318 (goto-char (xml-lite-tag-name-end last-tag-info)) | |
319 (not (looking-at "[ \t]*$")))) | |
320 (1+ (current-column))) | |
321 ;; otherwise, add indent-offset | |
322 (t | |
323 (goto-char (xml-lite-tag-start last-tag-info)) | |
324 (+ (current-column) xml-lite-indent-offset))))) | |
325 | |
326 ;; inside an element | |
327 (t | |
328 ;; indent to start of tag | |
329 (let ((here (point)) | |
330 indent-col) | |
331 (goto-char (xml-lite-tag-start ref-tag-info)) | |
332 (setq indent-col (current-column)) | |
333 (goto-char here) | |
334 ;; add xml-lite-indent-offset, unless we're looking at the matching | |
335 ;; end-tag | |
336 (unless (and (eq (length context) 1) (looking-at "</")) | |
337 (setq indent-col (+ indent-col xml-lite-indent-offset))) | |
338 indent-col)) | |
339 | |
340 )))) | |
341 | |
342 (defun xml-lite-indent-line () | |
343 "Indent the current line as XML." | |
344 (interactive) | |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
345 (let* ((savep (point)) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
346 (indent-col |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
347 (save-excursion |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
348 (beginning-of-line) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
349 (skip-chars-forward " \t") |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
350 (if (>= (point) savep) (setq savep nil)) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
351 ;; calculate basic indent |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
352 (xml-lite-calculate-indent)))) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
353 (if savep |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
354 (save-excursion (indent-line-to indent-col)) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
355 (indent-line-to indent-col)))) |
43687 | 356 |
357 | |
358 ;; Editing shortcuts | |
359 | |
360 (defun xml-lite-insert-end-tag () | |
361 "Insert an end-tag for the current element." | |
362 (interactive) | |
363 (let* ((context (xml-lite-get-context)) | |
364 (tag-info (car (last context))) | |
365 (type (and tag-info (xml-lite-tag-type tag-info)))) | |
366 | |
367 (cond | |
368 | |
369 ((null context) | |
370 (error "Nothing to close")) | |
371 | |
372 ;; inside a tag | |
373 ((xml-lite-inside-tag-p tag-info) | |
374 (cond | |
375 ((eq type 'open) (insert " />")) | |
376 ((eq type 'comment) (insert " -->")) | |
377 ((eq type 'cdata) (insert "]]>")) | |
378 ((eq type 'jsp) (insert "%>")) | |
379 ((eq type 'pi) (insert "?>")) | |
380 (t (insert ">")))) | |
381 | |
382 ;; inside an element | |
383 ((eq type 'open) | |
384 (insert "</" (xml-lite-tag-name tag-info) ">") | |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
385 (indent-according-to-mode)) |
43687 | 386 |
387 (t | |
388 (error "Nothing to close"))))) | |
389 | |
390 (defun xml-lite-slash (arg) | |
391 "Insert ARG slash characters. | |
392 Behaves electrically if `xml-lite-electric-slash' is non-nil." | |
393 (interactive "p") | |
394 (cond | |
395 ((not (and (eq (char-before) ?<) (= arg 1))) | |
396 (insert-char ?/ arg)) | |
397 ((eq xml-lite-electric-slash 'indent) | |
398 (insert-char ?/ 1) | |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
399 (indent-according-to-mode)) |
43687 | 400 ((eq xml-lite-electric-slash 'close) |
401 (delete-backward-char 1) | |
402 (xml-lite-insert-end-tag)) | |
403 (t | |
404 (insert-char ?/ arg)))) | |
405 | |
406 | |
407 ;; Keymap | |
408 | |
409 (defvar xml-lite-mode-map | |
410 (let ((map (make-sparse-keymap))) | |
411 (define-key map "\C-c/" 'xml-lite-insert-end-tag) | |
412 (define-key map "\C-c\C-s" 'xml-lite-show-context) | |
413 (define-key map "/" 'xml-lite-slash) | |
414 map) | |
415 "Key bindings for `xml-lite-mode'.") | |
416 | |
417 | |
418 ;; Minor mode | |
419 | |
420 ;;;###autoload | |
421 (define-minor-mode xml-lite-mode | |
422 "Toggle `xml-lite-mode'. | |
423 With ARG, enable xml-lite-mode if and only if ARG is positive. | |
424 | |
425 xml-lite-mode provides indentation for XML tags. The value of | |
426 `xml-lite-indent-offset' determines the amount of indentation. | |
427 | |
428 Key bindings: | |
429 \\{xml-lite-mode-map}" | |
430 nil ; initial value | |
431 " XML" ; mode indicator | |
432 'xml-lite-mode-map ; keymap | |
433 (if xml-lite-mode | |
434 (progn | |
44180
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
435 (if (eq major-mode 'fundamental-mode) (sgml-mode)) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
436 (set (make-local-variable 'sgml-xml-mode) t) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
437 (set (make-local-variable 'xml-lite-orig-indent-line-function) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
438 indent-line-function) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
439 (set (make-local-variable 'indent-line-function) 'xml-lite-indent-line)) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
440 (kill-local-variable 'sgml-xml-mode) |
e7a365c909ff
Don't require `custom'.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
44168
diff
changeset
|
441 (setq indent-line-function xml-lite-orig-indent-line-function))) |
43687 | 442 |
443 (provide 'xml-lite) | |
444 | |
445 ;;; xml-lite.el ends here |