lydown 0.10.0 → 0.12.4
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.
- checksums.yaml +4 -4
- data/README.md +452 -206
- data/bin/lydown +5 -1
- data/lib/lydown/cache.rb +1 -2
- data/lib/lydown/cli.rb +2 -0
- data/lib/lydown/cli/commands.rb +25 -7
- data/lib/lydown/cli/compiler.rb +32 -9
- data/lib/lydown/cli/diff.rb +1 -1
- data/lib/lydown/cli/installer.rb +175 -0
- data/lib/lydown/cli/proofing.rb +44 -41
- data/lib/lydown/cli/repl.rb +232 -0
- data/lib/lydown/cli/support.rb +33 -0
- data/lib/lydown/core_ext.rb +8 -0
- data/lib/lydown/lilypond.rb +1 -0
- data/lib/lydown/ly_lib/lib.ly +1 -1
- data/lib/lydown/parsing.rb +1 -1
- data/lib/lydown/rendering.rb +34 -0
- data/lib/lydown/rendering/base.rb +1 -1
- data/lib/lydown/rendering/movement.rb +0 -11
- data/lib/lydown/rendering/music.rb +2 -0
- data/lib/lydown/rendering/notes.rb +2 -0
- data/lib/lydown/rendering/settings.rb +34 -8
- data/lib/lydown/rendering/source_ref.rb +3 -2
- data/lib/lydown/templates/lilypond_doc.erb +5 -0
- data/lib/lydown/templates/movement.erb +1 -1
- data/lib/lydown/templates/variables.erb +5 -0
- data/lib/lydown/version.rb +1 -1
- data/lib/lydown/work.rb +9 -4
- data/lib/lydown/work_context.rb +6 -8
- metadata +7 -33
@@ -0,0 +1,232 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'readline'
|
5
|
+
|
6
|
+
module Lydown::CLI::REPL
|
7
|
+
class << self
|
8
|
+
def run
|
9
|
+
require 'lydown/version'
|
10
|
+
puts "Lydown version #{Lydown::VERSION}"
|
11
|
+
|
12
|
+
lilypond_version = Lydown::CLI::Support.detect_lilypond_version(true)
|
13
|
+
if lilypond_version
|
14
|
+
puts "Lilypond version #{lilypond_version}"
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'lydown'
|
18
|
+
|
19
|
+
orig_dir = FileUtils.pwd
|
20
|
+
|
21
|
+
trap("INT") do
|
22
|
+
Lydown::CLI::Proofing.unwatch # stop file watcher for proofing
|
23
|
+
save_history
|
24
|
+
puts
|
25
|
+
FileUtils.cd(orig_dir)
|
26
|
+
exit(0)
|
27
|
+
end
|
28
|
+
|
29
|
+
load_history
|
30
|
+
|
31
|
+
update_proofing_watcher(orig_dir)
|
32
|
+
|
33
|
+
while line = Readline.readline(prompt, true).chomp
|
34
|
+
maintain_clean_history(line)
|
35
|
+
process(line)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def maintain_clean_history(line)
|
40
|
+
if line =~ /^\s*$/ or Readline::HISTORY.to_a[-2] == line
|
41
|
+
Readline::HISTORY.pop
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
HISTORY_FN = File.expand_path('~/.lydown_history')
|
46
|
+
|
47
|
+
def load_history
|
48
|
+
IO.read(HISTORY_FN).lines.each do |l|
|
49
|
+
Readline::HISTORY << l.chomp
|
50
|
+
end
|
51
|
+
rescue
|
52
|
+
end
|
53
|
+
|
54
|
+
def save_history
|
55
|
+
File.open(HISTORY_FN, 'w+') do |f|
|
56
|
+
Readline::HISTORY.to_a.each do |l|
|
57
|
+
f.puts l
|
58
|
+
end
|
59
|
+
end
|
60
|
+
rescue => e
|
61
|
+
puts "Failed to save history: #{e.message}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def prompt
|
65
|
+
"#{File.basename(FileUtils.pwd)}♫ "
|
66
|
+
end
|
67
|
+
|
68
|
+
def process(line)
|
69
|
+
if line =~ /^([a-z]+)\s?(.*)$/
|
70
|
+
cmd = $1
|
71
|
+
args = $2
|
72
|
+
cmd_method = :"handle_#{cmd}"
|
73
|
+
if respond_to?(cmd_method)
|
74
|
+
send(cmd_method, args)
|
75
|
+
else
|
76
|
+
handle_default(line)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
HELP = <<EOF
|
82
|
+
|
83
|
+
pwd Print working directory
|
84
|
+
cd <path> Change working directory
|
85
|
+
ls [<path>] Show lydown files in working directory
|
86
|
+
|
87
|
+
cat <file> Show content of file
|
88
|
+
cat <file>:<line> Show content of file at specified line, or range of
|
89
|
+
lines, e.g. cat flute1:13, or cat flute1:25-27
|
90
|
+
|
91
|
+
edit <file> Edit file using vim
|
92
|
+
edit <file>:<line> Edit file using vim, place cursor at specified line
|
93
|
+
|
94
|
+
score Compile & open score
|
95
|
+
midi Compile & open MIDI file
|
96
|
+
<part> Compile & open part
|
97
|
+
|
98
|
+
To exit press ctrl-C
|
99
|
+
EOF
|
100
|
+
|
101
|
+
def handle_help(args)
|
102
|
+
puts HELP; puts
|
103
|
+
end
|
104
|
+
|
105
|
+
def handle_pwd(args)
|
106
|
+
puts FileUtils.pwd
|
107
|
+
end
|
108
|
+
|
109
|
+
def handle_cd(args)
|
110
|
+
path = File.expand_path(args)
|
111
|
+
FileUtils.cd(path)
|
112
|
+
update_proofing_watcher(path)
|
113
|
+
rescue => e
|
114
|
+
puts e.message
|
115
|
+
end
|
116
|
+
|
117
|
+
def handle_git(args)
|
118
|
+
puts `git #{args}`
|
119
|
+
end
|
120
|
+
|
121
|
+
def handle_edit(args)
|
122
|
+
if args =~ /(.*):(\d+)$/
|
123
|
+
fn = $1; line = $2
|
124
|
+
else
|
125
|
+
fn = args; line = nil
|
126
|
+
end
|
127
|
+
|
128
|
+
return unless fn = validate_filename(fn)
|
129
|
+
|
130
|
+
if line
|
131
|
+
system "vim +#{line} #{fn} -c 'normal zz'"
|
132
|
+
else
|
133
|
+
system "vim #{fn}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def validate_filename(fn)
|
138
|
+
unless File.file?(fn)
|
139
|
+
fn += '.ld'
|
140
|
+
unless File.file?(fn)
|
141
|
+
puts "File not found"
|
142
|
+
return nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
fn
|
146
|
+
end
|
147
|
+
|
148
|
+
def update_proofing_watcher(path)
|
149
|
+
opts = {path: path, proof_mode: true, open_target: true,
|
150
|
+
no_progress_bar: true, silent: true, repl: true}
|
151
|
+
Lydown::CLI::Support.detect_work_directory(opts)
|
152
|
+
Lydown::CLI::Support.detect_filename(opts)
|
153
|
+
|
154
|
+
Lydown::CLI::Proofing.watch(opts)
|
155
|
+
end
|
156
|
+
|
157
|
+
def handle_ls(args)
|
158
|
+
system 'ls'
|
159
|
+
end
|
160
|
+
|
161
|
+
def handle_cat(args)
|
162
|
+
if args =~ /^([^\s:]+):?(\d+)?\-?(\d+)?$/
|
163
|
+
fn = $1
|
164
|
+
line_start = $2
|
165
|
+
line_end = $3
|
166
|
+
|
167
|
+
if line_start
|
168
|
+
if line_end
|
169
|
+
line_range = (line_start.to_i - 1)..(line_end.to_i - 1)
|
170
|
+
else
|
171
|
+
line_range = (line_start.to_i - 1)..(line_start.to_i - 1)
|
172
|
+
end
|
173
|
+
else
|
174
|
+
line_range = nil
|
175
|
+
end
|
176
|
+
|
177
|
+
return unless fn = validate_filename(fn)
|
178
|
+
|
179
|
+
content = IO.read(fn)
|
180
|
+
unless line_range
|
181
|
+
puts content
|
182
|
+
else
|
183
|
+
puts content.lines[line_range].join
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def handle_score(args)
|
189
|
+
opts = {path: '.', open_target: true, mode: :score, repl: true}
|
190
|
+
$stderr.puts "Processing score..."
|
191
|
+
compile(opts)
|
192
|
+
end
|
193
|
+
|
194
|
+
def handle_midi(args)
|
195
|
+
opts = {path: '.', open_target: true, mode: :score, format: :midi,
|
196
|
+
repl: true
|
197
|
+
}
|
198
|
+
$stderr.puts "Processing MIDI..."
|
199
|
+
compile(opts)
|
200
|
+
end
|
201
|
+
|
202
|
+
def handle_default(args)
|
203
|
+
opts = {}
|
204
|
+
|
205
|
+
args.split(',').map(&:strip).each do |a|
|
206
|
+
if File.file?(a) || File.file?("#{a}.ld")
|
207
|
+
opts = {path: '.', parts: [a], mode: :part, open_target: true, repl: true}
|
208
|
+
elsif File.directory?(a)
|
209
|
+
opts = {path: '.', movements: [a], mode: :score, open_target: true, repl: true}
|
210
|
+
else
|
211
|
+
raise LydownError, "Invalid path specified - #{a}"
|
212
|
+
end
|
213
|
+
$stderr.puts "Processing #{a}..."
|
214
|
+
compile(opts)
|
215
|
+
end
|
216
|
+
rescue => e
|
217
|
+
# do nothing
|
218
|
+
end
|
219
|
+
|
220
|
+
def compile(opts)
|
221
|
+
Lydown::CLI::Support.detect_work_directory(opts)
|
222
|
+
Lydown::CLI::Support.detect_filename(opts)
|
223
|
+
|
224
|
+
prev_handler = trap("INT") do
|
225
|
+
puts
|
226
|
+
end
|
227
|
+
Lydown::CLI::Compiler.process(opts)
|
228
|
+
ensure
|
229
|
+
trap("INT", prev_handler)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
data/lib/lydown/cli/support.rb
CHANGED
@@ -49,6 +49,39 @@ module Lydown::CLI::Support
|
|
49
49
|
opts[:path] = parent_dir
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
MINIMAL_LILYPOND_VERSION = Gem::Version.new('2.18')
|
54
|
+
|
55
|
+
# detect the lilypond version. If lilypond is not found, or the version is
|
56
|
+
# less than the minimal supported version, display an error message.
|
57
|
+
def self.detect_lilypond_version(exit_on_error)
|
58
|
+
msg = `lilypond --version`
|
59
|
+
version = nil
|
60
|
+
if msg.lines.first =~ /LilyPond ([\d\.]+)/
|
61
|
+
version = $1
|
62
|
+
end
|
63
|
+
unless version && Gem::Version.new(version) >= MINIMAL_LILYPOND_VERSION
|
64
|
+
display_lilypond_version_error_msg(version)
|
65
|
+
exit!(1) if exit_on_error
|
66
|
+
version = nil
|
67
|
+
end
|
68
|
+
version
|
69
|
+
rescue => e
|
70
|
+
display_lilypond_version_error_msg(nil)
|
71
|
+
exit!(1) if exit_on_error
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.display_lilypond_version_error_msg(version)
|
75
|
+
if version
|
76
|
+
STDERR.puts "ERROR: The installed lilypond (version #{version}) is too old.
|
77
|
+
You can install lilypond by running `lydown install lilypond` or by
|
78
|
+
downloading a recent version from http://lilypond.org/"
|
79
|
+
else
|
80
|
+
STDERR.puts "ERROR: No copy of lilypond found.
|
81
|
+
You can install lilypond by running `lydown install lilypond` or by
|
82
|
+
downloading a recent version from http://lilypond.org/"
|
83
|
+
end
|
84
|
+
end
|
52
85
|
end
|
53
86
|
|
54
87
|
|
data/lib/lydown/core_ext.rb
CHANGED
@@ -213,3 +213,11 @@ class Pathname
|
|
213
213
|
self.new(path).relative_path_from(pwd).to_s
|
214
214
|
end
|
215
215
|
end
|
216
|
+
|
217
|
+
unless Binding.method_defined?(:local_variable_set)
|
218
|
+
class Binding
|
219
|
+
def local_variable_set(var, value)
|
220
|
+
eval("#{var.to_s} = #{value.inspect}")
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
data/lib/lydown/lilypond.rb
CHANGED
data/lib/lydown/ly_lib/lib.ly
CHANGED
data/lib/lydown/parsing.rb
CHANGED
data/lib/lydown/rendering.rb
CHANGED
@@ -63,6 +63,40 @@ module Lydown::Rendering
|
|
63
63
|
|
64
64
|
"\"#{varname}\""
|
65
65
|
end
|
66
|
+
|
67
|
+
def add_includes(filenames, context, key, opts)
|
68
|
+
includes = context.get_setting(key, opts)
|
69
|
+
filenames.concat(includes) if includes
|
70
|
+
end
|
71
|
+
|
72
|
+
def include_files(context, opts)
|
73
|
+
filenames = []
|
74
|
+
if opts.has_key?(:movement)
|
75
|
+
add_includes(filenames, context, :includes, opts)
|
76
|
+
case context.render_mode
|
77
|
+
when :score
|
78
|
+
add_includes(filenames, context, 'score/includes', opts)
|
79
|
+
when :part
|
80
|
+
add_includes(filenames, context, 'parts/includes', opts)
|
81
|
+
if opts[:part]
|
82
|
+
add_includes(filenames, context, "parts/#{opts[:part]}/includes", opts)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
else
|
86
|
+
# paths to be included at top of lilypond doc should be defined under
|
87
|
+
# document/includes
|
88
|
+
add_includes(filenames, context, 'document/includes', opts)
|
89
|
+
end
|
90
|
+
|
91
|
+
filenames.map do |fn|
|
92
|
+
case File.extname(fn)
|
93
|
+
when '.ely'
|
94
|
+
Lydown::Templates.render(fn, context)
|
95
|
+
else
|
96
|
+
"\\include \"#{fn}\""
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
66
100
|
end
|
67
101
|
end
|
68
102
|
|
@@ -43,17 +43,6 @@ module Lydown::Rendering
|
|
43
43
|
PAGE_BREAKS[setting] || {}
|
44
44
|
end
|
45
45
|
|
46
|
-
def self.include_files(context, opts)
|
47
|
-
(context.get_setting(:includes, opts) || []).map do |fn|
|
48
|
-
case File.extname(fn)
|
49
|
-
when '.ely'
|
50
|
-
Lydown::Templates.render(fn, context)
|
51
|
-
else
|
52
|
-
"\\include \"#{fn}\""
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
46
|
# Groups movements by bookparts. Whenever a movement requires a page break
|
58
47
|
# before, a new group is created
|
59
48
|
def self.bookparts(context, opts)
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'pathname'
|
5
|
+
|
1
6
|
module Lydown::Rendering
|
2
7
|
class Setting < Base
|
3
8
|
include Notes
|
@@ -7,7 +12,7 @@ module Lydown::Rendering
|
|
7
12
|
'accidentals', 'beams', 'end_barline', 'macros', 'empty_staves',
|
8
13
|
'midi_tempo', 'instrument_names', 'instrument_name_style',
|
9
14
|
'parts', 'score', 'movement_source', 'colla_parte', 'include',
|
10
|
-
'mode', 'nomode', 'bar_numbers'
|
15
|
+
'mode', 'nomode', 'bar_numbers', 'document', 'notation_size'
|
11
16
|
]
|
12
17
|
|
13
18
|
RENDERABLE_SETTING_KEYS = [
|
@@ -22,7 +27,8 @@ module Lydown::Rendering
|
|
22
27
|
'instrument_name_style' => ['normal', 'smallcaps'],
|
23
28
|
'page_break' => ['none', 'before', 'after', 'before and after', 'blank page before'],
|
24
29
|
'mode' => ['score', 'part', 'none'],
|
25
|
-
'bar_numbers' => ['hide', 'shows']
|
30
|
+
'bar_numbers' => ['hide', 'shows'],
|
31
|
+
'notation_size' => ['huge', 'large', 'normalsize', 'small', 'tiny', 'teeny']
|
26
32
|
}
|
27
33
|
|
28
34
|
def translate
|
@@ -60,10 +66,7 @@ module Lydown::Rendering
|
|
60
66
|
@context[:movement] = value
|
61
67
|
@context.reset(:movement)
|
62
68
|
when 'include'
|
63
|
-
|
64
|
-
includes ||= []
|
65
|
-
includes << value
|
66
|
-
@context.set_setting(:includes, includes)
|
69
|
+
add_include(:includes, value)
|
67
70
|
when 'mode'
|
68
71
|
set_mode(value.nil? ? :none : value.to_sym)
|
69
72
|
when 'nomode'
|
@@ -81,8 +84,13 @@ module Lydown::Rendering
|
|
81
84
|
while l < level
|
82
85
|
path << "#{@context['process/setting_levels'][l]}/"; l += 1
|
83
86
|
end
|
84
|
-
|
85
|
-
|
87
|
+
case key
|
88
|
+
when 'include'
|
89
|
+
add_include(path + 'includes', value)
|
90
|
+
else
|
91
|
+
path << key
|
92
|
+
@context.set_setting(path, value)
|
93
|
+
end
|
86
94
|
end
|
87
95
|
|
88
96
|
@context['process/setting_levels'] ||= {}
|
@@ -154,6 +162,24 @@ module Lydown::Rendering
|
|
154
162
|
def set_mode(mode)
|
155
163
|
@context['process/mode'] = (mode == :none) ? nil : mode
|
156
164
|
end
|
165
|
+
|
166
|
+
def add_include(includes_path, path)
|
167
|
+
includes = @context.get_current_setting(includes_path) || []
|
168
|
+
|
169
|
+
source_filename = @context['process/last_filename']
|
170
|
+
if source_filename
|
171
|
+
absolute_path = File.expand_path(
|
172
|
+
File.join(File.dirname(source_filename), path)
|
173
|
+
)
|
174
|
+
# calculate relative path to working directory
|
175
|
+
pwd = Pathname.new(FileUtils.pwd)
|
176
|
+
includes << Pathname.new(absolute_path).relative_path_from(pwd).to_s
|
177
|
+
else
|
178
|
+
includes << path
|
179
|
+
end
|
180
|
+
|
181
|
+
@context.set_setting(includes_path, includes)
|
182
|
+
end
|
157
183
|
end
|
158
184
|
end
|
159
185
|
|