gohanlonllc-haml 2.1.0 → 2.1.0.20080513000000

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ /coverage
2
+ /rdoc
3
+ /pkg
4
+ /test/rails
data/FAQ ADDED
@@ -0,0 +1,138 @@
1
+ = Frequently Asked Questions
2
+
3
+ == Haml
4
+
5
+ === How do I put a punctuation mark after an element, like "<tt>I like <strong>cake</strong>!</tt>"?
6
+
7
+ Expressing the structure of a document
8
+ and expressing inline formatting are two very different problems.
9
+ Haml is mostly designed for structure,
10
+ so the best way to deal with formatting is to leave it to other languages
11
+ that are designed for it.
12
+ You could use Textile:
13
+
14
+ %p
15
+ :textile
16
+ I like *cake*!
17
+
18
+ or Markdown:
19
+
20
+ %p
21
+ :markdown
22
+ I like **cake**!
23
+
24
+ or plain old XHTML:
25
+
26
+ %p I like <strong>cake</strong>!
27
+
28
+ If you're inserting something that's generated by a helper, like a link,
29
+ then it's even easier:
30
+
31
+ %p== I like #{link_to 'chocolate', 'http://franschocolates.com'}!
32
+
33
+ === How do I stop Haml from indenting the contents of my +pre+ and +textarea+ tags?
34
+
35
+ Because Haml automatically indents the HTML source code,
36
+ the contents of whitespace-sensitive tags like +pre+ and +textarea+
37
+ can get screwed up.
38
+ The solution is to replace the newlines inside these tags
39
+ with HTML newline entities (<tt>&#x000A;</tt>),
40
+ which Haml does using the Haml::Helpers#preserve and Haml::Helpers#find_and_preserve helpers.
41
+
42
+ Normally, Haml will do this for you automatically
43
+ when you're using a tag that needs it
44
+ (this can be customized using the <tt>:preserve</tt> option;
45
+ see the Options section of the {Haml reference}(../classes/Haml.html)).
46
+ For example,
47
+
48
+ %p
49
+ %textarea= "Foo\nBar"
50
+
51
+ will be compiled to
52
+
53
+ <p>
54
+ <textarea>Foo&#x000A;Bar</textarea>
55
+ </p>
56
+
57
+ However, if a helper is generating the tag,
58
+ Haml can't detect that and so you'll have to call +find_and_preserve+ yourself.
59
+ You can also use <tt>~</tt>, which is the same as <tt>=</tt>
60
+ except that it automatically runs +find_and_preserve+ on its input.
61
+ For example:
62
+
63
+ %p= find_and_preserve "<textarea>Foo\nBar</textarea>"
64
+
65
+ is the same as
66
+
67
+ %p~ "<textarea>Foo\nBar</textarea>"
68
+
69
+ and renders
70
+
71
+ <p><textarea>Foo&#x000A;Bar</textarea></p>
72
+
73
+ === How do I make my long lines of Ruby code look nicer in my Haml document?
74
+
75
+ Put them in a helper or your model.
76
+
77
+ Haml purposefully makes it annoying to put lots of Ruby code into your templates,
78
+ because lots of code doesn't belong in the view.
79
+ If you take that huge +link_to_remote+ call
80
+ and move it to a +update_sidebar_link+ helper,
81
+ it'll make your view both easier to read and more semantic.
82
+
83
+ If you absolutely must put lots of code in your template,
84
+ Haml offers a somewhat awkward multiline-continuation tool.
85
+ Put a <tt>|</tt> (pipe character) at the end of each line you want to be merged into one
86
+ (including the last line!).
87
+ For example:
88
+
89
+ %p= @this.is(way.too.much). |
90
+ code("and I should"). |
91
+ really_move.it.into( |
92
+ :a => @helper) |
93
+
94
+ === I have Haml installed. Why is Rails (only looking for <tt>.html.erb</tt> files | rendering Haml files as plain text | rendering Haml files as blank pages)?
95
+
96
+ There are several reasons these things might be happening.
97
+ First of all, make sure vendor/plugins/haml really exists
98
+ and has an init.rb file in there.
99
+ Then try restarting Mongrel or WEBrick or whatever you might be using.
100
+
101
+ Finally, if none of these work,
102
+ chances are you've got some localization plugin like Globalize installed.
103
+ Such plugins often don't play nicely with Haml.
104
+ Luckily, there's usually an easy fix.
105
+ For Globalize, just edit globalize/lib/globalize/rails/action_view.rb
106
+ and change
107
+
108
+ @@re_extension = /\.(rjs|rhtml|rxml)$/
109
+
110
+ to
111
+
112
+ @@re_extension = /\.(rjs|rhtml|rxml|erb|builder|haml)$/
113
+
114
+ For other plugins, a little searching will probably turn up a way to fix them as well.
115
+
116
+ == Sass
117
+
118
+ === Can I use a variable from my controller in my Sass file?
119
+
120
+ No. Sass files aren't views.
121
+ They're compiled once into static CSS files,
122
+ then left along until they're changed and need to be compiled again.
123
+ Not only don't you want to be running a full request cycle
124
+ every time someone requests a stylesheet,
125
+ but it's not a great idea to put much logic in there anyway
126
+ due to how browsers handle them.
127
+
128
+ If you really need some sort of dynamic CSS,
129
+ the best thing to do is put only the snippet you need to dynamically set
130
+ in the +head+ of your HTML document.
131
+
132
+ == You still haven't answered my question!
133
+
134
+ Sorry! Try looking at the Haml or Sass references,
135
+ in the doucmentation for the haml and Sass modules, respectively.
136
+ If you can't find an answer there,
137
+ feel free to ask in #haml on irc.freenode.net
138
+ or send an email to the {mailing list}[http://groups.google.com/group/haml?hl=en].
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006-2008 Hampton Catlin
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/TODO ADDED
@@ -0,0 +1,43 @@
1
+ # -*- mode: org -*-
2
+ #+STARTUP: nofold
3
+
4
+ * Documentation
5
+ Convert to YARD, Markdown
6
+ Redo tutorial?
7
+ Re-organize references?
8
+ ** Sass
9
+ Control structures
10
+ Partials
11
+ Mixin arguments
12
+ Interpolation
13
+ Bools
14
+ CSS Terminology (https://mail.google.com/mail/#label/Haml/1202d75234b3ce6b)
15
+ Convert to new property syntax
16
+ Stop calling it "alternate" - call it "new" instead
17
+ Document sassc somewhere obvious
18
+ ** FAQ
19
+ Multiline vs. helpers
20
+ form_for needs -, not =
21
+
22
+ * Code
23
+ ** Haml
24
+ Figure out alternate attribute syntax
25
+ ** Sass
26
+ CSS Terminology? (https://mail.google.com/mail/#label/Haml/1202d75234b3ce6b)
27
+
28
+ [2.4] Pre-parse everything possible: never call Node#interpolate
29
+ [2.4] Do all parsing in to_tree
30
+ [2.4] Allow semicolons for multiple props on one line
31
+ [2.4] Pull in Compass watcher stuff
32
+ [2.4] Internationalization
33
+ Particularly word constituents in Regexps
34
+ [2.4] Optimization
35
+ http://csstidy.sourceforge.net/
36
+ Also comma-folding identical rules where possible
37
+ Multiple levels
38
+ 0: No optimization
39
+ 1: Nothing that changes doc structure
40
+ No comma-folding
41
+ 2: Anything that keeps functionality identical to O2 (default)
42
+ 3: Assume order of rules doesn't matter
43
+ Comma-fold even if there are intervening rules that might interfere
data/VERSION.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  ---
2
2
  :major: 2
3
3
  :minor: 1
4
+ :timestamp: "20090513162728"
4
5
  :patch: 0
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'json'
4
+ set :port, 3123
5
+ set :environment, :production
6
+ Dir.chdir(File.dirname(__FILE__) + "/..")
7
+
8
+ post "/" do
9
+ payload = JSON.parse(params["payload"])
10
+
11
+ break unless payload["ref"] == "refs/heads/master"
12
+ system("rake release_edge &> edge-gem-output.log")
13
+ end
@@ -0,0 +1,596 @@
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
7
+ ;; Version: 1.0
8
+ ;; Keywords: markup, language
9
+
10
+ ;;; Commentary:
11
+
12
+ ;; Because Haml's indentation schema is similar
13
+ ;; to that of YAML and Python, many indentation-related
14
+ ;; functions are similar to those in yaml-mode and python-mode.
15
+
16
+ ;; To install, save this on your load path and add the following to
17
+ ;; your .emacs file:
18
+ ;;
19
+ ;; (require 'haml-mode)
20
+
21
+ ;;; Code:
22
+
23
+ (eval-when-compile (require 'cl))
24
+ (require 'ruby-mode)
25
+
26
+ ;; User definable variables
27
+
28
+ (defgroup haml nil
29
+ "Support for the Haml template language."
30
+ :group 'languages
31
+ :prefix "haml-")
32
+
33
+ (defcustom haml-mode-hook nil
34
+ "Hook run when entering Haml mode."
35
+ :type 'hook
36
+ :group 'haml)
37
+
38
+ (defcustom haml-indent-offset 2
39
+ "Amount of offset per level of indentation."
40
+ :type 'integer
41
+ :group 'haml)
42
+
43
+ (defcustom haml-backspace-backdents-nesting t
44
+ "Non-nil to have `haml-electric-backspace' re-indent all code
45
+ nested beneath the backspaced line be re-indented along with the
46
+ line itself."
47
+ :type 'boolean
48
+ :group 'haml)
49
+
50
+ (defface haml-tab-face
51
+ '((((class color)) (:background "hotpink"))
52
+ (t (:reverse-video t)))
53
+ "Face to use for highlighting tabs in Haml files."
54
+ :group 'faces
55
+ :group 'haml)
56
+
57
+ (defvar haml-indent-function 'haml-indent-p
58
+ "This function should look at the current line and return t
59
+ if the next line could be nested within this line.
60
+
61
+ The function can also return a positive integer to indicate
62
+ a specific level to which the current line could be indented.")
63
+
64
+ (defvar haml-block-openers
65
+ `("^ *\\([%\\.#][a-z0-9_:\\-]*\\)+\\({.*}\\)?\\(\\[.*\\]\\)?[><]*[ \t]*$"
66
+ "^ *[&!]?[-=~].*do[ \t]*\\(|.*|[ \t]*\\)?$"
67
+ ,(concat "^ *[&!][-=~][ \t]*\\("
68
+ (regexp-opt '("if" "unless" "while" "until" "else"
69
+ "begin" "elsif" "rescue" "ensure" "when"))
70
+ "\\)")
71
+ "^ */\\(\\[.*\\]\\)?[ \t]*$"
72
+ "^ *-#"
73
+ "^ *:")
74
+ "A list of regexps that match lines of Haml that could have
75
+ text nested beneath them.")
76
+
77
+ ;; Font lock
78
+
79
+ (defun haml-nested-regexp (re)
80
+ (concat "^\\( *\\)" re "\\(\n\\(?:\\(?:\\1 .*\\| *\\)\n\\)*\\(?:\\1 .*\\| *\\)?\\)?"))
81
+
82
+ (defconst haml-font-lock-keywords
83
+ `((,(haml-nested-regexp "\\(?:-#\\|/\\).*") 0 font-lock-comment-face)
84
+ (,(haml-nested-regexp ":\\w+") 0 font-lock-string-face)
85
+ (haml-highlight-interpolation 1 font-lock-variable-name-face prepend)
86
+ (haml-highlight-ruby-tag 1 font-lock-preprocessor-face)
87
+ (haml-highlight-ruby-script 1 font-lock-preprocessor-face)
88
+ ("^ *\\(\t\\)" 1 'haml-tab-face)
89
+ ("^!!!.*" 0 font-lock-constant-face)
90
+ ("| *$" 0 font-lock-string-face)))
91
+
92
+ (defconst haml-filter-re "^ *:\\w+")
93
+ (defconst haml-comment-re "^ *\\(?:-\\#\\|/\\)")
94
+
95
+ (defun haml-fontify-region-as-ruby (beg end)
96
+ "Use Ruby's font-lock variables to fontify the region between BEG and END."
97
+ (save-excursion
98
+ (save-match-data
99
+ (let ((font-lock-keywords ruby-font-lock-keywords)
100
+ (font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)
101
+ font-lock-keywords-only
102
+ font-lock-extend-region-functions
103
+ font-lock-keywords-case-fold-search)
104
+ ;; font-lock-fontify-region apparently isn't inclusive,
105
+ ;; so we have to move the beginning back one char
106
+ (font-lock-fontify-region (- beg 1) end)))))
107
+
108
+ (defun haml-highlight-ruby-script (limit)
109
+ "Highlight a Ruby script expression (-, =, or ~)."
110
+ (when (re-search-forward "^ *\\(-\\|[&!]?[=~]\\) \\(.*\\)$" limit t)
111
+ (haml-fontify-region-as-ruby (match-beginning 2) (match-end 2))))
112
+
113
+ (defun haml-highlight-ruby-tag (limit)
114
+ "Highlight Ruby code within a Haml tag.
115
+
116
+ This highlights the tag attributes and object refs of the tag,
117
+ as well as the script expression (-, =, or ~) following the tag.
118
+
119
+ For example, this will highlight all of the following:
120
+ %p{:foo => 'bar'}
121
+ %p[@bar]
122
+ %p= 'baz'
123
+ %p{:foo => 'bar'}[@bar]= 'baz'"
124
+ (when (re-search-forward "^ *[%.#]" limit t)
125
+ (let ((eol (save-excursion (end-of-line) (point))))
126
+ (forward-char -1)
127
+
128
+ ;; Highlight tag, classes, and ids
129
+ (while (looking-at "[.#%][a-z0-9_:\\-]*")
130
+ (put-text-property (match-beginning 0) (match-end 0) 'face
131
+ (case (char-after)
132
+ (?% font-lock-function-name-face)
133
+ (?# font-lock-keyword-face)
134
+ (?. font-lock-type-face)))
135
+ (goto-char (match-end 0)))
136
+
137
+ ;; Highlight obj refs
138
+ (when (eq (char-after) ?\[)
139
+ (let ((beg (point)))
140
+ (haml-limited-forward-sexp eol)
141
+ (haml-fontify-region-as-ruby beg (point))))
142
+
143
+ ;; Highlight attr hashes
144
+ (when (eq (char-after) ?\{)
145
+ (let ((beg (+ 1 (point))))
146
+ (haml-limited-forward-sexp eol)
147
+
148
+ ;; Check for multiline
149
+ (while (and (eolp) (eq (char-before) ?,))
150
+ (forward-line)
151
+ (let ((eol (save-excursion (end-of-line) (point))))
152
+ ;; If no sexps are closed,
153
+ ;; we're still continuing a multiline hash
154
+ (if (>= (car (parse-partial-sexp (point) eol)) 0)
155
+ (end-of-line)
156
+ ;; If sexps have been closed,
157
+ ;; set the point at the end of the total sexp
158
+ (goto-char beg)
159
+ (haml-limited-forward-sexp eol))))
160
+
161
+ (haml-fontify-region-as-ruby beg (point))))
162
+
163
+ ;; Move past end chars
164
+ (when (looking-at "[<>&!]+") (goto-char (match-end 0)))
165
+ ;; Highlight script
166
+ (if (looking-at "\\([=~]\\) \\(.*\\)$")
167
+ (haml-fontify-region-as-ruby (match-beginning 2) (match-end 2))
168
+ ;; Give font-lock something to highlight
169
+ (forward-char -1)
170
+ (looking-at "\\(\\)"))
171
+ t)))
172
+
173
+ (defun haml-highlight-interpolation (limit)
174
+ "Highlight Ruby interpolation (#{foo})."
175
+ (when (re-search-forward "\\(#{\\)" limit t)
176
+ (save-match-data
177
+ (forward-char -1)
178
+ (let ((beg (point)))
179
+ (haml-limited-forward-sexp limit)
180
+ (haml-fontify-region-as-ruby (+ 1 beg) (point)))
181
+
182
+ (when (eq (char-before) ?})
183
+ (put-text-property (- (point) 1) (point)
184
+ 'face font-lock-variable-name-face))
185
+ t)))
186
+
187
+ (defun haml-limited-forward-sexp (limit &optional arg)
188
+ "Move forward using `forward-sexp' or to limit,
189
+ whichever comes first."
190
+ (let (forward-sexp-function)
191
+ (condition-case err
192
+ (save-restriction
193
+ (narrow-to-region (point) limit)
194
+ (forward-sexp arg))
195
+ (scan-error
196
+ (unless (equal (nth 1 err) "Unbalanced parentheses")
197
+ (signal 'scan-error (cdr err)))
198
+ (goto-char limit)))))
199
+
200
+ (defun* haml-extend-region-filters-comments ()
201
+ "Extend the font-lock region to encompass filters and comments."
202
+ (let ((old-beg font-lock-beg)
203
+ (old-end font-lock-end))
204
+ (save-excursion
205
+ (goto-char font-lock-beg)
206
+ (beginning-of-line)
207
+ (unless (or (looking-at haml-filter-re)
208
+ (looking-at haml-comment-re))
209
+ (return-from haml-extend-region-filters-comments))
210
+ (setq font-lock-beg (point))
211
+ (haml-forward-sexp)
212
+ (beginning-of-line)
213
+ (setq font-lock-end (max font-lock-end (point))))
214
+ (or (/= old-beg font-lock-beg)
215
+ (/= old-end font-lock-end))))
216
+
217
+ (defun* haml-extend-region-multiline-hashes ()
218
+ "Extend the font-lock region to encompass multiline attribute hashes."
219
+ (let ((old-beg font-lock-beg)
220
+ (old-end font-lock-end))
221
+ (save-excursion
222
+ (goto-char font-lock-beg)
223
+ (let ((attr-props (haml-parse-multiline-attr-hash))
224
+ multiline-end)
225
+ (when attr-props
226
+ (setq font-lock-beg (cdr (assq 'point attr-props)))
227
+
228
+ (end-of-line)
229
+ ;; Move through multiline attrs
230
+ (when (eq (char-before) ?,)
231
+ (save-excursion
232
+ (while (progn (end-of-line) (eq (char-before) ?,))
233
+ (forward-line))
234
+
235
+ (forward-line -1)
236
+ (end-of-line)
237
+ (setq multiline-end (point))))
238
+
239
+ (goto-char (+ (cdr (assq 'point attr-props))
240
+ (cdr (assq 'hash-indent attr-props))
241
+ -1))
242
+ (haml-limited-forward-sexp
243
+ (or multiline-end
244
+ (save-excursion (end-of-line) (point))))
245
+ (setq font-lock-end (max font-lock-end (point))))))
246
+ (or (/= old-beg font-lock-beg)
247
+ (/= old-end font-lock-end))))
248
+
249
+
250
+ ;; Mode setup
251
+
252
+ (defvar haml-mode-syntax-table
253
+ (let ((table (make-syntax-table)))
254
+ (modify-syntax-entry ?: "." table)
255
+ (modify-syntax-entry ?_ "w" table)
256
+ table)
257
+ "Syntax table in use in haml-mode buffers.")
258
+
259
+ (defvar haml-mode-map
260
+ (let ((map (make-sparse-keymap)))
261
+ (define-key map [backspace] 'haml-electric-backspace)
262
+ (define-key map "\C-?" 'haml-electric-backspace)
263
+ (define-key map "\C-c\C-f" 'haml-forward-sexp)
264
+ (define-key map "\C-c\C-b" 'haml-backward-sexp)
265
+ (define-key map "\C-c\C-u" 'haml-up-list)
266
+ (define-key map "\C-c\C-d" 'haml-down-list)
267
+ (define-key map "\C-c\C-k" 'haml-kill-line-and-indent)
268
+ (define-key map "\C-c\C-r" 'haml-output-region)
269
+ (define-key map "\C-c\C-l" 'haml-output-buffer)
270
+ map))
271
+
272
+ ;;;###autoload
273
+ (define-derived-mode haml-mode fundamental-mode "Haml"
274
+ "Major mode for editing Haml files.
275
+
276
+ \\{haml-mode-map}"
277
+ (set-syntax-table haml-mode-syntax-table)
278
+ (add-to-list 'font-lock-extend-region-functions 'haml-extend-region-filters-comments)
279
+ (add-to-list 'font-lock-extend-region-functions 'haml-extend-region-multiline-hashes)
280
+ (set (make-local-variable 'font-lock-multiline) t)
281
+ (set (make-local-variable 'indent-line-function) 'haml-indent-line)
282
+ (set (make-local-variable 'indent-region-function) 'haml-indent-region)
283
+ (set (make-local-variable 'parse-sexp-lookup-properties) t)
284
+ (setq comment-start "-#")
285
+ (setq indent-tabs-mode nil)
286
+ (setq font-lock-defaults '((haml-font-lock-keywords) t t)))
287
+
288
+ ;; Useful functions
289
+
290
+ (defun haml-comment-block ()
291
+ "Comment the current block of Haml code."
292
+ (interactive)
293
+ (save-excursion
294
+ (let ((indent (current-indentation)))
295
+ (back-to-indentation)
296
+ (insert "-#")
297
+ (newline)
298
+ (indent-to indent)
299
+ (beginning-of-line)
300
+ (haml-mark-sexp)
301
+ (haml-reindent-region-by haml-indent-offset))))
302
+
303
+ (defun haml-uncomment-block ()
304
+ "Uncomment the current block of Haml code."
305
+ (interactive)
306
+ (save-excursion
307
+ (beginning-of-line)
308
+ (while (not (looking-at haml-comment-re))
309
+ (haml-up-list)
310
+ (beginning-of-line))
311
+ (haml-mark-sexp)
312
+ (kill-line 1)
313
+ (haml-reindent-region-by (- haml-indent-offset))))
314
+
315
+ (defun haml-replace-region (start end)
316
+ "Replaces the current block of Haml code with the HTML equivalent."
317
+ (interactive "r")
318
+ (save-excursion
319
+ (goto-char end)
320
+ (setq end (point-marker))
321
+ (goto-char start)
322
+ (let ((ci (current-indentation)))
323
+ (while (re-search-forward "^ +" end t)
324
+ (replace-match (make-string (- (current-indentation) ci) ? ))))
325
+ (shell-command-on-region start end "haml" "haml-output" t)))
326
+
327
+ (defun haml-output-region (start end)
328
+ "Displays the HTML output for the current block of Haml code."
329
+ (interactive "r")
330
+ (kill-new (buffer-substring start end))
331
+ (with-temp-buffer
332
+ (yank)
333
+ (haml-indent-region (point-min) (point-max))
334
+ (shell-command-on-region (point-min) (point-max) "haml" "haml-output")))
335
+
336
+ (defun haml-output-buffer ()
337
+ "Displays the HTML output for entire buffer."
338
+ (interactive)
339
+ (haml-output-region (point-min) (point-max)))
340
+
341
+ ;; Navigation
342
+
343
+ (defun haml-forward-through-whitespace (&optional backward)
344
+ "Move the point forward at least one line, until it reaches
345
+ either the end of the buffer or a line with no whitespace.
346
+
347
+ If `backward' is non-nil, move the point backward instead."
348
+ (let ((arg (if backward -1 1))
349
+ (endp (if backward 'bobp 'eobp)))
350
+ (loop do (forward-line arg)
351
+ while (and (not (funcall endp))
352
+ (looking-at "^[ \t]*$")))))
353
+
354
+ (defun haml-at-indent-p ()
355
+ "Returns whether or not the point is at the first
356
+ non-whitespace character in a line or whitespace preceding that
357
+ character."
358
+ (let ((opoint (point)))
359
+ (save-excursion
360
+ (back-to-indentation)
361
+ (>= (point) opoint))))
362
+
363
+ (defun haml-forward-sexp (&optional arg)
364
+ "Move forward across one nested expression.
365
+ With `arg', do it that many times. Negative arg -N means move
366
+ backward across N balanced expressions.
367
+
368
+ A sexp in Haml is defined as a line of Haml code as well as any
369
+ lines nested beneath it."
370
+ (interactive "p")
371
+ (or arg (setq arg 1))
372
+ (if (and (< arg 0) (not (haml-at-indent-p)))
373
+ (back-to-indentation)
374
+ (while (/= arg 0)
375
+ (let ((indent (current-indentation)))
376
+ (loop do (haml-forward-through-whitespace (< arg 0))
377
+ while (and (not (eobp))
378
+ (not (bobp))
379
+ (> (current-indentation) indent)))
380
+ (back-to-indentation)
381
+ (setq arg (+ arg (if (> arg 0) -1 1)))))))
382
+
383
+ (defun haml-backward-sexp (&optional arg)
384
+ "Move backward across one nested expression.
385
+ With ARG, do it that many times. Negative arg -N means move
386
+ forward across N balanced expressions.
387
+
388
+ A sexp in Haml is defined as a line of Haml code as well as any
389
+ lines nested beneath it."
390
+ (interactive "p")
391
+ (haml-forward-sexp (if arg (- arg) -1)))
392
+
393
+ (defun haml-up-list (&optional arg)
394
+ "Move out of one level of nesting.
395
+ With ARG, do this that many times."
396
+ (interactive "p")
397
+ (or arg (setq arg 1))
398
+ (while (> arg 0)
399
+ (let ((indent (current-indentation)))
400
+ (loop do (haml-forward-through-whitespace t)
401
+ while (and (not (bobp))
402
+ (>= (current-indentation) indent)))
403
+ (setq arg (- arg 1))))
404
+ (back-to-indentation))
405
+
406
+ (defun haml-down-list (&optional arg)
407
+ "Move down one level of nesting.
408
+ With ARG, do this that many times."
409
+ (interactive "p")
410
+ (or arg (setq arg 1))
411
+ (while (> arg 0)
412
+ (let ((indent (current-indentation)))
413
+ (haml-forward-through-whitespace)
414
+ (when (<= (current-indentation) indent)
415
+ (haml-forward-through-whitespace t)
416
+ (back-to-indentation)
417
+ (error "Nothing is nested beneath this line"))
418
+ (setq arg (- arg 1))))
419
+ (back-to-indentation))
420
+
421
+ (defun haml-mark-sexp ()
422
+ "Marks the next Haml block."
423
+ (let ((forward-sexp-function 'haml-forward-sexp))
424
+ (mark-sexp)))
425
+
426
+ (defun haml-mark-sexp-but-not-next-line ()
427
+ "Marks the next Haml block, but puts the mark at the end of the
428
+ last line of the sexp rather than the first non-whitespace
429
+ character of the next line."
430
+ (haml-mark-sexp)
431
+ (set-mark
432
+ (save-excursion
433
+ (goto-char (mark))
434
+ (forward-line -1)
435
+ (end-of-line)
436
+ (point))))
437
+
438
+ ;; Indentation and electric keys
439
+
440
+ (defun* haml-indent-p ()
441
+ "Returns t if the current line can have lines nested beneath it."
442
+ (let ((attr-props (haml-parse-multiline-attr-hash)))
443
+ (when attr-props
444
+ (end-of-line)
445
+ (return-from haml-indent-p
446
+ (if (eq (char-before) ?,) (cdr (assq 'hash-indent attr-props))
447
+ (beginning-of-line)
448
+ (+ (cdr (assq 'indent attr-props)) haml-indent-offset)))))
449
+ (loop for opener in haml-block-openers
450
+ if (looking-at opener) return t
451
+ finally return nil))
452
+
453
+ (defun* haml-parse-multiline-attr-hash ()
454
+ "Parses a multiline attribute hash, and returns
455
+ an alist with the following keys:
456
+
457
+ INDENT is the indentation of the line beginning the hash.
458
+
459
+ HASH-INDENT is the indentation of the first character
460
+ within the attribute hash.
461
+
462
+ POINT is the character position at the beginning of the line
463
+ beginning the hash."
464
+ (save-excursion
465
+ (while t
466
+ (beginning-of-line)
467
+ (if (looking-at "^ *\\(?:[.#%][a-z0-9_:\\-]+\\)+{")
468
+ (progn
469
+ (goto-char (- (match-end 0) 1))
470
+ (haml-limited-forward-sexp (save-excursion (end-of-line) (point)))
471
+ (return-from haml-parse-multiline-attr-hash
472
+ (if (eq (char-before) ?,)
473
+ `((indent . ,(current-indentation))
474
+ (hash-indent . ,(- (match-end 0) (match-beginning 0)))
475
+ (point . ,(match-beginning 0)))
476
+ nil)))
477
+ (forward-line -1)
478
+ (end-of-line)
479
+ (when (not (eq (char-before) ?,))
480
+ (return-from haml-parse-multiline-attr-hash nil))))))
481
+
482
+ (defun haml-compute-indentation ()
483
+ "Calculate the maximum sensible indentation for the current line."
484
+ (save-excursion
485
+ (beginning-of-line)
486
+ (if (bobp) 0
487
+ (haml-forward-through-whitespace t)
488
+ (let ((indent (funcall haml-indent-function)))
489
+ (cond
490
+ ((integerp indent) indent)
491
+ (indent (+ (current-indentation) haml-indent-offset))
492
+ (t (current-indentation)))))))
493
+
494
+ (defun haml-indent-region (start end)
495
+ "Indent each nonblank line in the region.
496
+ This is done by indenting the first line based on
497
+ `haml-compute-indentation' and preserving the relative
498
+ indentation of the rest of the region.
499
+
500
+ If this command is used multiple times in a row, it will cycle
501
+ between possible indentations."
502
+ (save-excursion
503
+ (goto-char end)
504
+ (setq end (point-marker))
505
+ (goto-char start)
506
+ (let (this-line-column current-column
507
+ (next-line-column
508
+ (if (and (equal last-command this-command) (/= (current-indentation) 0))
509
+ (* (/ (- (current-indentation) 1) haml-indent-offset) haml-indent-offset)
510
+ (haml-compute-indentation))))
511
+ (while (< (point) end)
512
+ (setq this-line-column next-line-column
513
+ current-column (current-indentation))
514
+ ;; Delete whitespace chars at beginning of line
515
+ (delete-horizontal-space)
516
+ (unless (eolp)
517
+ (setq next-line-column (save-excursion
518
+ (loop do (forward-line 1)
519
+ while (and (not (eobp)) (looking-at "^[ \t]*$")))
520
+ (+ this-line-column
521
+ (- (current-indentation) current-column))))
522
+ ;; Don't indent an empty line
523
+ (unless (eolp) (indent-to this-line-column)))
524
+ (forward-line 1)))
525
+ (move-marker end nil)))
526
+
527
+ (defun haml-indent-line ()
528
+ "Indent the current line.
529
+ The first time this command is used, the line will be indented to the
530
+ maximum sensible indentation. Each immediately subsequent usage will
531
+ back-dent the line by `haml-indent-offset' spaces. On reaching column
532
+ 0, it will cycle back to the maximum sensible indentation."
533
+ (interactive "*")
534
+ (let ((ci (current-indentation))
535
+ (cc (current-column))
536
+ (need (haml-compute-indentation)))
537
+ (save-excursion
538
+ (beginning-of-line)
539
+ (delete-horizontal-space)
540
+ (if (and (equal last-command this-command) (/= ci 0))
541
+ (indent-to (* (/ (- ci 1) haml-indent-offset) haml-indent-offset))
542
+ (indent-to need)))
543
+ (if (< (current-column) (current-indentation))
544
+ (forward-to-indentation 0))))
545
+
546
+ (defun haml-reindent-region-by (n)
547
+ "Add N spaces to the beginning of each line in the region.
548
+ If N is negative, will remove the spaces instead. Assumes all
549
+ lines in the region have indentation >= that of the first line."
550
+ (let ((ci (current-indentation)))
551
+ (save-excursion
552
+ (replace-regexp (concat "^" (make-string ci ? ))
553
+ (make-string (max 0 (+ ci n)) ? )
554
+ nil (point) (mark)))))
555
+
556
+ (defun haml-electric-backspace (arg)
557
+ "Delete characters or back-dent the current line.
558
+ If invoked following only whitespace on a line, will back-dent
559
+ the line and all nested lines to the immediately previous
560
+ multiple of `haml-indent-offset' spaces.
561
+
562
+ Set `haml-backspace-backdents-nesting' to nil to just back-dent
563
+ the current line."
564
+ (interactive "*p")
565
+ (if (or (/= (current-indentation) (current-column))
566
+ (bolp)
567
+ (looking-at "^[ \t]+$"))
568
+ (backward-delete-char arg)
569
+ (save-excursion
570
+ (let ((ci (current-column)))
571
+ (beginning-of-line)
572
+ (if haml-backspace-backdents-nesting
573
+ (haml-mark-sexp-but-not-next-line)
574
+ (set-mark (save-excursion (end-of-line) (point))))
575
+ (haml-reindent-region-by (* (- arg) haml-indent-offset))
576
+ (back-to-indentation)
577
+ (pop-mark)))))
578
+
579
+ (defun haml-kill-line-and-indent ()
580
+ "Kill the current line, and re-indent all lines nested beneath it."
581
+ (interactive)
582
+ (beginning-of-line)
583
+ (haml-mark-sexp-but-not-next-line)
584
+ (kill-line 1)
585
+ (haml-reindent-region-by (* -1 haml-indent-offset)))
586
+
587
+ (defun haml-indent-string ()
588
+ "Return the indentation string for `haml-indent-offset'."
589
+ (mapconcat 'identity (make-list haml-indent-offset " ") ""))
590
+
591
+ ;;;###autoload
592
+ (add-to-list 'auto-mode-alist '("\\.haml$" . haml-mode))
593
+
594
+ ;; Setup/Activation
595
+ (provide 'haml-mode)
596
+ ;;; haml-mode.el ends here