lydown 0.10.0 → 0.12.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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