22
|
1 ;;; hm--html-indentation.el
|
|
2 ;;; v1.00; 9-Feb-1997
|
|
3 ;;; Copyright (C) 1997 Heiko Muenkel
|
|
4 ;;; email: muenkel@tnt.uni-hannover.de
|
|
5 ;;;
|
|
6 ;;; This program is free software; you can redistribute it and/or modify
|
|
7 ;;; it under the terms of the GNU General Public License as published by
|
|
8 ;;; the Free Software Foundation; either version 1, or (at your option)
|
|
9 ;;; any later version.
|
|
10 ;;;
|
|
11 ;;; This program is distributed in the hope that it will be useful,
|
|
12 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 ;;; GNU General Public License for more details.
|
|
15 ;;;
|
|
16 ;;; You should have received a copy of the GNU General Public License
|
|
17 ;;; along with this program; if not, write to the Free Software
|
|
18 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
19 ;;;
|
|
20 ;;;
|
|
21 ;;; Description:
|
|
22 ;;;
|
|
23 ;;; Defines functions for the indentation.
|
|
24 ;;;
|
|
25 ;;; Installation:
|
|
26 ;;;
|
|
27 ;;; Put this file in one of your load path directories.
|
|
28 ;;;
|
|
29
|
|
30 (defun hm--html-point-between-strings-p (string-1
|
|
31 string-2
|
|
32 &optional boundary)
|
|
33 "Returns non nil, if the current point is between STRING-1 and STRING-2."
|
|
34 (when (and (re-search-backward (concat "\\("
|
|
35 (regexp-quote string-1)
|
|
36 "\\)\\|\\("
|
|
37 (regexp-quote string-2)
|
|
38 "\\)")
|
|
39 boundary
|
|
40 t)
|
|
41 (match-string 1))
|
|
42 (point)))
|
|
43
|
|
44 (defun hm--html-in-comment-p ()
|
|
45 "Checks if the current point is in a comment block.
|
|
46 If this is the case, then the start point of the comment is returned.
|
|
47 Otherwise nil is returned."
|
|
48 (save-excursion
|
|
49 (hm--html-point-between-strings-p comment-start comment-end)))
|
|
50
|
|
51 (defun hm--html-previous-line-start ()
|
|
52 "Returns the start of the previous non blank line."
|
|
53 (save-excursion
|
|
54 (beginning-of-line)
|
|
55 (skip-chars-backward " \t\n")
|
|
56 (beginning-of-line)
|
|
57 (point)))
|
|
58
|
|
59 (defun hm--html-look-at-comment-end-p ()
|
|
60 "T, if the current line starts with the comment end."
|
|
61 (looking-at (regexp-quote comment-end)))
|
|
62
|
|
63 (defun hm--html-column-of-previous-regexp (regexp)
|
|
64 "Returns the column of the start of the previous REGEXP.
|
|
65 It searches backward until the REGEXP is found. If no
|
|
66 REGEXP is found, then it returns 0."
|
|
67 (save-excursion
|
|
68 (if (re-search-backward regexp nil t)
|
|
69 (current-column)
|
|
70 0)))
|
|
71
|
|
72 (defun hm--html-look-at-end-tag-p ()
|
|
73 "Returns the end tag name if the point is at the start of an end tag.
|
|
74 nil is returned otherwise."
|
|
75 (when (looking-at "\\(<[ \t\n]*/[ \t\n]*\\)\\([^ \t\n>]+\\)")
|
|
76 (match-string 2)))
|
|
77
|
|
78
|
|
79 (defun hm--html-previous-line-indentation ()
|
|
80 "Returns the indentation of the previous non blank line."
|
|
81 (save-excursion
|
|
82 (beginning-of-line)
|
|
83 (skip-chars-backward " \t\n")
|
|
84 (back-to-indentation)
|
|
85 (current-column)))
|
|
86
|
|
87 (defun hm--html-in-tag-p ()
|
|
88 "Checks if the current point is in a tag.
|
|
89 If this is the case, then the start point of the tag is returned.
|
|
90 Otherwise nil is returned."
|
|
91 (save-excursion
|
|
92 (let ((start (re-search-backward "\\(<\\)\\|\\(>\\)" nil t)))
|
|
93 (when (match-string 1)
|
|
94 start))))
|
|
95
|
|
96 (defun hm--html-return-beginning-of-line ()
|
|
97 "Returns the beginning of the current line."
|
|
98 (save-excursion
|
|
99 (beginning-of-line)
|
|
100 (point)))
|
|
101
|
|
102 (defun hm--html-return-end-of-line ()
|
|
103 "Returns the end of the current line."
|
|
104 (save-excursion
|
|
105 (end-of-line)
|
|
106 (point)))
|
|
107
|
|
108 (defun hm--html-paramter-column-in-line-after-point (point)
|
|
109 "Returns the column where the second non blank text after POINT starts.
|
|
110 This point must be in the line with POINT otherwise it returns nil."
|
|
111 (save-excursion
|
|
112 (goto-char point)
|
|
113 (when (re-search-forward "<[ \t]*[^ \t]+[ \t]"
|
|
114 (hm--html-return-end-of-line)
|
|
115 t)
|
|
116 (when (looking-at "[^\n]")
|
|
117 (current-column)))))
|
|
118
|
|
119 (defun hm--html-column-of-point (point)
|
|
120 "Returns the column of the POINT."
|
|
121 (save-excursion
|
|
122 (goto-char point)
|
|
123 (current-column)))
|
|
124
|
|
125 (defun hm--html-search-previous-tag-in-current-line ()
|
|
126 "Searches tags from the `(point)' to the beginning of the line.
|
|
127 It returns nil, if there is no tag and the tag name, if there is
|
|
128 a tag. The tag name contains a leading /, if it is an end tag."
|
|
129 (when (re-search-backward ">" (hm--html-return-beginning-of-line) t)
|
|
130 (when (re-search-backward
|
|
131 "\\(<[ \t\n]*\\(/?\\)\\([ \t\n]*[^> \t\n]+\\)[^>]*\\)"
|
|
132 nil
|
|
133 t)
|
|
134 (concat (match-string 2) (match-string 3)))))
|
|
135
|
|
136 (defun hm--html-search-start-tag (tag-name until)
|
|
137 "Searches start tag backwards from the current point until the point UNTIL.
|
|
138 The name of the tag is TAG-NAME. After this function the point is at UNTIL
|
|
139 (then it returns nil) or at the start of the tag, then it returns t."
|
|
140 (if (re-search-backward (concat "\\(<[ \t\n]*\\)\\(/?\\)\\("
|
|
141 tag-name
|
|
142 "\\)\\([^>]*>\\)") until t)
|
|
143 (if (string= "/" (match-string 2))
|
|
144 (progn
|
|
145 (hm--html-search-start-tag tag-name until)
|
|
146 (hm--html-search-start-tag tag-name until))
|
|
147 t)
|
|
148 (goto-char until)
|
|
149 nil))
|
|
150
|
|
151 (defun hm--html-is-one-element-tag-p (tag-name)
|
|
152 "Returns t, if the tag with the tag-name is a one element tag."
|
153
|
153 (assoc ':hm--html-one-element-tag
|
24
|
154 (cdr (assoc* (downcase tag-name)
|
|
155 hm--html-tag-name-alist
|
|
156 :test 'string=))))
|
22
|
157
|
|
158 (defun hm--html-calculate-indent-according-to-previous-tags ()
|
|
159 "Calculate the indent according to the previous tags in this line.
|
|
160 If no tags are found, then nil is returned."
|
|
161 (save-excursion
|
|
162 (let ((tag (hm--html-search-previous-tag-in-current-line)))
|
|
163 (cond ((not tag) nil)
|
|
164
|
|
165 ((eq ?/ (elt tag 0)) ; end tag found
|
|
166 (if (hm--html-search-start-tag
|
|
167 (substring tag 1)
|
|
168 (point-min))
|
|
169 (or (hm--html-calculate-indent-according-to-previous-tags)
|
|
170 (progn
|
|
171 (backward-to-indentation 0)
|
|
172 (current-column)))
|
|
173 0)) ; it may be that the current indentation is better here
|
|
174
|
|
175 ((hm--html-is-one-element-tag-p tag) ; one element tag
|
|
176 (or (hm--html-calculate-indent-according-to-previous-tags)
|
|
177 (progn
|
|
178 (backward-to-indentation 0)
|
|
179 (current-column))))
|
|
180
|
|
181 (t ; start tag found
|
|
182 (+ (current-column) hm--html-inter-tag-indent))))))
|
|
183
|
|
184
|
|
185 (defun hm--html-calculate-indent ()
|
|
186 "Calculate the indentation of the current line."
|
|
187 (let ((match-point)
|
|
188 (tag))
|
|
189 (save-excursion
|
|
190 (beginning-of-line)
|
|
191 (back-to-indentation)
|
|
192 (cond ((eq (count-lines (point-min) (point)) 0) 0) ; Filestart
|
|
193
|
|
194 ((setq match-point (hm--html-in-comment-p)) ; in a comment
|
|
195 (if (>= match-point (hm--html-previous-line-start)) ; 1. line
|
|
196 (if (hm--html-look-at-comment-end-p)
|
|
197 (hm--html-column-of-previous-regexp
|
|
198 (regexp-quote comment-start))
|
|
199 (+ (hm--html-column-of-previous-regexp
|
|
200 (regexp-quote comment-start))
|
|
201 hm--html-comment-indent))
|
|
202 (if (hm--html-look-at-comment-end-p)
|
|
203 (- (hm--html-previous-line-indentation)
|
|
204 hm--html-comment-indent)
|
|
205 (hm--html-previous-line-indentation))))
|
|
206
|
|
207 ((setq tag (hm--html-look-at-end-tag-p)) ; look at end tag
|
|
208 (hm--html-search-start-tag tag (point-min))
|
|
209 (current-column))
|
|
210
|
|
211 ((looking-at ">")
|
|
212 (hm--html-column-of-previous-regexp "<"))
|
|
213
|
|
214 ((setq match-point (hm--html-in-tag-p))
|
|
215 (if (>= match-point (hm--html-previous-line-start)) ; 1. line
|
|
216 (or (hm--html-paramter-column-in-line-after-point match-point)
|
|
217 (+ (hm--html-column-of-point match-point)
|
|
218 hm--html-intra-tag-indent))
|
|
219 (hm--html-previous-line-indentation)))
|
|
220
|
|
221 (t (or (save-excursion ; check previous line
|
|
222 (skip-chars-backward " \t\n")
|
|
223 (hm--html-calculate-indent-according-to-previous-tags))
|
|
224 (hm--html-previous-line-indentation)))
|
|
225 ))))
|
|
226
|
153
|
227
|
|
228 ;;; Indentation commands
|
|
229
|
22
|
230 (defun hm--html-indent-line ()
|
|
231 "Indent the current line line."
|
|
232 (interactive)
|
|
233 (unless hm--html-disable-indentation
|
153
|
234 (let ((pos (- (point-max) (point))))
|
|
235 (indent-line-to (max 0 (hm--html-calculate-indent)))
|
|
236 (when (> (- (point-max) pos) (point))
|
|
237 (goto-char (- (point-max) pos))))))
|
22
|
238
|
153
|
239 ;(defun hm--html-indent-region (begin end)
|
|
240 ; "Indents the region between BEGIN and END according to the major mode."
|
|
241 ; (interactive "d\nm")
|
|
242 ; (when (< end begin)
|
|
243 ; (let ((a end))
|
|
244 ; (setq end begin)
|
|
245 ; (setq begin a)))
|
|
246 ; (save-excursion
|
|
247 ; (goto-char begin)
|
|
248 ; (let ((old-point))
|
|
249 ; (while (and (<= (point) end)
|
|
250 ; (not (eq (point) old-point)))
|
|
251 ; (setq old-point (point))
|
|
252 ; (indent-according-to-mode)
|
|
253 ; (forward-line)
|
|
254 ; ))))
|
22
|
255
|
|
256 (defun hm--html-indent-region (begin end)
|
|
257 "Indents the region between BEGIN and END according to the major mode."
|
|
258 (interactive "d\nm")
|
|
259 (when (< end begin)
|
|
260 (let ((a end))
|
|
261 (setq end begin)
|
|
262 (setq begin a)))
|
153
|
263 (let ((lines (count-lines begin end)))
|
|
264 (save-excursion
|
|
265 (goto-char begin)
|
|
266 (loop repeat lines
|
|
267 do (indent-according-to-mode)
|
|
268 (forward-line))))
|
|
269 )
|
22
|
270
|
|
271 (provide 'hm--html-indentation)
|