deplate 0.7.3

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.
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
+