File: hm--html-indentation.el

package info (click to toggle)
xemacs20 20.4-13
  • links: PTS
  • area: main
  • in suites: slink
  • size: 67,324 kB
  • ctags: 57,643
  • sloc: lisp: 586,197; ansic: 184,662; sh: 4,296; asm: 3,179; makefile: 2,021; perl: 1,059; csh: 96; sed: 22
file content (271 lines) | stat: -rw-r--r-- 8,808 bytes parent folder | download | duplicates (13)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
;;; hm--html-indentation.el
;;; v1.00;  9-Feb-1997
;;; Copyright (C) 1997 Heiko Muenkel
;;; email: muenkel@tnt.uni-hannover.de
;;;
;;;  This program is free software; you can redistribute it and/or modify
;;;  it under the terms of the GNU General Public License as published by
;;;  the Free Software Foundation; either version 1, or (at your option)
;;;  any later version.
;;;
;;;  This program is distributed in the hope that it will be useful,
;;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;;  GNU General Public License for more details.
;;;
;;;  You should have received a copy of the GNU General Public License
;;;  along with this program; if not, write to the Free Software
;;;  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;;;
;;; 
;;; Description:
;;;
;;;	Defines functions for the indentation.
;;; 
;;; Installation: 
;;;   
;;;	Put this file in one of your load path directories.
;;;

(defun hm--html-point-between-strings-p (string-1
					 string-2
					 &optional boundary)
  "Returns non nil, if the current point is between STRING-1 and STRING-2."
  (when (and (re-search-backward (concat "\\("
					 (regexp-quote string-1)
					 "\\)\\|\\("
					 (regexp-quote string-2)
					 "\\)")
				 boundary
				 t)
	     (match-string 1))
    (point)))

(defun hm--html-in-comment-p ()
  "Checks if the current point is in a comment block.
If this is the case, then the start point of the comment is returned.
Otherwise nil is returned."
  (save-excursion
    (hm--html-point-between-strings-p comment-start comment-end)))

(defun hm--html-previous-line-start ()
  "Returns the start of the previous non blank line."
  (save-excursion
    (beginning-of-line)
    (skip-chars-backward " \t\n")
    (beginning-of-line)
    (point)))

(defun hm--html-look-at-comment-end-p ()
  "T, if the current line starts with the comment end."
  (looking-at (regexp-quote comment-end)))

(defun hm--html-column-of-previous-regexp (regexp)
  "Returns the column of the start of the previous REGEXP.
It searches backward until the REGEXP is found. If no
REGEXP is found, then it returns 0."
  (save-excursion
    (if (re-search-backward regexp nil t)
	(current-column)
      0)))

(defun hm--html-look-at-end-tag-p ()
  "Returns the end tag name if the point is at the start of an end tag.
nil is returned otherwise."
  (when (looking-at "\\(<[ \t\n]*/[ \t\n]*\\)\\([^ \t\n>]+\\)")
    (match-string 2)))
    

(defun hm--html-previous-line-indentation ()
  "Returns the indentation of the previous non blank line."
  (save-excursion
    (beginning-of-line)
    (skip-chars-backward " \t\n")
    (back-to-indentation)
    (current-column)))

(defun hm--html-in-tag-p ()
  "Checks if the current point is in a tag.
If this is the case, then the start point of the tag is returned.
Otherwise nil is returned."
  (save-excursion
    (let ((start (re-search-backward "\\(<\\)\\|\\(>\\)" nil t)))
      (when (match-string 1)
	start))))

(defun hm--html-return-beginning-of-line ()
  "Returns the beginning of the current line."
  (save-excursion
    (beginning-of-line)
    (point)))

(defun hm--html-return-end-of-line ()
  "Returns the end of the current line."
  (save-excursion
    (end-of-line)
    (point)))

(defun hm--html-paramter-column-in-line-after-point (point)
  "Returns the column where the second non blank text after POINT starts.
This point must be in the line with POINT otherwise it returns nil."
  (save-excursion
    (goto-char point)
    (when (re-search-forward "<[ \t]*[^ \t]+[ \t]"
			     (hm--html-return-end-of-line)
			     t)
      (when (looking-at "[^\n]")
	(current-column)))))

(defun hm--html-column-of-point (point)
  "Returns the column of the POINT."
  (save-excursion
    (goto-char point)
    (current-column)))

(defun hm--html-search-previous-tag-in-current-line ()
  "Searches tags from the `(point)' to the beginning of the line.
It returns nil, if there is no tag and the tag name, if there is
a tag. The tag name contains a leading /, if it is an end tag."
  (when (re-search-backward ">" (hm--html-return-beginning-of-line) t)
    (when (re-search-backward
	   "\\(<[ \t\n]*\\(/?\\)\\([ \t\n]*[^> \t\n]+\\)[^>]*\\)"
	   nil
	   t)
      (concat (match-string 2) (match-string 3)))))

(defun hm--html-search-start-tag (tag-name until)
  "Searches start tag backwards from the current point until the point UNTIL.
The name of the tag is TAG-NAME. After this function the point is at UNTIL
 (then it returns nil) or at the start of the tag, then it returns t."
  (if (re-search-backward (concat "\\(<[ \t\n]*\\)\\(/?\\)\\("
				  tag-name 
				  "\\)\\([^>]*>\\)") until t)
      (if (string= "/" (match-string 2))
	  (progn
	    (hm--html-search-start-tag tag-name until)
	    (hm--html-search-start-tag tag-name until)) 
	t)
    (goto-char until)
    nil))

(defun hm--html-is-one-element-tag-p (tag-name)
  "Returns t, if the tag with the tag-name is a one element tag."
  (assoc ':hm--html-one-element-tag
	 (cdr (assoc* (downcase tag-name)
		      hm--html-tag-name-alist
		      :test 'string=))))

(defun hm--html-calculate-indent-according-to-previous-tags ()
  "Calculate the indent according to the previous tags in this line.
If no tags are found, then nil is returned."
  (save-excursion
    (let ((tag (hm--html-search-previous-tag-in-current-line)))
      (cond ((not tag) nil)
	    
	    ((eq ?/ (elt tag 0)) ; end tag found
	     (if (hm--html-search-start-tag 
		  (substring tag 1)
		  (point-min))
		 (or (hm--html-calculate-indent-according-to-previous-tags)
		     (progn
		       (backward-to-indentation 0)
		       (current-column)))
	       0)) ; it may be that the current indentation is better here

	    ((hm--html-is-one-element-tag-p tag) ; one element tag
	     (or (hm--html-calculate-indent-according-to-previous-tags)
		 (progn
		   (backward-to-indentation 0)
		   (current-column))))

	    (t ; start tag found
	     (+ (current-column) hm--html-inter-tag-indent))))))


(defun hm--html-calculate-indent ()
  "Calculate the indentation of the current line."
  (let ((match-point)
	(tag))
    (save-excursion
      (beginning-of-line)
      (back-to-indentation)
      (cond ((eq (count-lines (point-min) (point)) 0) 0) ; Filestart
	    
	    ((setq match-point (hm--html-in-comment-p)) ; in a comment
	     (if (>= match-point (hm--html-previous-line-start)) ; 1. line
		 (if (hm--html-look-at-comment-end-p)
		     (hm--html-column-of-previous-regexp
		      (regexp-quote comment-start))
		   (+ (hm--html-column-of-previous-regexp
		       (regexp-quote comment-start))
		      hm--html-comment-indent))
	       (if (hm--html-look-at-comment-end-p)
		   (- (hm--html-previous-line-indentation)
		      hm--html-comment-indent)
		 (hm--html-previous-line-indentation))))
	    
	    ((setq tag (hm--html-look-at-end-tag-p)) ; look at end tag
	     (hm--html-search-start-tag tag (point-min))
	     (current-column))
	    
	    ((looking-at ">")
	     (hm--html-column-of-previous-regexp "<"))

	    ((setq match-point (hm--html-in-tag-p))
	     (if (>= match-point (hm--html-previous-line-start)) ; 1. line
		 (or (hm--html-paramter-column-in-line-after-point match-point)
		     (+ (hm--html-column-of-point match-point)
			hm--html-intra-tag-indent))
	       (hm--html-previous-line-indentation)))

	    (t (or (save-excursion  ; check previous line
		     (skip-chars-backward " \t\n")
		     (hm--html-calculate-indent-according-to-previous-tags))
		   (hm--html-previous-line-indentation)))
	    ))))


;;; Indentation commands

(defun hm--html-indent-line ()
  "Indent the current line line."
  (interactive)
  (unless hm--html-disable-indentation
    (let ((pos (- (point-max) (point))))
      (indent-line-to (max 0 (hm--html-calculate-indent)))
      (when (> (- (point-max) pos) (point))
	(goto-char (- (point-max) pos))))))

;(defun hm--html-indent-region (begin end)
;  "Indents the region between BEGIN and END according to the major mode."
;  (interactive "d\nm")
;  (when (< end begin)
;    (let ((a end))
;      (setq end begin)
;      (setq begin a)))
;  (save-excursion
;    (goto-char begin)
;    (let ((old-point))
;      (while (and (<= (point) end)
;		  (not (eq (point) old-point)))
;	(setq old-point (point))
;	(indent-according-to-mode)
;	(forward-line)
;	))))

(defun hm--html-indent-region (begin end)
  "Indents the region between BEGIN and END according to the major mode."
  (interactive "d\nm")
  (when (< end begin)
    (let ((a end))
      (setq end begin)
      (setq begin a)))
  (let ((lines (count-lines begin end)))
    (save-excursion
      (goto-char begin)
      (loop repeat lines
            do (indent-according-to-mode)
            (forward-line))))
  )

(provide 'hm--html-indentation)