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.
@@ -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
@@ -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
 
@@ -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
@@ -138,6 +138,7 @@ module Lydown
138
138
  bar.progress = idx + 1 if idx
139
139
  end
140
140
  end
141
+ bar.progress = STATUS_TOTAL
141
142
  end
142
143
  else
143
144
  info = f.read
@@ -85,7 +85,7 @@ ficta = {
85
85
 
86
86
 
87
87
  \layout {
88
- #(layout-set-staff-size 14)
88
+ #(layout-set-staff-size 17)
89
89
  indent = 0\cm
90
90
 
91
91
  \context {
@@ -6,7 +6,7 @@ require 'lydown/parsing/lydown.treetop'
6
6
 
7
7
  class LydownParser
8
8
  def self.parse(source, opts = {})
9
- if opts[:no_progress]
9
+ if opts[:no_progress_bar]
10
10
  do_parse(source, opts)
11
11
  else
12
12
  Lydown::CLI.show_progress('Parse', source.length * 2) do |bar|
@@ -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
 
@@ -10,7 +10,7 @@ module Lydown::Rendering
10
10
  def translate
11
11
  # do nothing by default
12
12
  end
13
-
13
+
14
14
  def next_event
15
15
  idx = @idx + 1
16
16
  while idx < @stream.size
@@ -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,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'lydown/rendering/figures'
2
4
  require 'lydown/rendering/notes'
3
5
 
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'lydown/rendering/figures'
2
4
 
3
5
  module Lydown::Rendering
@@ -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
- includes = @context.get_current_setting(:includes)
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
- path << key
85
- @context.set_setting(path, value)
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