jekyll-lilypond 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +99 -0
  5. data/LICENSE +21 -0
  6. data/README.md +98 -0
  7. data/files/rite.png +0 -0
  8. data/jekyll-lilypond.gemspec +23 -0
  9. data/lib/jekyll-lilypond/file_processor.rb +67 -0
  10. data/lib/jekyll-lilypond/lilypond_tag.rb +34 -0
  11. data/lib/jekyll-lilypond/tag.rb +17 -0
  12. data/lib/jekyll-lilypond/tag_processor.rb +56 -0
  13. data/lib/jekyll-lilypond/templates/basic.ly +45 -0
  14. data/lib/jekyll-lilypond/templates/empty.ly +1 -0
  15. data/lib/jekyll-lilypond/templates/figure.html +25 -0
  16. data/lib/jekyll-lilypond/templates/img.html +4 -0
  17. data/lib/jekyll-lilypond/templates/raw.html +1 -0
  18. data/lib/jekyll-lilypond/templates/raw.ly +1 -0
  19. data/lib/jekyll-lilypond/templates/showsource.html +36 -0
  20. data/lib/jekyll-lilypond/templates.rb +60 -0
  21. data/lib/jekyll-lilypond/version.rb +5 -0
  22. data/lib/jekyll-lilypond.rb +11 -0
  23. data/spec/file_processor_spec.rb +167 -0
  24. data/spec/fixtures/.gitignore +5 -0
  25. data/spec/fixtures/404.html +25 -0
  26. data/spec/fixtures/Gemfile +31 -0
  27. data/spec/fixtures/_config.yml +56 -0
  28. data/spec/fixtures/_layouts/basic_html.html +1 -0
  29. data/spec/fixtures/_layouts/vacuous_html.html +1 -0
  30. data/spec/fixtures/_layouts/vacuous_ly.ly +1 -0
  31. data/spec/fixtures/_layouts/variables_html.html +1 -0
  32. data/spec/fixtures/_layouts/variables_ly.ly +1 -0
  33. data/spec/fixtures/_posts/2021-01-16-welcome-to-jekyll.markdown +29 -0
  34. data/spec/fixtures/about.markdown +18 -0
  35. data/spec/fixtures/index.markdown +6 -0
  36. data/spec/fixtures/page.md +8 -0
  37. data/spec/integration_spec.rb +115 -0
  38. data/spec/spec_helper.rb +88 -0
  39. data/spec/tag_processor_spec.rb +135 -0
  40. data/spec/tag_spec.rb +51 -0
  41. data/spec/templates_spec.rb +175 -0
  42. metadata +118 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 03f518ed64fd17a4aa282f1e11c82f1ea127de1231919ad2f22f419f3a95d942
4
+ data.tar.gz: 8225e9fd20e2be85d2be52781a01d65de431313399d7313d754e416f78148c6c
5
+ SHA512:
6
+ metadata.gz: 48f09dbd1c6101a2ff2d13500690f72efee15bfc7b33cc647ecf050de11f082de1bc195a16fa56d52958b7605c362cf7a21258498f0cce8c51015436261056c5
7
+ data.tar.gz: 0b51587b3ff6e62de63486833c9269bd961d025d047770431adcb8b7fb0c98207eb6798efee19ee6e175e7a705d4811216395004290f7fe223755552dac9788c
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ spec/dest
2
+ *.gem
3
+ *.rbc
4
+ /.config
5
+ /coverage/
6
+ /InstalledFiles
7
+ /pkg/
8
+ /spec/reports/
9
+ /spec/examples.txt
10
+ /test/tmp/
11
+ /test/version_tmp/
12
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "jekyll"
4
+ gem "minima"
5
+
6
+ group :development, :test do
7
+ gem "rspec"
8
+ gem 'simplecov', require: false, group: :test
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,99 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.7.0)
5
+ public_suffix (>= 2.0.2, < 5.0)
6
+ colorator (1.1.0)
7
+ concurrent-ruby (1.1.7)
8
+ diff-lcs (1.4.4)
9
+ docile (1.3.5)
10
+ em-websocket (0.5.2)
11
+ eventmachine (>= 0.12.9)
12
+ http_parser.rb (~> 0.6.0)
13
+ eventmachine (1.2.7)
14
+ ffi (1.14.2)
15
+ forwardable-extended (2.6.0)
16
+ http_parser.rb (0.6.0)
17
+ i18n (1.8.7)
18
+ concurrent-ruby (~> 1.0)
19
+ jekyll (4.2.0)
20
+ addressable (~> 2.4)
21
+ colorator (~> 1.0)
22
+ em-websocket (~> 0.5)
23
+ i18n (~> 1.0)
24
+ jekyll-sass-converter (~> 2.0)
25
+ jekyll-watch (~> 2.0)
26
+ kramdown (~> 2.3)
27
+ kramdown-parser-gfm (~> 1.0)
28
+ liquid (~> 4.0)
29
+ mercenary (~> 0.4.0)
30
+ pathutil (~> 0.9)
31
+ rouge (~> 3.0)
32
+ safe_yaml (~> 1.0)
33
+ terminal-table (~> 2.0)
34
+ jekyll-feed (0.15.1)
35
+ jekyll (>= 3.7, < 5.0)
36
+ jekyll-sass-converter (2.1.0)
37
+ sassc (> 2.0.1, < 3.0)
38
+ jekyll-seo-tag (2.7.1)
39
+ jekyll (>= 3.8, < 5.0)
40
+ jekyll-watch (2.2.1)
41
+ listen (~> 3.0)
42
+ kramdown (2.3.0)
43
+ rexml
44
+ kramdown-parser-gfm (1.1.0)
45
+ kramdown (~> 2.0)
46
+ liquid (4.0.3)
47
+ listen (3.4.1)
48
+ rb-fsevent (~> 0.10, >= 0.10.3)
49
+ rb-inotify (~> 0.9, >= 0.9.10)
50
+ mercenary (0.4.0)
51
+ minima (2.5.1)
52
+ jekyll (>= 3.5, < 5.0)
53
+ jekyll-feed (~> 0.9)
54
+ jekyll-seo-tag (~> 2.1)
55
+ pathutil (0.16.2)
56
+ forwardable-extended (~> 2.6)
57
+ public_suffix (4.0.6)
58
+ rb-fsevent (0.10.4)
59
+ rb-inotify (0.10.1)
60
+ ffi (~> 1.0)
61
+ rexml (3.2.4)
62
+ rouge (3.26.0)
63
+ rspec (3.10.0)
64
+ rspec-core (~> 3.10.0)
65
+ rspec-expectations (~> 3.10.0)
66
+ rspec-mocks (~> 3.10.0)
67
+ rspec-core (3.10.1)
68
+ rspec-support (~> 3.10.0)
69
+ rspec-expectations (3.10.1)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.10.0)
72
+ rspec-mocks (3.10.1)
73
+ diff-lcs (>= 1.2.0, < 2.0)
74
+ rspec-support (~> 3.10.0)
75
+ rspec-support (3.10.1)
76
+ safe_yaml (1.0.5)
77
+ sassc (2.4.0)
78
+ ffi (~> 1.9)
79
+ simplecov (0.21.2)
80
+ docile (~> 1.1)
81
+ simplecov-html (~> 0.11)
82
+ simplecov_json_formatter (~> 0.1)
83
+ simplecov-html (0.12.3)
84
+ simplecov_json_formatter (0.1.2)
85
+ terminal-table (2.0.0)
86
+ unicode-display_width (~> 1.1, >= 1.1.1)
87
+ unicode-display_width (1.7.0)
88
+
89
+ PLATFORMS
90
+ universal-darwin-19
91
+
92
+ DEPENDENCIES
93
+ jekyll
94
+ minima
95
+ rspec
96
+ simplecov
97
+
98
+ BUNDLED WITH
99
+ 2.2.5
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Leah Velleman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # jekyll-lilypond
2
+
3
+ <p align="center">
4
+ <img src="files/rite.png" width="75%"/>
5
+ </p>
6
+
7
+ Automatically generate sheet music images by adding Lilypond blocks to your markdown files. Customize their
8
+ appearance using Liquid attributes. The plugin caches the images it generates, making auto-regeneration fast.
9
+
10
+ For complete documentation, see [the plugin website](https://www.velleman.org/jekyll-lilypond).
11
+
12
+
13
+ ## Installation
14
+
15
+ The plugin requires Lilypond and Inkscape. To use it in a Jekyll site,
16
+ add
17
+
18
+ ```ruby
19
+ gem 'jekyll-lilypond'
20
+ ```
21
+
22
+ to your Gemfile and
23
+
24
+ ```yaml
25
+ plugins:
26
+ - jekyll-lilypond
27
+ ```
28
+
29
+ to your `_config.yml`.
30
+
31
+ ## Quick start
32
+
33
+ Inside the block, write a Lilypond music expression.
34
+ ```
35
+ {% lilypond alt: "Five notes of the A-minor scale" %}
36
+ a b c d e
37
+ {% endlilypond %}
38
+ ```
39
+ The expression can include multiple staves, expressive marks, time and key signature changes, and any of the other notation Lilypond supports within a music
40
+ expression. For details, see [this brief summary](https://lilypond.org/doc/v2.20/Documentation/learning/score-is-a-_0028single_0029-compound-musical-expression) in the Lilypond teaching manual or [Wikipedia's list of common music expression details](https://en.wikipedia.org/wiki/Help:Score#Syntax).
41
+
42
+ To make customizations that can't be make within a music expression — for instance, to change the width or height of the score or specify a custom font —
43
+ use attributes on the `{% lilypond %}` tag. For more information on attributes, see [the plugin documentation](http://127.0.0.1:4000/jekyll-lilypond#attributes).
44
+
45
+ ## Approach
46
+
47
+ ### Caching
48
+
49
+ Lilypond runs more slowly than Jekyll, and regenerating every score would create a noticeable lag. This would be especially painful in auto-regenerate mode,
50
+ which is normally very responsive. To solve this, I cache images. Each Lilypond source file, and each resulting image, has a filename derived from the MD5 hash
51
+ of the source code. The plugin only compiles a Lilypond source file when the corresponding image does not yet exist.
52
+
53
+ To force the plugin to regenerate all of the score images for a site, which is sometimes useful for debugging, empty the `lilypond_files` directory.
54
+
55
+ To keep upload size to a minimum, you can also empty the `lilypond_files` directory and regenerate the site before deploying. This removes "stale" images
56
+ that are no longer in use.
57
+
58
+ ### Templates
59
+
60
+ The plugin generates two kinds of code: Lilypond source files, which it uses to generate images, and HTML includes, which appear in the finished page
61
+ and contain the `img` element and surrounding markup.
62
+
63
+ To generate both kinds of source code, it uses Liquid templates. Liquid is the native templating language of Jekyll. Just as Jekyll users can write their own
64
+ templates to create new page layouts, users of this plugin can write their own templates to add simple features and customizations.
65
+
66
+ As well as allowing customization, using a template to generate Lilypond source avoids the need to repeat boilerplate. For instance, the default Lilypond
67
+ template begins like this:
68
+ ```
69
+ \version "2.20.0"
70
+ \paper {
71
+ indent = 0\mm
72
+ short-indent = 0\mm
73
+ bottom-margin = 4\mm
74
+ oddHeaderMarkup = ##f
75
+ evenHeaderMarkup = ##f
76
+ oddFooterMarkup = ##f
77
+ evenFooterMarkup = ##f
78
+ ...
79
+ }
80
+ ```
81
+ These settings produce clean output without extraneous marks, headers, footers, or whitespace, but it would be a hassle to retype them in every Lilypond block.
82
+ Later parts of the template include correct code for setting the page width, font, and so on, which saves the user from needing to remember the somewhat
83
+ arbitrary syntax for doing those things.
84
+
85
+ ### Future plans
86
+
87
+ The next thing on my agenda is to generate assets other than images. For instance, Lilypond can generate MIDI files and software synthesizers can generate
88
+ mp3 audio from MIDI. It would be nice to support those — and, beyond that, to support other workflows that users might think of. (Maybe someone will want to
89
+ generate video? Or do musical analysis on MIDI files?)
90
+
91
+ The most flexible way to do all this would be to let users specify workflow steps in a sitewide Rakefile, alongside whatever other deployment and
92
+ asset-processing tasks they may have specified there. Templates could then specify what sorts of generated files they require, and the plugin could call on
93
+ Rake to generate those that don't exist.
94
+
95
+ ## Testing
96
+
97
+ `bundle exec rspec` runs tests. A minimal sample Jekyll site for tests to call on is in `spec/fixtures`,
98
+ with the interesting details being the sample templates in `spec/fixtures/layouts`.
data/files/rite.png ADDED
Binary file
@@ -0,0 +1,23 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require "jekyll-lilypond/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.version = "0.1.1"
8
+ spec.authors = "Leah Velleman"
9
+ spec.name = "jekyll-lilypond"
10
+ spec.summary = "Lilypond music snippets in Jekyll"
11
+ spec.homepage = "https://www.velleman.org/jekyll-lilypond.html"
12
+ spec.license = "MIT"
13
+ spec.files = `git ls-files -z`.split("\x0")
14
+ spec.metadata = {
15
+ "documentation_uri" => "https://www.velleman.org/jekyll-lilypond.html",
16
+ "source_code_uri" => "https://github.com/leahvelleman/jekyll-lilypond"
17
+ }
18
+ spec.require_paths = ["lib"]
19
+ spec.add_dependency "jekyll", ">= 3.0", "< 5.0"
20
+ spec.add_development_dependency "rspec", "~> 3.5"
21
+ end
22
+
23
+
@@ -0,0 +1,67 @@
1
+ require "digest"
2
+
3
+ module Jekyll
4
+ module Lilypond
5
+ class FileProcessor
6
+ def initialize(working_dir, hash, source)
7
+ @hash = hash
8
+ @source = source
9
+ @working_dir = working_dir
10
+ end
11
+
12
+ def filepath
13
+ "#{@working_dir}/#{@hash}"
14
+ end
15
+
16
+ def write
17
+ unless File.directory?(@working_dir)
18
+ FileUtils.mkdir_p(@working_dir)
19
+ end
20
+ unless File.exist?("#{filepath}.ly")
21
+ File.open("#{filepath}.ly", "w") do |f|
22
+ f.write(@source)
23
+ end
24
+ end
25
+ end
26
+
27
+ def compile
28
+ unless File.exist?("#{filepath}.svg")
29
+ puts "Jekyll-lilypond: making #{@hash}.svg"
30
+ Kernel.system("lilypond", "-lERROR",
31
+ "-dbackend=svg",
32
+ "--output=#{filepath}",
33
+ "#{filepath}.ly")
34
+ end
35
+ end
36
+
37
+ def trim_svg
38
+ unless File.exist?("#{filepath}-trimmed.svg")
39
+ if File.exist?("#{filepath}.svg")
40
+ puts "Jekyll-lilypond: making #{@hash}-trimmed.svg"
41
+ Kernel.system("inkscape",
42
+ "#{filepath}.svg",
43
+ "--export-area-drawing",
44
+ "--export-type=svg",
45
+ "--export-filename=#{filepath}-trimmed.svg")
46
+ else
47
+ raise RuntimeError.new(
48
+ "Cannot trim SVG: expected SVG file #{filepath}.svg does not exist")
49
+ end
50
+ end
51
+ end
52
+
53
+ def make_mp3
54
+ unless File.exist?("#{filepath}.mp3")
55
+ if File.exist?("#{filepath}.midi")
56
+ puts "Jekyll-lilypond: making #{@hash}.mp3"
57
+ Kernel.system("timidity #{filepath}.midi -Ow -o - | ffmpeg -i - -acodec libmp3lame -ab 64k #{filepath}.mp3", [:out, :err] => "/dev/null")
58
+ else
59
+ raise RuntimeError.new(
60
+ "Cannot generate mp3: expected MIDI file #{filepath}.midi does not exist.")
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,34 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ class LilypondTag < Liquid::Block
4
+ def initialize(_, argtext, _)
5
+ super
6
+ @attributes = parse_attributes(argtext)
7
+ end
8
+
9
+ def parse_attributes(text)
10
+ attributes = {}
11
+ text.scan(Liquid::TagAttributes) do |key, value|
12
+ value=value.delete_prefix('"').delete_prefix("'")
13
+ value=value.delete_suffix('"').delete_suffix("'")
14
+ attributes[key] = value
15
+ end
16
+ attributes["attr_text"] = text
17
+ attributes
18
+ end
19
+
20
+ def render(context)
21
+ content = super.strip
22
+ site = context.registers[:site]
23
+
24
+ tag = Tag.new(@attributes, content)
25
+ tp = TagProcessor.new(site, tag)
26
+ tp.run!
27
+ tp.include
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ Liquid::Template.register_tag("lilypond", Jekyll::Lilypond::LilypondTag)
34
+
@@ -0,0 +1,17 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ class Tag
4
+ attr_accessor :attrs, :template_names, :template_code
5
+
6
+ def initialize(attrs, content)
7
+ @attrs = attrs
8
+ @attrs["content"] = content
9
+ @template_names = { source: @attrs.delete("source_template"),
10
+ include: @attrs.delete("include_template") }
11
+ @template_code = { source: @attrs.delete("source_template_code"),
12
+ include: @attrs.delete("include_template_code") }
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,56 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ class TagProcessor
4
+ attr_accessor :site
5
+
6
+ def initialize(site, tag)
7
+ @site = site
8
+ @tag = tag
9
+ end
10
+
11
+ def source
12
+ source_template_obj.render(@tag)
13
+ end
14
+
15
+ def source_template_obj
16
+ Template.new(@site, @tag, :source)
17
+ end
18
+
19
+ def hash
20
+ Digest::MD5.hexdigest(source)
21
+ end
22
+
23
+ def include
24
+ @tag.attrs.update("filename" => hash)
25
+ include_template_obj.render(@tag)
26
+ end
27
+
28
+ def include_template_obj
29
+ Template.new(@site, @tag, :include)
30
+ end
31
+
32
+ def file_processor
33
+ FileProcessor.new("#{site.source}/lilypond_files", hash, source)
34
+ end
35
+
36
+ def run!
37
+ fp = file_processor
38
+ fp.write
39
+ fp.compile
40
+ fp.trim_svg
41
+ fp.make_mp3 if @tag.attrs["mp3"] == "true"
42
+
43
+ @site.static_files << StaticFile.new(site,
44
+ site.source,
45
+ "lilypond_files",
46
+ "#{hash}-trimmed.svg")
47
+
48
+ @site.static_files << StaticFile.new(site,
49
+ site.source,
50
+ "lilypond_files",
51
+ "#{hash}.mp3") if @tag.attrs["mp3"] == "true"
52
+ end
53
+ end
54
+ end
55
+ end
56
+
@@ -0,0 +1,45 @@
1
+ \version "2.20.0"
2
+ \include "articulate.ly"
3
+ \paper {
4
+ indent = 0\mm
5
+ short-indent = 0\mm
6
+ {% if width %}
7
+ paper-width = {{ width }}\in
8
+ {% if height %}
9
+ paper-height = {{ height }}\in
10
+ {% else %}
11
+ page-breaking = #ly:one-page-breaking
12
+ {% endif %}
13
+ {% else %}
14
+ page-breaking = #ly:one-line-breaking
15
+ {% endif %}
16
+ left-margin = 4\mm
17
+ right-margin = 4\mm
18
+ top-margin = 4\mm
19
+ bottom-margin = 4\mm
20
+ oddHeaderMarkup = ##f
21
+ evenHeaderMarkup = ##f
22
+ oddFooterMarkup = ##f
23
+ evenFooterMarkup = ##f
24
+ }
25
+ \score {
26
+ \unfoldRepeats \articulate
27
+ <<
28
+ {{ content }}
29
+ >>
30
+ \layout {
31
+ #(layout-set-staff-size 16)
32
+ \context {
33
+ \Lyrics
34
+ {% if lyricfont %}
35
+ \override LyricText #'font-name = #"{{ lyricfont }}"
36
+ {% endif %}
37
+ {% if lyricsize %}
38
+ \override LyricText #'font-size = #{{ lyricsize }}
39
+ {% endif %}
40
+ }
41
+ }
42
+ \midi {
43
+ \tempo 4 = {{ tempo | default: "120" }}
44
+ }
45
+ }
@@ -0,0 +1 @@
1
+ {{ content }}
@@ -0,0 +1,25 @@
1
+ <figure>
2
+ <img
3
+ src="lilypond_files/{{ filename }}-trimmed.svg"
4
+ {%- if style %}
5
+ style="{{ style }}"
6
+ {% endif -%}
7
+ {%- if class %}
8
+ class="{{ class }}"
9
+ {% endif -%}
10
+ {%- if alt %}
11
+ alt="{{ alt }}"
12
+ title="{{ alt }}"
13
+ {% endif -%}
14
+ />
15
+ {%- if mp3 %}
16
+ <audio controls>
17
+ <source src="lilypond_files/{{ filename }}.mp3" type="audio/mp3" />
18
+ Your browser does not support the <code>audio</code> element.
19
+ </audio>
20
+ {% endif -%}
21
+ {%- if caption %}
22
+ <figcaption>{{ caption }}</figcaption>
23
+ {% endif -%}
24
+ </figure>
25
+
@@ -0,0 +1,4 @@
1
+ <img src="lilypond_files/{{ filename }}-trimmed.svg"
2
+ alt="{{ alt }}"
3
+ class="{{ class }}"
4
+ style="{{ style }}"/>
@@ -0,0 +1 @@
1
+ {{ content }}
@@ -0,0 +1 @@
1
+ {{ content }}
@@ -0,0 +1,36 @@
1
+ <figure
2
+ {%- if style %}
3
+ style="{{ style }}"
4
+ {% endif -%}
5
+ {%- if class %}
6
+ class="{{ class }}"
7
+ {% endif -%}
8
+ >
9
+ <img src="lilypond_files/{{ filename }}-trimmed.svg"
10
+ {%- if alt %}
11
+ alt="{{ alt }}"
12
+ title="{{ alt }}"
13
+ {% endif -%}
14
+ />
15
+ {%- if mp3 %}
16
+ <audio controls>
17
+ <source src="lilypond_files/{{ filename }}.mp3" type="audio/mp3" />
18
+ Your browser does not support the <code>audio</code> element.
19
+ </audio>
20
+ {% endif -%}
21
+ {%- if caption %}
22
+ <figcaption>{{ caption }}</figcaption>
23
+ {% endif -%}
24
+ <details>
25
+ <summary>Show source</summary>
26
+ <pre>
27
+ {%- raw -%}{% {% endraw %}
28
+ lilypond {{ attr_text -}}
29
+ {%- raw %}%}{% endraw %}
30
+ {{ content | escape -}}
31
+ {%- raw -%}
32
+ {% endlilypond %}
33
+ {% endraw %}
34
+ </pre>
35
+ </details>
36
+ </figure>
@@ -0,0 +1,60 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ class Template
4
+ def initialize(site, tag, type)
5
+ @site = site
6
+ @type = type
7
+ @tag_template_names = tag.template_names
8
+ @tag_template_code = tag.template_code
9
+ end
10
+
11
+ def render(tag)
12
+ Liquid::Template.parse(template_code).render(tag.attrs)
13
+ end
14
+
15
+ def template_name
16
+ @tag_template_names[@type] || sitewide_template_names[@type] || plugin_template_names[@type]
17
+ end
18
+
19
+ def template_code
20
+ @tag_template_code[@type] or
21
+ fetch_site_template(template_name) or
22
+ fetch_plugin_template(template_name) or
23
+ raise LoadError.new("No template named #{template_name}.#{extension}")
24
+ end
25
+
26
+
27
+ private
28
+ def sitewide_template_names
29
+ if @site.respond_to? :lilypond and @site.lilypond.respond_to? :template_names
30
+ @site.lilypond.template_names
31
+ else
32
+ { source: nil, include: nil }
33
+ end
34
+ end
35
+
36
+ def plugin_template_names
37
+ { source: "basic", include: "img" }
38
+ end
39
+
40
+ def fetch_site_template(name)
41
+ if @site.layouts[name]
42
+ @site.layouts[name].content.strip
43
+ end
44
+ end
45
+
46
+ def fetch_plugin_template(name)
47
+ dir = File.join(File.dirname(__dir__), "/jekyll-lilypond/templates/")
48
+ filename = File.join(dir, "#{name}.#{extension}")
49
+ if File.exists?(filename)
50
+ File.read(filename).strip
51
+ end
52
+ end
53
+
54
+ def extension
55
+ if @type == :source then "ly" else "html" end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,5 @@
1
+ module Jekyll
2
+ module Lilypond
3
+ VERSION = "0.0.0"
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ require "jekyll"
2
+ require "jekyll-lilypond/tag.rb"
3
+ require "jekyll-lilypond/file_processor.rb"
4
+ require "jekyll-lilypond/templates.rb"
5
+ require "jekyll-lilypond/tag_processor.rb"
6
+ require "jekyll-lilypond/lilypond_tag.rb"
7
+
8
+ module Jekyll
9
+ module Lilypond
10
+ end
11
+ end