angry_mob_common_targets 0.1.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.
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)