deplate 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS.TXT +26 -0
- data/CHANGES.TXT +177 -0
- data/LICENSE.TXT +340 -0
- data/NEWS.TXT +29 -0
- data/README.TXT +86 -0
- data/TODO.TXT +202 -0
- data/VERSION.TXT +1 -0
- data/bin/deplate +3 -0
- data/bin/deplate.bat +2 -0
- data/etc/deplate.ini +361 -0
- data/lib/deplate.rb +31 -0
- data/lib/deplate/abstract-class.rb +30 -0
- data/lib/deplate/builtin.rb +11 -0
- data/lib/deplate/cache.rb +59 -0
- data/lib/deplate/commands.rb +693 -0
- data/lib/deplate/common.rb +335 -0
- data/lib/deplate/converter.rb +99 -0
- data/lib/deplate/core.rb +2705 -0
- data/lib/deplate/css/article.css +545 -0
- data/lib/deplate/css/deplate.css +699 -0
- data/lib/deplate/css/heading-navbar.css +29 -0
- data/lib/deplate/css/layout-deplate-print.css +540 -0
- data/lib/deplate/css/layout-deplate.css +764 -0
- data/lib/deplate/css/sans-serif.css +160 -0
- data/lib/deplate/css/serif-e.css +170 -0
- data/lib/deplate/css/serif-rel.css +121 -0
- data/lib/deplate/css/serif.css +190 -0
- data/lib/deplate/css/slides.css +11 -0
- data/lib/deplate/css/tabbar-left.css +91 -0
- data/lib/deplate/css/tabbar-right-ie.css +14 -0
- data/lib/deplate/css/tabbar-right.css +118 -0
- data/lib/deplate/css/tabbar-top.css +64 -0
- data/lib/deplate/css/tabbar.css +81 -0
- data/lib/deplate/css/text-sans-serif.css +154 -0
- data/lib/deplate/css/text-serif.css +175 -0
- data/lib/deplate/define.rb +439 -0
- data/lib/deplate/docbook.rb +738 -0
- data/lib/deplate/elements.rb +1355 -0
- data/lib/deplate/etc.rb +199 -0
- data/lib/deplate/external.rb +135 -0
- data/lib/deplate/fmt/dbk-article-4.1.2.rb +21 -0
- data/lib/deplate/fmt/dbk-article.rb +46 -0
- data/lib/deplate/fmt/dbk-book.rb +46 -0
- data/lib/deplate/fmt/dbk-ref.rb +105 -0
- data/lib/deplate/fmt/dbk-slides.rb +47 -0
- data/lib/deplate/fmt/dbk-snippet.rb +21 -0
- data/lib/deplate/fmt/html-snippet.rb +21 -0
- data/lib/deplate/fmt/html.rb +1696 -0
- data/lib/deplate/fmt/htmlsite.rb +419 -0
- data/lib/deplate/fmt/htmlslides.rb +21 -0
- data/lib/deplate/fmt/htmlwebsite.rb +70 -0
- data/lib/deplate/fmt/latex-snippet.rb +22 -0
- data/lib/deplate/fmt/latex.rb +1242 -0
- data/lib/deplate/fmt/php.rb +19 -0
- data/lib/deplate/fmt/phpsite.rb +19 -0
- data/lib/deplate/fmt/plain.rb +598 -0
- data/lib/deplate/fmt/template.rb +34 -0
- data/lib/deplate/fmt/xhtml10t.rb +41 -0
- data/lib/deplate/formatter-snippet.rb +17 -0
- data/lib/deplate/formatter.rb +1210 -0
- data/lib/deplate/input.rb +492 -0
- data/lib/deplate/input/deplate-headings.rb +48 -0
- data/lib/deplate/input/deplate-restricted.rb +70 -0
- data/lib/deplate/input/deplate.rb +28 -0
- data/lib/deplate/input/rdoc.rb +277 -0
- data/lib/deplate/input/template.rb +29 -0
- data/lib/deplate/lib/latex/highlight-extra.sty +15 -0
- data/lib/deplate/lib/latex/highlight-typical.sty +15 -0
- data/lib/deplate/lib/tabmenu.js +146 -0
- data/lib/deplate/locale/de.latin1 +708 -0
- data/lib/deplate/locale/ru.koi8-r +48 -0
- data/lib/deplate/locale/zh_cn.gb2312 +35 -0
- data/lib/deplate/macros.rb +639 -0
- data/lib/deplate/messages.rb +120 -0
- data/lib/deplate/metadata.rb +77 -0
- data/lib/deplate/metadata/marshal.rb +24 -0
- data/lib/deplate/metadata/xml.rb +42 -0
- data/lib/deplate/metadata/yaml.rb +26 -0
- data/lib/deplate/mod/anyword.rb +56 -0
- data/lib/deplate/mod/babelfish.rb +27 -0
- data/lib/deplate/mod/code-gvim.rb +52 -0
- data/lib/deplate/mod/code-highlight.rb +91 -0
- data/lib/deplate/mod/colored-log.rb +17 -0
- data/lib/deplate/mod/de.rb +19 -0
- data/lib/deplate/mod/en.rb +17 -0
- data/lib/deplate/mod/endnotes.rb +60 -0
- data/lib/deplate/mod/fr.rb +46 -0
- data/lib/deplate/mod/html-asciimath.rb +40 -0
- data/lib/deplate/mod/html-deplate-button.rb +15 -0
- data/lib/deplate/mod/html-headings-navbar.rb +39 -0
- data/lib/deplate/mod/html-obfuscate-email.rb +47 -0
- data/lib/deplate/mod/html-sidebar.rb +232 -0
- data/lib/deplate/mod/htmlslides-navbar-fh.rb +32 -0
- data/lib/deplate/mod/iconv.rb +35 -0
- data/lib/deplate/mod/imgurl.rb +30 -0
- data/lib/deplate/mod/inlatex-compound.rb +69 -0
- data/lib/deplate/mod/koma.rb +109 -0
- data/lib/deplate/mod/latex-emph-table-head.rb +38 -0
- data/lib/deplate/mod/latex-styles.rb +461 -0
- data/lib/deplate/mod/latex-verbatim-small.rb +29 -0
- data/lib/deplate/mod/makefile.rb +194 -0
- data/lib/deplate/mod/mark-external-urls.rb +38 -0
- data/lib/deplate/mod/markup-1-warn.rb +37 -0
- data/lib/deplate/mod/markup-1.rb +41 -0
- data/lib/deplate/mod/navbar-png.rb +33 -0
- data/lib/deplate/mod/noindent.rb +32 -0
- data/lib/deplate/mod/numpara.rb +40 -0
- data/lib/deplate/mod/particle-math.rb +34 -0
- data/lib/deplate/mod/php-extra.rb +44 -0
- data/lib/deplate/mod/pstoedit.rb +71 -0
- data/lib/deplate/mod/recode.rb +57 -0
- data/lib/deplate/mod/ru_koi8-r.rb +20 -0
- data/lib/deplate/mod/smiley.rb +50 -0
- data/lib/deplate/mod/soffice.rb +23 -0
- data/lib/deplate/mod/symbols-latin1.rb +58 -0
- data/lib/deplate/mod/symbols-od-utf-8.rb +16 -0
- data/lib/deplate/mod/symbols-plain.rb +58 -0
- data/lib/deplate/mod/symbols-sgml.rb +97 -0
- data/lib/deplate/mod/symbols-utf-8.rb +81 -0
- data/lib/deplate/mod/symbols-xml.rb +34 -0
- data/lib/deplate/mod/syntax-region-alt.rb +37 -0
- data/lib/deplate/mod/utf8.rb +49 -0
- data/lib/deplate/mod/validate-html.rb +35 -0
- data/lib/deplate/mod/xmlrpc.rb +233 -0
- data/lib/deplate/mod/zh-cn-autospace.rb +108 -0
- data/lib/deplate/mod/zh-cn.rb +59 -0
- data/lib/deplate/once-method.rb +44 -0
- data/lib/deplate/output.rb +249 -0
- data/lib/deplate/particles.rb +815 -0
- data/lib/deplate/regions.rb +1076 -0
- data/lib/deplate/structured.rb +763 -0
- data/lib/deplate/template.rb +430 -0
- data/lib/deplate/templates/html-doc.html +28 -0
- data/lib/deplate/templates/html-left-tabbar-js.html +37 -0
- data/lib/deplate/templates/html-left-tabbar.html +31 -0
- data/lib/deplate/templates/html-tabbar-right-table.html +43 -0
- data/lib/deplate/templates/html-tabbar-right.html +23 -0
- data/lib/deplate/templates/html-tabbar-top.html +43 -0
- data/lib/deplate/templates/html-tabbar.html +31 -0
- data/lib/deplate/wiki-markup.rb +117 -0
- data/lib/deplate/xml.rb +109 -0
- data/lib/deplate/zh-cn.rb +59 -0
- data/lib/ps2ppm.rb +239 -0
- data/man/man1/deplate.1 +692 -0
- 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
|
+
|