slim 1.1.1 → 1.2.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.
@@ -45,6 +45,10 @@ module Slim
45
45
  [:slim, :attr, name, escape, access(value)]
46
46
  end
47
47
 
48
+ def on_slim_splat(code)
49
+ [:slim, :splat, access(code)]
50
+ end
51
+
48
52
  def on_dynamic(code)
49
53
  raise 'Embedded code is forbidden in sections mode'
50
54
  end
@@ -1,5 +1,5 @@
1
1
  module Slim
2
2
  # Slim version string
3
3
  # @api public
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.0'
5
5
  end
@@ -10,8 +10,8 @@ Gem::Specification.new do |s|
10
10
  s.email = ['andy@stonean.com', 'ifredwu@gmail.com', 'mail@daniel-mendler.de']
11
11
  s.summary = 'Slim is a template language.'
12
12
  s.description = 'Slim is a template language whose goal is reduce the syntax to the essential parts without becoming cryptic.'
13
- s.homepage = 'http://github.com/stonean/slim'
14
- s.extra_rdoc_files = %w(README.md)
13
+ s.homepage = 'http://slim-lang.com/'
14
+ s.extra_rdoc_files = %w(README.md LICENSE CHANGES)
15
15
  s.rdoc_options = %w(--charset=UTF-8)
16
16
  s.rubyforge_project = s.name
17
17
 
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = %w(lib)
21
21
 
22
22
  s.add_runtime_dependency('temple', ['~> 0.4.0'])
23
- s.add_runtime_dependency('tilt', ['~> 1.3.2'])
23
+ s.add_runtime_dependency('tilt', ['~> 1.3.3'])
24
24
 
25
25
  s.add_development_dependency('rake', ['>= 0.8.7'])
26
26
  s.add_development_dependency('sass', ['>= 3.1.0'])
@@ -9,7 +9,7 @@ MiniTest::Unit.autorun
9
9
 
10
10
  Slim::Engine.after Slim::Parser, Temple::Filters::Validator, :grammar => Slim::Grammar
11
11
  Slim::Engine.before Slim::Compiler, Temple::Filters::Validator, :grammar => Slim::Grammar
12
- Slim::Engine.before :Pretty, Temple::Filters::Validator
12
+ Slim::Engine.before :AttributeMerger, Temple::Filters::Validator
13
13
 
14
14
  class TestSlim < MiniTest::Unit::TestCase
15
15
  def setup
@@ -194,6 +194,14 @@ p id="#{(false ? 'notshown' : 'shown')}" = output_number
194
194
  assert_html '<p id="shown">1337</p>', source
195
195
  end
196
196
 
197
+ def test_ternary_operation_in_attribute_2
198
+ source = %q{
199
+ p id=(false ? 'notshown' : 'shown') = output_number
200
+ }
201
+
202
+ assert_html '<p id="shown">1337</p>', source
203
+ end
204
+
197
205
  def test_class_attribute_merging
198
206
  source = %{
199
207
  .alpha class="beta" Test it
@@ -136,8 +136,8 @@ p(id="test")==hello_world
136
136
  def test_render_with_backslash_end
137
137
  # Keep trailing spaces!
138
138
  source = %q{
139
- p = \
140
- "Hello" + \
139
+ p = \
140
+ "Hello" + \
141
141
  " Ruby!"
142
142
  - variable = 1 + \
143
143
  2 + \
@@ -15,14 +15,13 @@ p
15
15
  end
16
16
 
17
17
  def test_render_with_markdown
18
- # Keep the trailing spaces.
19
18
  source = %q{
20
19
  markdown:
21
20
  #Header
22
21
  Hello from #{"Markdown!"}
23
-
22
+
24
23
  #{1+2}
25
-
24
+
26
25
  * one
27
26
  * two
28
27
  }
@@ -77,7 +76,6 @@ p Hi
77
76
  end
78
77
 
79
78
  def test_render_with_javascript_with_tabs
80
- # Keep the trailing space behind "javascript: "!
81
79
  source = "javascript:\n\t$(function() {});\n\talert('hello')\np Hi"
82
80
  assert_html "<script type=\"text/javascript\">$(function() {});\nalert('hello')</script><p>Hi</p>", source
83
81
  end
@@ -15,7 +15,6 @@ html
15
15
  end
16
16
 
17
17
  def test_html_tag_with_text_and_empty_line
18
- # Keep the trailing space behind "body "!
19
18
  source = %q{
20
19
  p Hello
21
20
 
@@ -74,10 +73,21 @@ h1#title This is my title
74
73
  def test_render_with_overwritten_default_tag
75
74
  source = %q{
76
75
  #notice.hello.world
76
+ = hello_world
77
+ }
78
+
79
+ assert_html '<section class="hello world" id="notice">Hello World from @env</section>', source, :default_tag => 'section'
80
+ end
81
+
82
+ def test_render_with_custom_shortcut
83
+ source = %q{
84
+ #notice.hello.world@test
85
+ = hello_world
86
+ @abc
77
87
  = hello_world
78
88
  }
79
89
 
80
- assert_html '<section class="hello world" id="notice">Hello World from @env</section>', source, :default_tag => 'section'
90
+ assert_html '<div class="hello world" id="notice" role="test">Hello World from @env</div><section role="abc">Hello World from @env</section>', source, :shortcut => {'#' => 'id', '.' => 'class', '@' => 'section role'}
81
91
  end
82
92
 
83
93
  def test_render_with_text_block
@@ -468,4 +478,94 @@ input[value=succ_x]
468
478
  assert_html %{<input value="1" /><input value="2" />}, source
469
479
  end
470
480
 
481
+ def test_shortcut_splat
482
+ source = %q{
483
+ *hash This is my title
484
+ }
485
+
486
+ assert_html '<div a="The letter a" b="The letter b">This is my title</div>', source
487
+ end
488
+
489
+ def test_splat
490
+ source = %q{
491
+ h1 *hash This is my title
492
+ }
493
+
494
+ assert_html '<h1 a="The letter a" b="The letter b">This is my title</h1>', source
495
+ end
496
+
497
+ def test_splat_tag_name
498
+ source = %q{
499
+ *{:tag => 'h1', :id => 'title'} This is my title
500
+ }
501
+
502
+ assert_html '<h1 id="title">This is my title</h1>', source
503
+ end
504
+
505
+
506
+ def test_splat_empty_tag_name
507
+ source = %q{
508
+ *{:tag => '', :id => 'test'} This is my title
509
+ }
510
+
511
+ assert_html '<div id="test">This is my title</div>', source, :remove_empty_attrs => true
512
+ assert_html '<div id="test">This is my title</div>', source, :remove_empty_attrs => false
513
+ end
514
+
515
+ def test_closed_splat_tag
516
+ source = %q{
517
+ *hash / This is my title
518
+ }
519
+
520
+ assert_html '<div a="The letter a" b="The letter b"/>', source
521
+ end
522
+
523
+ def test_splat_with_id_shortcut
524
+ source = %q{
525
+ #myid*hash This is my title
526
+ }
527
+
528
+ assert_html '<div a="The letter a" b="The letter b" id="myid">This is my title</div>', source
529
+ end
530
+
531
+ def test_splat_with_class_shortcut
532
+ source = %q{
533
+ .myclass*hash This is my title
534
+ }
535
+
536
+ assert_html '<div a="The letter a" b="The letter b" class="myclass">This is my title</div>', source
537
+ end
538
+
539
+ def test_splat_with_id_and_class_shortcuts
540
+ source = %q{
541
+ #myid.myclass*hash This is my title
542
+ }
543
+
544
+ assert_html '<div a="The letter a" b="The letter b" class="myclass" id="myid">This is my title</div>', source
545
+ end
546
+
547
+ def test_splat_with_class_merging
548
+ source = %q{
549
+ #myid.myclass *{:class => [:secondclass, %w(x y z)]} *hash This is my title
550
+ }
551
+
552
+ assert_html '<div a="The letter a" b="The letter b" class="myclass secondclass x y z" id="myid">This is my title</div>', source
553
+ end
554
+
555
+ def test_splat_with_boolean_attribute
556
+ source = %q{
557
+ *{:disabled => true, :empty1 => false, :empty2 => '', :empty3 => nil} This is my title
558
+ }
559
+
560
+ assert_html '<div disabled="disabled">This is my title</div>', source
561
+ assert_html '<div disabled="disabled" empty1="" empty2="" empty3="">This is my title</div>', source, :remove_empty_attrs => false
562
+ end
563
+
564
+ def test_splat_with_other_attributes
565
+ source = %q{
566
+ h1 data-id="123" *hash This is my title
567
+ }
568
+
569
+ assert_html '<h1 a="The letter a" b="The letter b" data-id="123">This is my title</h1>', source
570
+ end
471
571
  end
@@ -82,7 +82,7 @@ p
82
82
  img src=[hash[1] + hash[2]
83
83
  }
84
84
 
85
- assert_syntax_error "Expected closing attribute delimiter ]\n (__TEMPLATE__), Line 3\n img src=[hash[1] + hash[2]\n ^\n", source
85
+ assert_syntax_error "Expected closing delimiter ]\n (__TEMPLATE__), Line 3\n img src=[hash[1] + hash[2]\n ^\n", source
86
86
  end
87
87
 
88
88
  def test_expected_attribute
@@ -194,9 +194,16 @@ div
194
194
  assert_runtime_error 'Explicit end statements are forbidden', source
195
195
  end
196
196
 
197
- def test_id_attribute_merging2
197
+ def test_multiple_id_attribute
198
198
  source = %{
199
199
  #alpha id="beta" Test it
200
+ }
201
+ assert_runtime_error 'Multiple id attributes specified', source
202
+ end
203
+
204
+ def test_splat_multiple_id_attribute
205
+ source = %{
206
+ #alpha *{:id =>"beta"} Test it
200
207
  }
201
208
  assert_runtime_error 'Multiple id attributes specified', source
202
209
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slim
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,11 +11,11 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-02-29 00:00:00.000000000 Z
14
+ date: 2012-03-30 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: temple
18
- requirement: &17637820 !ruby/object:Gem::Requirement
18
+ requirement: &4011380 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
21
  - - ~>
@@ -23,21 +23,21 @@ dependencies:
23
23
  version: 0.4.0
24
24
  type: :runtime
25
25
  prerelease: false
26
- version_requirements: *17637820
26
+ version_requirements: *4011380
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: tilt
29
- requirement: &17637240 !ruby/object:Gem::Requirement
29
+ requirement: &4026080 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
32
32
  - - ~>
33
33
  - !ruby/object:Gem::Version
34
- version: 1.3.2
34
+ version: 1.3.3
35
35
  type: :runtime
36
36
  prerelease: false
37
- version_requirements: *17637240
37
+ version_requirements: *4026080
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: rake
40
- requirement: &17636740 !ruby/object:Gem::Requirement
40
+ requirement: &4025180 !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
43
  - - ! '>='
@@ -45,10 +45,10 @@ dependencies:
45
45
  version: 0.8.7
46
46
  type: :development
47
47
  prerelease: false
48
- version_requirements: *17636740
48
+ version_requirements: *4025180
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: sass
51
- requirement: &17636160 !ruby/object:Gem::Requirement
51
+ requirement: &4024320 !ruby/object:Gem::Requirement
52
52
  none: false
53
53
  requirements:
54
54
  - - ! '>='
@@ -56,10 +56,10 @@ dependencies:
56
56
  version: 3.1.0
57
57
  type: :development
58
58
  prerelease: false
59
- version_requirements: *17636160
59
+ version_requirements: *4024320
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: minitest
62
- requirement: &17652060 !ruby/object:Gem::Requirement
62
+ requirement: &4023580 !ruby/object:Gem::Requirement
63
63
  none: false
64
64
  requirements:
65
65
  - - ! '>='
@@ -67,10 +67,10 @@ dependencies:
67
67
  version: '0'
68
68
  type: :development
69
69
  prerelease: false
70
- version_requirements: *17652060
70
+ version_requirements: *4023580
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: kramdown
73
- requirement: &17651560 !ruby/object:Gem::Requirement
73
+ requirement: &4022620 !ruby/object:Gem::Requirement
74
74
  none: false
75
75
  requirements:
76
76
  - - ! '>='
@@ -78,10 +78,10 @@ dependencies:
78
78
  version: '0'
79
79
  type: :development
80
80
  prerelease: false
81
- version_requirements: *17651560
81
+ version_requirements: *4022620
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: creole
84
- requirement: &17650940 !ruby/object:Gem::Requirement
84
+ requirement: &4021940 !ruby/object:Gem::Requirement
85
85
  none: false
86
86
  requirements:
87
87
  - - ! '>='
@@ -89,10 +89,10 @@ dependencies:
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
- version_requirements: *17650940
92
+ version_requirements: *4021940
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: builder
95
- requirement: &17649640 !ruby/object:Gem::Requirement
95
+ requirement: &4021020 !ruby/object:Gem::Requirement
96
96
  none: false
97
97
  requirements:
98
98
  - - ! '>='
@@ -100,7 +100,7 @@ dependencies:
100
100
  version: '0'
101
101
  type: :development
102
102
  prerelease: false
103
- version_requirements: *17649640
103
+ version_requirements: *4021020
104
104
  description: Slim is a template language whose goal is reduce the syntax to the essential
105
105
  parts without becoming cryptic.
106
106
  email:
@@ -112,6 +112,8 @@ executables:
112
112
  extensions: []
113
113
  extra_rdoc_files:
114
114
  - README.md
115
+ - LICENSE
116
+ - CHANGES
115
117
  files:
116
118
  - .gemtest
117
119
  - .gitignore
@@ -130,8 +132,6 @@ files:
130
132
  - benchmarks/view.haml
131
133
  - benchmarks/view.slim
132
134
  - bin/slimrb
133
- - extra/slim-mode.el
134
- - extra/test.slim
135
135
  - lib/slim.rb
136
136
  - lib/slim/command.rb
137
137
  - lib/slim/compiler.rb
@@ -205,7 +205,7 @@ files:
205
205
  - test/slim/test_slim_template.rb
206
206
  - test/slim/test_text_interpolation.rb
207
207
  - test/slim/test_wrapper.rb
208
- homepage: http://github.com/stonean/slim
208
+ homepage: http://slim-lang.com/
209
209
  licenses: []
210
210
  post_install_message:
211
211
  rdoc_options:
@@ -226,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
226
  version: '0'
227
227
  requirements: []
228
228
  rubyforge_project: slim
229
- rubygems_version: 1.8.15
229
+ rubygems_version: 1.8.11
230
230
  signing_key:
231
231
  specification_version: 3
232
232
  summary: Slim is a template language.
@@ -1,409 +0,0 @@
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