angry_mob_common_targets 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +38 -0
  3. data/lib/common_mob.rb +9 -0
  4. data/lib/common_mob/digest.rb +43 -0
  5. data/lib/common_mob/erb.rb +72 -0
  6. data/lib/common_mob/file.rb +55 -0
  7. data/lib/common_mob/patch.rb +51 -0
  8. data/lib/common_mob/resource_locator.rb +9 -0
  9. data/lib/common_mob/shell.rb +323 -0
  10. data/lib/common_mob/template.rb +23 -0
  11. data/lib/common_mob/version.rb +3 -0
  12. data/targets/crontab_patch.rb +37 -0
  13. data/targets/extract.rb +40 -0
  14. data/targets/fetch.rb +40 -0
  15. data/targets/files.rb +244 -0
  16. data/targets/git.rb +84 -0
  17. data/targets/group.rb +33 -0
  18. data/targets/packages.rb +94 -0
  19. data/targets/ruby.rb +13 -0
  20. data/targets/services.rb +184 -0
  21. data/targets/shell.rb +43 -0
  22. data/targets/user.rb +108 -0
  23. data/vendor/mustache/CONTRIBUTORS +9 -0
  24. data/vendor/mustache/HISTORY.md +135 -0
  25. data/vendor/mustache/LICENSE +20 -0
  26. data/vendor/mustache/README.md +405 -0
  27. data/vendor/mustache/Rakefile +103 -0
  28. data/vendor/mustache/benchmarks/complex.erb +15 -0
  29. data/vendor/mustache/benchmarks/complex.haml +12 -0
  30. data/vendor/mustache/benchmarks/helper.rb +20 -0
  31. data/vendor/mustache/benchmarks/simple.erb +5 -0
  32. data/vendor/mustache/benchmarks/speed.rb +78 -0
  33. data/vendor/mustache/bin/mustache +90 -0
  34. data/vendor/mustache/contrib/mustache-mode.el +278 -0
  35. data/vendor/mustache/contrib/mustache.vim +69 -0
  36. data/vendor/mustache/examples/hash.rb +16 -0
  37. data/vendor/mustache/examples/hash.yml +5 -0
  38. data/vendor/mustache/examples/projects.mustache +26 -0
  39. data/vendor/mustache/examples/projects.yml +28 -0
  40. data/vendor/mustache/examples/self.mustache +4 -0
  41. data/vendor/mustache/examples/self.yml +3 -0
  42. data/vendor/mustache/examples/simple.mustache +10 -0
  43. data/vendor/mustache/examples/simple.rb +24 -0
  44. data/vendor/mustache/lib/mustache.rb +358 -0
  45. data/vendor/mustache/lib/mustache/context.rb +108 -0
  46. data/vendor/mustache/lib/mustache/generator.rb +160 -0
  47. data/vendor/mustache/lib/mustache/parser.rb +230 -0
  48. data/vendor/mustache/lib/mustache/sinatra.rb +180 -0
  49. data/vendor/mustache/lib/mustache/template.rb +59 -0
  50. data/vendor/mustache/lib/mustache/version.rb +3 -0
  51. data/vendor/mustache/lib/rack/bug/panels/mustache_panel.rb +81 -0
  52. data/vendor/mustache/lib/rack/bug/panels/mustache_panel/mustache_extension.rb +27 -0
  53. data/vendor/mustache/lib/rack/bug/panels/mustache_panel/view.mustache +46 -0
  54. data/vendor/mustache/man/mustache.1 +180 -0
  55. data/vendor/mustache/man/mustache.1.html +204 -0
  56. data/vendor/mustache/man/mustache.1.ron +127 -0
  57. data/vendor/mustache/man/mustache.5 +576 -0
  58. data/vendor/mustache/man/mustache.5.html +415 -0
  59. data/vendor/mustache/man/mustache.5.ron +324 -0
  60. data/vendor/mustache/mustache.gemspec +32 -0
  61. data/vendor/mustache/test/autoloading_test.rb +52 -0
  62. data/vendor/mustache/test/fixtures/comments.mustache +1 -0
  63. data/vendor/mustache/test/fixtures/comments.rb +14 -0
  64. data/vendor/mustache/test/fixtures/complex_view.mustache +17 -0
  65. data/vendor/mustache/test/fixtures/complex_view.rb +34 -0
  66. data/vendor/mustache/test/fixtures/crazy_recursive.mustache +9 -0
  67. data/vendor/mustache/test/fixtures/crazy_recursive.rb +31 -0
  68. data/vendor/mustache/test/fixtures/delimiters.mustache +8 -0
  69. data/vendor/mustache/test/fixtures/delimiters.rb +23 -0
  70. data/vendor/mustache/test/fixtures/double_section.mustache +7 -0
  71. data/vendor/mustache/test/fixtures/double_section.rb +14 -0
  72. data/vendor/mustache/test/fixtures/escaped.mustache +1 -0
  73. data/vendor/mustache/test/fixtures/escaped.rb +14 -0
  74. data/vendor/mustache/test/fixtures/inner_partial.mustache +1 -0
  75. data/vendor/mustache/test/fixtures/inner_partial.txt +1 -0
  76. data/vendor/mustache/test/fixtures/inverted_section.mustache +7 -0
  77. data/vendor/mustache/test/fixtures/inverted_section.rb +14 -0
  78. data/vendor/mustache/test/fixtures/lambda.mustache +7 -0
  79. data/vendor/mustache/test/fixtures/lambda.rb +31 -0
  80. data/vendor/mustache/test/fixtures/namespaced.mustache +1 -0
  81. data/vendor/mustache/test/fixtures/namespaced.rb +25 -0
  82. data/vendor/mustache/test/fixtures/nested_objects.mustache +17 -0
  83. data/vendor/mustache/test/fixtures/nested_objects.rb +35 -0
  84. data/vendor/mustache/test/fixtures/node.mustache +8 -0
  85. data/vendor/mustache/test/fixtures/partial_with_module.mustache +3 -0
  86. data/vendor/mustache/test/fixtures/partial_with_module.rb +37 -0
  87. data/vendor/mustache/test/fixtures/passenger.conf +5 -0
  88. data/vendor/mustache/test/fixtures/passenger.rb +27 -0
  89. data/vendor/mustache/test/fixtures/recursive.mustache +4 -0
  90. data/vendor/mustache/test/fixtures/recursive.rb +14 -0
  91. data/vendor/mustache/test/fixtures/simple.mustache +5 -0
  92. data/vendor/mustache/test/fixtures/simple.rb +26 -0
  93. data/vendor/mustache/test/fixtures/template_partial.mustache +2 -0
  94. data/vendor/mustache/test/fixtures/template_partial.rb +18 -0
  95. data/vendor/mustache/test/fixtures/template_partial.txt +4 -0
  96. data/vendor/mustache/test/fixtures/unescaped.mustache +1 -0
  97. data/vendor/mustache/test/fixtures/unescaped.rb +14 -0
  98. data/vendor/mustache/test/fixtures/utf8.mustache +3 -0
  99. data/vendor/mustache/test/fixtures/utf8_partial.mustache +1 -0
  100. data/vendor/mustache/test/helper.rb +7 -0
  101. data/vendor/mustache/test/mustache_test.rb +536 -0
  102. data/vendor/mustache/test/parser_test.rb +54 -0
  103. data/vendor/mustache/test/partial_test.rb +168 -0
  104. metadata +167 -0
@@ -0,0 +1,103 @@
1
+ require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+
4
+ #
5
+ # Helpers
6
+ #
7
+
8
+ def command?(command)
9
+ system("type #{command} > /dev/null")
10
+ end
11
+
12
+
13
+ #
14
+ # Tests
15
+ #
16
+
17
+ task :default => :test
18
+
19
+ if command? :turn
20
+ desc "Run tests"
21
+ task :test do
22
+ suffix = "-n #{ENV['TEST']}" if ENV['TEST']
23
+ sh "turn test/*.rb #{suffix}"
24
+ end
25
+ else
26
+ Rake::TestTask.new do |t|
27
+ t.libs << 'lib'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+ end
32
+
33
+ if command? :kicker
34
+ desc "Launch Kicker (like autotest)"
35
+ task :kicker do
36
+ puts "Kicking... (ctrl+c to cancel)"
37
+ exec "kicker -e rake test lib examples"
38
+ end
39
+ end
40
+
41
+
42
+ #
43
+ # Ron
44
+ #
45
+
46
+ if command? :ronn
47
+ desc "Show the manual"
48
+ task :man => "man:build" do
49
+ exec "man man/mustache.1"
50
+ end
51
+
52
+ desc "Build the manual"
53
+ task "man:build" do
54
+ sh "ronn -br5 --organization=DEFUNKT --manual='Mustache Manual' man/*.ron"
55
+ end
56
+ end
57
+
58
+
59
+ #
60
+ # Gems
61
+ #
62
+
63
+ desc "Push a new version to Gemcutter and publish docs."
64
+ task :publish do
65
+ require File.dirname(__FILE__) + '/lib/mustache/version'
66
+
67
+ system "git tag v#{Mustache::Version}"
68
+ sh "gem build mustache.gemspec"
69
+ sh "gem push mustache-#{Mustache::Version}.gem"
70
+ sh "git push origin master --tags"
71
+ sh "git clean -fd"
72
+ exec "rake pages"
73
+ end
74
+
75
+ #
76
+ # Documentation
77
+ #
78
+
79
+ begin
80
+ require 'sdoc_helpers'
81
+ rescue LoadError
82
+ warn "sdoc support not enabled. Please gem install sdoc-helpers."
83
+ end
84
+
85
+ desc "Publish to GitHub Pages"
86
+ task :pages => [ "man:build" ] do
87
+ Dir['man/*.html'].each do |f|
88
+ cp f, File.basename(f).sub('.html', '.newhtml')
89
+ end
90
+
91
+ `git commit -am 'generated manual'`
92
+ `git checkout site`
93
+
94
+ Dir['*.newhtml'].each do |f|
95
+ mv f, f.sub('.newhtml', '.html')
96
+ end
97
+
98
+ `git add .`
99
+ `git commit -m updated`
100
+ `git push site site:master`
101
+ `git checkout master`
102
+ puts :done
103
+ end
@@ -0,0 +1,15 @@
1
+ <h1><%= header %></h1>
2
+ <% if not item.empty? %>
3
+ <ul>
4
+ <% for i in item %>
5
+ <% if i[:current] %>
6
+ <li><strong><%= i[:name] %></strong></li>
7
+ <% else %>
8
+ <li><a href="<%= i[:url] %>"><%= i[:name] %></a></li>
9
+ <% end %>
10
+ <% end %>
11
+ </ul>
12
+ <% end %>
13
+ <% if item.empty? %>
14
+ <p>The list is empty.</p>
15
+ <% end %>
@@ -0,0 +1,12 @@
1
+ %h1= header
2
+ - if not item.empty?
3
+ %ul
4
+ - for i in item
5
+ - if i[:current]
6
+ %li
7
+ %strong= i[:name]
8
+ - else
9
+ %li
10
+ %a{:href => i[:url]}= i[:name]
11
+ - if item.empty?
12
+ %p The list is empty.
@@ -0,0 +1,20 @@
1
+ require 'benchmark'
2
+
3
+ count = (ENV['COUNT'] || 5000).to_i
4
+
5
+ $benches = []
6
+ def bench(name, &block)
7
+ $benches.push([name, block])
8
+ end
9
+
10
+ at_exit do
11
+ Benchmark.bmbm do |x|
12
+ $benches.each do |name, block|
13
+ x.report name.to_s do
14
+ count.times do
15
+ block.call
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ Hello <%= name %>
2
+ You have just won $<%= value %>!
3
+ <% if in_ca %>
4
+ Well, $<%= taxed_value %>, after taxes.
5
+ <% end %>
@@ -0,0 +1,78 @@
1
+ require 'erb'
2
+
3
+ $LOAD_PATH.unshift File.dirname(__FILE__)
4
+ require 'helper'
5
+
6
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../test/fixtures'
7
+ require 'complex_view'
8
+
9
+ ## erb
10
+ unless ENV['NOERB']
11
+ template = File.read(File.dirname(__FILE__) + '/complex.erb')
12
+
13
+ erb = ERB.new(template)
14
+ erb_scope = ComplexView.new
15
+ erb_scope.instance_eval("def render_erb; #{erb.src}; end")
16
+ bench 'ERB w/ caching' do
17
+ erb_scope.render_erb
18
+ end
19
+
20
+ unless ENV['CACHED']
21
+ erb_nocache_scope = ComplexView.new.send(:binding)
22
+ bench 'ERB w/o caching' do
23
+ ERB.new(template).result(erb_nocache_scope)
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+ ## haml
30
+ unless ENV['NOHAML']
31
+ require 'haml'
32
+ template = File.read(File.dirname(__FILE__) + '/complex.haml')
33
+
34
+ haml = Haml::Engine.new(template, :ugly => true)
35
+ haml_scope = ComplexView.new
36
+ haml.def_method(haml_scope, :render_haml)
37
+ bench 'HAML w/ caching' do
38
+ haml_scope.render_haml
39
+ end
40
+
41
+ unless ENV['CACHED']
42
+ haml_nocache_scope = ComplexView.new.send(:binding)
43
+ bench 'HAML w/o caching' do
44
+ Haml::Engine.new(template).render(haml_nocache_scope)
45
+ end
46
+ end
47
+ end
48
+
49
+
50
+ ## mustache
51
+ tpl = ComplexView.new
52
+ tpl.template
53
+
54
+ tpl[:header] = 'Chris'
55
+ tpl[:empty] = false
56
+ tpl[:list] = true
57
+
58
+ items = []
59
+ items << { :name => 'red', :current => true, :url => '#Red' }
60
+ items << { :name => 'green', :current => false, :url => '#Green' }
61
+ items << { :name => 'blue', :current => false, :url => '#Blue' }
62
+
63
+ tpl[:item] = items
64
+
65
+ bench '{{ w/ caching' do
66
+ tpl.to_html
67
+ end
68
+
69
+ content = File.read(ComplexView.template_file)
70
+
71
+ unless ENV['CACHED']
72
+ bench '{{ w/o caching' do
73
+ ctpl = ComplexView.new
74
+ ctpl.template = content
75
+ ctpl[:item] = items
76
+ ctpl.to_html
77
+ end
78
+ end
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+ require 'optparse'
5
+
6
+ require 'mustache'
7
+ require 'mustache/version'
8
+
9
+ class Mustache
10
+ class CLI
11
+ # Return a structure describing the options.
12
+ def self.parse_options(args)
13
+ opts = OptionParser.new do |opts|
14
+ opts.banner = "Usage: mustache [-c] [-t] FILE ..."
15
+
16
+ opts.separator " "
17
+
18
+ opts.separator "Examples:"
19
+ opts.separator " $ mustache data.yml template.mustache"
20
+ opts.separator " $ cat data.yml | mustache - template.mustache"
21
+ opts.separator " $ mustache -c template.mustache"
22
+
23
+ opts.separator " "
24
+
25
+ opts.separator " See mustache(1) or " +
26
+ "http://mustache.github.com/mustache.1.html"
27
+ opts.separator " for more details."
28
+
29
+ opts.separator " "
30
+ opts.separator "Options:"
31
+
32
+ opts.on("-c", "--compile FILE",
33
+ "Print the compiled Ruby for a given template.") do |file|
34
+ puts Mustache::Template.new(File.read(file)).compile
35
+ exit
36
+ end
37
+
38
+ opts.on("-t", "--tokens FILE",
39
+ "Print the tokenized form of a given template.") do |file|
40
+ require 'pp'
41
+ pp Mustache::Template.new(File.read(file)).tokens
42
+ exit
43
+ end
44
+
45
+ opts.separator "Common Options:"
46
+
47
+ opts.on("-v", "--version", "Print the version") do |v|
48
+ puts "Mustache v#{Mustache::Version}"
49
+ exit
50
+ end
51
+
52
+ opts.on_tail("-h", "--help", "Show this message") do
53
+ puts opts
54
+ exit
55
+ end
56
+ end
57
+
58
+ opts.separator ""
59
+
60
+ opts.parse!(args)
61
+ end
62
+
63
+ # Does the dirty work of reading files from STDIN and the command
64
+ # line then processing them. The meat of this script, if you will.
65
+ def self.process_files(input_stream)
66
+ doc = input_stream.read
67
+
68
+ if doc =~ /^(\s*---(.+)---\s*)/m
69
+ yaml = $2.strip
70
+ template = doc.sub($1, '')
71
+
72
+ YAML.each_document(yaml) do |data|
73
+ puts Mustache.render(template, data)
74
+ end
75
+ else
76
+ puts Mustache.render(doc)
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ # Help is the default.
83
+ ARGV << '-h' if ARGV.empty? && $stdin.tty?
84
+
85
+ # Process options
86
+ Mustache::CLI.parse_options(ARGV) if $stdin.tty?
87
+
88
+ # Still here - process ARGF
89
+ Mustache::CLI.process_files(ARGF)
90
+
@@ -0,0 +1,278 @@
1
+ ;;; tpl-mode.el -- a major mode for editing Google CTemplate files.
2
+ ;;; By Tony Gentilcore, July 2006
3
+ ;;;
4
+ ;;; Very minor, backwards compatible changes added for Mustache compatibility
5
+ ;;; by Chris Wanstrath, October 2009
6
+ ;;;
7
+ ;;; TO USE:
8
+ ;;; 1) Copy this file somewhere you in emacs load-path. To see what
9
+ ;;; your load-path is, run inside emacs: C-h v load-path<RET>
10
+ ;;; 2) Add the following two lines to your .emacs file:
11
+ ;;; (setq auto-mode-alist (cons '("\\.tpl$" . tpl-mode) auto-mode-alist))
12
+ ;;; (autoload 'tpl-mode "tpl-mode" "Major mode for editing CTemplate files." t)
13
+ ;;; 3) Optionally (but recommended), add this third line as well:
14
+ ;;; (add-hook 'tpl-mode-hook '(lambda () (font-lock-mode 1)))
15
+ ;;; ---
16
+ ;;;
17
+ ;;; While the Mustache language can be used for any types of text,
18
+ ;;; this mode is intended for using Mustache to write HTML.
19
+ ;;;
20
+ ;;; The indentation still has minor bugs due to the fact that
21
+ ;;; templates do not require valid HTML.
22
+ ;;;
23
+ ;;; It would be nice to be able to highlight attributes of HTML tags,
24
+ ;;; however this is difficult due to the presence of CTemplate symbols
25
+ ;;; embedded within attributes.
26
+
27
+ (eval-when-compile
28
+ (require 'font-lock))
29
+
30
+ (defgroup tpl-mode nil
31
+ "Major mode for editing Google CTemplate and Mustache files"
32
+ :group 'languages)
33
+
34
+ (defvar tpl-mode-version "1.1"
35
+ "Version of `tpl-mode.el'.")
36
+
37
+ (defvar tpl-mode-abbrev-table nil
38
+ "Abbrev table for use in tpl-mode buffers.")
39
+
40
+ (define-abbrev-table 'tpl-mode-abbrev-table ())
41
+
42
+ (defcustom tpl-mode-hook nil
43
+ "*Hook that runs upon entering tpl-mode."
44
+ :type 'hook)
45
+
46
+ (defvar tpl-mode-map nil
47
+ "Keymap for tpl-mode major mode")
48
+
49
+ (if tpl-mode-map
50
+ nil
51
+ (setq tpl-mode-map (make-sparse-keymap)))
52
+
53
+ (define-key tpl-mode-map "\t" 'tpl-indent-command)
54
+ (define-key tpl-mode-map "\C-m" 'reindent-then-newline-and-indent)
55
+ (define-key tpl-mode-map "\C-ct" 'tpl-insert-tag)
56
+ (define-key tpl-mode-map "\C-cv" 'tpl-insert-variable)
57
+ (define-key tpl-mode-map "\C-cs" 'tpl-insert-section)
58
+
59
+
60
+ (defvar tpl-mode-syntax-table nil
61
+ "Syntax table in use in tpl-mode buffers.")
62
+
63
+ ;; Syntax table.
64
+ (if tpl-mode-syntax-table
65
+ nil
66
+ (setq tpl-mode-syntax-table (make-syntax-table text-mode-syntax-table))
67
+ (modify-syntax-entry ?< "(> " tpl-mode-syntax-table)
68
+ (modify-syntax-entry ?> ")< " tpl-mode-syntax-table)
69
+ (modify-syntax-entry ?\" ". " tpl-mode-syntax-table)
70
+ (modify-syntax-entry ?\\ ". " tpl-mode-syntax-table)
71
+ (modify-syntax-entry ?' "w " tpl-mode-syntax-table))
72
+
73
+ (defvar tpl-basic-offset 2
74
+ "The basic indentation offset.")
75
+
76
+ ;; Constant regular expressions to identify template elements.
77
+ (defconst tpl-mode-tpl-token "[a-zA-Z_][a-zA-Z0-9_:=\?!-]*?")
78
+ (defconst tpl-mode-section (concat "\\({{[#^/]\s*"
79
+ tpl-mode-tpl-token
80
+ "\s*}}\\)"))
81
+ (defconst tpl-mode-open-section (concat "\\({{#\s*"
82
+ tpl-mode-tpl-token
83
+ "\s*}}\\)"))
84
+ (defconst tpl-mode-close-section (concat "{{/\\(\s*"
85
+ tpl-mode-tpl-token
86
+ "\s*\\)}}"))
87
+ ;; TODO(tonyg) Figure out a way to support multiline comments.
88
+ (defconst tpl-mode-comment "\\({{!.*?}}\\)")
89
+ (defconst tpl-mode-include (concat "\\({{[><]\s*"
90
+ tpl-mode-tpl-token
91
+ "\s*}}\\)"))
92
+ (defconst tpl-mode-variable (concat "\\({{\s*"
93
+ tpl-mode-tpl-token
94
+ "\s*}}\\)"))
95
+ (defconst tpl-mode-builtins
96
+ (concat
97
+ "\\({{\\<\s*"
98
+ (regexp-opt
99
+ '("BI_NEWLINE" "BI_SPACE")
100
+ t)
101
+ "\s*\\>}}\\)"))
102
+ (defconst tpl-mode-close-section-at-start (concat "^[ \t]*?"
103
+ tpl-mode-close-section))
104
+
105
+ ;; Constant regular expressions to identify html tags.
106
+ ;; Taken from HTML 4.01 / XHTML 1.0 Reference found at:
107
+ ;; http://www.w3schools.com/tags/default.asp.
108
+ (defconst tpl-mode-html-constant "\\(&#?[a-z0-9]\\{2,5\\};\\)")
109
+ (defconst tpl-mode-pair-tag
110
+ (concat
111
+ "\\<"
112
+ (regexp-opt
113
+ '("a" "abbr" "acronym" "address" "applet" "area" "b" "bdo"
114
+ "big" "blockquote" "body" "button" "caption" "center" "cite"
115
+ "code" "col" "colgroup" "dd" "del" "dfn" "dif" "div" "dl"
116
+ "dt" "em" "fieldset" "font" "form" "frame" "frameset" "h1"
117
+ "h2" "h3" "h4" "h5" "h6" "head" "html" "i" "iframe" "ins"
118
+ "kbd" "label" "legend" "li" "link" "map" "menu" "noframes"
119
+ "noscript" "object" "ol" "optgroup" "option" "p" "pre" "q"
120
+ "s" "samp" "script" "select" "small" "span" "strike"
121
+ "strong" "style" "sub" "sup" "table" "tbody" "td" "textarea"
122
+ "tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var")
123
+ t)
124
+ "\\>"))
125
+ (defconst tpl-mode-standalone-tag
126
+ (concat
127
+ "\\<"
128
+ (regexp-opt
129
+ '("base" "br" "hr" "img" "input" "meta" "param")
130
+ t)
131
+ "\\>"))
132
+ (defconst tpl-mode-open-tag (concat "<\\("
133
+ tpl-mode-pair-tag
134
+ "\\)"))
135
+ (defconst tpl-mode-close-tag (concat "</\\("
136
+ tpl-mode-pair-tag
137
+ "\\)>"))
138
+ (defconst tpl-mode-close-tag-at-start (concat "^[ \t]*?"
139
+ tpl-mode-close-tag))
140
+
141
+ (defconst tpl-mode-blank-line "^[ \t]*?$")
142
+ (defconst tpl-mode-dangling-open (concat "\\("
143
+ tpl-mode-open-section
144
+ "\\)\\|\\("
145
+ tpl-mode-open-tag
146
+ "\\)[^/]*$"))
147
+
148
+ (defun tpl-indent-command ()
149
+ "Command for indenting text. Just calls tpl-indent."
150
+ (interactive)
151
+ (tpl-indent))
152
+
153
+ (defun tpl-insert-tag (tag)
154
+ "Inserts an HTML tag."
155
+ (interactive "sTag: ")
156
+ (tpl-indent)
157
+ (insert (concat "<" tag ">"))
158
+ (insert "\n\n")
159
+ (insert (concat "</" tag ">"))
160
+ (tpl-indent)
161
+ (forward-line -1)
162
+ (tpl-indent))
163
+
164
+ (defun tpl-insert-variable (variable)
165
+ "Inserts a tpl variable."
166
+ (interactive "sVariable: ")
167
+ (insert (concat "{{" variable "}}")))
168
+
169
+ (defun tpl-insert-section (section)
170
+ "Inserts a tpl section."
171
+ (interactive "sSection: ")
172
+ (tpl-indent)
173
+ (insert (concat "{{#" section "}}\n"))
174
+ (insert "\n")
175
+ (insert (concat "{{/" section "}}"))
176
+ (tpl-indent)
177
+ (forward-line -1)
178
+ (tpl-indent))
179
+
180
+ ;; Function to control indenting.
181
+ (defun tpl-indent ()
182
+ "Indent current line"
183
+ ;; Set the point to beginning of line.
184
+ (beginning-of-line)
185
+ ;; If we are at the beginning of the file, indent to 0.
186
+ (if (bobp)
187
+ (indent-line-to 0)
188
+ (let ((tag-stack 1) (close-tag "") (cur-indent 0) (old-pnt (point-marker))
189
+ (close-at-start) (open-token) (dangling-open))
190
+ (progn
191
+ ;; Determine if this is a template line or an html line.
192
+ (if (looking-at "^[ \t]*?{{")
193
+ (setq close-at-start tpl-mode-close-section-at-start
194
+ open-token "{{#")
195
+ (setq close-at-start tpl-mode-close-tag-at-start
196
+ open-token "<"))
197
+ ;; If there is a closing tag at the start of the line, search back
198
+ ;; for its opener and indent to that level.
199
+ (if (looking-at close-at-start)
200
+ (progn
201
+ (save-excursion
202
+ (setq close-tag (match-string 1))
203
+ ;; Keep searching for a match for the close tag until
204
+ ;; the tag-stack is 0.
205
+ (while (and (not (bobp))
206
+ (> tag-stack 0)
207
+ (re-search-backward (concat open-token
208
+ "\\(/?\\)"
209
+ close-tag) nil t))
210
+ (if (string-equal (match-string 1) "/")
211
+ ;; We found another close tag, so increment tag-stack.
212
+ (setq tag-stack (+ tag-stack 1))
213
+ ;; We found an open tag, so decrement tag-stack.
214
+ (setq tag-stack (- tag-stack 1)))
215
+ (setq cur-indent (current-indentation))))
216
+ (if (> tag-stack 0)
217
+ (save-excursion
218
+ (forward-line -1)
219
+ (setq cur-indent (current-indentation)))))
220
+ ;; This was not a closing tag, so we check if the previous line
221
+ ;; was an opening tag.
222
+ (save-excursion
223
+ ;; Keep moving back until we find a line that is not blank
224
+ (while (progn
225
+ (forward-line -1)
226
+ (and (not (bobp)) (looking-at tpl-mode-blank-line))))
227
+ (setq cur-indent (current-indentation))
228
+ (if (re-search-forward tpl-mode-dangling-open old-pnt t)
229
+ (setq cur-indent (+ cur-indent tpl-basic-offset)))))
230
+ ;; Finally, we execute the actual indentation.
231
+ (if (> cur-indent 0)
232
+ (indent-line-to cur-indent)
233
+ (indent-line-to 0))))))
234
+
235
+ ;; controls highlighting
236
+ (defconst tpl-mode-font-lock-keywords
237
+ (list
238
+ (list tpl-mode-section
239
+ '(1 font-lock-keyword-face))
240
+ (list tpl-mode-comment
241
+ '(1 font-lock-comment-face))
242
+ (list tpl-mode-include
243
+ '(1 font-lock-function-name-face))
244
+ (list tpl-mode-builtins
245
+ '(1 font-lock-variable-name-face))
246
+ (list tpl-mode-variable
247
+ '(1 font-lock-reference-face))
248
+ (list (concat "</?\\(" tpl-mode-pair-tag "\\)")
249
+ '(1 font-lock-function-name-face))
250
+ (list (concat "<\\(" tpl-mode-standalone-tag "\\)")
251
+ '(1 font-lock-function-name-face))
252
+ (list tpl-mode-html-constant
253
+ '(1 font-lock-variable-name-face))))
254
+
255
+ (put 'tpl-mode 'font-lock-defaults '(tpl-font-lock-keywords nil t))
256
+
257
+ (defun tpl-mode ()
258
+ "Major mode for editing Google CTemplate file."
259
+ (interactive)
260
+ (kill-all-local-variables)
261
+ (use-local-map tpl-mode-map)
262
+ (setq major-mode 'tpl-mode)
263
+ (setq mode-name "tpl-mode")
264
+ (setq local-abbrev-table tpl-mode-abbrev-table)
265
+ (setq indent-tabs-mode nil)
266
+ (set-syntax-table tpl-mode-syntax-table)
267
+ ;; show trailing whitespace, but only when the user can fix it
268
+ (setq show-trailing-whitespace (not buffer-read-only))
269
+ (make-local-variable 'indent-line-function)
270
+ (setq indent-line-function 'tpl-indent)
271
+ (setq font-lock-defaults '(tpl-mode-font-lock-keywords))
272
+ (run-hooks 'tpl-mode-hook))
273
+
274
+ ;; Automatically load tpl-mode for .mustache files.
275
+ (add-to-list 'auto-mode-alist '("\\.mustache$" . tpl-mode))
276
+ (add-hook 'tpl-mode-hook '(lambda () (font-lock-mode 1)))
277
+
278
+ (provide 'mustache-mode)