slim 0.7.0.beta.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- slim (0.7.0.beta.1)
4
+ slim (0.7.0)
5
5
  escape_utils (>= 0.1.9)
6
- temple (~> 0.1.2)
6
+ temple (~> 0.1.3)
7
7
  tilt (~> 1.1)
8
8
 
9
9
  GEM
@@ -19,8 +19,9 @@ GEM
19
19
  rake (0.8.7)
20
20
  rcov (0.9.9)
21
21
  rdiscount (1.6.5)
22
- temple (0.1.2)
22
+ temple (0.1.3)
23
23
  tilt (1.1)
24
+ yard (0.6.1)
24
25
 
25
26
  PLATFORMS
26
27
  ruby
@@ -35,5 +36,6 @@ DEPENDENCIES
35
36
  rcov
36
37
  rdiscount
37
38
  slim!
38
- temple (~> 0.1.2)
39
+ temple (~> 0.1.3)
39
40
  tilt (~> 1.1)
41
+ yard
data/README.md CHANGED
@@ -5,14 +5,19 @@ Slim is a template language whose goal is to reduce the view syntax to the essen
5
5
 
6
6
  ## What?
7
7
 
8
- Slim is a fast, lightweight templating engine for __Rails 3__. It has been tested on Ruby 1.9.2 and Ruby/REE 1.8.7. Slim is heavily influenced by [Haml](http://github.com/nex3/haml) and [Jade](http://github.com/visionmedia/jade).
8
+ Slim is a fast, lightweight templating engine with support for __Rails 3__. It has been tested on Ruby 1.9.2 and Ruby/REE 1.8.7.
9
9
 
10
+ Slim's core syntax is guided by one thought: "What's the minimum required to make this work".
11
+
12
+ As more people have contributed to Slim, there have been ___optional___ syntax additions influenced from their use of [Haml](http://github.com/nex3/haml) and [Jade](http://github.com/visionmedia/jade). The Slim team is open to these optional additions because we know beauty is in the eye of the beholder.
13
+
14
+ Slim uses [Temple](http://github.com/judofyr/temple) for parsing/compilation and is also integrated into [Tilt](http://github.com/rtomayko/tilt), so it can be used together with [Sinatra](http://github.com/sinatra/sinatra) or plain [Rack](http://github.com/rack/rack).
10
15
 
11
16
  ## Why?
12
17
 
13
- Within the Rails community, _Erb_ and _Haml_ are without doubt the two most popular templating engines. However, _Erb_'s syntax is cumbersome and Haml's performance isn't exactly the best. Slim was born to bring the minimalist syntax approach of _Haml_ and the higher performance of Erb into once solution.
18
+ Within the Rails community, _Erb_ and _Haml_ are without doubt the two most popular templating engines. However, _Erb_'s syntax is cumbersome and Haml's performance isn't exactly the best.
14
19
 
15
- ___Yes, Slim is speedy!___ Benchmarks are provided at the end of this README file. Alternatively, a benchmark rake task is provided so you could test it yourself (`rake bench`).
20
+ Slim was born to bring a minimalist syntax approach with speed. If people chose not to use Slim, it would not be because of speed. ___Yes, Slim is speedy!___ Benchmarks are provided at the end of this README file. Alternatively, a benchmark rake task is provided so you could test it yourself (`rake bench`).
16
21
 
17
22
 
18
23
  ## How?
@@ -31,12 +36,21 @@ In `config/application.rb`, add the following line near the top (i.e. just below
31
36
 
32
37
  That's it!
33
38
 
39
+ If you want to use the Slim template directly, you can use the Tilt interface:
40
+
41
+ Tilt.new['template.slim'].render(scope)
42
+ Slim::Template.new(filename, optional_option_hash).render(scope)
43
+ Slim::Template.new(optional_option_hash) { source }.render(scope)
44
+
45
+ ## Syntax Highlighters
46
+
47
+ Syntax highlight support for __Vim__ (very beta) and __Emacs__ are included in the `extra` folder. There is also a [Textmate bundle](http://github.com/fredwu/ruby-slim-textmate-bundle).
34
48
 
35
49
  ## The syntax
36
50
 
37
51
  As a Rails developer, you might already be very familiar with _Haml_'s syntax and you think it is fantastic - until you entered the magic kingdom of _node.js_ and got introduced to _Jade_.
38
52
 
39
- Slim's syntax is inspired by both _Haml_ and _Jade_.
53
+ Slim's syntax has been influenced by both _Haml_ and _Jade_.
40
54
 
41
55
  Here's a quick example to demonstrate what a Slim template looks like:
42
56
 
@@ -117,9 +131,9 @@ __Please note that all line indicators must be followed by a space__
117
131
  If you want to first indent 2 spaces, then 5 spaces, it's your choice. To nest markup you only need to indent by one space, the rest is gravy.
118
132
 
119
133
  #### If your ruby code needs to use multiple lines, append a `\` at the end of the lines, for example:
120
- `javascript_include_tag \
121
- "jquery", \
122
- "application"`
134
+ = javascript_include_tag \
135
+ "jquery", \
136
+ "application"`
123
137
 
124
138
  ### Wrap attributes with delimiters
125
139
 
@@ -247,7 +261,7 @@ __Please note that all line indicators must be followed by a space__
247
261
  body
248
262
  p
249
263
  / This line won't get displayed.
250
- / Neither does this line.
264
+ Neither does this line.
251
265
 
252
266
  The parsed result of the above:
253
267
 
@@ -308,6 +322,7 @@ __Please note that all line indicators must be followed by a space__
308
322
 
309
323
  * [Andrew Stone](http://github.com/stonean)
310
324
  * [Fred Wu](http://github.com/fredwu)
325
+ * [Daniel Mendler](http://github.com/minad)
311
326
 
312
327
  ## Discuss
313
328
 
data/Rakefile CHANGED
@@ -11,18 +11,18 @@ task :bench, :iterations do |t, args|
11
11
  ruby("benchmarks/run.rb #{args[:iterations]}")
12
12
  end
13
13
 
14
- Rake::TestTask.new(:test) do |test|
15
- test.libs << 'lib' << 'test'
16
- test.pattern = 'test/**/test_*.rb'
17
- test.verbose = true
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.libs << 'lib' << 'test'
16
+ t.pattern = 'test/**/test_*.rb'
17
+ t.verbose = true
18
18
  end
19
19
 
20
20
  begin
21
21
  require 'rcov/rcovtask'
22
- Rcov::RcovTask.new do |test|
23
- test.libs << 'lib' << 'test'
24
- test.pattern = 'test/**/test_*.rb'
25
- test.verbose = true
22
+ Rcov::RcovTask.new do |t|
23
+ t.libs << 'lib' << 'test'
24
+ t.pattern = 'test/**/test_*.rb'
25
+ t.verbose = true
26
26
  end
27
27
  rescue LoadError
28
28
  task :rcov do
@@ -30,4 +30,18 @@ rescue LoadError
30
30
  end
31
31
  end
32
32
 
33
+ begin
34
+ require 'yard'
35
+ YARD::Rake::YardocTask.new do |t|
36
+ t.files = %w(lib/**/*.rb)
37
+ end
38
+ rescue LoadError
39
+ task :yard do
40
+ abort "YARD is not available. In order to run yard, you must: gem install yard"
41
+ end
42
+ end
43
+
44
+ desc "Generate Documentation"
45
+ task :doc => :yard
46
+
33
47
  task :default => 'test'
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $: << File.join(File.dirname(__FILE__), '..', 'lib') << File.join(File.dirname(__FILE__), 'src')
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'), File.join(File.dirname(__FILE__), 'src'))
4
4
 
5
5
  require 'slim'
6
6
  require 'complex_view'
@@ -28,12 +28,12 @@ class SlimBenchmarks
28
28
  fast_erubis = Erubis::FastEruby.new(tpl_erb)
29
29
  haml = Haml::Engine.new(tpl_haml)
30
30
  haml_ugly = Haml::Engine.new(tpl_haml, :ugly => true)
31
- slim = Slim::Engine.new(tpl_slim)
31
+ slim = Slim::Template.new { tpl_slim }
32
32
 
33
33
  bench('erb') { ERB.new(tpl_erb).result(eview) }
34
34
  bench('erubis') { Erubis::Eruby.new(tpl_erb).result(eview) }
35
35
  bench('fast erubis') { Erubis::Eruby.new(tpl_erb).result(eview) }
36
- bench('slim') { Slim::Engine.new(tpl_slim).render(view) }
36
+ bench('slim') { Slim::Template.new { tpl_slim }.render(view) }
37
37
  bench('haml') { Haml::Engine.new(tpl_haml).render(view) }
38
38
  bench('haml ugly') { Haml::Engine.new(tpl_haml, :ugly => true).render(view) }
39
39
  bench('erb (cached)') { erb.result(eview) }
@@ -13,6 +13,6 @@ body
13
13
  strong == i[:name]
14
14
  - else
15
15
  li
16
- a href="#{i[:url]}" == i[:name]
16
+ a href=i[:url] == i[:name]
17
17
  - else
18
18
  p The list is empty.
@@ -2,7 +2,7 @@ require 'tilt'
2
2
 
3
3
  class ComplexView
4
4
  include Tilt::CompileSite
5
-
5
+
6
6
  def header
7
7
  "Colors"
8
8
  end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + '/../lib'
4
+ require 'slim/command'
5
+
6
+ cmd = Slim::Command.new(ARGV)
7
+ cmd.run
@@ -0,0 +1,409 @@
1
+ ;;; slim-mode.el --- Major mode for editing Slim files
2
+
3
+ ;; Copyright (c) 2007, 2008 Nathan Weizenbaum
4
+ ;; Modified slightly for Slim by Daniel Mendler
5
+
6
+ ;; Author: Nathan Weizenbaum
7
+ ;; URL: http://github.com/stonean/slim
8
+ ;; Version: 1.0
9
+ ;; Keywords: markup, language
10
+
11
+ ;;; Commentary:
12
+
13
+ ;; Because Slim's indentation schema is similar
14
+ ;; to that of YAML and Python, many indentation-related
15
+ ;; functions are similar to those in yaml-mode and python-mode.
16
+
17
+ ;; TODO: This whole file has to be reworked to provide optimal support
18
+ ;; for Slim. This is only a slightly adapted haml version.
19
+
20
+ ;; To install, save this on your load path and add the following to
21
+ ;; your .emacs file:
22
+
23
+ ;;
24
+ ;; (require 'slim-mode)
25
+
26
+ ;;; Code:
27
+
28
+ (eval-when-compile (require 'cl))
29
+
30
+ ;; User definable variables
31
+
32
+ (defgroup slim nil
33
+ "Support for the Slim template language."
34
+ :group 'languages
35
+ :prefix "slim-")
36
+
37
+ (defcustom slim-mode-hook nil
38
+ "Hook run when entering Slim mode."
39
+ :type 'hook
40
+ :group 'slim)
41
+
42
+ (defcustom slim-indent-offset 2
43
+ "Amount of offset per level of indentation."
44
+ :type 'integer
45
+ :group 'slim)
46
+
47
+ (defcustom slim-backspace-backdents-nesting t
48
+ "Non-nil to have `slim-electric-backspace' re-indent all code
49
+ nested beneath the backspaced line be re-indented along with the
50
+ line itself."
51
+ :type 'boolean
52
+ :group 'slim)
53
+
54
+ (defface slim-tab-face
55
+ '((((class color)) (:background "hotpink"))
56
+ (t (:reverse-video t)))
57
+ "Face to use for highlighting tabs in Slim files."
58
+ :group 'faces
59
+ :group 'slim)
60
+
61
+ (defvar slim-indent-function 'slim-indent-p
62
+ "This function should look at the current line and return true
63
+ if the next line could be nested within this line.")
64
+
65
+ (defvar slim-block-openers
66
+ `("^ *\\([\\.#a-z][^ \t]*\\)\\(\\[.*\\]\\)?[ \t]*$"
67
+ "^ *[-=].*do[ \t]*\\(|.*|[ \t]*\\)?$"
68
+ ,(concat "^ *-[ \t]*\\("
69
+ (regexp-opt '("if" "unless" "while" "until" "else"
70
+ "begin" "elsif" "rescue" "ensure" "when"))
71
+ "\\)")
72
+ "^ *|"
73
+ "^ */"
74
+ "^ *[a-z0-9_]:")
75
+ "A list of regexps that match lines of Slim that could have
76
+ text nested beneath them.")
77
+
78
+ ;; Font lock
79
+
80
+ ;; Helper for nested block (comment, embedded, text)
81
+ (defun slim-nested-re (re)
82
+ (concat "^\\( *\\)" re "\n\\(?:\\(?:\\1 .*\\)\n\\)*"))
83
+
84
+ (defconst slim-font-lock-keywords
85
+ `((,(slim-nested-re "/.*") 0 font-lock-comment-face) ;; Comment block
86
+ (,(slim-nested-re "[a-z0-9_]+:") 0 font-lock-string-face) ;; Embedded block
87
+ (,(slim-nested-re "[\|'`].*") 0 font-lock-string-face) ;; Text block
88
+ ("^!.*" 0 font-lock-constant-face) ;; Directive
89
+ ("^ *\\(\t\\)" 1 'slim-tab-face)
90
+ ("\\('[^']*'\\)" 1 font-lock-string-face append) ;; Single quote string TODO
91
+ ("\\(\"[^\"]*\"\\)" 1 font-lock-string-face append) ;; Double quoted string TODO
92
+ ("@[a-z0-9_]+" 0 font-lock-variable-name-face append) ;; Class variable TODO
93
+ ("^ *\\(#[a-z0-9_]+\/?\\)" 1 font-lock-keyword-face) ;; #id
94
+ ("^ *\\(\\.[a-z0-9_]+\/?\\)" 1 font-lock-type-face) ;; .class
95
+ ("^ *\\([a-z0-9_]+\/?\\)" 1 font-lock-function-name-face) ;; div
96
+ ("^ *\\(#[a-z0-9_]+\/?\\)" (1 font-lock-keyword-face) ;; #id.class
97
+ ("\\.[a-z0-9_]+" nil nil (0 font-lock-type-face)))
98
+ ("^ *\\(\\.[a-z0-9_]+\/?\\)" (1 font-lock-type-face) ;; .class.class
99
+ ("\\.[a-z0-9_]+" nil nil (0 font-lock-type-face)))
100
+ ("^ *\\(\\.[a-z0-9_]+\/?\\)" (1 font-lock-type-face) ;; .class#id
101
+ ("\\#[a-z0-9_]+" nil nil (0 font-lock-keyword-face)))
102
+ ("^ *\\([a-z0-9_]+\/?\\)" (1 font-lock-function-name-face) ;; div.class
103
+ ("\\.[a-z0-9_]+" nil nil (0 font-lock-type-face)))
104
+ ("^ *\\([a-z0-9_]+\/?\\)" (1 font-lock-function-name-face) ;; div#id
105
+ ("\\#[a-z0-9_]+" nil nil (0 font-lock-keyword-face)))
106
+ ("^ *\\(\\(==?|-\\) .*\\)" 1 font-lock-preprocessor-face prepend) ;; ==, =, -
107
+ ("^ *[\\.#a-z0-9_]+\\(==? .*\\)" 1 font-lock-preprocessor-face prepend))) ;; tag ==, tag =
108
+
109
+ (defconst slim-embedded-re "^ *[a-z0-9_]+:")
110
+ (defconst slim-comment-re "^ */")
111
+
112
+ (defun* slim-extend-region ()
113
+ "Extend the font-lock region to encompass embedded engines and comments."
114
+ (let ((old-beg font-lock-beg)
115
+ (old-end font-lock-end))
116
+ (save-excursion
117
+ (goto-char font-lock-beg)
118
+ (beginning-of-line)
119
+ (unless (or (looking-at slim-embedded-re)
120
+ (looking-at slim-comment-re))
121
+ (return-from slim-extend-region))
122
+ (setq font-lock-beg (point))
123
+ (slim-forward-sexp)
124
+ (beginning-of-line)
125
+ (setq font-lock-end (max font-lock-end (point))))
126
+ (or (/= old-beg font-lock-beg)
127
+ (/= old-end font-lock-end))))
128
+
129
+
130
+ ;; Mode setup
131
+
132
+ (defvar slim-mode-syntax-table
133
+ (let ((table (make-syntax-table)))
134
+ (modify-syntax-entry ?: "." table)
135
+ (modify-syntax-entry ?_ "w" table)
136
+ table)
137
+ "Syntax table in use in slim-mode buffers.")
138
+
139
+ (defvar slim-mode-map
140
+ (let ((map (make-sparse-keymap)))
141
+ (define-key map [backspace] 'slim-electric-backspace)
142
+ (define-key map "\C-?" 'slim-electric-backspace)
143
+ (define-key map "\C-c\C-f" 'slim-forward-sexp)
144
+ (define-key map "\C-c\C-b" 'slim-backward-sexp)
145
+ (define-key map "\C-c\C-u" 'slim-up-list)
146
+ (define-key map "\C-c\C-d" 'slim-down-list)
147
+ (define-key map "\C-c\C-k" 'slim-kill-line-and-indent)
148
+ map))
149
+
150
+ ;;;###autoload
151
+ (define-derived-mode slim-mode fundamental-mode "Slim"
152
+ "Major mode for editing Slim files.
153
+
154
+ \\{slim-mode-map}"
155
+ (set-syntax-table slim-mode-syntax-table)
156
+ (add-to-list 'font-lock-extend-region-functions 'slim-extend-region)
157
+ (set (make-local-variable 'font-lock-multiline) t)
158
+ (set (make-local-variable 'indent-line-function) 'slim-indent-line)
159
+ (set (make-local-variable 'indent-region-function) 'slim-indent-region)
160
+ (set (make-local-variable 'parse-sexp-lookup-properties) t)
161
+ (setq comment-start "/")
162
+ (setq indent-tabs-mode nil)
163
+ (setq font-lock-defaults '((slim-font-lock-keywords) nil t)))
164
+
165
+ ;; Useful functions
166
+
167
+ (defun slim-comment-block ()
168
+ "Comment the current block of Slim code."
169
+ (interactive)
170
+ (save-excursion
171
+ (let ((indent (current-indentation)))
172
+ (back-to-indentation)
173
+ (insert "/")
174
+ (newline)
175
+ (indent-to indent)
176
+ (beginning-of-line)
177
+ (slim-mark-sexp)
178
+ (slim-reindent-region-by slim-indent-offset))))
179
+
180
+ (defun slim-uncomment-block ()
181
+ "Uncomment the current block of Slim code."
182
+ (interactive)
183
+ (save-excursion
184
+ (beginning-of-line)
185
+ (while (not (looking-at slim-comment-re))
186
+ (slim-up-list)
187
+ (beginning-of-line))
188
+ (slim-mark-sexp)
189
+ (kill-line 1)
190
+ (slim-reindent-region-by (- slim-indent-offset))))
191
+
192
+ ;; Navigation
193
+
194
+ (defun slim-forward-through-whitespace (&optional backward)
195
+ "Move the point forward at least one line, until it reaches
196
+ either the end of the buffer or a line with no whitespace.
197
+
198
+ If `backward' is non-nil, move the point backward instead."
199
+ (let ((arg (if backward -1 1))
200
+ (endp (if backward 'bobp 'eobp)))
201
+ (loop do (forward-line arg)
202
+ while (and (not (funcall endp))
203
+ (looking-at "^[ \t]*$")))))
204
+
205
+ (defun slim-at-indent-p ()
206
+ "Returns whether or not the point is at the first
207
+ non-whitespace character in a line or whitespace preceding that
208
+ character."
209
+ (let ((opoint (point)))
210
+ (save-excursion
211
+ (back-to-indentation)
212
+ (>= (point) opoint))))
213
+
214
+ (defun slim-forward-sexp (&optional arg)
215
+ "Move forward across one nested expression.
216
+ With `arg', do it that many times. Negative arg -N means move
217
+ backward across N balanced expressions.
218
+
219
+ A sexp in Slim is defined as a line of Slim code as well as any
220
+ lines nested beneath it."
221
+ (interactive "p")
222
+ (or arg (setq arg 1))
223
+ (if (and (< arg 0) (not (slim-at-indent-p)))
224
+ (back-to-indentation)
225
+ (while (/= arg 0)
226
+ (let ((indent (current-indentation)))
227
+ (loop do (slim-forward-through-whitespace (< arg 0))
228
+ while (and (not (eobp))
229
+ (not (bobp))
230
+ (> (current-indentation) indent)))
231
+ (back-to-indentation)
232
+ (setq arg (+ arg (if (> arg 0) -1 1)))))))
233
+
234
+ (defun slim-backward-sexp (&optional arg)
235
+ "Move backward across one nested expression.
236
+ With ARG, do it that many times. Negative arg -N means move
237
+ forward across N balanced expressions.
238
+
239
+ A sexp in Slim is defined as a line of Slim code as well as any
240
+ lines nested beneath it."
241
+ (interactive "p")
242
+ (slim-forward-sexp (if arg (- arg) -1)))
243
+
244
+ (defun slim-up-list (&optional arg)
245
+ "Move out of one level of nesting.
246
+ With ARG, do this that many times."
247
+ (interactive "p")
248
+ (or arg (setq arg 1))
249
+ (while (> arg 0)
250
+ (let ((indent (current-indentation)))
251
+ (loop do (slim-forward-through-whitespace t)
252
+ while (and (not (bobp))
253
+ (>= (current-indentation) indent)))
254
+ (setq arg (- arg 1))))
255
+ (back-to-indentation))
256
+
257
+ (defun slim-down-list (&optional arg)
258
+ "Move down one level of nesting.
259
+ With ARG, do this that many times."
260
+ (interactive "p")
261
+ (or arg (setq arg 1))
262
+ (while (> arg 0)
263
+ (let ((indent (current-indentation)))
264
+ (slim-forward-through-whitespace)
265
+ (when (<= (current-indentation) indent)
266
+ (slim-forward-through-whitespace t)
267
+ (back-to-indentation)
268
+ (error "Nothing is nested beneath this line"))
269
+ (setq arg (- arg 1))))
270
+ (back-to-indentation))
271
+
272
+ (defun slim-mark-sexp ()
273
+ "Marks the next Slim block."
274
+ (let ((forward-sexp-function 'slim-forward-sexp))
275
+ (mark-sexp)))
276
+
277
+ (defun slim-mark-sexp-but-not-next-line ()
278
+ "Marks the next Slim block, but puts the mark at the end of the
279
+ last line of the sexp rather than the first non-whitespace
280
+ character of the next line."
281
+ (slim-mark-sexp)
282
+ (set-mark
283
+ (save-excursion
284
+ (goto-char (mark))
285
+ (forward-line -1)
286
+ (end-of-line)
287
+ (point))))
288
+
289
+ ;; Indentation and electric keys
290
+
291
+ (defun slim-indent-p ()
292
+ "Returns true if the current line can have lines nested beneath it."
293
+ (loop for opener in slim-block-openers
294
+ if (looking-at opener) return t
295
+ finally return nil))
296
+
297
+ (defun slim-compute-indentation ()
298
+ "Calculate the maximum sensible indentation for the current line."
299
+ (save-excursion
300
+ (beginning-of-line)
301
+ (if (bobp) 0
302
+ (slim-forward-through-whitespace t)
303
+ (+ (current-indentation)
304
+ (if (funcall slim-indent-function) slim-indent-offset
305
+ 0)))))
306
+
307
+ (defun slim-indent-region (start end)
308
+ "Indent each nonblank line in the region.
309
+ This is done by indenting the first line based on
310
+ `slim-compute-indentation' and preserving the relative
311
+ indentation of the rest of the region.
312
+
313
+ If this command is used multiple times in a row, it will cycle
314
+ between possible indentations."
315
+ (save-excursion
316
+ (goto-char end)
317
+ (setq end (point-marker))
318
+ (goto-char start)
319
+ (let (this-line-column current-column
320
+ (next-line-column
321
+ (if (and (equal last-command this-command) (/= (current-indentation) 0))
322
+ (* (/ (- (current-indentation) 1) slim-indent-offset) slim-indent-offset)
323
+ (slim-compute-indentation))))
324
+ (while (< (point) end)
325
+ (setq this-line-column next-line-column
326
+ current-column (current-indentation))
327
+ ;; Delete whitespace chars at beginning of line
328
+ (delete-horizontal-space)
329
+ (unless (eolp)
330
+ (setq next-line-column (save-excursion
331
+ (loop do (forward-line 1)
332
+ while (and (not (eobp)) (looking-at "^[ \t]*$")))
333
+ (+ this-line-column
334
+ (- (current-indentation) current-column))))
335
+ ;; Don't indent an empty line
336
+ (unless (eolp) (indent-to this-line-column)))
337
+ (forward-line 1)))
338
+ (move-marker end nil)))
339
+
340
+ (defun slim-indent-line ()
341
+ "Indent the current line.
342
+ The first time this command is used, the line will be indented to the
343
+ maximum sensible indentation. Each immediately subsequent usage will
344
+ back-dent the line by `slim-indent-offset' spaces. On reaching column
345
+ 0, it will cycle back to the maximum sensible indentation."
346
+ (interactive "*")
347
+ (let ((ci (current-indentation))
348
+ (cc (current-column))
349
+ (need (slim-compute-indentation)))
350
+ (save-excursion
351
+ (beginning-of-line)
352
+ (delete-horizontal-space)
353
+ (if (and (equal last-command this-command) (/= ci 0))
354
+ (indent-to (* (/ (- ci 1) slim-indent-offset) slim-indent-offset))
355
+ (indent-to need)))
356
+ (if (< (current-column) (current-indentation))
357
+ (forward-to-indentation 0))))
358
+
359
+ (defun slim-reindent-region-by (n)
360
+ "Add N spaces to the beginning of each line in the region.
361
+ If N is negative, will remove the spaces instead. Assumes all
362
+ lines in the region have indentation >= that of the first line."
363
+ (let ((ci (current-indentation)))
364
+ (save-excursion
365
+ (replace-regexp (concat "^" (make-string ci ? ))
366
+ (make-string (max 0 (+ ci n)) ? )
367
+ nil (point) (mark)))))
368
+
369
+ (defun slim-electric-backspace (arg)
370
+ "Delete characters or back-dent the current line.
371
+ If invoked following only whitespace on a line, will back-dent
372
+ the line and all nested lines to the immediately previous
373
+ multiple of `slim-indent-offset' spaces.
374
+
375
+ Set `slim-backspace-backdents-nesting' to nil to just back-dent
376
+ the current line."
377
+ (interactive "*p")
378
+ (if (or (/= (current-indentation) (current-column))
379
+ (bolp)
380
+ (looking-at "^[ \t]+$"))
381
+ (backward-delete-char arg)
382
+ (save-excursion
383
+ (let ((ci (current-column)))
384
+ (beginning-of-line)
385
+ (if slim-backspace-backdents-nesting
386
+ (slim-mark-sexp-but-not-next-line)
387
+ (set-mark (save-excursion (end-of-line) (point))))
388
+ (slim-reindent-region-by (* (- arg) slim-indent-offset))
389
+ (back-to-indentation)
390
+ (pop-mark)))))
391
+
392
+ (defun slim-kill-line-and-indent ()
393
+ "Kill the current line, and re-indent all lines nested beneath it."
394
+ (interactive)
395
+ (beginning-of-line)
396
+ (slim-mark-sexp-but-not-next-line)
397
+ (kill-line 1)
398
+ (slim-reindent-region-by (* -1 slim-indent-offset)))
399
+
400
+ (defun slim-indent-string ()
401
+ "Return the indentation string for `slim-indent-offset'."
402
+ (mapconcat 'identity (make-list slim-indent-offset " ") ""))
403
+
404
+ ;;;###autoload
405
+ (add-to-list 'auto-mode-alist '("\\.slim$" . slim-mode))
406
+
407
+ ;; Setup/Activation
408
+ (provide 'slim-mode)
409
+ ;;; slim-mode.el ends here