summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/lilyglyphs/lily-image-commands.py
blob: 741ad40e9b45174ba045cd4abd91521568eb25b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#!/usr/bin/env python

# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#                                                                        %
#      This file is part of the 'lilyglyphs' LaTeX package.              %
#                                ==========                              %
#                                                                        %
#              https://github.com/openlilylib/lilyglyphs                 %
#               http://www.openlilylib.org/lilyglyphs                    %
#                                                                        %
#  Copyright 2012-2020 Urs Liska and others, ul@openlilylib.org          %
#                                                                        %
#  'lilyglyphs' is free software: you can redistribute it and/or modify  %
#  it under the terms of the LaTeX Project Public License, either        %
#  version 1.3 of this license or (at your option) any later version.    %
#  You may find the latest version of this license at                    %
#               http://www.latex-project.org/lppl.txt                    %
#  more information on                                                   %
#               http://latex-project.org/lppl/                           %
#  and version 1.3 or later is part of all distributions of LaTeX        %
#  version 2005/12/01 or later.                                          %
#                                                                        %
#  This work has the LPPL maintenance status 'maintained'.               %
#  The Current Maintainer of this work is Urs Liska (see above).         %
#                                                                        %
#  This work consists of the files listed in the file 'manifest.txt'     %
#  which can be found in the 'license' directory.                        %
#                                                                        %
#  This program is distributed in the hope that it will be useful,       %
#  but WITHOUT ANY WARRANTY; without even the implied warranty of        %
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                  %
#                                                                        %
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

import os, sys,  getopt,  datetime,  subprocess, argparse, lilyglyphs_common as lg



# ###############
# string to be printed before the actual command
lily_src_prefix = """\\version "2.16.2"

#(set-global-staff-size 14)

\paper {
  indent = 0
}
\header {
  tagline = ""
}

"""

# string to be printed after the actual command definition
lily_src_score = """
  \\score {
  \\new Staff \\with {
    \\remove "Staff_symbol_engraver"
    \\remove "Clef_engraver"
    \\remove "Time_signature_engraver"
  }
"""

def main():
    """Do the actual work of the script"""
    print('')
    print('buildglyphimages.py,')
    print('Part of lilyglyphs.')
    print('')
    
    # set CWD and ensure the necessary subdirs are present
    check_paths()
    print('')

    # load and parse input file
    lg.read_input_file(in_file)
    read_entries()
    print('')

    # generate LilyPond source files for each command
    # and compile them
    write_lily_src_files()
    print('')
    lg.compile_lily_files()
    print('')
    
    # remove intermediate files and move pdfs to pdf directory
    lg.cleanup_lily_files()
    print('')
    
    # generate latex commands and example code
    # and write them to the output file
    lg.generate_latex_commands()
    print('')
    write_latex_file()

    
def check_paths():
    """Sets CWD to 'glyphimages' subdir or root of lilyglyphs_private
       and makes sure that the necessary subdirectories are present"""
    
    # one level above 'definitions' is 'glyphimages'
    os.chdir(os.path.join(in_path, '..'))

    # check the presence of the necessary subdirectories
    # and create them if necessary
    # (otherwise we'll get errors when trying to write in them)
    ls = os.listdir('.')
    if not lg.dir_lysrc in ls:
        os.mkdir(lg.dir_lysrc)
    if not lg.dir_pdfs in ls:
        os.mkdir(lg.dir_pdfs)
    if not lg.dir_cmd in ls:
        os.mkdir(lg.dir_cmd)

def cmd_filename(cmd_name):
    if cmd_name.startswith('lily'):
        return cmd_name[:4] + '-' + cmd_name[4:]
    elif cmd_name.startswith('lily-'):
        return cmd_name
    else:
        return 'lily-' + cmd_name

# set default scale and raise arguments to empty
scale = ''
rais = ''

def read_entries():
    """Parses the input source file and extracts glyph entries"""
    print('Read entries of LilyPond commands:')
    for i in range(len(lg.definitions_file)):
        if '%%lilyglyphs' in lg.definitions_file[i]:
            i = read_entry(i)
    print(lg.lily_files)

def read_entry(i):
    """Reads a single glyph entry from the input file and stores it
    in the global dictionary lg.in_cmds"""
    global scale,  rais
    # read comment line(s)
    i += 1
    is_protected = False
    comment = []
    # loop over the comment line(s)
    while i < len(lg.definitions_file):
        line = lg.definitions_file[i].strip()
        # check for 'protected' entries that shouldn't be processed newly
        if not line[0] == '%':
            break
        elif '%%protected' in line:
            is_protected = True
        elif 'scale=' in line:
            dummy, scale = line.split('=')
        elif 'raise=' in line:
            dummy,  rais = line.split('=')
        else:
            line = line[1:].strip()
            comment.append(line)
        i += 1

    # remove any empty lines
    while len(lg.definitions_file[i].strip()) == 0:
        i += 1

    # read command name
    line = lg.definitions_file[i].strip()
    cmd_name = line[: line.find('=') - 1]
    print('- ' + cmd_name, end=' ')
    if is_protected:
        print('(protected and skipped)')
    else:
        print('') #(for line break only)

    # read actual command until we find a line the begins with a closing curly bracket
    i += 1
    lilySrc = []
    while lg.definitions_file[i][0] != '}':
        lilySrc.append(lg.definitions_file[i])
        i += 1
    if not is_protected:
        lg.in_cmds[cmd_name] = {}
        lg.in_cmds[cmd_name]['comment'] = comment
        lg.in_cmds[cmd_name]['lilySrc'] = lilySrc
        lg.in_cmds[cmd_name]['element'] = cmd_filename(cmd_name)
        lg.in_cmds[cmd_name]['type'] = 'image'
        if scale:
            lg.in_cmds[cmd_name]['scale'] = scale
        if rais:
            lg.in_cmds[cmd_name]['raise'] = rais

        lg.lily_files.append(cmd_filename(cmd_name))
    return i


def usage():
    print("""buildglyphimages. Part of the lilyglyphs package.
    Parses a template file, creates
    single .ly files from it, uses LilyPond to create single glyph
    pdf files and set up template files to be used in LaTeX.
    The input file has to be located in the glyphimages folder
    of either the lilyglyph package itself or of a copy of 
    the lilyglyphs_private directory structure contained in the
    distribution.
    For detailed instructions refer to the manual.
    Usage:
    buildglyphimages.py in-file-name.
    """)

def write_file_info(name, fout):
    """Formats file specific information for the lilyPond source file"""
    long_line = '% This file defines a single glyph to be created with LilyPond: %\n'
    width = len(long_line) - 1
    header = '%' * width + '\n'
    spacer = '%' + ' ' * (width - 2) + '%\n'
    padding = width - len(name) - 8
    fout.write(header)
    fout.write(spacer)
    fout.write(long_line)
    fout.write(spacer)
    fout.write('%   ' + name + '.ly' + ' ' * padding + '%\n')
    fout.write(spacer)
    fout.write(header)
    fout.write(lg.signature())
    fout.write('\n\n')

def write_latex_file():
    """Composes LaTeX file and writes it to disk"""
    print('Generate LaTeX file')
    print(lg.dir_cmd, in_basename)
    lg.write_latex_file(os.path.join(os.getcwd(), lg.dir_cmd,  in_basename + '.tex'))

def write_lily_src_files():
    """Generates one .ly file for each found new command"""
    skip_cmds = []
    print('Write .ly files for each entry:')
    for cmd_name in lg.in_cmds:
        print('- ' + cmd_name)
        gen_src_name = os.path.join(lg.dir_lysrc, cmd_filename(cmd_name) + '.ly')
        # handle existing commands
        if os.path.exists(gen_src_name):
            action = ''
            while not (action == 'Y' or action == 'N'):
                action = input('already present. Overwrite (y/n)? ')
                action = action.upper()
            if action == 'N':
                skip_cmds.append(cmd_name)
                continue
        
        # open a single lily src file for write access
        fout = open(gen_src_name,  'w')

        #output the license information
        fout.write(lg.lilyglyphs_copyright_string)
        fout.write('\n')

        #output information on the actual file
        write_file_info(cmd_name, fout)

        #write the default LilyPond stuff
        fout.write(lily_src_prefix)

        # write the comment for the command
        fout.write('%{\n')
        for line in lg.in_cmds[cmd_name]['comment']:
            fout.write(line + '\n')
        fout.write('%}\n\n')

        # write the actual command
        fout.write(cmd_name + ' = {\n')
        for line in lg.in_cmds[cmd_name]['lilySrc']:
            fout.write(line + '\n')
        fout.write('}\n')

        # write the score definition
        fout.write(lily_src_score)

        # finish the LilyPond file
        fout.write('  \\' + cmd_name + '\n')
        fout.write('}\n\n')

        fout.close()
    
    # remove skipped commands from in_cmds
    print(skip_cmds)
    for cmd_name in skip_cmds:
        del lg.in_cmds[cmd_name]
        lg.lily_files.remove(cmd_filename(cmd_name))

# ####################################
# Finally launch the program
if __name__ == "__main__":
    
    # parse command line arguments
    parser = argparse.ArgumentParser(
                      description='Process templates to LilyPond input files,' +
                      'compile these and generate LaTeX commands.', 
                      parents=[lg.common_arguments])
    parser.add_argument('i', 
                        type=lg.is_file, 
                        metavar='INPUT', 
                        help='File with command templates.')
    args = parser.parse_args()
    
    # if we have exactly one existing file
    # join its components and run the program

    # process filename argument, providing absolute path
    script_path, script_name = os.path.split(sys.argv[0])

    in_file = os.path.join(os.getcwd(), vars(args)['i'])
    # check if the input file is in the right place
    # this has to be the definitions subdir of
    # the package directory or the lilyglyphs_private dir
    in_path, in_filename = os.path.split(in_file)
    in_path = os.path.normpath(in_path)
    if not (('lilyglyphs' in in_path) and (in_path.endswith('definitions'))):
        print('File in the wrong location: ' + in_path)
        usage()
        sys.exit(2)
    in_basename, in_ext = os.path.splitext(in_filename)
    main()