texzip 0.1.8 → 0.1.9
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/History.txt +5 -0
- data/bin/texzip +27 -34
- data/lib/texzip/Project.rb +516 -518
- data/lib/texzip.rb +8 -13
- data/spec/spec_helper.rb +1 -2
- data/spec/texzip_spec.rb +38 -41
- data/version.txt +1 -1
- metadata +34 -33
data/lib/texzip/Project.rb
CHANGED
@@ -8,522 +8,520 @@ class TeXzip::Error < Exception; end
|
|
8
8
|
|
9
9
|
class TeXzip::Project < HighLine
|
10
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
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
end
|
528
|
-
end
|
11
|
+
PACKAGE_EXTENSIONS = %w(.sty .cls).freeze
|
12
|
+
IMAGE_EXTENSIONS = %w(.png .jpg .pdf .eps .pstex).freeze
|
13
|
+
TEXIMAGE_EXTENSIONS = %w(.pspdftex .pdf_t .pstex_t).freeze
|
14
|
+
|
15
|
+
class Quit < Exception; end
|
16
|
+
|
17
|
+
attr_accessor :overwrite_all
|
18
|
+
|
19
|
+
class FilePath
|
20
|
+
def initialize(root_dir, file)
|
21
|
+
@root_dir = Pathname.new(root_dir).expand_path
|
22
|
+
@file = Pathname.new(file)
|
23
|
+
@file = @root_dir.join(file).expand_path.relative_path_from(@root_dir)
|
24
|
+
@out_file = @file
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_output_directory(dir)
|
28
|
+
@out_dir = Pathname.new(dir).expand_path
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_plain_output_directory(dir)
|
32
|
+
set_output_directory dir
|
33
|
+
@out_file = @file.basename
|
34
|
+
end
|
35
|
+
|
36
|
+
def file
|
37
|
+
@file
|
38
|
+
end
|
39
|
+
|
40
|
+
def out_file=(file)
|
41
|
+
@out_file = Pathname.new(file)
|
42
|
+
end
|
43
|
+
|
44
|
+
def output_path
|
45
|
+
@out_dir.join(@out_file).expand_path
|
46
|
+
end
|
47
|
+
|
48
|
+
def path
|
49
|
+
@root_dir.join(@file).expand_path
|
50
|
+
end
|
51
|
+
|
52
|
+
def extname
|
53
|
+
@file.extname
|
54
|
+
end
|
55
|
+
|
56
|
+
def hash
|
57
|
+
path.to_s.hash
|
58
|
+
end
|
59
|
+
|
60
|
+
def eql?(other)
|
61
|
+
path.to_s.eql? other.path.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize(master_file)
|
66
|
+
super()
|
67
|
+
@tex_master_file = Pathname.new(master_file).expand_path
|
68
|
+
|
69
|
+
# All possible include-paths for TeX
|
70
|
+
@tex_dirs = [@tex_master_file.dirname]
|
71
|
+
@tex_dirs.concat((ENV['TEXINPUTS'] || '').split(':').map {|d| Pathname.new(d)})
|
72
|
+
@tex_dirs.map!(&:expand_path)
|
73
|
+
@tex_dirs.uniq!
|
74
|
+
|
75
|
+
@overwrite_all = false
|
76
|
+
|
77
|
+
parse_files
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse_files
|
81
|
+
# The hash of all files, including the whole text.
|
82
|
+
@tex_files = {}
|
83
|
+
@image_files = Set.new
|
84
|
+
@bib_files = Set.new
|
85
|
+
@cites = Set.new
|
86
|
+
|
87
|
+
# Read all files recursively
|
88
|
+
unparsed_files = [@tex_master_file]
|
89
|
+
until unparsed_files.empty?
|
90
|
+
fname = unparsed_files.pop
|
91
|
+
file = find_file(fname)
|
92
|
+
if file.nil? then
|
93
|
+
if PACKAGE_EXTENSIONS.include?(File.extname(fname))
|
94
|
+
next
|
95
|
+
else
|
96
|
+
raise TeXzip::Error, "Can't find file: #{fname}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
unless @tex_files.has_key?(file)
|
101
|
+
included_files = parse_file file
|
102
|
+
unparsed_files.concat included_files
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if !@bib_files.empty?
|
107
|
+
@bib = nil
|
108
|
+
else
|
109
|
+
@bib = BibTeX::Bibliography.new
|
110
|
+
@bib_files.each do |bib_file|
|
111
|
+
bib = BibTeX.open(bib_file.path)
|
112
|
+
bib.replace_strings
|
113
|
+
@bib.add(bib.data)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns the master-file's path.
|
119
|
+
def master_file
|
120
|
+
@tex_master_file
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns a list of included tex and sty files.
|
124
|
+
# @return [Array<Pathname>] Included tex files.
|
125
|
+
def tex_files
|
126
|
+
@tex_files.keys
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns a list of included image-files.
|
130
|
+
# @return [Array<Pathname>] Included image files.
|
131
|
+
def image_files
|
132
|
+
@image_files.to_a
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns a list of included BibTeX-files.
|
136
|
+
# @return [Array<Pathname>] Included BibTeX files.
|
137
|
+
def bib_files
|
138
|
+
@bib_files.to_a
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns a list of citations.
|
142
|
+
# @return [Array<String>] Citations.
|
143
|
+
def cites
|
144
|
+
@cites.to_a
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns the full path for a certain file.
|
148
|
+
#
|
149
|
+
# The file is searched in the current directory as well as all
|
150
|
+
# directories given by the environment variable +TEXINPUTS+
|
151
|
+
#
|
152
|
+
# @param [String] file The (relative) path of the file.
|
153
|
+
# @param [Array<String>] extensions The (possible) file extensions.
|
154
|
+
# @return [Pathname,nil] The path to the file if exist.
|
155
|
+
def find_file(file, extensions = [])
|
156
|
+
extensions.unshift '' # the empty extension
|
157
|
+
extensions.uniq!
|
158
|
+
|
159
|
+
@tex_dirs.each do |d|
|
160
|
+
extensions.each do |ext|
|
161
|
+
file_path = d.join(file + ext).expand_path
|
162
|
+
return FilePath.new(d, file + ext) if File.file?(file_path)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns the full paths for all variants of a certain file.
|
169
|
+
#
|
170
|
+
# The files are searched in the current directory as well as all
|
171
|
+
# directories given by the environment variable +TEXINPUTS+
|
172
|
+
#
|
173
|
+
# @param [String] file The base file-name.
|
174
|
+
# @param [Array<String>] extensions The possible file-extensions.
|
175
|
+
# @return [Array<Pathname>] All found files.
|
176
|
+
def find_files(file, extensions)
|
177
|
+
extensions.uniq!
|
178
|
+
|
179
|
+
files = []
|
180
|
+
|
181
|
+
extensions.each do |ext|
|
182
|
+
@tex_dirs.each do |d|
|
183
|
+
file_path = d.join(file + ext).expand_path
|
184
|
+
if file_path.file?
|
185
|
+
files << FilePath.new(d, file + ext)
|
186
|
+
break
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
files
|
192
|
+
end
|
193
|
+
|
194
|
+
# Load and parse a single tex-file.
|
195
|
+
#
|
196
|
+
# The file is parsed for commands including images, BibTeX-files
|
197
|
+
# and citations. The command along with the command's argument is
|
198
|
+
# passed to the block. The block is assumed to return a list of
|
199
|
+
# further tex-files to be parsed.
|
200
|
+
#
|
201
|
+
# @param [Pathname,String] file_name The name of the TeX-file to parse
|
202
|
+
# @return [Array<String>] A list of included TeX-files.
|
203
|
+
def parse_file(file_name, &block)
|
204
|
+
text = nil
|
205
|
+
File.open(file_name.path, 'rb') do |f|
|
206
|
+
text = f.read
|
207
|
+
end
|
208
|
+
@tex_files[file_name] = text
|
209
|
+
|
210
|
+
block = method(:handle_command) unless block
|
211
|
+
|
212
|
+
included_files = []
|
213
|
+
text_without_comments = ''
|
214
|
+
text.each_line do |line|
|
215
|
+
comment_match = line.match(/(?:\\)*%/)
|
216
|
+
if comment_match && (comment_match.end(0) - comment_match.begin(0)).odd?
|
217
|
+
line = line[0...comment_match.end(0)]
|
218
|
+
end
|
219
|
+
text_without_comments.concat line
|
220
|
+
end
|
221
|
+
|
222
|
+
text_without_comments.scan(/\\(documentclass|usepackage|include|input|includegraphics|bibliography|cite)(?:\[[^\]]+\])?\{([^}]+)\}/) do |cmd, arg|
|
223
|
+
new_files = block.call(cmd, arg)
|
224
|
+
included_files.concat(new_files) if new_files
|
225
|
+
end
|
226
|
+
included_files
|
227
|
+
end
|
228
|
+
|
229
|
+
# Handles parsed commands.
|
230
|
+
def handle_command(command, argument)
|
231
|
+
case command
|
232
|
+
when 'includegraphics'
|
233
|
+
add_image argument
|
234
|
+
when 'bibliography'
|
235
|
+
argument.split(',').uniq.each {|f| add_bib f.strip}
|
236
|
+
when 'usepackage'
|
237
|
+
return [argument + '.sty']
|
238
|
+
when 'documentclass'
|
239
|
+
return [argument + '.cls']
|
240
|
+
when 'cite'
|
241
|
+
@cites.merge argument.split(',').map(&:strip)
|
242
|
+
else
|
243
|
+
ext = File.extname(argument)
|
244
|
+
if TEXIMAGE_EXTENSIONS.include?(ext)
|
245
|
+
file = find_file(argument)
|
246
|
+
unless file
|
247
|
+
puts "WARNING: Can't find tex-image file #{argument}"
|
248
|
+
return nil
|
249
|
+
end
|
250
|
+
dir = File.dirname(argument)
|
251
|
+
parse_file file do |command, arg|
|
252
|
+
if command == 'includegraphics'
|
253
|
+
add_image File.join(dir, arg)
|
254
|
+
else
|
255
|
+
raise TeXzip::Error, "Unexpected command '\\#{command}' in tex-image file: \\#{argument}"
|
256
|
+
end
|
257
|
+
nil
|
258
|
+
end
|
259
|
+
elsif ext != '.tex'
|
260
|
+
argument += '.tex'
|
261
|
+
end
|
262
|
+
return [argument]
|
263
|
+
end
|
264
|
+
nil
|
265
|
+
end
|
266
|
+
|
267
|
+
# Adds an image to the list of included images.
|
268
|
+
# @param [String] image_file_name The path of the image-file
|
269
|
+
def add_image(image_file_name)
|
270
|
+
ext = File.extname(image_file_name)
|
271
|
+
image_files = if ext == ''
|
272
|
+
find_files(image_file_name, IMAGE_EXTENSIONS)
|
273
|
+
else
|
274
|
+
[find_file(image_file_name)].compact
|
275
|
+
end
|
276
|
+
|
277
|
+
if image_files.empty?
|
278
|
+
puts "WARNING: Can't find included image #{image_file_name}"
|
279
|
+
else
|
280
|
+
@image_files.merge image_files
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# Adds a BibTeX-file to the list of included BibTeX-files.
|
285
|
+
# @param [String] image_file_name The path of the BibTeX-file.
|
286
|
+
def add_bib(bib_file_name)
|
287
|
+
bib_file = find_file(bib_file_name, ['.bib'])
|
288
|
+
|
289
|
+
if bib_file.nil?
|
290
|
+
puts "WARNING: Can't find included BibTeX file #{bib_file_name}"
|
291
|
+
else
|
292
|
+
@bib_files.add bib_file
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def modify_files(outdir, image_dir, plain_img, bibtex_file)
|
297
|
+
@output_directory = Pathname.new(outdir).expand_path
|
298
|
+
@output_image_directory = @output_directory.join(Pathname.new(image_dir)).expand_path
|
299
|
+
@output_bibtex = @output_directory.join(Pathname.new(bibtex_file)).expand_path
|
300
|
+
@modified_files = {}
|
301
|
+
|
302
|
+
plain_img_files = Hash.new {|h,k| h[k] = []}
|
303
|
+
|
304
|
+
@tex_files.each_key do |file|
|
305
|
+
if TEXIMAGE_EXTENSIONS.include? file.extname
|
306
|
+
if plain_img
|
307
|
+
file.set_plain_output_directory @output_image_directory
|
308
|
+
plain_img_files[file.file.to_s] << file
|
309
|
+
else
|
310
|
+
file.set_output_directory @output_image_directory
|
311
|
+
end
|
312
|
+
else
|
313
|
+
file.set_output_directory @output_directory
|
314
|
+
end
|
315
|
+
end
|
316
|
+
@tex_files.each_pair do |file, text|
|
317
|
+
@modified_files[file] = update_file file, text, plain_img
|
318
|
+
end
|
319
|
+
|
320
|
+
@image_files.each do |file|
|
321
|
+
if plain_img
|
322
|
+
file.set_plain_output_directory @output_image_directory
|
323
|
+
plain_img_files[file.file.to_s] << file
|
324
|
+
else
|
325
|
+
file.set_output_directory @output_image_directory
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
# maybe rename some files
|
330
|
+
plain_img_files.each_pair do |fname, files|
|
331
|
+
ext = File.extname(fname)
|
332
|
+
next if files.size <= 1
|
333
|
+
# TODO: not supported when updating references
|
334
|
+
raise 'Multiple images with the same name but different directories'
|
335
|
+
cnt = 2
|
336
|
+
files.each do |file|
|
337
|
+
loop do
|
338
|
+
new_fname = fname.basename.sub_ext("#{cnt}#{ext}")
|
339
|
+
if plain_img_files.include?(new_fname.to_s)
|
340
|
+
cnt += 1
|
341
|
+
else
|
342
|
+
file.out_file = new_fname
|
343
|
+
break
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
filter_bibtex
|
350
|
+
end
|
351
|
+
|
352
|
+
def update_file(tex_file, text, plain)
|
353
|
+
ext = tex_file.path.extname
|
354
|
+
|
355
|
+
new_text = ''
|
356
|
+
text.each_line do |line|
|
357
|
+
comment_match = line.match(/(?:\\)*%/)
|
358
|
+
if comment_match && (comment_match.end(0) - comment_match.begin(0)).odd?
|
359
|
+
comment = line[comment_match.end(0)..-1]
|
360
|
+
line = line[0...comment_match.end(0)]
|
361
|
+
else
|
362
|
+
comment = ''
|
363
|
+
end
|
364
|
+
new_line = line.gsub(/(\\(include|input|includegraphics|bibliography)(?:\[[^\]]+\])?)\{([^}]+)\}/) do |m|
|
365
|
+
start = $1
|
366
|
+
cmd = $2
|
367
|
+
file = $3
|
368
|
+
if cmd == 'includegraphics'
|
369
|
+
if TEXIMAGE_EXTENSIONS.include? ext
|
370
|
+
file = File.join(tex_file.file.dirname, file)
|
371
|
+
end
|
372
|
+
new_file = @output_image_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
|
373
|
+
# TODO: this does not support multiple files with same name
|
374
|
+
new_file = @output_image_directory.join(new_file.basename).relative_path_from(@output_directory) if plain
|
375
|
+
elsif cmd == 'bibliography'
|
376
|
+
new_file = @output_bibtex.basename.to_s.gsub(/\.bib$/, '')
|
377
|
+
elsif TEXIMAGE_EXTENSIONS.include?(File.extname(file))
|
378
|
+
new_file = @output_image_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
|
379
|
+
# TODO: this does not support multiple files with same name
|
380
|
+
new_file = @output_image_directory.join(new_file.basename).relative_path_from(@output_directory) if plain
|
381
|
+
else
|
382
|
+
new_file = @output_directory.join(Pathname.new(file)).relative_path_from(@output_directory)
|
383
|
+
end
|
384
|
+
"#{start}{#{new_file}}"
|
385
|
+
end
|
386
|
+
new_text.concat new_line
|
387
|
+
new_text.concat comment
|
388
|
+
end
|
389
|
+
|
390
|
+
new_text
|
391
|
+
end
|
392
|
+
|
393
|
+
def filter_bibtex
|
394
|
+
if @bib
|
395
|
+
cites = @cites.to_a.map(&:to_s)
|
396
|
+
seen_cites = cites.to_set
|
397
|
+
until cites.empty?
|
398
|
+
cite = cites.pop
|
399
|
+
entries = @bib[cite]
|
400
|
+
if entries.nil?
|
401
|
+
puts "WARNING: Can't find BibTeX-entry #{cite}"
|
402
|
+
else
|
403
|
+
entries = [entries] unless entries.is_a?(Array)
|
404
|
+
entries.each do |entry|
|
405
|
+
crossref = entry['crossref']
|
406
|
+
if crossref
|
407
|
+
crossref.split(',').map(&:strip).each do |ref|
|
408
|
+
ref = ref.to_s
|
409
|
+
cites << ref if seen_cites.add? ref
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
@bib = BibTeX::Bibliography.new.add(@bib.data.select {|entry| seen_cites.include? entry.key.to_s})
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
def write_files(force = false)
|
421
|
+
cwd = Pathname.getwd.expand_path
|
422
|
+
write_data do |path, data|
|
423
|
+
puts "Write file #{path.relative_path_from(cwd)}"
|
424
|
+
FileUtils.mkdir_p path.dirname unless path.dirname.exist?
|
425
|
+
if data.is_a? Pathname
|
426
|
+
FileUtils.copy data, path
|
427
|
+
else
|
428
|
+
File.open(path, 'wb') do |f|
|
429
|
+
f.write data
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
def write_archive(archive_file, force = false)
|
436
|
+
require 'ffi-libarchive'
|
437
|
+
|
438
|
+
archive_file = Pathname.new(archive_file).expand_path
|
439
|
+
return unless ask_overwrite(archive_file)
|
440
|
+
|
441
|
+
compression = case File.basename(archive_file.to_s)
|
442
|
+
when /\.tgz$/, /\.tar\.gz$/
|
443
|
+
:gzip
|
444
|
+
when /\.tbz2$/, /\.tar\.bz2$/
|
445
|
+
:bzip2
|
446
|
+
when /\.txz$/, /\.tar\.xz$/
|
447
|
+
:xz
|
448
|
+
when /\.tlzma$/, /\.tar\.lzma$/
|
449
|
+
:lzma
|
450
|
+
when /\.tZ$/, /\.tar\.Z$/
|
451
|
+
:Z
|
452
|
+
when /\.tar$/
|
453
|
+
:none
|
454
|
+
else
|
455
|
+
raise TeXzip::Error, "Can't derive archive-type from file name #{archive_file}"
|
456
|
+
end
|
457
|
+
|
458
|
+
puts "Write archive #{archive_file.relative_path_from(Pathname.getwd)}"
|
459
|
+
Archive.write_open_filename archive_file.to_s, compression, :tar do |ar|
|
460
|
+
write_data true do |path, data|
|
461
|
+
ar.add_entry do |e|
|
462
|
+
e.pathname = path.relative_path_from(@output_directory).to_s
|
463
|
+
if data.is_a? Pathname
|
464
|
+
e.copy_stat(data.to_s)
|
465
|
+
File.open(data, 'rb', &:read)
|
466
|
+
else
|
467
|
+
e.mode = 0644
|
468
|
+
e.atime = Time.now
|
469
|
+
e.mtime = Time.now
|
470
|
+
e.filetype = :file
|
471
|
+
data
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
def write_data(force = false)
|
479
|
+
raise ArgumentError, 'Block required' unless block_given?
|
480
|
+
|
481
|
+
overwrite_all = force
|
482
|
+
commands = []
|
483
|
+
|
484
|
+
@modified_files.each_pair do |file, text|
|
485
|
+
if force || ask_overwrite(file.output_path)
|
486
|
+
commands << [file.output_path, text]
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
@image_files.each do |file|
|
491
|
+
if force || ask_overwrite(file.output_path)
|
492
|
+
commands << [file.output_path, file.path]
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
if @bib && (force || ask_overwrite(@output_bibtex))
|
497
|
+
commands << [@output_bibtex, @bib.to_s]
|
498
|
+
end
|
499
|
+
|
500
|
+
commands.each do |path, data|
|
501
|
+
yield(path, data)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def ask_overwrite(file)
|
506
|
+
if !@overwrite_all && File.exist?(file)
|
507
|
+
ask("File #{file.relative_path_from(Pathname.getwd)} exists. Overwrite? [Ynaq]") do |q|
|
508
|
+
q.character = true
|
509
|
+
q.validate = /[ynaq\r ]/
|
510
|
+
q.case = :down
|
511
|
+
q.overwrite = false
|
512
|
+
q.answer_type = lambda do |c|
|
513
|
+
case c
|
514
|
+
when 'q' then raise Quit
|
515
|
+
when 'y' then true
|
516
|
+
when 'n' then false
|
517
|
+
when 'a' then
|
518
|
+
@overwrite_all = true
|
519
|
+
true
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
523
|
+
else
|
524
|
+
true
|
525
|
+
end
|
526
|
+
end
|
529
527
|
end
|