public
Description: HTML Abstraction Markup Language - A Markup Haiku
Homepage: http://haml.hamptoncatlin.com
Clone URL: git://github.com/nex3/haml.git
haml / extra / haml-mode.el
f312b31e » technomancy 2009-01-14 Updated headers for haml-mo... 1 ;;; haml-mode.el --- Major mode for editing Haml files
2
3 ;; Copyright (c) 2007, 2008 Nathan Weizenbaum
4
5 ;; Author: Nathan Weizenbaum
6 ;; URL: http://github.com/nex3/haml/tree/master
25e06a12 » nex3 2009-10-08 Bump the VERSION to 2.2.7. 7 ;; Version: 2.2.7
1e5c070f » gdelfino 2009-04-11 [Emacs] Updated header info... 8 ;; Created: 2007-03-08
9 ;; By: Nathan Weizenbaum
10 ;; Keywords: markup, language, html
f312b31e » technomancy 2009-01-14 Updated headers for haml-mo... 11
12 ;;; Commentary:
13
14 ;; Because Haml's indentation schema is similar
15 ;; to that of YAML and Python, many indentation-related
16 ;; functions are similar to those in yaml-mode and python-mode.
17
18 ;; To install, save this on your load path and add the following to
19 ;; your .emacs file:
20 ;;
21 ;; (require 'haml-mode)
23f8e7d4 » nex3 2007-03-15 Okay, let's fix the massive... 22
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 23 ;;; Code:
24
57d05a12 » nex3 2008-04-22 Add a custom indent-region ... 25 (eval-when-compile (require 'cl))
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 26 (require 'ruby-mode)
57d05a12 » nex3 2008-04-22 Add a custom indent-region ... 27
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 28 ;; User definable variables
29
30 (defgroup haml nil
31 "Support for the Haml template language."
32 :group 'languages
33 :prefix "haml-")
34
35 (defcustom haml-mode-hook nil
4d973434 » nex3 2008-04-22 Clean up haml- and sass-mod... 36 "Hook run when entering Haml mode."
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 37 :type 'hook
38 :group 'haml)
39
40 (defcustom haml-indent-offset 2
4d973434 » nex3 2008-04-22 Clean up haml- and sass-mod... 41 "Amount of offset per level of indentation."
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 42 :type 'integer
43 :group 'haml)
44
7b9c2d5f » nex3 2008-05-04 [Emacs] Have haml-electric-... 45 (defcustom haml-backspace-backdents-nesting t
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 46 "Non-nil to have `haml-electric-backspace' re-indent blocks of code.
47 This means that all code nested beneath the backspaced line is
48 re-indented along with the line itself."
7b9c2d5f » nex3 2008-05-04 [Emacs] Have haml-electric-... 49 :type 'boolean
50 :group 'haml)
51
23f8e7d4 » nex3 2007-03-15 Okay, let's fix the massive... 52 (defface haml-tab-face
d08fc6ed » nex3 2008-04-22 Highlight invalid tabs in h... 53 '((((class color)) (:background "hotpink"))
54 (t (:reverse-video t)))
23f8e7d4 » nex3 2007-03-15 Okay, let's fix the massive... 55 "Face to use for highlighting tabs in Haml files."
56 :group 'faces
57 :group 'haml)
58
839ad959 » nex3 2008-04-24 Further DRY up haml- and sa... 59 (defvar haml-indent-function 'haml-indent-p
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 60 "A function for checking if nesting is allowed.
61 This function should look at the current line and return t
317e2dd7 » nex3 2009-03-06 [Emacs] Allow haml-indent-f... 62 if the next line could be nested within this line.
63
64 The function can also return a positive integer to indicate
65 a specific level to which the current line could be indented.")
839ad959 » nex3 2008-04-24 Further DRY up haml- and sa... 66
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 67 (defconst haml-tag-beg-re
68 "^ *\\(?:[%\\.#][a-z0-9_:\\-]*\\)+\\(?:(.*)\\|{.*}\\|\\[.*\\]\\)*"
69 "A regexp matching the beginning of a Haml tag, through (), {}, and [].")
70
839ad959 » nex3 2008-04-24 Further DRY up haml- and sa... 71 (defvar haml-block-openers
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 72 `(,(concat haml-tag-beg-re "[><]*[ \t]*$")
1400a0b8 » nex3 2009-03-17 [Emacs] Add ~ some places w... 73 "^ *[&!]?[-=~].*do[ \t]*\\(|.*|[ \t]*\\)?$"
6e2fd116 » nex3 2009-05-20 [Emacs] Fix the Haml indent... 74 ,(concat "^ *[&!]?[-=~][ \t]*\\("
4895df91 » nex3 2008-07-28 Add more Ruby block keyword... 75 (regexp-opt '("if" "unless" "while" "until" "else"
76 "begin" "elsif" "rescue" "ensure" "when"))
3e922fbd » nex3 2008-05-10 [Emacs] Make indentation wo... 77 "\\)")
839ad959 » nex3 2008-04-24 Further DRY up haml- and sa... 78 "^ */\\(\\[.*\\]\\)?[ \t]*$"
79 "^ *-#"
80 "^ *:")
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 81 "A list of regexps that match lines of Haml that open blocks.
82 That is, a Haml line that can have text nested beneath it should
83 be matched by a regexp in this list.")
13c868e0 » nex3 2008-04-22 Make sass-mode inherit from... 84
827aaa31 » nex3 2007-03-17 Some syntax highlighting fo... 85 ;; Font lock
2d39c8a3 » nex3 2007-04-02 More haml-mode font stuff. ... 86
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 87 (defun haml-nested-regexp (re)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 88 "Create a regexp to match a block starting with RE.
89 The line containing RE is matched, as well as all lines indented beneath it."
7ecdf694 » nex3 2009-03-17 [Emacs] Make filter- and co... 90 (concat "^\\( *\\)" re "\\(\n\\(?:\\(?:\\1 .*\\| *\\)\n\\)*\\(?:\\1 .*\\| *\\)?\\)?"))
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 91
4d973434 » nex3 2008-04-22 Clean up haml- and sass-mod... 92 (defconst haml-font-lock-keywords
1b694ba8 » nex3 2009-03-17 [Emacs] Treat loud comments... 93 `((,(haml-nested-regexp "\\(?:-#\\|/\\).*") 0 font-lock-comment-face)
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 94 (,(haml-nested-regexp ":\\w+") 0 font-lock-string-face)
3c2d1fc9 » nex3 2009-03-07 [Emacs] Highlight #{ in pre... 95 (haml-highlight-interpolation 1 font-lock-variable-name-face prepend)
0e5c7e1c » nex3 2009-03-06 [Emacs] Highlight interpola... 96 (haml-highlight-ruby-tag 1 font-lock-preprocessor-face)
97 (haml-highlight-ruby-script 1 font-lock-preprocessor-face)
98 ("^ *\\(\t\\)" 1 'haml-tab-face)
99 ("^!!!.*" 0 font-lock-constant-face)
1b694ba8 » nex3 2009-03-17 [Emacs] Treat loud comments... 100 ("| *$" 0 font-lock-string-face)))
827aaa31 » nex3 2007-03-17 Some syntax highlighting fo... 101
1b694ba8 » nex3 2009-03-17 [Emacs] Treat loud comments... 102 (defconst haml-filter-re "^ *:\\w+")
103 (defconst haml-comment-re "^ *\\(?:-\\#\\|/\\)")
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 104
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 105 (defun haml-fontify-region-as-ruby (beg end)
106 "Use Ruby's font-lock variables to fontify the region between BEG and END."
107 (save-excursion
108 (save-match-data
109 (let ((font-lock-keywords ruby-font-lock-keywords)
110 (font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)
743cbeb8 » nex3 2009-03-17 [Emacs] Don't highlight str... 111 font-lock-keywords-only
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 112 font-lock-extend-region-functions
113 font-lock-keywords-case-fold-search)
114 ;; font-lock-fontify-region apparently isn't inclusive,
115 ;; so we have to move the beginning back one char
116 (font-lock-fontify-region (- beg 1) end)))))
117
118 (defun haml-highlight-ruby-script (limit)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 119 "Highlight a Ruby script expression (-, =, or ~).
120 LIMIT works as it does in `re-search-forward'."
25865722 » nex3 2009-03-17 [Emacs] Fully support &= an... 121 (when (re-search-forward "^ *\\(-\\|[&!]?[=~]\\) \\(.*\\)$" limit t)
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 122 (haml-fontify-region-as-ruby (match-beginning 2) (match-end 2))))
123
3e60f704 » nex3 2009-03-06 [Emacs] Factor out some fun... 124 (defun haml-highlight-ruby-tag (limit)
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 125 "Highlight Ruby code within a Haml tag.
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 126 LIMIT works as it does in `re-search-forward'.
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 127
d5b0000a » nex3 2009-03-04 [Emacs] Fontify [] as well. 128 This highlights the tag attributes and object refs of the tag,
129 as well as the script expression (-, =, or ~) following the tag.
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 130
131 For example, this will highlight all of the following:
132 %p{:foo => 'bar'}
d5b0000a » nex3 2009-03-04 [Emacs] Fontify [] as well. 133 %p[@bar]
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 134 %p= 'baz'
d5b0000a » nex3 2009-03-04 [Emacs] Fontify [] as well. 135 %p{:foo => 'bar'}[@bar]= 'baz'"
28d624ff » nex3 2009-03-06 [Emacs] Cleaner way of high... 136 (when (re-search-forward "^ *[%.#]" limit t)
9503ed1b » nex3 2009-05-25 [Emacs] Fix some edge cases. 137 (forward-char -1)
138
139 ;; Highlight tag, classes, and ids
140 (while (haml-move "\\([.#%]\\)[a-z0-9_:\\-]*")
141 (put-text-property (match-beginning 0) (match-end 0) 'face
142 (case (char-after (match-beginning 1))
143 (?% font-lock-function-name-face)
144 (?# font-lock-keyword-face)
145 (?. font-lock-type-face))))
146
147 (block loop
148 (while t
149 (let ((eol (save-excursion (end-of-line) (point))))
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 150 (case (char-after)
151 ;; Highlight obj refs
152 (?\[
153 (let ((beg (point)))
154 (haml-limited-forward-sexp eol)
155 (haml-fontify-region-as-ruby beg (point))))
156 ;; Highlight new attr hashes
157 (?\(
158 (forward-char 1)
9503ed1b » nex3 2009-05-25 [Emacs] Fix some edge cases. 159 (while
160 (and (haml-parse-new-attr-hash
161 (lambda (type beg end)
162 (case type
163 (name (put-text-property beg end 'face font-lock-constant-face))
164 (value (haml-fontify-region-as-ruby beg end)))))
165 (not (eobp)))
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 166 (forward-line 1)
167 (beginning-of-line)))
168 ;; Highlight old attr hashes
169 (?\{
170 (let ((beg (point)))
171 (haml-limited-forward-sexp eol)
172
173 ;; Check for multiline
174 (while (and (eolp) (eq (char-before) ?,) (not (eobp)))
175 (forward-line)
176 (let ((eol (save-excursion (end-of-line) (point))))
177 ;; If no sexps are closed,
178 ;; we're still continuing a multiline hash
179 (if (>= (car (parse-partial-sexp (point) eol)) 0)
180 (end-of-line)
181 ;; If sexps have been closed,
182 ;; set the point at the end of the total sexp
183 (goto-char beg)
184 (haml-limited-forward-sexp eol))))
185
186 (haml-fontify-region-as-ruby (+ 1 beg) (point))))
9503ed1b » nex3 2009-05-25 [Emacs] Fix some edge cases. 187 (t (return-from loop))))))
188
189 ;; Move past end chars
190 (when (looking-at "[<>&!]+") (goto-char (match-end 0)))
191 ;; Highlight script
192 (if (looking-at "\\([=~]\\) \\(.*\\)$")
193 (haml-fontify-region-as-ruby (match-beginning 2) (match-end 2))
194 ;; Give font-lock something to highlight
195 (forward-char -1)
196 (looking-at "\\(\\)"))
197 t))
c5cb722d » nex3 2009-03-05 [Emacs] Highlight Ruby code... 198
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 199 (defun haml-move (re)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 200 "Try matching and moving to the end of regular expression RE.
201 Returns non-nil if the expression was sucessfully matched."
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 202 (when (looking-at re)
203 (goto-char (match-end 0))
204 t))
205
0e5c7e1c » nex3 2009-03-06 [Emacs] Highlight interpola... 206 (defun haml-highlight-interpolation (limit)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 207 "Highlight Ruby interpolation (#{foo}).
208 LIMIT works as it does in `re-search-forward'."
0e5c7e1c » nex3 2009-03-06 [Emacs] Highlight interpola... 209 (when (re-search-forward "\\(#{\\)" limit t)
210 (save-match-data
211 (forward-char -1)
212 (let ((beg (point)))
213 (haml-limited-forward-sexp limit)
214 (haml-fontify-region-as-ruby (+ 1 beg) (point)))
215
216 (when (eq (char-before) ?})
217 (put-text-property (- (point) 1) (point)
218 'face font-lock-variable-name-face))
219 t)))
220
3e60f704 » nex3 2009-03-06 [Emacs] Factor out some fun... 221 (defun haml-limited-forward-sexp (limit &optional arg)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 222 "Move forward using `forward-sexp' or to LIMIT, whichever comes first.
223 With ARG, do it that many times."
3e60f704 » nex3 2009-03-06 [Emacs] Factor out some fun... 224 (let (forward-sexp-function)
225 (condition-case err
226 (save-restriction
227 (narrow-to-region (point) limit)
228 (forward-sexp arg))
229 (scan-error
230 (unless (equal (nth 1 err) "Unbalanced parentheses")
231 (signal 'scan-error (cdr err)))
232 (goto-char limit)))))
233
1ee16d0f » nex3 2009-03-07 [Emacs] Highlight multiline... 234 (defun* haml-extend-region-filters-comments ()
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 235 "Extend the font-lock region to encompass filters and comments."
236 (let ((old-beg font-lock-beg)
237 (old-end font-lock-end))
238 (save-excursion
239 (goto-char font-lock-beg)
240 (beginning-of-line)
241 (unless (or (looking-at haml-filter-re)
242 (looking-at haml-comment-re))
1ee16d0f » nex3 2009-03-07 [Emacs] Highlight multiline... 243 (return-from haml-extend-region-filters-comments))
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 244 (setq font-lock-beg (point))
245 (haml-forward-sexp)
246 (beginning-of-line)
247 (setq font-lock-end (max font-lock-end (point))))
248 (or (/= old-beg font-lock-beg)
249 (/= old-end font-lock-end))))
250
1ee16d0f » nex3 2009-03-07 [Emacs] Highlight multiline... 251 (defun* haml-extend-region-multiline-hashes ()
252 "Extend the font-lock region to encompass multiline attribute hashes."
253 (let ((old-beg font-lock-beg)
254 (old-end font-lock-end))
255 (save-excursion
256 (goto-char font-lock-beg)
257 (let ((attr-props (haml-parse-multiline-attr-hash))
258 multiline-end)
259 (when attr-props
260 (setq font-lock-beg (cdr (assq 'point attr-props)))
261
262 (end-of-line)
263 ;; Move through multiline attrs
264 (when (eq (char-before) ?,)
265 (save-excursion
2c11b40b » nex3 2009-08-27 Get rid of another haml-mod... 266 (while (progn (end-of-line)
267 (and (eq (char-before) ?,) (not (eobp))))
1ee16d0f » nex3 2009-03-07 [Emacs] Highlight multiline... 268 (forward-line))
269
270 (forward-line -1)
271 (end-of-line)
272 (setq multiline-end (point))))
273
274 (goto-char (+ (cdr (assq 'point attr-props))
275 (cdr (assq 'hash-indent attr-props))
276 -1))
277 (haml-limited-forward-sexp
278 (or multiline-end
279 (save-excursion (end-of-line) (point))))
280 (setq font-lock-end (max font-lock-end (point))))))
281 (or (/= old-beg font-lock-beg)
282 (/= old-end font-lock-end))))
283
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 284
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 285 ;; Mode setup
286
2d39c8a3 » nex3 2007-04-02 More haml-mode font stuff. ... 287 (defvar haml-mode-syntax-table
288 (let ((table (make-syntax-table)))
289 (modify-syntax-entry ?: "." table)
290 (modify-syntax-entry ?_ "w" table)
291 table)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 292 "Syntax table in use in `haml-mode' buffers.")
79f3f71b » nex3 2007-03-23 Updated haml-mode, thanks t... 293
4d973434 » nex3 2008-04-22 Clean up haml- and sass-mod... 294 (defvar haml-mode-map
295 (let ((map (make-sparse-keymap)))
296 (define-key map [backspace] 'haml-electric-backspace)
297 (define-key map "\C-?" 'haml-electric-backspace)
36d69ad8 » nex3 2008-11-18 Don't clobber normal sexp f... 298 (define-key map "\C-c\C-f" 'haml-forward-sexp)
299 (define-key map "\C-c\C-b" 'haml-backward-sexp)
300 (define-key map "\C-c\C-u" 'haml-up-list)
301 (define-key map "\C-c\C-d" 'haml-down-list)
302 (define-key map "\C-c\C-k" 'haml-kill-line-and-indent)
13b699a8 » technomancy 2009-01-14 Added haml-output-buffer fu... 303 (define-key map "\C-c\C-r" 'haml-output-region)
304 (define-key map "\C-c\C-l" 'haml-output-buffer)
4d973434 » nex3 2008-04-22 Clean up haml- and sass-mod... 305 map))
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 306
fe46a65d » nex3 2008-11-27 Autoload emacs modes. 307 ;;;###autoload
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 308 (define-derived-mode haml-mode fundamental-mode "Haml"
4d973434 » nex3 2008-04-22 Clean up haml- and sass-mod... 309 "Major mode for editing Haml files.
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 310
311 \\{haml-mode-map}"
79f3f71b » nex3 2007-03-23 Updated haml-mode, thanks t... 312 (set-syntax-table haml-mode-syntax-table)
1ee16d0f » nex3 2009-03-07 [Emacs] Highlight multiline... 313 (add-to-list 'font-lock-extend-region-functions 'haml-extend-region-filters-comments)
314 (add-to-list 'font-lock-extend-region-functions 'haml-extend-region-multiline-hashes)
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 315 (set (make-local-variable 'font-lock-multiline) t)
23f8e7d4 » nex3 2007-03-15 Okay, let's fix the massive... 316 (set (make-local-variable 'indent-line-function) 'haml-indent-line)
57d05a12 » nex3 2008-04-22 Add a custom indent-region ... 317 (set (make-local-variable 'indent-region-function) 'haml-indent-region)
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 318 (set (make-local-variable 'parse-sexp-lookup-properties) t)
0f39b4f2 » nex3 2008-12-11 [Emacs] Add support for com... 319 (setq comment-start "-#")
fe9e7db9 » nex3 2008-10-06 Make sure haml- and sass-mo... 320 (setq indent-tabs-mode nil)
743cbeb8 » nex3 2009-03-17 [Emacs] Don't highlight str... 321 (setq font-lock-defaults '((haml-font-lock-keywords) t t)))
23f8e7d4 » nex3 2007-03-15 Okay, let's fix the massive... 322
f061b66c » nex3 2008-12-11 [Emacs] Add a function for ... 323 ;; Useful functions
324
325 (defun haml-comment-block ()
326 "Comment the current block of Haml code."
327 (interactive)
328 (save-excursion
329 (let ((indent (current-indentation)))
330 (back-to-indentation)
331 (insert "-#")
332 (newline)
333 (indent-to indent)
a961edb1 » nex3 2008-12-15 [Emacs] Add a function for ... 334 (beginning-of-line)
335 (haml-mark-sexp)
336 (haml-reindent-region-by haml-indent-offset))))
337
338 (defun haml-uncomment-block ()
339 "Uncomment the current block of Haml code."
340 (interactive)
341 (save-excursion
342 (beginning-of-line)
343 (while (not (looking-at haml-comment-re))
344 (haml-up-list)
345 (beginning-of-line))
346 (haml-mark-sexp)
347 (kill-line 1)
348 (haml-reindent-region-by (- haml-indent-offset))))
f061b66c » nex3 2008-12-11 [Emacs] Add a function for ... 349
ec90f8cf » febuiles 2008-12-30 Reindent code regions befor... 350 (defun haml-replace-region (start end)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 351 "Replace the current block of Haml code with the HTML equivalent.
352 Called from a program, START and END specify the region to indent."
8a9e0bcb » febuiles 2008-12-29 Adding two new commands to ... 353 (interactive "r")
ec90f8cf » febuiles 2008-12-30 Reindent code regions befor... 354 (save-excursion
355 (goto-char end)
356 (setq end (point-marker))
357 (goto-char start)
358 (let ((ci (current-indentation)))
359 (while (re-search-forward "^ +" end t)
360 (replace-match (make-string (- (current-indentation) ci) ? ))))
361 (shell-command-on-region start end "haml" "haml-output" t)))
362
363 (defun haml-output-region (start end)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 364 "Displays the HTML output for the current block of Haml code.
365 Called from a program, START and END specify the region to indent."
8a9e0bcb » febuiles 2008-12-29 Adding two new commands to ... 366 (interactive "r")
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 367 (kill-new (buffer-substring start end))
ec90f8cf » febuiles 2008-12-30 Reindent code regions befor... 368 (with-temp-buffer
369 (yank)
370 (haml-indent-region (point-min) (point-max))
371 (shell-command-on-region (point-min) (point-max) "haml" "haml-output")))
8a9e0bcb » febuiles 2008-12-29 Adding two new commands to ... 372
13b699a8 » technomancy 2009-01-14 Added haml-output-buffer fu... 373 (defun haml-output-buffer ()
374 "Displays the HTML output for entire buffer."
375 (interactive)
376 (haml-output-region (point-min) (point-max)))
377
b4337e56 » nex3 2008-05-04 [Emacs] Add forward- and ba... 378 ;; Navigation
379
380 (defun haml-forward-through-whitespace (&optional backward)
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 381 "Move the point forward through any whitespace.
382 The point will move forward at least one line, until it reaches
b4337e56 » nex3 2008-05-04 [Emacs] Add forward- and ba... 383 either the end of the buffer or a line with no whitespace.
384
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 385 If BACKWARD is non-nil, move the point backward instead."
b4337e56 » nex3 2008-05-04 [Emacs] Add forward- and ba... 386 (let ((arg (if backward -1 1))
387 (endp (if backward 'bobp 'eobp)))
388 (loop do (forward-line arg)
389 while (and (not (funcall endp))
390 (looking-at "^[ \t]*$")))))
391
392 (defun haml-at-indent-p ()
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 393 "Return non-nil if the point is before any text on the line."
b4337e56 » nex3 2008-05-04 [Emacs] Add forward- and ba... 394 (let ((opoint (point)))
395 (save-excursion
396 (back-to-indentation)
397 (>= (point) opoint))))
398
399 (defun haml-forward-sexp (&optional arg)
400 "Move forward across one nested expression.
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 401 With ARG, do it that many times. Negative arg -N means move
b4337e56 » nex3 2008-05-04 [Emacs] Add forward- and ba... 402 backward across N balanced expressions.
403
404 A sexp in Haml is defined as a line of Haml code as well as any
405 lines nested beneath it."
406 (interactive "p")
407 (or arg (setq arg 1))
408 (if (and (< arg 0) (not (haml-at-indent-p)))
409 (back-to-indentation)
410 (while (/= arg 0)
411 (let ((indent (current-indentation)))
412 (loop do (haml-forward-through-whitespace (< arg 0))
413 while (and (not (eobp))
414 (not (bobp))
415 (> (current-indentation) indent)))
416 (back-to-indentation)
a961edb1 » nex3 2008-12-15 [Emacs] Add a function for ... 417 (setq arg (+ arg (if (> arg 0) -1 1)))))))
b4337e56 » nex3 2008-05-04 [Emacs] Add forward- and ba... 418
419 (defun haml-backward-sexp (&optional arg)
420 "Move backward across one nested expression.
421 With ARG, do it that many times. Negative arg -N means move
422 forward across N balanced expressions.
423
424 A sexp in Haml is defined as a line of Haml code as well as any
425 lines nested beneath it."
426 (interactive "p")
427 (haml-forward-sexp (if arg (- arg) -1)))
428
ca796ea2 » nex3 2008-05-04 [Emacs] Add up-list and dow... 429 (defun haml-up-list (&optional arg)
430 "Move out of one level of nesting.
431 With ARG, do this that many times."
432 (interactive "p")
433 (or arg (setq arg 1))
434 (while (> arg 0)
435 (let ((indent (current-indentation)))
436 (loop do (haml-forward-through-whitespace t)
437 while (and (not (bobp))
438 (>= (current-indentation) indent)))
439 (setq arg (- arg 1))))
440 (back-to-indentation))
441
442 (defun haml-down-list (&optional arg)
443 "Move down one level of nesting.
444 With ARG, do this that many times."
445 (interactive "p")
446 (or arg (setq arg 1))
447 (while (> arg 0)
448 (let ((indent (current-indentation)))
449 (haml-forward-through-whitespace)
450 (when (<= (current-indentation) indent)
451 (haml-forward-through-whitespace t)
452 (back-to-indentation)
453 (error "Nothing is nested beneath this line"))
454 (setq arg (- arg 1))))
455 (back-to-indentation))
456
a961edb1 » nex3 2008-12-15 [Emacs] Add a function for ... 457 (defun haml-mark-sexp ()
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 458 "Mark the next Haml block."
a961edb1 » nex3 2008-12-15 [Emacs] Add a function for ... 459 (let ((forward-sexp-function 'haml-forward-sexp))
460 (mark-sexp)))
461
509165e3 » nex3 2008-05-04 [Emacs] Add a function to k... 462 (defun haml-mark-sexp-but-not-next-line ()
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 463 "Mark the next Haml block, but not the next line.
464 Put the mark at the end of the last line of the sexp rather than
465 the first non-whitespace character of the next line."
a961edb1 » nex3 2008-12-15 [Emacs] Add a function for ... 466 (haml-mark-sexp)
509165e3 » nex3 2008-05-04 [Emacs] Add a function to k... 467 (set-mark
468 (save-excursion
469 (goto-char (mark))
470 (forward-line -1)
471 (end-of-line)
472 (point))))
473
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 474 ;; Indentation and electric keys
475
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 476 (defun* haml-indent-p ()
317e2dd7 » nex3 2009-03-06 [Emacs] Allow haml-indent-f... 477 "Returns t if the current line can have lines nested beneath it."
920102ec » nex3 2009-03-06 [Emacs] Have haml-parse-mul... 478 (let ((attr-props (haml-parse-multiline-attr-hash)))
479 (when attr-props
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 480 (return-from haml-indent-p
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 481 (if (haml-unclosed-attr-hash-p) (cdr (assq 'hash-indent attr-props))
381e8242 » nex3 2009-05-25 [Emacs] Indent multiline at... 482 (list (+ (cdr (assq 'indent attr-props)) haml-indent-offset) nil)))))
839ad959 » nex3 2008-04-24 Further DRY up haml- and sa... 483 (loop for opener in haml-block-openers
484 if (looking-at opener) return t
3e922fbd » nex3 2008-05-10 [Emacs] Make indentation wo... 485 finally return nil))
839ad959 » nex3 2008-04-24 Further DRY up haml- and sa... 486
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 487 (defun* haml-parse-multiline-attr-hash ()
488 "Parses a multiline attribute hash, and returns
920102ec » nex3 2009-03-06 [Emacs] Have haml-parse-mul... 489 an alist with the following keys:
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 490
920102ec » nex3 2009-03-06 [Emacs] Have haml-parse-mul... 491 INDENT is the indentation of the line beginning the hash.
492
493 HASH-INDENT is the indentation of the first character
494 within the attribute hash.
495
496 POINT is the character position at the beginning of the line
497 beginning the hash."
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 498 (save-excursion
499 (while t
500 (beginning-of-line)
1810b981 » nex3 2009-07-27 Get rid of a compile error ... 501 (if (looking-at (concat haml-tag-beg-re "\\([{(]\\)"))
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 502 (progn
503 (goto-char (- (match-end 0) 1))
504 (haml-limited-forward-sexp (save-excursion (end-of-line) (point)))
593c150e » nex3 2009-03-16 [Emacs] Don't loop endlessl... 505 (return-from haml-parse-multiline-attr-hash
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 506 (when (or (string-equal (match-string 1) "(") (eq (char-before) ?,))
507 `((indent . ,(current-indentation))
508 (hash-indent . ,(- (match-end 0) (match-beginning 0)))
509 (point . ,(match-beginning 0))))))
510 (when (bobp) (return-from haml-parse-multiline-attr-hash))
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 511 (forward-line -1)
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 512 (unless (haml-unclosed-attr-hash-p)
513 (return-from haml-parse-multiline-attr-hash))))))
514
515 (defun* haml-unclosed-attr-hash-p ()
516 "Return t if this line has an unclosed attribute hash, new or old."
517 (save-excursion
518 (end-of-line)
519 (when (eq (char-before) ?,) (return-from haml-unclosed-attr-hash-p t))
520 (re-search-backward "(\\|^")
521 (haml-move "(")
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 522 (haml-parse-new-attr-hash)))
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 523
524 (defun* haml-parse-new-attr-hash (&optional (fn (lambda (type beg end) ())))
525 "Parse a new-style attribute hash on this line, and returns
526 t if it's not finished on the current line.
527
528 FN should take three parameters: TYPE, BEG, and END.
529 TYPE is the type of text parsed ('name or 'value)
530 and BEG and END delimit that text in the buffer."
531 (let ((eol (save-excursion (end-of-line) (point))))
9503ed1b » nex3 2009-05-25 [Emacs] Fix some edge cases. 532 (while (not (haml-move ")"))
533 (haml-move " *")
534 (unless (haml-move "[a-z0-9_:\\-]+")
535 (return-from haml-parse-new-attr-hash (haml-move " *$")))
536 (funcall fn 'name (match-beginning 0) (match-end 0))
537 (haml-move " *")
538 (when (haml-move "=")
d1e095bd » nex3 2009-05-25 [Emacs] Support new attribu... 539 (haml-move " *")
9503ed1b » nex3 2009-05-25 [Emacs] Fix some edge cases. 540 (unless (looking-at "[\"'@a-z]") (return-from haml-parse-new-attr-hash))
541 (let ((beg (point)))
542 (haml-limited-forward-sexp eol)
543 (funcall fn 'value beg (point)))
544 (haml-move " *")))
545 nil))
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 546
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 547 (defun haml-compute-indentation ()
548 "Calculate the maximum sensible indentation for the current line."
549 (save-excursion
550 (beginning-of-line)
381e8242 » nex3 2009-05-25 [Emacs] Indent multiline at... 551 (if (bobp) (list 0 nil)
b4337e56 » nex3 2008-05-04 [Emacs] Add forward- and ba... 552 (haml-forward-through-whitespace t)
919f13b5 » nex3 2009-03-06 [Emacs] Properly indent mul... 553 (let ((indent (funcall haml-indent-function)))
554 (cond
381e8242 » nex3 2009-05-25 [Emacs] Indent multiline at... 555 ((consp indent) indent)
556 ((integerp indent) (list indent t))
557 (indent (list (+ (current-indentation) haml-indent-offset) nil))
558 (t (list (current-indentation) nil)))))))
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 559
57d05a12 » nex3 2008-04-22 Add a custom indent-region ... 560 (defun haml-indent-region (start end)
561 "Indent each nonblank line in the region.
562 This is done by indenting the first line based on
839ad959 » nex3 2008-04-24 Further DRY up haml- and sa... 563 `haml-compute-indentation' and preserving the relative
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 564 indentation of the rest of the region. START and END specify the
565 region to indent.
240251c1 » nex3 2008-04-22 Repeating haml-indent-regio... 566
567 If this command is used multiple times in a row, it will cycle
568 between possible indentations."
57d05a12 » nex3 2008-04-22 Add a custom indent-region ... 569 (save-excursion
570 (goto-char end)
571 (setq end (point-marker))
572 (goto-char start)
573 (let (this-line-column current-column
240251c1 » nex3 2008-04-22 Repeating haml-indent-regio... 574 (next-line-column
575 (if (and (equal last-command this-command) (/= (current-indentation) 0))
576 (* (/ (- (current-indentation) 1) haml-indent-offset) haml-indent-offset)
381e8242 » nex3 2009-05-25 [Emacs] Indent multiline at... 577 (car (haml-compute-indentation)))))
57d05a12 » nex3 2008-04-22 Add a custom indent-region ... 578 (while (< (point) end)
579 (setq this-line-column next-line-column
580 current-column (current-indentation))
581 ;; Delete whitespace chars at beginning of line
582 (delete-horizontal-space)
583 (unless (eolp)
584 (setq next-line-column (save-excursion
585 (loop do (forward-line 1)
586 while (and (not (eobp)) (looking-at "^[ \t]*$")))
587 (+ this-line-column
588 (- (current-indentation) current-column))))
589 ;; Don't indent an empty line
590 (unless (eolp) (indent-to this-line-column)))
591 (forward-line 1)))
592 (move-marker end nil)))
593
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 594 (defun haml-indent-line ()
595 "Indent the current line.
596 The first time this command is used, the line will be indented to the
597 maximum sensible indentation. Each immediately subsequent usage will
598 back-dent the line by `haml-indent-offset' spaces. On reaching column
599 0, it will cycle back to the maximum sensible indentation."
600 (interactive "*")
601 (let ((ci (current-indentation))
381e8242 » nex3 2009-05-25 [Emacs] Indent multiline at... 602 (cc (current-column)))
603 (destructuring-bind (need strict) (haml-compute-indentation)
604 (save-excursion
605 (beginning-of-line)
606 (delete-horizontal-space)
607 (if (and (not strict) (equal last-command this-command) (/= ci 0))
608 (indent-to (* (/ (- ci 1) haml-indent-offset) haml-indent-offset))
609 (indent-to need))))
610 (when (< (current-column) (current-indentation))
611 (forward-to-indentation 0))))
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 612
509165e3 » nex3 2008-05-04 [Emacs] Add a function to k... 613 (defun haml-reindent-region-by (n)
614 "Add N spaces to the beginning of each line in the region.
615 If N is negative, will remove the spaces instead. Assumes all
616 lines in the region have indentation >= that of the first line."
617 (let ((ci (current-indentation)))
618 (save-excursion
b21d4966 » nex3 2009-07-18 [Emacs] Remove a warning. 619 (while (re-search-forward (concat "^" (make-string ci ?\s)) (mark) t)
620 (replace-match (make-string (max 0 (+ ci n)) ?\s))))))
509165e3 » nex3 2008-05-04 [Emacs] Add a function to k... 621
04cd0278 » nex3 2007-03-07 Added a handy backspace bin... 622 (defun haml-electric-backspace (arg)
623 "Delete characters or back-dent the current line.
7b9c2d5f » nex3 2008-05-04 [Emacs] Have haml-electric-... 624 If invoked following only whitespace on a line, will back-dent
625 the line and all nested lines to the immediately previous
d3bdfb6f » nex3 2009-09-21 [Emacs] Fix up all the chec... 626 multiple of `haml-indent-offset' spaces. With ARG, do it that
627 many times.
7b9c2d5f » nex3 2008-05-04 [Emacs] Have haml-electric-... 628
629 Set `haml-backspace-backdents-nesting' to nil to just back-dent
630 the current line."
04cd0278 » nex3 2007-03-07 Added a handy backspace bin... 631 (interactive "*p")
7b9c2d5f » nex3 2008-05-04 [Emacs] Have haml-electric-... 632 (if (or (/= (current-indentation) (current-column))
633 (bolp)
634 (looking-at "^[ \t]+$"))
fdb9ff88 » nex3 2008-04-22 Don't allow customization o... 635 (backward-delete-char arg)
36d69ad8 » nex3 2008-11-18 Don't clobber normal sexp f... 636 (save-excursion
637 (let ((ci (current-column)))
638 (beginning-of-line)
639 (if haml-backspace-backdents-nesting
640 (haml-mark-sexp-but-not-next-line)
641 (set-mark (save-excursion (end-of-line) (point))))
642 (haml-reindent-region-by (* (- arg) haml-indent-offset))
643 (back-to-indentation)
644 (pop-mark)))))
04cd0278 » nex3 2007-03-07 Added a handy backspace bin... 645
509165e3 » nex3 2008-05-04 [Emacs] Add a function to k... 646 (defun haml-kill-line-and-indent ()
647 "Kill the current line, and re-indent all lines nested beneath it."
648 (interactive)
649 (beginning-of-line)
650 (haml-mark-sexp-but-not-next-line)
651 (kill-line 1)
652 (haml-reindent-region-by (* -1 haml-indent-offset)))
653
13605b4a » nex3 2008-12-05 [Emacs] Better support for ... 654 (defun haml-indent-string ()
655 "Return the indentation string for `haml-indent-offset'."
656 (mapconcat 'identity (make-list haml-indent-offset " ") ""))
657
1880b877 » technomancy 2009-01-14 Add autoloads for auto-mode... 658 ;;;###autoload
659 (add-to-list 'auto-mode-alist '("\\.haml$" . haml-mode))
04cd0278 » nex3 2007-03-07 Added a handy backspace bin... 660
1880b877 » technomancy 2009-01-14 Add autoloads for auto-mode... 661 ;; Setup/Activation
e7555b40 » nex3 2007-03-07 Added a very basic haml-mod... 662 (provide 'haml-mode)
1880b877 » technomancy 2009-01-14 Add autoloads for auto-mode... 663 ;;; haml-mode.el ends here