deplate 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. data/AUTHORS.TXT +26 -0
  2. data/CHANGES.TXT +177 -0
  3. data/LICENSE.TXT +340 -0
  4. data/NEWS.TXT +29 -0
  5. data/README.TXT +86 -0
  6. data/TODO.TXT +202 -0
  7. data/VERSION.TXT +1 -0
  8. data/bin/deplate +3 -0
  9. data/bin/deplate.bat +2 -0
  10. data/etc/deplate.ini +361 -0
  11. data/lib/deplate.rb +31 -0
  12. data/lib/deplate/abstract-class.rb +30 -0
  13. data/lib/deplate/builtin.rb +11 -0
  14. data/lib/deplate/cache.rb +59 -0
  15. data/lib/deplate/commands.rb +693 -0
  16. data/lib/deplate/common.rb +335 -0
  17. data/lib/deplate/converter.rb +99 -0
  18. data/lib/deplate/core.rb +2705 -0
  19. data/lib/deplate/css/article.css +545 -0
  20. data/lib/deplate/css/deplate.css +699 -0
  21. data/lib/deplate/css/heading-navbar.css +29 -0
  22. data/lib/deplate/css/layout-deplate-print.css +540 -0
  23. data/lib/deplate/css/layout-deplate.css +764 -0
  24. data/lib/deplate/css/sans-serif.css +160 -0
  25. data/lib/deplate/css/serif-e.css +170 -0
  26. data/lib/deplate/css/serif-rel.css +121 -0
  27. data/lib/deplate/css/serif.css +190 -0
  28. data/lib/deplate/css/slides.css +11 -0
  29. data/lib/deplate/css/tabbar-left.css +91 -0
  30. data/lib/deplate/css/tabbar-right-ie.css +14 -0
  31. data/lib/deplate/css/tabbar-right.css +118 -0
  32. data/lib/deplate/css/tabbar-top.css +64 -0
  33. data/lib/deplate/css/tabbar.css +81 -0
  34. data/lib/deplate/css/text-sans-serif.css +154 -0
  35. data/lib/deplate/css/text-serif.css +175 -0
  36. data/lib/deplate/define.rb +439 -0
  37. data/lib/deplate/docbook.rb +738 -0
  38. data/lib/deplate/elements.rb +1355 -0
  39. data/lib/deplate/etc.rb +199 -0
  40. data/lib/deplate/external.rb +135 -0
  41. data/lib/deplate/fmt/dbk-article-4.1.2.rb +21 -0
  42. data/lib/deplate/fmt/dbk-article.rb +46 -0
  43. data/lib/deplate/fmt/dbk-book.rb +46 -0
  44. data/lib/deplate/fmt/dbk-ref.rb +105 -0
  45. data/lib/deplate/fmt/dbk-slides.rb +47 -0
  46. data/lib/deplate/fmt/dbk-snippet.rb +21 -0
  47. data/lib/deplate/fmt/html-snippet.rb +21 -0
  48. data/lib/deplate/fmt/html.rb +1696 -0
  49. data/lib/deplate/fmt/htmlsite.rb +419 -0
  50. data/lib/deplate/fmt/htmlslides.rb +21 -0
  51. data/lib/deplate/fmt/htmlwebsite.rb +70 -0
  52. data/lib/deplate/fmt/latex-snippet.rb +22 -0
  53. data/lib/deplate/fmt/latex.rb +1242 -0
  54. data/lib/deplate/fmt/php.rb +19 -0
  55. data/lib/deplate/fmt/phpsite.rb +19 -0
  56. data/lib/deplate/fmt/plain.rb +598 -0
  57. data/lib/deplate/fmt/template.rb +34 -0
  58. data/lib/deplate/fmt/xhtml10t.rb +41 -0
  59. data/lib/deplate/formatter-snippet.rb +17 -0
  60. data/lib/deplate/formatter.rb +1210 -0
  61. data/lib/deplate/input.rb +492 -0
  62. data/lib/deplate/input/deplate-headings.rb +48 -0
  63. data/lib/deplate/input/deplate-restricted.rb +70 -0
  64. data/lib/deplate/input/deplate.rb +28 -0
  65. data/lib/deplate/input/rdoc.rb +277 -0
  66. data/lib/deplate/input/template.rb +29 -0
  67. data/lib/deplate/lib/latex/highlight-extra.sty +15 -0
  68. data/lib/deplate/lib/latex/highlight-typical.sty +15 -0
  69. data/lib/deplate/lib/tabmenu.js +146 -0
  70. data/lib/deplate/locale/de.latin1 +708 -0
  71. data/lib/deplate/locale/ru.koi8-r +48 -0
  72. data/lib/deplate/locale/zh_cn.gb2312 +35 -0
  73. data/lib/deplate/macros.rb +639 -0
  74. data/lib/deplate/messages.rb +120 -0
  75. data/lib/deplate/metadata.rb +77 -0
  76. data/lib/deplate/metadata/marshal.rb +24 -0
  77. data/lib/deplate/metadata/xml.rb +42 -0
  78. data/lib/deplate/metadata/yaml.rb +26 -0
  79. data/lib/deplate/mod/anyword.rb +56 -0
  80. data/lib/deplate/mod/babelfish.rb +27 -0
  81. data/lib/deplate/mod/code-gvim.rb +52 -0
  82. data/lib/deplate/mod/code-highlight.rb +91 -0
  83. data/lib/deplate/mod/colored-log.rb +17 -0
  84. data/lib/deplate/mod/de.rb +19 -0
  85. data/lib/deplate/mod/en.rb +17 -0
  86. data/lib/deplate/mod/endnotes.rb +60 -0
  87. data/lib/deplate/mod/fr.rb +46 -0
  88. data/lib/deplate/mod/html-asciimath.rb +40 -0
  89. data/lib/deplate/mod/html-deplate-button.rb +15 -0
  90. data/lib/deplate/mod/html-headings-navbar.rb +39 -0
  91. data/lib/deplate/mod/html-obfuscate-email.rb +47 -0
  92. data/lib/deplate/mod/html-sidebar.rb +232 -0
  93. data/lib/deplate/mod/htmlslides-navbar-fh.rb +32 -0
  94. data/lib/deplate/mod/iconv.rb +35 -0
  95. data/lib/deplate/mod/imgurl.rb +30 -0
  96. data/lib/deplate/mod/inlatex-compound.rb +69 -0
  97. data/lib/deplate/mod/koma.rb +109 -0
  98. data/lib/deplate/mod/latex-emph-table-head.rb +38 -0
  99. data/lib/deplate/mod/latex-styles.rb +461 -0
  100. data/lib/deplate/mod/latex-verbatim-small.rb +29 -0
  101. data/lib/deplate/mod/makefile.rb +194 -0
  102. data/lib/deplate/mod/mark-external-urls.rb +38 -0
  103. data/lib/deplate/mod/markup-1-warn.rb +37 -0
  104. data/lib/deplate/mod/markup-1.rb +41 -0
  105. data/lib/deplate/mod/navbar-png.rb +33 -0
  106. data/lib/deplate/mod/noindent.rb +32 -0
  107. data/lib/deplate/mod/numpara.rb +40 -0
  108. data/lib/deplate/mod/particle-math.rb +34 -0
  109. data/lib/deplate/mod/php-extra.rb +44 -0
  110. data/lib/deplate/mod/pstoedit.rb +71 -0
  111. data/lib/deplate/mod/recode.rb +57 -0
  112. data/lib/deplate/mod/ru_koi8-r.rb +20 -0
  113. data/lib/deplate/mod/smiley.rb +50 -0
  114. data/lib/deplate/mod/soffice.rb +23 -0
  115. data/lib/deplate/mod/symbols-latin1.rb +58 -0
  116. data/lib/deplate/mod/symbols-od-utf-8.rb +16 -0
  117. data/lib/deplate/mod/symbols-plain.rb +58 -0
  118. data/lib/deplate/mod/symbols-sgml.rb +97 -0
  119. data/lib/deplate/mod/symbols-utf-8.rb +81 -0
  120. data/lib/deplate/mod/symbols-xml.rb +34 -0
  121. data/lib/deplate/mod/syntax-region-alt.rb +37 -0
  122. data/lib/deplate/mod/utf8.rb +49 -0
  123. data/lib/deplate/mod/validate-html.rb +35 -0
  124. data/lib/deplate/mod/xmlrpc.rb +233 -0
  125. data/lib/deplate/mod/zh-cn-autospace.rb +108 -0
  126. data/lib/deplate/mod/zh-cn.rb +59 -0
  127. data/lib/deplate/once-method.rb +44 -0
  128. data/lib/deplate/output.rb +249 -0
  129. data/lib/deplate/particles.rb +815 -0
  130. data/lib/deplate/regions.rb +1076 -0
  131. data/lib/deplate/structured.rb +763 -0
  132. data/lib/deplate/template.rb +430 -0
  133. data/lib/deplate/templates/html-doc.html +28 -0
  134. data/lib/deplate/templates/html-left-tabbar-js.html +37 -0
  135. data/lib/deplate/templates/html-left-tabbar.html +31 -0
  136. data/lib/deplate/templates/html-tabbar-right-table.html +43 -0
  137. data/lib/deplate/templates/html-tabbar-right.html +23 -0
  138. data/lib/deplate/templates/html-tabbar-top.html +43 -0
  139. data/lib/deplate/templates/html-tabbar.html +31 -0
  140. data/lib/deplate/wiki-markup.rb +117 -0
  141. data/lib/deplate/xml.rb +109 -0
  142. data/lib/deplate/zh-cn.rb +59 -0
  143. data/lib/ps2ppm.rb +239 -0
  144. data/man/man1/deplate.1 +692 -0
  145. metadata +210 -0
@@ -0,0 +1,34 @@
1
+ # template.rb
2
+ # @Author: Thomas Link (samul AT web.de)
3
+ # @Website: http://deplate.sf.net/
4
+ # @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
5
+ # @Created: 25-M�r-2005.
6
+ # @Last Change: 23-Okt-2005.
7
+ # @Revision: 0.21
8
+ #
9
+ # = Description
10
+ # The formatter for templates
11
+
12
+ # A pseudo-formatter used for templates.
13
+ class Deplate::Formatter::Template < Deplate::Formatter
14
+ self.myname = "template"
15
+ self.rx = /template/i
16
+ self.suffix = ".out"
17
+
18
+ self.label_mode = :delegate
19
+ self.label_delegate = []
20
+ self.label_once = []
21
+
22
+ def plain_text(text, escaped=false)
23
+ return text
24
+ end
25
+
26
+ def format_unknown(invoker)
27
+ invoker.elt
28
+ end
29
+
30
+ def format_paragraph(invoker)
31
+ invoker.elt
32
+ end
33
+ end
34
+
@@ -0,0 +1,41 @@
1
+ # fmt-xhtml.rb
2
+ # @Author: Thomas Link (samul AT web.de)
3
+ # @Website: http://deplate.sf.net/
4
+ # @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
5
+ # @Created: 03-Aug-2004.
6
+ # @Last Change: 23-Okt-2005.
7
+ # @Revision: 0.35
8
+
9
+ require "deplate/fmt/html"
10
+
11
+ class Deplate::Formatter::XHTML10transitional < Deplate::Formatter::HTML
12
+ self.myname = "xhtml10t"
13
+ self.rx = /x?html?/i
14
+ self.suffix = ".xhtml"
15
+
16
+ def head_doctype
17
+ return %Q{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
18
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">}
19
+ end
20
+
21
+ def html_lang(stripped=false)
22
+ end
23
+
24
+ def html_def
25
+ acc = [%{xmlns="http://www.w3.org/1999/xhtml"}]
26
+ lang = @deplate.options.messages.prop('lang', self)
27
+ if lang
28
+ acc << %{lang="#{lang}"} << %{xml:lang="#{lang}"}
29
+ end
30
+ "<html #{acc.join(" ")}>"
31
+ end
32
+
33
+ def head_meta_tag(text)
34
+ return %Q{<meta #{text} />}
35
+ end
36
+
37
+ def head_link_tag(text)
38
+ return %Q{<link #{text} />}
39
+ end
40
+ end
41
+
@@ -0,0 +1,17 @@
1
+ # formatter-snippet.rb
2
+ # @Author: Thomas Link (samul AT web.de)
3
+ # @Website: http://deplate.sf.net/
4
+ # @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
5
+ # @Created: 11-Aug-2005.
6
+ # @Last Change: 23-Okt-2005.
7
+ # @Revision: 0.3
8
+
9
+ module Deplate::Snippet
10
+ def formatter_initialize_snippet
11
+ unless @deplate.options.included
12
+ log(['Not run in included mode'], :error)
13
+ log(['Set included mode'], :error)
14
+ @deplate.options.included = true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,1210 @@
1
+ # formatter.rb
2
+ # @Author: Thomas Link (samul AT web.de)
3
+ # @Website: http://deplate.sf.net/
4
+ # @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
5
+ # @Created: 31-Okt-2004.
6
+ # @Last Change: 02-Nov-2005.
7
+ # @Revision: 0.923
8
+
9
+ require "deplate/abstract-class"
10
+
11
+ # Description:
12
+ # An abstract formatter class
13
+ #
14
+ # Usage:
15
+ #
16
+ # TODO:
17
+ #
18
+ # CHANGES:
19
+ #
20
+
21
+ class Deplate::Formatter
22
+ class << self
23
+ def noop(context, name)
24
+ context.module_eval %{
25
+ def #{name}(*args)
26
+ return ""
27
+ end
28
+ }
29
+ end
30
+
31
+ attr_writer :suffix, :myname, :rx, :label_mode, :label_delegate, :label_once
32
+
33
+ def get_class_attrib(name, default=nil)
34
+ if self == Deplate::Formatter
35
+ return default
36
+ end
37
+ iv = "@#{name}"
38
+ if self.instance_variables.include?(iv)
39
+ val = self.instance_variable_get(iv)
40
+ if val
41
+ return val
42
+ end
43
+ end
44
+ return self.superclass.get_class_attrib(name, default)
45
+ end
46
+
47
+ def suffix
48
+ get_class_attrib('suffix')
49
+ end
50
+
51
+ def myname
52
+ get_class_attrib('myname')
53
+ end
54
+
55
+ def myname=(name)
56
+ @myname = name
57
+ klass = self
58
+ Deplate::Core.class_eval {declare_formatter(klass)}
59
+ end
60
+
61
+ def rx
62
+ get_class_attrib('rx')
63
+ end
64
+
65
+ def label_mode
66
+ get_class_attrib('label_mode', :enclose)
67
+ end
68
+
69
+ def label_delegate
70
+ get_class_attrib('label_delegate', [])
71
+ end
72
+
73
+ def label_once
74
+ get_class_attrib('label_once', [])
75
+ end
76
+ end
77
+
78
+ @@custom_particles = {}
79
+
80
+ attr_reader :deplate
81
+ attr_reader :advices
82
+ attr_accessor :special_symbols
83
+
84
+ def initialize(deplate, args={})
85
+ @deplate = deplate
86
+ @variables = deplate.variables
87
+ @bibentries = {}
88
+ @open_labels = []
89
+ @advices = args[:advices] || {}
90
+ @inlatex_idx = 0
91
+ @encodings = {}
92
+ @consumed_labels = []
93
+ @consumed_ids = []
94
+ end
95
+
96
+ def retrieve_particle(id, body=nil, specific=false)
97
+ fmt = specific ? formatter_name : '_'
98
+ particles = @@custom_particles[fmt] ||= {}
99
+ particle = particles[id]
100
+ if particle
101
+ if body.nil? or particle[:body] == body
102
+ return particle[:class]
103
+ end
104
+ end
105
+ return nil
106
+ end
107
+
108
+ def store_particle(id, body, particle, specific=false)
109
+ fmt = specific ? formatter_name : '_'
110
+ particles = @@custom_particles[fmt] ||= {}
111
+ particles[id] = {:body => body, :class => particle}
112
+ end
113
+
114
+ def def_advice(applicant, agent, args)
115
+ this = @advices[agent] ||= {}
116
+ for type in [:wrap]
117
+ thistype = []
118
+ prc = args[type]
119
+ if prc
120
+ if prc.kind_of?(Proc)
121
+ thistype << {:applicant => applicant, :prc => prc}
122
+ else
123
+ raise "Not a Proc: %s" % prc
124
+ end
125
+ end
126
+ unless thistype.empty?
127
+ if this[type]
128
+ this[type] += thistype
129
+ else
130
+ this[type] = thistype
131
+ end
132
+ end
133
+ end
134
+ for type in [:before, :around, :after]
135
+ prc = args[type]
136
+ if prc
137
+ log(["Unsupported advice type", type, applicant, prc], :error)
138
+ end
139
+ end
140
+ end
141
+
142
+ def log(*args)
143
+ Deplate::Core.log(*args)
144
+ end
145
+
146
+ def canonic_enc_name(enc, table=@encodings)
147
+ case enc.downcase
148
+ when 'latin-1', 'latin1', 'l1', 'isolat1', 'iso-8859-1'
149
+ cen = 'latin1'
150
+ when 'latin-9', 'latin9', 'l9', 'isolat9', 'iso-8859-15'
151
+ cen = 'latin9'
152
+ when 'gb2312', 'gbk'
153
+ cen = 'gb2312'
154
+ when 'koi8-r'
155
+ cen = 'koi8-r'
156
+ when 'utf8', 'utf-8'
157
+ cen = 'utf-8'
158
+ else
159
+ log(['Unsupported encoding', enc], :anyway)
160
+ cen = enc
161
+ end
162
+ return table[cen] || cen
163
+ end
164
+
165
+ def join_blocks(blocks)
166
+ blocks.flatten.compact.join("\n")
167
+ end
168
+
169
+ def join_inline(strings)
170
+ strings.flatten.compact.join
171
+ end
172
+
173
+ def format_particle(agent, invoker, *args)
174
+ # rv = with_agent(agent, Array, invoker, *args)
175
+ # rv.empty? ? format_unknown_particle(invoker) : rv.join
176
+ with_agent(agent, Array, invoker, *args)
177
+ end
178
+
179
+ def format_particle_as_string(agent, object, *args)
180
+ join_inline(format_particle(agent, object, *args))
181
+ end
182
+
183
+ def format_element(agent, invoker, *args)
184
+ # rv = with_agent(agent, Array, invoker, *args)
185
+ # rv.empty? ? format_unknown(invoker) : join_blocks(rv)
186
+ with_agent(agent, Array, invoker, *args)
187
+ end
188
+
189
+ def format_element_as_string(agent, object, *args)
190
+ format_element(agent, object, *args)
191
+ end
192
+
193
+ def with_agent(agent, prototype, invoker, *args)
194
+ log(["Call with agent", agent, invoker.class, args], :debug)
195
+ if respond_to?(agent)
196
+ before = []
197
+ inner = nil
198
+ after = []
199
+ stylish = @advices[agent]
200
+ if stylish
201
+ # pre = stylish[:before]
202
+ # if pre
203
+ # for advice in pre
204
+ # before << advice[:prc].call(invoker, *args)
205
+ # end
206
+ # end
207
+
208
+ inner = self.send(agent, invoker, *args)
209
+ prototype ||= inner.class
210
+ around = stylish[:wrap]
211
+ if around
212
+ inner = around.inject(inner) do |acc, advice|
213
+ advice[:prc].call(agent, acc, invoker, *args)
214
+ end
215
+ end
216
+
217
+ # post = stylish[:after]
218
+ # if post
219
+ # for advice in post
220
+ # after << advice[:prc].call(invoker, *args)
221
+ # end
222
+ # end
223
+ else
224
+ args = args.unshift(invoker)
225
+ begin
226
+ inner = self.send(agent, *args)
227
+ rescue Exception => e
228
+ puts "DBG: #{agent}"
229
+ puts e.backtrace[0..10].join("\n")
230
+ raise e
231
+ end
232
+ prototype ||= inner.class
233
+ end
234
+ # if prototype == String
235
+ # rv = [before, inner, after].join
236
+ # elsif prototype == Integer
237
+ # rv = [before, inner, after].join.to_i
238
+ # elsif inner.kind_of?(Array)
239
+ # rv = before + inner + after
240
+ # else
241
+ # rv = before + [inner] + after
242
+ # end
243
+ # return rv
244
+ return inner
245
+ else
246
+ invoker.log(["Unknown formatting agent", agent], :error)
247
+ return nil
248
+ end
249
+ end
250
+
251
+ def output(invoker, *body)
252
+ output_at(invoker.doc_type, invoker.doc_slot, *body)
253
+ end
254
+
255
+ def output_preferably_at(invoker, type, slot, *body)
256
+ type = defined?(invoker.doc_type) ? invoker.doc_type(type) : type
257
+ slot = defined?(invoker.doc_slot) ? invoker.doc_slot(slot) : slot
258
+ output_at(type, slot, *body)
259
+ end
260
+
261
+ def output_empty_at?(type, slot)
262
+ @deplate.output.empty_at?(type, slot)
263
+ end
264
+
265
+ # def_delegator(:@deplate, :add_at, :output_at)
266
+ def output_at(type, slot, *body)
267
+ log(["Output at", "#{type}@#{slot}", body], :debug)
268
+ @deplate.output.add_at(type, slot, *body)
269
+ end
270
+
271
+ # def_delegator(:@deplate, :union_at)
272
+ def union_at(type, slot, *body)
273
+ @deplate.output.union_at(type, slot, *body)
274
+ end
275
+
276
+ # def_delegator(:@deplate, :set_at)
277
+ def set_at(type, slot, *body)
278
+ @deplate.output.set_at(type, slot, *body)
279
+ end
280
+
281
+ # push *options to variables['classOptions']
282
+ def push_class_option(*options)
283
+ acc = [@deplate.variables["classOptions"]]
284
+ acc += options
285
+ acc.compact!
286
+ @deplate.variables["classOptions"] = acc.join(' ')
287
+ end
288
+
289
+ # Properly format +text+ as formatter-valid plain text.
290
+ #
291
+ # If +escaped+ is true, +text+ appears in a special context and was
292
+ # escaped by a backslash or similar.
293
+ #
294
+ # If a block is given, convert normal text using this block.
295
+ #
296
+ # Special characters are translated on the basis of @special_symbols.
297
+ def plain_text(text, escaped=false)
298
+ if defined?(@plain_text_rx)
299
+ acc = []
300
+ text.split(@plain_text_rx).each_with_index do |e, i|
301
+ if i.modulo(2) == 0
302
+ acc << plain_text_recode(e) unless e.empty?
303
+ else
304
+ r = @special_symbols[e]
305
+ case r
306
+ when String
307
+ acc << r
308
+ when Proc
309
+ acc << r.call(escaped)
310
+ else
311
+ raise "Internal error: Strange symbol replacement for '#{e}'"
312
+ end
313
+ end
314
+ end
315
+ acc.join
316
+ else
317
+ plain_text_recode(text)
318
+ end
319
+ end
320
+
321
+ # Recode normal text for #plain_text
322
+ def plain_text_recode(text)
323
+ text
324
+ end
325
+
326
+ def encode_id(id)
327
+ id ? Deplate::Core.clean_file_name(id, "__") : id
328
+ end
329
+
330
+ def label_mode
331
+ self.class.label_mode
332
+ end
333
+
334
+ def label_once
335
+ self.class.label_once
336
+ end
337
+
338
+ def label_delegate
339
+ self.class.label_delegate
340
+ end
341
+
342
+ def suffix
343
+ self.class.suffix
344
+ end
345
+
346
+ def formatter_name
347
+ self.class.myname
348
+ end
349
+
350
+ def formatter_rx
351
+ self.class.rx
352
+ end
353
+
354
+ def setup
355
+ end
356
+
357
+ def pre_process
358
+ end
359
+
360
+ def prepare
361
+ end
362
+
363
+ def matches?(text)
364
+ if text[0..0] == "~"
365
+ rv = (formatter_name =~ Regexp.new(text[1..-1]))
366
+ else
367
+ rv = (text =~ formatter_rx)
368
+ end
369
+ return rv ? true : false
370
+ end
371
+
372
+ def format_GET(invoker)
373
+ elt = invoker.elt
374
+ if elt
375
+ elt.format_clip(invoker, Deplate::Element)
376
+ else
377
+ invoker.log("Dropped!", :error)
378
+ end
379
+ end
380
+
381
+ def format_LIST(invoker)
382
+ acc = []
383
+ elt = invoker.elt
384
+ meth = "format_list_of_" + elt
385
+ if respond_to?(meth)
386
+ args = invoker.args
387
+ begin
388
+ acc << send(meth, invoker)
389
+ acc << format_pagebreak(invoker) if args["page"]
390
+ rescue StandardError => e
391
+ log(["Formatting on LIST failed", elt.inspect, e, e.backtrace[0..10]], :error)
392
+ end
393
+ else
394
+ log(["Unknown LIST type", elt.inspect], :error)
395
+ end
396
+ join_blocks(acc)
397
+ end
398
+
399
+ def format_PAGEBREAK(invoker)
400
+ format_pagebreak(invoker, nil, true)
401
+ end
402
+
403
+ def fill_in_template(invoker)
404
+ invoker.elt
405
+ end
406
+
407
+ def read_bib(bibfiles)
408
+ end
409
+
410
+ def format_unknown(invoker)
411
+ log(["Unknown element", invoker.class], :error, invoker.source)
412
+ elt = invoker.elt
413
+ if elt.kind_of?(Array)
414
+ elt = elt.join("\n")
415
+ end
416
+ format_verbatim(invoker, elt)
417
+ end
418
+
419
+ def format_unknown_particle(invoker)
420
+ return plain_text(invoker.args[:match][0])
421
+ end
422
+
423
+ def format_unknown_macro(invoker)
424
+ return %{#{plain_text("{")}#{invoker.elt}#{plain_text("}")}}
425
+ end
426
+
427
+
428
+ ### General
429
+ def_abstract :format_label, :format_figure, :include_image
430
+
431
+ ### Elements
432
+ def_abstract :format_note, :format_table, :format_heading, :format_list,
433
+ :format_break, :format_anchor, :format_paragraph
434
+
435
+ ### Regions
436
+ def_abstract :format_verbatim, :format_abstract, :format_quote,
437
+ :format_header, :format_footer
438
+
439
+ ### Commands
440
+ def_abstract :format_title, :format_MAKEBIB, :format_IDX,
441
+ :format_pagebreak
442
+
443
+ ### Particles
444
+ def_abstract :format_emphasize, :format_code, :format_url, :format_wiki, :format_symbol,
445
+ :doublequote_open, :doublequote_close, :singlequote_open, :singlequote_close
446
+
447
+ ### Macros
448
+ def_abstract :format_index, :format_footnote, :format_ref,
449
+ :format_linebreak, :format_subscript, :format_superscript, :format_stacked,
450
+ :format_pagenumber
451
+
452
+ def format_cite(invoker)
453
+ container = invoker.container
454
+ args = invoker.args
455
+ n = args['n']
456
+ p = args['p']
457
+ np = args['np']
458
+ y = args['y']
459
+ acc = []
460
+ pmsg = @deplate.msg('p.\\ ')
461
+ for c in invoker.elt
462
+ cc = bib_entry(c)
463
+ if cc
464
+ yr = cc.assoc('year')
465
+ yr = if yr then yr[1] else '' end
466
+ if p
467
+ p = @deplate.parse_and_format_without_wikinames(container, "#{pmsg}#{p}")
468
+ yr += ": #{p}"
469
+ # yr += ": " + p if p
470
+ end
471
+ if y
472
+ acc << referenced_bib_entry(invoker, c, yr)
473
+ else
474
+ nm = cc.assoc('author') || cc.assoc('editor') || cc.assoc('howpublished')
475
+ if nm
476
+ nm = nm[1]
477
+ nm = nm.gsub(/\s+/, ' ').split(' and ').collect do |a|
478
+ a.scan(/\w+$/)
479
+ end
480
+ nm = nm.join(', ')
481
+ acc << referenced_bib_entry(invoker, c, [nm, yr].join(' '))
482
+ else
483
+ acc << referenced_bib_entry(invoker, c, c)
484
+ end
485
+ end
486
+ end
487
+ end
488
+ n &&= n + plain_text(' ', true)
489
+ acc = acc.join('; ')
490
+ if np
491
+ return %{#{plain_text(' ', true)}#{n}#{acc}}
492
+ else
493
+ return %{#{plain_text(' ', true)}(#{n}#{acc})}
494
+ end
495
+ end
496
+
497
+ # Check if ch (a number representing a character) is a multi-byte leader.
498
+ # This method always returns false unless it is overwritten by some module.
499
+ def multibyte_leader?(ch)
500
+ false
501
+ end
502
+
503
+ # Return the first character of string while taking care whether string
504
+ # starts with a multi-byte sequence. Return the character in upper case if
505
+ # upcase is true (this usually doesn't work for multi-byte characters.
506
+ def get_first_char(string, upcase=false)
507
+ ch = string[0..0]
508
+ upcase and ch ? ch.upcase : ch
509
+ end
510
+
511
+ # Return the alphabethically sorted index data.
512
+ # def sort_index_entries(data)
513
+ # return data.sort do |a,b|
514
+ # aa = get_first_char(a, true)
515
+ # bb = get_first_char(b, true)
516
+ # aa <=> bb
517
+ # end
518
+ # end
519
+ def sort_index_entries(data)
520
+ return data.sort {|a,b| a[0].upcase <=> b[0].upcase}
521
+ end
522
+
523
+ # Return the maximum row size for the table data in elt.
524
+ def table_row_size(elt)
525
+ max = 0
526
+ for row in elt
527
+ i = row.cols.size
528
+ if i > max
529
+ max = i
530
+ end
531
+ end
532
+ max
533
+ end
534
+
535
+ # Takes an optional block that takes a string as argument and returns
536
+ # true if we shouldn't wrap the text at this position
537
+ def wrap_text(text, args={})
538
+ moreIndent = args[:indent] || ""
539
+ innerMargin = args[:margin] || 66
540
+ outerMargin = args[:maxmargin] || 72
541
+ hanging = args[:hanging] || nil
542
+ hang_idt = hanging ? " " * hanging : nil
543
+ acc = []
544
+ block = args[:check]
545
+ break_at = args[:break_at]
546
+ if break_at
547
+ rx = /(\s+|([#{break_at}]+))/
548
+ else
549
+ rx = /\s+/
550
+ end
551
+ text.each do |text|
552
+ m = /^(\s*)(.*)$/.match(text)
553
+ idt = m[1] + moreIndent
554
+ accum = [m[1]]
555
+ idtx = idt.size
556
+ imx = innerMargin - idtx
557
+ rest = m[2]
558
+ while rest
559
+ this, rest = break_line(rest, rx, imx, block)
560
+ accum << this
561
+ if rest
562
+ accum << "\n"
563
+ accum << idt
564
+ accum << hang_idt if hang_idt
565
+ end
566
+ end
567
+ acc << accum.join
568
+ end
569
+ return acc.join("\n")
570
+ end
571
+
572
+ def break_line(line, rx, inner_margin, block=nil, delta=-1)
573
+ max = line.size
574
+ if inner_margin >= max
575
+ return line, nil
576
+ else
577
+ m = rx.match(line[inner_margin..-1])
578
+ if m
579
+ pre = m.pre_match
580
+ tt = line[0..inner_margin-1] + pre
581
+ if block and block.call(tt)
582
+ return break_line(line, rx, inner_margin + delta, block, delta)
583
+ else
584
+ if m[1]
585
+ x = m[1].size + 1
586
+ return tt[0..-x], m[1] + m.post_match
587
+ else
588
+ return tt, m.post_match
589
+ end
590
+ end
591
+ else
592
+ return break_line(line, rx, inner_margin + 1, block, 1)
593
+ end
594
+ end
595
+ end
596
+
597
+ def prelude(name)
598
+ @deplate.variables[name]
599
+ end
600
+
601
+ # Format the Inlatex region
602
+ def format_inlatex(invoker)
603
+ args = invoker.args
604
+ inline = args["inline"]
605
+ args["h"] ||= (args["inlineLatexHeight"] || args["inlatexHeight"]) if inline
606
+ acc = []
607
+ elt = invoker.elt
608
+ if elt
609
+ for i in elt
610
+ acc << format_element(:format_figure, invoker, inline, i)
611
+ end
612
+ else
613
+ invoker.log(['Empty element', 'inlatex'], :error)
614
+ end
615
+ join_blocks(acc)
616
+ end
617
+
618
+ # Format the ltx macro
619
+ def format_ltx(invoker, other_args={})
620
+ args = invoker.args
621
+ acc = []
622
+ args["h"] ||= (args["inlineLatexHeight"] || other_args["h"])
623
+ args["alt"] ||= invoker.text
624
+ args["style"] = "latex"
625
+ inlatex = invoker.elt
626
+ if !inlatex or inlatex.empty?
627
+ acc << invoker.text
628
+ else
629
+ for i in inlatex
630
+ # acc << @deplate.formatter.include_image(i, args, true)
631
+ acc << format_element(:format_figure, invoker, true, i)
632
+ end
633
+ end
634
+ return acc.flatten.join("\n")
635
+ end
636
+
637
+ # Format the math macro
638
+ alias :format_math :format_ltx
639
+
640
+ # Process inline latex. The file names of the output are saved as an
641
+ # array in <tt>invoker.elt</tt>.
642
+ def inlatex(invoker)
643
+ pkgs, body = inlatex_split(invoker.accum)
644
+ id = inlatex_id(invoker)
645
+ sfx = invoker.args["sfx"] || @deplate.variables['ltxSfx'] || inlatex_sfx
646
+ currDir = Dir.pwd
647
+ @deplate.in_working_dir do
648
+ ftex = id + ".tex"
649
+ flog = id + ".log"
650
+ faux = id + ".aux"
651
+ fdvi = id + ".dvi"
652
+ fps = id + ".ps"
653
+ checkOW = true
654
+
655
+ case sfx
656
+ when "ps"
657
+ device = nil
658
+ fout = fps
659
+ checkOW = false
660
+ when "pdf"
661
+ device = "pdfwrite"
662
+ fout = id + ".*.pdf"
663
+ when "jpeg", "jpg"
664
+ device = "jpeg"
665
+ fout = id + ".*.jpeg"
666
+ else
667
+ raise "Unknown device/suffix: #{sfx}"
668
+ end
669
+
670
+ acc = [
671
+ "\\documentclass[12pt,a4paper,notitlepage]{article}",
672
+ "\\usepackage{amsmath}",
673
+ "\\usepackage{amsfonts}",
674
+ ]
675
+ acc += pkgs
676
+ acc << "\\begin{document}" << "\\pagestyle{empty}"
677
+ acc += body
678
+ acc << "\\end{document}"
679
+
680
+ if Deplate::Region.check_file(invoker, fout, ftex, acc)
681
+ invoker.log(["Files exist! Using", fout], :anyway)
682
+ else
683
+ if checkOW and !@deplate.options.force
684
+ for f in [ftex, flog, faux, fdvi, fout]
685
+ if !Dir[f].empty?
686
+ raise "Please delete '#{f}' or change the id before proceeding:\n#{invoker.accum.join("\n")}"
687
+ end
688
+ end
689
+ end
690
+
691
+ acc = acc.join("\n")
692
+
693
+ Deplate::External.write_file(invoker, ftex) {|io| io.puts(acc)}
694
+ inlatex_process_latex(invoker, ftex, faux, flog)
695
+ if block_given?
696
+ yield(invoker, device, fdvi, fps, fout)
697
+ else
698
+ inlatex_process_dvi(invoker, fdvi, fps) if File.exist?(fdvi)
699
+ if device
700
+ inlatex_process_ps(invoker, device, fps, fout, invoker.args)
701
+ elsif fps != fout
702
+ File.rename(fps, fout)
703
+ end
704
+ end
705
+ end
706
+
707
+ invoker.elt = Dir[fout]
708
+ if invoker.elt.empty?
709
+ code = invoker.accum.join("\n")
710
+ invoker.log(["Conversion if Inline LaTeX failed", code], :error)
711
+ end
712
+ end
713
+ end
714
+
715
+ def inlatex_id(invoker, last=false)
716
+ id = invoker.args["id"]
717
+ unless id
718
+ unless last
719
+ @inlatex_idx += 1
720
+ end
721
+ id = @deplate.auxiliary_auto_filename('ltx', @inlatex_idx, invoker.accum)
722
+ invoker.log(["No id given", invoker.accum])
723
+ end
724
+ id
725
+ end
726
+
727
+ def inlatex_process_latex(invoker, ftex, faux, flog)
728
+ latex2dvi(invoker, ftex, faux, flog)
729
+ end
730
+
731
+ def inlatex_process_dvi(invoker, fdvi, fps)
732
+ dvi2ps(invoker, fdvi, fps)
733
+ end
734
+
735
+ def inlatex_process_ps(invoker, device, fps, fout, args)
736
+ ps2img(invoker, device, fps, fout, args) if File.exist?(fps)
737
+ end
738
+
739
+ # Divert lines in invoker#accum to the preamble or the body.
740
+ def inlatex_split(accum)
741
+ pkgs = []
742
+ body = []
743
+ for l in accum.join("\n")
744
+ if l =~ /^\s*\\(usepackage|input)\s*(\[.*?\])?\s*\{.+?\}\s*$/
745
+ pkgs << l.chomp
746
+ elsif l =~ /%%%\s*$/
747
+ pkgs << l.chomp
748
+ else
749
+ body << l.chomp
750
+ end
751
+ end
752
+ return pkgs.uniq, body
753
+ end
754
+
755
+ # The default suffix/device to be used for inlatex output.
756
+ def inlatex_sfx
757
+ "jpeg"
758
+ end
759
+
760
+ def latex2dvi(invoker, ftex, faux, flog)
761
+ if Deplate::External.latex(invoker, ftex) and @deplate.options.clean
762
+ for i in [faux, flog]
763
+ if File.exist?(i)
764
+ File.delete(i)
765
+ invoker.log(["Deleting", i])
766
+ end
767
+ end
768
+ end
769
+ end
770
+
771
+ def dvi2ps(invoker, fdvi, fps, other_options=nil)
772
+ # -Pwww
773
+ if Deplate::External.dvi2ps(invoker, fdvi, fps, other_options) and @deplate.options.clean
774
+ File.delete(fdvi) if @deplate.options.clean
775
+ invoker.log(["Deleting", fdvi])
776
+ end
777
+ end
778
+
779
+ def ps2img(invoker, device, fps, fout, args)
780
+ if Deplate::External.ps2img(invoker, device, fps, fout, args) and @deplate.options.clean
781
+ File.delete(fps)
782
+ invoker.log(["Deleting", fps])
783
+ end
784
+ end
785
+
786
+
787
+ private
788
+ def referenced_bib_entry(invoker, key, text)
789
+ text
790
+ end
791
+
792
+ def formatted_block(env, text, opts=nil, args=nil, no_id=false, no_indent=false)
793
+ text = indent_text(text) unless no_indent
794
+ return join_blocks([get_open(env, opts, args, :no_id => no_id), text, get_close(env, args)])
795
+ end
796
+
797
+ def_abstract :get_open, :get_close
798
+
799
+ def formatted_inline(env, text, opts=nil, args=nil, no_id=false)
800
+ return join_inline([get_open(env, opts, args, :no_id => no_id), text, get_close(env, args)])
801
+ end
802
+
803
+ def formatted_single(env, opts=nil, args=nil, no_id=false)
804
+ return get_open(env, opts, args, :single => true, :no_id => no_id)
805
+ end
806
+
807
+ def use_id(args, opts={}, set=true)
808
+ if args
809
+ set &&= !args[:id]
810
+ else
811
+ args = {}
812
+ end
813
+ id = opts['id'] || args[:id] || args['id']
814
+ # || args['label']
815
+ args[:id] = id if set
816
+ id
817
+ end
818
+
819
+ def use_labels(args, labels, opts={})
820
+ args ||= {}
821
+ labels = labels ? labels.dup : []
822
+ id = use_id(args, opts)
823
+ l = args["label"]
824
+ labels << l if l
825
+ # i = opts[:invoker]
826
+ # if i
827
+ # labels += i.label
828
+ # end
829
+ if opts[:with_id]
830
+ labels << id
831
+ elsif id
832
+ labels.delete(id)
833
+ end
834
+ labels.delete_if {|e| @consumed_labels.include?(e)}
835
+ labels.flatten!
836
+ labels.compact!
837
+ labels.uniq!
838
+ @consumed_labels += labels unless labels.empty?
839
+ return labels
840
+ end
841
+
842
+ def format_indent(level, shift=false)
843
+ if level < 0
844
+ log(["Negative indentation level", level], :error)
845
+ return ""
846
+ else
847
+ l = level * 2
848
+ # l += 1 if shift
849
+ return " " * l
850
+ end
851
+ end
852
+
853
+ def indent_text(text, mult=1, shift=false)
854
+ if text
855
+ indent = format_indent(mult)
856
+ return text.collect {|l| "%s%s" % [indent, l.chomp]}.join("\n")
857
+ end
858
+ end
859
+
860
+ def keywords
861
+ kw = @deplate.variables["keywords"]
862
+ if kw.kind_of?(Array)
863
+ kw
864
+ elsif kw.kind_of?(String)
865
+ kw.split(/\s*[,;]\s*/)
866
+ elsif kw
867
+ log(["Shouldn't be here", kw, kw.class], :error)
868
+ else
869
+ nil
870
+ end
871
+ end
872
+
873
+ # Create @plain_text_rx, which contains the keys of @special_symbols
874
+ # in a group. This rx will be used by #plain_text.
875
+ def build_plain_text_rx
876
+ @plain_text_rx = Regexp.new("(%s)" % @special_symbols.keys.collect {|x| Regexp.escape(x)}.join("|"))
877
+ end
878
+
879
+
880
+ ################################################ Bibliography {{{1
881
+ def simple_bibtex_reader(bibfiles)
882
+ acc = []
883
+ for b in bibfiles
884
+ b = File.expand_path(b)
885
+ unless File.exist?(b)
886
+ b = Deplate::External.kpsewhich(self, b)
887
+ if b.empty?
888
+ next
889
+ end
890
+ end
891
+ File.open(b) {|io| acc << io.read}
892
+ end
893
+ acc = acc.join("\n")
894
+ loop do
895
+ m = /^\s*(@\w+\{\s*(\S+?)\s*,.*?)(?=(^@|\z))/m.match(acc)
896
+ if m
897
+ id = m[2]
898
+ e = m[1]
899
+ arr = e.scan(/^\s*(\w+)\s*=\s*(\{.*?\}|\d+)\s*[,}]\s*$/m)
900
+ arr.collect! do |var, val, rest|
901
+ n = /^\s*\{(.*?)\}\s*($|\}\s*\z)/m.match(val)
902
+ if n
903
+ val = n[1]
904
+ end
905
+ [var, val]
906
+ end
907
+ arr << ["type", m[2]]
908
+ @bibentries[id] = arr
909
+ acc = m.post_match
910
+ else
911
+ break
912
+ end
913
+ end
914
+ end
915
+
916
+ def cited_keys
917
+ @deplate.options.citations.collect {|c| c.elt}.flatten.uniq
918
+ end
919
+
920
+ def format_bibliography(invoker)
921
+ acc = []
922
+ for k in cited_keys
923
+ b = bib_entry(k)
924
+ bb = format_bib_entry(invoker, b)
925
+ i = encode_id(k)
926
+ l = format_label(invoker, :string, [i])
927
+ if block_given?
928
+ acc << [yield(i, l, bb), bb]
929
+ else
930
+ acc << [bb, bb]
931
+ end
932
+ end
933
+ acc = acc.sort {|a,b| a[1] <=> b[1]}
934
+ acc.collect! {|e| e[0]}
935
+ join_blocks(acc)
936
+ end
937
+
938
+ def format_bib_entry(invoker, bibdef)
939
+ key, author = bibdef.assoc("author")
940
+ key, editor = bibdef.assoc("editor")
941
+ key, how = bibdef.assoc("howpublished")
942
+ author = reformat_authors(author)
943
+ editor = reformat_authors(editor)
944
+ au = [nil, author || editor || how || "???"]
945
+ yr = bibdef.assoc("year")
946
+ au[1] = "%s (%s)" % [au, yr[1]] if yr
947
+ ti = bibdef.assoc("title")
948
+ bt = bibdef.assoc("booktitle")
949
+ pu = bibdef.assoc("publisher")
950
+ i = bibdef.assoc("journal")
951
+ if i
952
+ vol = bibdef.assoc("volume")
953
+ vol &&= vol[1]
954
+ nr = bibdef.assoc("number")
955
+ nr &&= "(" + nr[1] +")"
956
+ i[1] += [" ", vol, nr].join if vol or nr
957
+ elsif author and editor
958
+ i = [nil, editor]
959
+ t = bt || ti
960
+ if t
961
+ i << ": " << t[1]
962
+ end
963
+ end
964
+ p = bibdef.assoc("pages")
965
+ if i
966
+ hi = "journal"
967
+ elsif bt
968
+ hi = "booktitle"
969
+ else
970
+ hi = "title"
971
+ end
972
+ bb = [au, ti, bt, pu, i, p].compact.collect do |key, val|
973
+ val = simple_latex_reformat(val)
974
+ val = %{__#{val}__} if key == hi
975
+ val
976
+ end
977
+ return @deplate.parse_and_format_without_wikinames(invoker, bb.join(". ") + ".")
978
+ end
979
+
980
+ def simple_latex_reformat(text)
981
+ text.gsub!(/^\{(.*)\}$/, "\\1")
982
+ text.gsub!(/\s+/m, " ")
983
+ text.gsub!(/``/, %{"})
984
+ text.gsub!(/''/, %{"})
985
+ text.gsub!(/`/, %{'})
986
+ text.gsub!(/'/, %{'})
987
+ # text.gsub!(/--/, %{--})
988
+ text.gsub!(/\\([$&%#_{}^~|])(\{\})?/, "\\1")
989
+ return text
990
+ end
991
+
992
+ def bib_entry(key)
993
+ b = @bibentries[key] || []
994
+ crossref = b.assoc("crossref")
995
+ if crossref
996
+ cb = @bibentries[crossref[1]]
997
+ b += cb if cb
998
+ end
999
+ return b
1000
+ end
1001
+
1002
+ def reformat_authors(text)
1003
+ if text
1004
+ au = []
1005
+ for a in text.split(/ and /)
1006
+ m = /^((.+?)?\s+)?(\S+)$/.match(a.strip)
1007
+ if m[2]
1008
+ au << m[3] + ", " + m[2]
1009
+ else
1010
+ au << a
1011
+ end
1012
+ end
1013
+ return au.join("; ")
1014
+ end
1015
+ end
1016
+
1017
+ def authors_split(text)
1018
+ text.split(/ and /) if text
1019
+ end
1020
+
1021
+
1022
+ # this is the general function used for formatting lists of any kind; it
1023
+ # relies on #format_list, #format_indent and #format_list_item to
1024
+ # do the actual output
1025
+ def printable_list(invoker, list=nil)
1026
+ list ||= invoker.elt
1027
+ unless list.nil? or list.empty?
1028
+ @levels = []
1029
+ @types = []
1030
+ @endTags = []
1031
+ accum = []
1032
+ # level0 = list.sort {|a,b| a.level <=> b.level}[0].level
1033
+ level0 = list.min {|a,b| a.level <=> b.level}.level
1034
+ ind = 0
1035
+ max = list.size - 1
1036
+
1037
+ list.each_with_index do |i, idx|
1038
+ # :listtype, :type, :level, :item, :body
1039
+ t = i.type
1040
+ s = list_subtype(t, i.item)
1041
+ c = [i.listtype, s]
1042
+ l = i.level
1043
+ if last_listtype
1044
+ # there is a list environment, so this isn't the first item
1045
+ if last_level and l != last_level
1046
+ if l < last_level
1047
+ # close a nested list
1048
+ ind = printable_close_lists_until(invoker, accum, ind, l)
1049
+ elsif l > last_level and t != "Paragraph"
1050
+ # open a new nested list
1051
+ # p "DBG --- 1054: #{c} != #{last_listtype}"
1052
+ ind = printable_open_list(invoker, accum, c, ind, l, s)
1053
+ @endTags << nil
1054
+ end
1055
+ end
1056
+ if last_level and last_listtype and c != last_listtype and t != "Paragraph"
1057
+ if l <= last_level
1058
+ # close the previous list and start a new one
1059
+ ind = printable_list_close_endtag(invoker, accum, ind)
1060
+ # p "DBG ---- #{last_listtype} #{t}"
1061
+ end
1062
+ if c != last_listtype and l <= last_level
1063
+ # p "DBG --- 1067: #{c} != #{last_listtype}"
1064
+ ind = printable_close_list(invoker, accum, ind)
1065
+ ind = printable_open_list(invoker, accum, c, ind, l, s)
1066
+ @endTags << nil
1067
+ end
1068
+ end
1069
+ else
1070
+ # start a new list
1071
+ ind = printable_open_list(invoker, accum, c, ind, l, s)
1072
+ end
1073
+ if @levels.empty? and idx < max
1074
+ # something weired happened (e.g. the previous list item was
1075
+ # deeper nested, but this item doesn't continue anything --
1076
+ # which should probably considered as a syntax error anyway)
1077
+ invoker.log(["Malformed list hierarchy", last_listtype, idx], :error)
1078
+ ind = printable_open_list(invoker, accum, c, ind, l, s)
1079
+ end
1080
+ if t == "Paragraph"
1081
+ acc, etag = format_list_item(invoker, t, ind, i)
1082
+ accum << acc
1083
+ else
1084
+ ind = printable_list_close_endtag(invoker, accum, ind)
1085
+ # p "DBG #{' ' * l} Item (#{@types} #{@levels})"
1086
+ acc, etag = format_list_item(invoker, t, ind, i)
1087
+ @endTags << [etag, l, ind]
1088
+ accum << acc
1089
+ ind += 1
1090
+ end
1091
+ if i.label and !i.label.empty?
1092
+ lab = format_label(invoker, :string, i.label)
1093
+ if lab
1094
+ accum[-1] += lab
1095
+ end
1096
+ end
1097
+ end
1098
+
1099
+ # close all open tags & lists
1100
+ while !@endTags.empty?
1101
+ ind = printable_list_close_endtag(invoker, accum, ind)
1102
+ end
1103
+ while !@levels.empty?
1104
+ ind = printable_close_list(invoker, accum, ind)
1105
+ end
1106
+ if ind < 0
1107
+ invoker.log("Malformed list or internal error", :error)
1108
+ end
1109
+
1110
+ accum.delete_if {|e| e == :empty}
1111
+ return accum.join("\n")
1112
+ else
1113
+ return ""
1114
+ end
1115
+ end
1116
+
1117
+ def last_level
1118
+ @levels.last
1119
+ end
1120
+
1121
+ def last_listtype
1122
+ @types.last
1123
+ end
1124
+
1125
+ # def last_type
1126
+ # @types.last
1127
+ # end
1128
+
1129
+ # def last_listtype
1130
+ # c, s = last_type
1131
+ # c
1132
+ # end
1133
+
1134
+ # def last_subtype
1135
+ # c, s = last_type
1136
+ # s
1137
+ # end
1138
+
1139
+ def list_subtype(type, item)
1140
+ case type
1141
+ when "Numbered"
1142
+ if item =~ /^[A-Z]\.?$/
1143
+ return "A"
1144
+ elsif item =~ /^[a-z?@]\.?$/
1145
+ return "a"
1146
+ else
1147
+ return "1"
1148
+ end
1149
+ when "Itemize"
1150
+ return nil
1151
+ when "Description"
1152
+ return nil
1153
+ when "Paragraph"
1154
+ return nil
1155
+ else
1156
+ raise "Unknown list type: #{type}"
1157
+ end
1158
+ end
1159
+
1160
+ def printable_close_lists_until(invoker, accum, ind, level)
1161
+ begin
1162
+ ind = printable_list_close_endtag(invoker, accum, ind)
1163
+ ind = printable_close_list(invoker, accum, ind)
1164
+ end until @levels.empty? or @levels.last <= level
1165
+ ind
1166
+ end
1167
+
1168
+ def printable_close_list(invoker, accum, ind)
1169
+ ind -= 1
1170
+ lev = @levels.pop
1171
+ tp, sp = @types.pop
1172
+ # p "DBG #{' ' * (lev || 1)}>close #{lev} #{tp} #{sp} #{caller[0]}"
1173
+ le = format_list_env(invoker, tp, ind, :close, sp)
1174
+ accum << le if le
1175
+ ind
1176
+ end
1177
+
1178
+ def printable_open_list(invoker, accum, type, ind, level, subtype=nil)
1179
+ t, s = type
1180
+ le = format_list_env(invoker, t, ind, :open, subtype)
1181
+ accum << le if le
1182
+ ind += 1
1183
+ @levels << level
1184
+ @types << type
1185
+ # p "DBG #{' ' * (level || 1)}<open #{level} #{type} #{subtype} #{caller[0]}"
1186
+ ind
1187
+ end
1188
+
1189
+ def printable_list_close_endtag(invoker, accum, ind)
1190
+ tag, level, ind0 = @endTags.pop
1191
+ if tag
1192
+ while @levels.last and @levels.last > level
1193
+ ind = printable_close_list(invoker, accum, ind)
1194
+ end
1195
+ accum << tag unless tag == :none
1196
+ end
1197
+ return ind0 || ind
1198
+ end
1199
+
1200
+ def list_item_explicit_value(item, explicit=false)
1201
+ if @deplate.variables['noExplicitNumbering']
1202
+ nil
1203
+ elsif explicit or item.explicit and item.item and !item.item.empty?
1204
+ item.item
1205
+ else
1206
+ nil
1207
+ end
1208
+ end
1209
+ end
1210
+