slim 0.7.0.beta.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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