review-retrovert 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +9 -0
  3. data/.editorconfig +3 -0
  4. data/.github/workflows/retrovert.yml +20 -5
  5. data/.gitignore +1 -0
  6. data/.vscode/launch.json +48 -0
  7. data/Gemfile.lock +13 -4
  8. data/Makefile +24 -0
  9. data/docker/review.Dockerfile +10 -0
  10. data/lib/review/retrovert/converter.rb +374 -111
  11. data/lib/review/retrovert/reviewcompat.rb +57 -0
  12. data/lib/review/retrovert/reviewdef.rb +70 -0
  13. data/lib/review/retrovert/sty/{ird.sty → ird.sty.erb} +9 -1
  14. data/lib/review/retrovert/sty/review-retrovert-custom.sty.erb +6 -0
  15. data/lib/review/retrovert/utils.rb +35 -0
  16. data/lib/review/retrovert/version.rb +1 -1
  17. data/lib/review/retrovert/yamlconfig.rb +0 -1
  18. data/package-lock.json +6 -0
  19. data/package.json +1 -0
  20. data/review-retrovert.gemspec +5 -1
  21. data/testdata/mybook/.gitignore +3 -1
  22. data/testdata/mybook/.textlintrc +11 -0
  23. data/testdata/mybook/Rakefile +8 -0
  24. data/testdata/mybook/catalog.yml +36 -10
  25. data/testdata/mybook/config-starter.yml +134 -9
  26. data/testdata/mybook/config.yml +44 -15
  27. data/testdata/mybook/contents/00-preface.re +48 -2
  28. data/testdata/mybook/contents/01-install.re +38 -5
  29. data/testdata/mybook/contents/02-tutorial.re +333 -113
  30. data/testdata/mybook/contents/03-syntax.re +2370 -373
  31. data/testdata/mybook/contents/04-customize.re +424 -88
  32. data/testdata/mybook/contents/05-faq.re +288 -10
  33. data/testdata/mybook/contents/06-bestpractice.re +431 -59
  34. data/testdata/mybook/contents/91-compare.re +402 -2
  35. data/testdata/mybook/contents/92-filelist.re +14 -8
  36. data/testdata/mybook/contents/93-background.re +10 -10
  37. data/testdata/mybook/contents/99-postface.re +2 -1
  38. data/testdata/mybook/contents/r0-root.re +1 -1
  39. data/testdata/mybook/css/webstyle.css +180 -2
  40. data/testdata/mybook/data/terms.txt +3 -0
  41. data/testdata/mybook/data/words.txt +15 -0
  42. data/testdata/mybook/images/03-syntax/index-page.png +0 -0
  43. data/testdata/mybook/images/03-syntax/order-detail.png +0 -0
  44. data/testdata/mybook/images/04-customize/section_decoration_samples.png +0 -0
  45. data/testdata/mybook/images/05-faq/dummy-image.png +0 -0
  46. data/testdata/mybook/images/06-bestpractice/section_title_wlines.png +0 -0
  47. data/testdata/mybook/images/avatar-b.png +0 -0
  48. data/testdata/mybook/images/avatar-g.png +0 -0
  49. data/testdata/mybook/images/avatar-r.png +0 -0
  50. data/testdata/mybook/images/caution-icon.png +0 -0
  51. data/testdata/mybook/images/info-icon.png +0 -0
  52. data/testdata/mybook/images/warning-icon.png +0 -0
  53. data/testdata/mybook/layouts/layout.html5.erb +3 -1
  54. data/testdata/mybook/layouts/layout.tex.erb +265 -379
  55. data/testdata/mybook/layouts/layout.tex.erb.orig +386 -0
  56. data/testdata/mybook/lib/ruby/review-book.rb +64 -0
  57. data/testdata/mybook/lib/ruby/review-builder.rb +902 -63
  58. data/testdata/mybook/lib/ruby/review-compiler.rb +675 -22
  59. data/testdata/mybook/lib/ruby/review-epubbuilder.rb +33 -0
  60. data/testdata/mybook/lib/ruby/review-epubmaker.rb +10 -7
  61. data/testdata/mybook/lib/ruby/review-htmlbuilder.rb +354 -66
  62. data/testdata/mybook/lib/ruby/review-latexbuilder.rb +429 -146
  63. data/testdata/mybook/lib/ruby/review-maker.rb +117 -6
  64. data/testdata/mybook/lib/ruby/review-markdownbuilder.rb +945 -0
  65. data/testdata/mybook/lib/ruby/review-markdownmaker.rb +91 -0
  66. data/testdata/mybook/lib/ruby/review-monkeypatch.rb +2 -0
  67. data/testdata/mybook/lib/ruby/review-pdfmaker.rb +160 -82
  68. data/testdata/mybook/lib/ruby/review-webmaker.rb +20 -5
  69. data/testdata/mybook/lib/tasks/review.rake +14 -0
  70. data/testdata/mybook/lib/tasks/starter.rake +148 -4
  71. data/testdata/mybook/sty/indexstyle.ist +25 -0
  72. data/testdata/mybook/sty/mytextsize.sty +29 -0
  73. data/testdata/mybook/sty/mytitlepage.sty +34 -11
  74. data/testdata/mybook/sty/review-base.sty +276 -0
  75. data/testdata/mybook/sty/starter-codeblock.sty +237 -106
  76. data/testdata/mybook/sty/starter-color.sty +72 -17
  77. data/testdata/mybook/sty/starter-heading.sty +60 -13
  78. data/testdata/mybook/sty/starter-misc.sty +894 -0
  79. data/testdata/mybook/sty/starter-note.sty +67 -14
  80. data/testdata/mybook/sty/starter-talklist.sty +105 -0
  81. data/testdata/mybook/sty/starter-util.sty +35 -0
  82. data/testdata/mybook/sty/starter.sty +8 -526
  83. metadata +80 -4
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+
4
+ require 'review/epubbuilder'
5
+
6
+
7
+ module ReVIEW
8
+
9
+ defined?(EPUBBuilder) or
10
+ raise "ReVIEW::EPUBBuilder class not found."
11
+
12
+
13
+ class EPUBBuilder
14
+
15
+ def target_name
16
+ "epub"
17
+ end
18
+
19
+ def inline_par(arg)
20
+ case arg
21
+ when 'i'
22
+ #"<p class=\"indent\">"
23
+ "<p class=\"indent\"></p>" # TODO: (workaround)
24
+ else
25
+ #"<p>"
26
+ "<p></p>" # TODO: (workaround)
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+
33
+ end
@@ -119,9 +119,10 @@ module ReVIEW
119
119
  log('Call ePUB producer.')
120
120
  @producer.produce(epubname, builddir, epubtmpdir)
121
121
  log('Finished.')
122
- rescue ApplicationError => e
122
+ rescue ApplicationError => ex
123
123
  raise if debug?()
124
- error(e.message)
124
+ #error(ex.message)
125
+ error(colored_errmsg(ex.message))
125
126
  ensure
126
127
  FileUtils.remove_entry_secure(builddir) unless debug?()
127
128
  end
@@ -253,7 +254,7 @@ module ReVIEW
253
254
  build_chap(chap, base_path, nil)
254
255
  end
255
256
  end
256
- check_compile_status
257
+ check_compile_status()
257
258
  end
258
259
 
259
260
  def new_renderer()
@@ -286,10 +287,12 @@ module ReVIEW
286
287
  @converter.convert(filename, File.join(@builddir, htmlfile))
287
288
  write_info_body(htmlfile, chaptype)
288
289
  remove_hidden_title(htmlfile)
289
- rescue => e
290
+ ## 文法エラーだけキャッチし、それ以外のエラーはキャッチしないよう変更
291
+ #rescue => ex
292
+ rescue ApplicationError => ex
290
293
  @compile_errors = true
291
- warn "compile error in #{filename} (#{e.class})"
292
- warn e.message
294
+ warn "compile error in #{filename} (#{ex.class})"
295
+ warn colored_errmsg(ex.message)
293
296
  end
294
297
  end
295
298
 
@@ -327,7 +330,7 @@ module ReVIEW
327
330
  end
328
331
 
329
332
  def detect_properties(path)
330
- doc = File.open(path) {|f| REXML::Document.new(f) }
333
+ doc = File.open(path, encoding: 'utf-8') {|f| REXML::Document.new(f) }
331
334
  has_math = REXML::XPath.first(doc, '//m:math', 'm' => 'http://www.w3.org/1998/Math/MathML')
332
335
  has_svg = REXML::XPath.first(doc, '//s:svg', 's' => 'http://www.w3.org/2000/svg')
333
336
  properties = []
@@ -16,6 +16,10 @@ module ReVIEW
16
16
 
17
17
  attr_accessor :starter_config
18
18
 
19
+ def target_name
20
+ "html"
21
+ end
22
+
19
23
  def layoutfile
20
24
  ## 'rake web' のときに使うレイアウトファイルを 'layout.html5.erb' へ変更
21
25
  if @book.config.maker == 'webmaker'
@@ -59,7 +63,7 @@ module ReVIEW
59
63
  @toc = ReVIEW::WEBTOCPrinter.book_to_html(@book, @chapter) #+
60
64
  end
61
65
 
62
- ReVIEW::Template.load(layoutfile).result(binding)
66
+ ReVIEW::Template.load(layoutfile()).result(binding())
63
67
  end
64
68
 
65
69
  def headline(level, label, caption)
@@ -99,62 +103,109 @@ module ReVIEW
99
103
  attrs.map {|k, arr| " #{k}=\"#{arr.join(' ')}\"" }.join()
100
104
  end
101
105
 
102
- def image_image(id, caption, metric)
103
- src = @chapter.image(id).path.sub(%r{\A\./}, '')
106
+ ## 画像
107
+
108
+ def _render_image(id, image_filepath, caption, opts)
109
+ src = image_filepath.sub(/\A\.\//, '')
104
110
  alt = escape_html(compile_inline(caption))
105
- metrics = parse_metric('html', metric)
106
- metrics = " class=\"img\"" unless metrics.present?
111
+ #
112
+ classes = ["img"]
113
+ styles = []
114
+ #
115
+ if opts[:scale]
116
+ case (scale = opts[:scale])
117
+ when /\A\d+\z/, /\A\d\.\d*\z/, /\A\.\d+\z/
118
+ per = (scale.to_f * 100).round()
119
+ when /\A\d+(\.\d+)?%\z/
120
+ per = scale.sub(/%\z/, '').to_f.round()
121
+ else
122
+ error "scale=#{scale}: invalid scale value."
123
+ end
124
+ found = PERCENT_THRESHOLDS.find {|x| x == per }
125
+ if found
126
+ classes << 'width-%03dper' % per
127
+ else
128
+ styles << "max-width:#{per}%"
129
+ end
130
+ end
131
+ #
132
+ classes << opts[:class] if opts[:class]
133
+ classes << "border" if opts[:border]
134
+ classes << "draft" if opts[:draft]
135
+ styles << opts[:style] if opts[:style]
136
+ styles << "width:#{opts[:width]}" if opts[:width]
137
+ #
107
138
  puts "<div id=\"#{normalize_id(id)}\" class=\"image\">"
108
- puts "<img src=\"#{src}\" alt=\"#{alt}\"#{metrics} />"
139
+ print "<img src=\"#{src}\" alt=\"#{alt}\""
140
+ print " class=\"#{classes.join(' ')}\"" unless classes.empty?
141
+ print " style=\"#{styles.join(' ')}\"" unless styles.empty?
142
+ puts " />"
109
143
  image_header(id, caption)
110
144
  puts "</div>"
111
145
  end
112
146
 
113
- ## コードブロック(//program, //terminal)
147
+ PERCENT_THRESHOLDS = [
148
+ 10, 20, 25, 30, 33, 40, 50, 60, 67, 70, 75, 80, 90, 100,
149
+ ]
114
150
 
115
- def program(lines, id=nil, caption=nil, optionstr=nil)
116
- _codeblock('program', 'code', lines, id, caption, optionstr)
117
- end
151
+ protected
152
+
153
+ ## コードブロック(//program, //terminal, //output)
118
154
 
119
- def terminal(lines, id=nil, caption=nil, optionstr=nil)
120
- _codeblock('terminal', 'cmd-code', lines, id, caption, optionstr)
155
+ CLASSNAMES = {
156
+ "program" => "code",
157
+ "terminal" => "cmd-code",
158
+ "list" => "caption-code",
159
+ "listnum" => "code",
160
+ "emlist" => "emlist-code",
161
+ "emlistnum" => "emlistnum-code",
162
+ "source" => "source-code",
163
+ "cmd" => "cmd-code",
164
+ "output" => "output",
165
+ }
166
+
167
+ def _codeblock_eolmark()
168
+ "<small class=\"startereolmark\"></small>"
121
169
  end
122
170
 
123
- protected
171
+ def _codeblock_indentmark()
172
+ '<span class="indentbar"> </span>'
173
+ end
124
174
 
125
- def _codeblock(blockname, classname, lines, id, caption, optionstr)
126
- ## ブロックコマンドのオプション引数はCompilerクラスでパースすべき。
127
- ## しかしCompilerクラスがそのような設計になってないので、
128
- ## 仕方ないのでBuilderクラスでパースする。
129
- opts = _parse_codeblock_optionstr(optionstr, blockname)
130
- CODEBLOCK_OPTIONS.each {|k, v| opts[k] = v unless opts.key?(k) }
175
+ def _render_codeblock(blockname, lines, id, caption_str, opts)
176
+ caption = caption_str
131
177
  #
132
178
  if opts['eolmark']
133
- lines = lines.map {|line| "#{detab(line)}<small class=\"startereolmark\"></small>" }
179
+ eolmark = _codeblock_eolmark() # ex: '{\startereolmark}'
134
180
  else
135
- lines = lines.map {|line| detab(line) }
181
+ eolmark = nil
136
182
  end
137
183
  #
138
- indent_w = opts['indentwidth']
139
- if indent_w && indent_w > 0
140
- indent_str = " " * (indent_w - 1) + '<span class="indentbar"> </span>'
141
- lines = lines.map {|line|
142
- line.sub(/\A( +)/) {
143
- m, n = ($1.length - 1).divmod indent_w
144
- " " << indent_str * m << " " * n
145
- }
146
- }
184
+ eol = eolmark ? "#{eolmark}\n" : "\n"
185
+ lines = lines.map {|line|
186
+ line = _parse_inline(line) {|text| escape(text) }
187
+ }
188
+ #
189
+ indent_width = opts['indent']
190
+ if indent_width && indent_width > 0
191
+ lines = _add_indent_mark(lines, indent_width)
147
192
  end
148
193
  #
194
+ classname = CLASSNAMES[blockname] || "code"
195
+ classname += " #{opts['classname']}" if opts['classname']
149
196
  puts "<div id=\"#{normalize_id(id)}\" class=\"#{classname}\">" if id.present?
150
197
  puts "<div class=\"#{classname}\">" unless id.present?
151
198
  #
199
+ classattr = nil
152
200
  if id.present? || caption.present?
153
201
  str = _build_caption_str(id, caption)
154
202
  print "<span class=\"caption\">#{str}</span>\n"
155
203
  classattr = "list"
204
+ end
205
+ if blockname == "output"
206
+ classattr = blockname
156
207
  else
157
- classattr = "emlist"
208
+ classattr ||= "emlist"
158
209
  end
159
210
  #
160
211
  lang = opts['lang']
@@ -165,7 +216,7 @@ module ReVIEW
165
216
  #
166
217
  gen = opts['lineno'] ? LineNumberGenerator.new(opts['lineno']).each : nil
167
218
  if gen
168
- width = opts['linenowidth']
219
+ width = opts['linenowidth'] || -1
169
220
  if width < 0
170
221
  format = "%s"
171
222
  elsif width == 0
@@ -177,10 +228,10 @@ module ReVIEW
177
228
  end
178
229
  end
179
230
  buf = []
180
- start_tag = opts['linenowidth'] >= 0 ? "<em class=\"linenowidth\">" : "<em class=\"lineno\">"
231
+ start_tag = (opts['linenowidth'] || -1) >= 0 ? "<em class=\"linenowidth\">" : "<em class=\"lineno\">"
181
232
  lines.each_with_index do |line, i|
182
233
  buf << start_tag << (format % gen.next) << ": </em>" if gen
183
- buf << line << "\n"
234
+ buf << line #<< "\n"
184
235
  end
185
236
  puts highlight(body: buf.join(), lexer: lang,
186
237
  format: "html", linenum: !!gen,
@@ -191,27 +242,43 @@ module ReVIEW
191
242
  print "</div>\n"
192
243
  end
193
244
 
245
+ def _add_indent_mark(lines, indent_width)
246
+ space = " "
247
+ rexp = /\A( +)/
248
+ #
249
+ width = indent_width
250
+ mark = _codeblock_indentmark() # ex: '{\starterindentmark}'
251
+ indent = space * (width - 1) + mark
252
+ nchar = space.length
253
+ return lines.map {|line|
254
+ line.sub(rexp) {
255
+ m, n = ($1.length / nchar - 1).divmod width
256
+ "#{space}#{indent * m}#{space * n}"
257
+ }
258
+ }
259
+ end
260
+
194
261
  public
195
262
 
196
263
  ## コードリスト(//list, //emlist, //listnum, //emlistnum, //cmd, //source)
197
264
  def list(lines, id=nil, caption=nil, lang=nil)
198
- _codeblock("list", "caption-code", lines, id, caption, _codeblock_optstr(lang, false))
265
+ _codeblock("list", lines, id, caption, _codeblock_optstr(lang, false))
199
266
  end
200
267
  def listnum(lines, id=nil, caption=nil, lang=nil)
201
- _codeblock("listnum", "code", lines, id, caption, _codeblock_optstr(lang, true))
268
+ _codeblock("listnum", lines, id, caption, _codeblock_optstr(lang, true))
202
269
  end
203
270
  def emlist(lines, caption=nil, lang=nil)
204
- _codeblock("emlist", "emlist-code", lines, nil, caption, _codeblock_optstr(lang, false))
271
+ _codeblock("emlist", lines, nil, caption, _codeblock_optstr(lang, false))
205
272
  end
206
273
  def emlistnum(lines, caption=nil, lang=nil)
207
- _codeblock("emlistnum", "emlistnum-code", lines, nil, caption, _codeblock_optstr(lang, true))
274
+ _codeblock("emlistnum", lines, nil, caption, _codeblock_optstr(lang, true))
208
275
  end
209
276
  def source(lines, caption=nil, lang=nil)
210
- _codeblock("source", "source-code", lines, nil, caption, _codeblock_optstr(lang, false))
277
+ _codeblock("source", lines, nil, caption, _codeblock_optstr(lang, false))
211
278
  end
212
279
  def cmd(lines, caption=nil, lang=nil)
213
280
  lang ||= "shell-session"
214
- _codeblock("cmd", "cmd-code", lines, nil, caption, _codeblock_optstr(lang, false))
281
+ _codeblock("cmd", lines, nil, caption, _codeblock_optstr(lang, false))
215
282
  end
216
283
  def _codeblock_optstr(lang, lineno_flag)
217
284
  arr = []
@@ -295,19 +362,16 @@ module ReVIEW
295
362
  puts "</li>"
296
363
  end
297
364
 
298
- ## 入れ子可能なブロック命令
365
+ def dl_dd_begin()
366
+ puts "<dd>"
367
+ end
299
368
 
300
- def on_minicolumn(type, caption, &b)
301
- puts "<div class=\"#{type}\">"
302
- puts "<p class=\"caption\">#{compile_inline(caption)}</p>" if caption.present?
303
- yield
304
- puts '</div>'
369
+ def dl_dd_end()
370
+ puts "</dd>"
305
371
  end
306
- protected :on_minicolumn
307
372
 
308
- def on_sideimage_block(imagefile, imagewidth, option_str=nil, &b)
309
- imagefile, imagewidth, opts = validate_sideimage_args(imagefile, imagewidth, option_str)
310
- filepath = find_image_filepath(imagefile)
373
+ ## 画像横に文章
374
+ def _render_sideimage(filepath, imagewidth, opts, &b)
311
375
  side = (opts['side'] || 'L') == 'L' ? 'left' : 'right'
312
376
  imgclass = opts['border'] ? "image-bordered" : nil
313
377
  normalize = proc {|s| s =~ /^\A(\d+(\.\d+))%\z/ ? "#{$1.to_f/100.0}\\textwidth" : s }
@@ -327,6 +391,18 @@ module ReVIEW
327
391
  puts "</div>\n"
328
392
  end
329
393
 
394
+ ## 入れ子可能なブロック命令
395
+
396
+ def on_minicolumn(type, caption=nil, &b)
397
+ with_context(:minicolumn) do
398
+ puts "<div class=\"miniblock miniblock-#{type}\">"
399
+ puts "<p class=\"miniblock-caption\">#{compile_inline(caption)}</p>" if caption.present?
400
+ yield
401
+ puts '</div>'
402
+ end
403
+ end
404
+ protected :on_minicolumn
405
+
330
406
  #### ブロック命令
331
407
 
332
408
  def footnote(id, str)
@@ -385,22 +461,91 @@ module ReVIEW
385
461
  end
386
462
 
387
463
  ## 章 (Chapter) の概要
388
- def abstract(lines)
464
+ def on_abstract_block()
389
465
  puts '<div class="abstract">'
390
- puts lines
466
+ yield
391
467
  puts '</div>'
392
468
  end
393
469
 
470
+ ## 章 (Chapter) の著者
471
+ def on_chapterauthor_block(name)
472
+ puts "<div class=\"chapterauthor\">#{escape(name)}</div>"
473
+ end
474
+
475
+ ## 会話リスト
476
+ def _render_talklist(opts, &b)
477
+ c = opts[:classname]
478
+ s = c ? " #{c}" : nil
479
+ puts "<div class=\"talk-outer#{s}\">"
480
+ puts " <ul class=\"talk-list#{s}\">"
481
+ yield
482
+ puts " </ul>"
483
+ puts "</div>"
484
+ end
485
+
486
+ ## 会話項目
487
+ def _render_talk(image_filepath=nil, name=nil, &b)
488
+ puts "<li class=\"talk-item\">"
489
+ print " <span class=\"talk-chara\">"
490
+ if image_filepath.present?
491
+ print "<img class=\"talk-image\" src=\"#{image_filepath}\"/>"
492
+ else
493
+ s = compile_inline(name || '')
494
+ print "<b class=\"talk-name\">#{s}</b>"
495
+ end
496
+ puts "</span>"
497
+ print " <div class=\"talk-text\">"
498
+ yield
499
+ if @output.string.end_with?("\n")
500
+ @output.seek(-1, IO::SEEK_CUR) # 改行文字を取り除く
501
+ #@output.string.chomp! # これだとヌル文字が入ってしまう
502
+ end
503
+ puts "</div>"
504
+ puts "</li>"
505
+ end
506
+
507
+ ## キーと説明文のリスト
508
+ def _render_desclist(opts, &b)
509
+ bkup = @_desclist_opts
510
+ @_desclist_opts = opts
511
+ classnames = ['desc-list']
512
+ classnames << 'compact' if opts[:compact]
513
+ classnames << 'item-bold' if opts[:bold]
514
+ classnames << opts[:classname] if opts[:classname]
515
+ puts "<dl class=\"#{classnames.join(' ')}\">"
516
+ yield
517
+ puts "</dl>"
518
+ @_desclist_opts = bkup
519
+ end
520
+
521
+ ## キーと説明文
522
+ def _render_desc(key, &b)
523
+ opts = @_desclist_opts
524
+ s = compile_inline(key)
525
+ s = "<b>#{s}</b>" if opts[:bold]
526
+ puts " <dt class=\"desc\">#{s}</dt>"
527
+ puts " <dd class=\"desc\">"
528
+ yield
529
+ puts " </dd>"
530
+ end
531
+
532
+ ## 縦方向の空きを入れる
533
+ def _render_vspace(size)
534
+ puts "<div class=\"vspace\" style=\"height:#{size}\"></div>"
535
+ end
536
+
537
+ def _render_addvspace(size)
538
+ puts "<div class=\"addvspace\" style=\"height:#{size}\"></div>"
539
+ end
540
+
394
541
  ## 章タイトルを独立したページに
395
542
  def makechaptitlepage(option=nil)
396
543
  puts '' # HTMLでは特に何もしない
397
544
  end
398
545
 
399
546
  ## 縦方向のスペースがなければ改ページ
400
- def needvspace(builder_name, height)
401
- if builder_name == 'html' || builder_name == 'epub'
402
- puts "<div style=\"height:#{height}\"></div>"
403
- end
547
+ def _render_needvspace(height)
548
+ puts "<div style=\"height:#{height}\"></div>"
404
549
  end
405
550
 
406
551
  ## 段(Paragraph)の終わりにスペースを入れる
@@ -445,15 +590,17 @@ module ReVIEW
445
590
  ## ノート(//note{ ... //})
446
591
  ## (入れ子対応なので、中に箇条書きや別のブロックを入れられる)
447
592
  def on_note_block(label=nil, caption=nil)
448
- caption, label = label, nil if caption.nil?
449
- if label
450
- puts "<div class=\"note\" id=\"#{label}\">"
451
- else
452
- puts "<div class=\"note\">"
593
+ with_context(:minicolumn) do
594
+ caption, label = label, nil if caption.nil?
595
+ if label
596
+ puts "<div class=\"note\" id=\"#{label}\">"
597
+ else
598
+ puts "<div class=\"note\">"
599
+ end
600
+ puts "<h5>#{compile_inline(caption)}</h5>" if caption.present?
601
+ yield
602
+ puts "</div>"
453
603
  end
454
- puts "<h5>#{compile_inline(caption)}</h5>" if caption.present?
455
- yield
456
- puts "</div>"
457
604
  end
458
605
  def note(lines, label=nil, caption=nil)
459
606
  on_quote_block(label, caption) do
@@ -472,6 +619,89 @@ module ReVIEW
472
619
  puts "</div>"
473
620
  end
474
621
 
622
+ ## テーブル
623
+ def table(lines, id=nil, caption=nil, option=nil)
624
+ super
625
+ end
626
+
627
+ def table_header(id, caption, options)
628
+ if id.present?
629
+ begin
630
+ num = @chapter.table(id).number
631
+ rescue KeyError
632
+ error "no such table: #{id}"
633
+ end
634
+ s1 = I18n.t('table')
635
+ s2 = get_chap() \
636
+ ? I18n.t('format_number_header', [get_chap(), num]) \
637
+ : I18n.t('format_number_header_without_chapter', [num])
638
+ s3 = I18n.t('caption_prefix')
639
+ puts "<p class=\"caption\">#{s1}#{s2}#{s3}#{compile_inline(caption||'')}</p>"
640
+ elsif caption.present?
641
+ puts "<p class=\"caption\">#{compile_inline(caption||'')}</p>"
642
+ end
643
+ end
644
+
645
+ def table_begin(_ncols, fontsize: nil)
646
+ if fontsize
647
+ puts "<table style=\"font-size:#{fontsize}\">"
648
+ else
649
+ puts "<table>"
650
+ end
651
+ end
652
+
653
+ protected
654
+
655
+ def _table_before(id, caption, opts)
656
+ class_ = opts[:csv] ? "table table-nohline" : "table"
657
+ if id.present?
658
+ puts "<div id=\"#{normalize_id(id)}\" class=\"#{class_}\">"
659
+ else
660
+ puts "<div class=\"#{class_}\">"
661
+ end
662
+ end
663
+
664
+ def _table_after(id, caption, opts)
665
+ puts "</div>"
666
+ end
667
+
668
+ def _table_bottom(hline: false)
669
+ end
670
+
671
+ def _table_tr(cells, hline: false)
672
+ if hline
673
+ "<tr class=\"hline\">#{cells.join}</tr>"
674
+ else
675
+ "<tr>#{cells.join}</tr>"
676
+ end
677
+ end
678
+
679
+ public
680
+
681
+ ## //imgtable
682
+ def imgtable(lines, id, caption=nil, option=nil)
683
+ super
684
+ end
685
+
686
+ protected
687
+
688
+ def _render_imgtable(id, caption, opts)
689
+ puts "<div id=\"#{normalize_id(id)}\" class=\"imgtable image\">"
690
+ table_header(id, caption, opts)
691
+ puts " <div>"
692
+ yield
693
+ puts " </div>"
694
+ puts "</div>"
695
+ end
696
+
697
+ def _render_imgtable_caption(caption)
698
+ end
699
+
700
+ def _render_imgtable_label(id)
701
+ end
702
+
703
+ public
704
+
475
705
  #### インライン命令
476
706
 
477
707
  def inline_fn(id)
@@ -485,6 +715,16 @@ module ReVIEW
485
715
  error "unknown footnote: #{id}"
486
716
  end
487
717
 
718
+ ## 改段落(箇条書き内では空行を入れられないため)
719
+ def inline_par(arg)
720
+ case arg
721
+ when 'i'
722
+ "<p class=\"indent\">"
723
+ else
724
+ "<p>"
725
+ end
726
+ end
727
+
488
728
  ## ファイル名
489
729
  def inline_file(str)
490
730
  on_inline_file { escape(str) }
@@ -552,7 +792,7 @@ module ReVIEW
552
792
 
553
793
  def on_inline_i() ; "<i>#{yield}</i>" ; end
554
794
  def on_inline_b() ; "<b>#{yield}</b>" ; end
555
- def on_inline_code() ; "<code>#{yield}</code>" ; end
795
+ #def on_inline_code() ; "<code>#{yield}</code>" ; end
556
796
  def on_inline_tt() ; "<tt>#{yield}</tt>" ; end
557
797
  def on_inline_del() ; "<s>#{yield}</s>" ; end
558
798
  def on_inline_sub() ; "<sub>#{yield}</sub>" ; end
@@ -563,6 +803,15 @@ module ReVIEW
563
803
  def on_inline_ami() ; "<span class=\"ami\">#{yield}</span>"; end
564
804
  def on_inline_balloon(); "<span class=\"balloon\">← #{yield}</span>"; end
565
805
 
806
+ def on_inline_code()
807
+ return "<code class=\"inline-code\">#{yield}</code>"
808
+ end
809
+
810
+ ## 「“」と「”」で囲む
811
+ def on_inline_qq()
812
+ "“#{yield}”"
813
+ end
814
+
566
815
  def build_inline_href(url, escaped_label) # compile_href()をベースに改造
567
816
  flag_link = @book.config['externallink']
568
817
  return _inline_hyperlink(url, escaped_label, flag_link)
@@ -571,7 +820,8 @@ module ReVIEW
571
820
  def inline_hlink(str)
572
821
  url, label = str.split(/, /, 2)
573
822
  flag_link = @book.config['externallink']
574
- return _inline_hyperlink(url, escape(label), flag_link)
823
+ label_ = label.present? ? escape(label) : nil
824
+ return _inline_hyperlink(url, label_, flag_link)
575
825
  end
576
826
 
577
827
  def _inline_hyperlink(url, escaped_label, flag_link)
@@ -609,11 +859,49 @@ module ReVIEW
609
859
  "<a>#{escape(s)}</a>"
610
860
  end
611
861
 
862
+ ## 索引に載せる語句 (@<idx>{}, @<term>{})
863
+ public
864
+ def inline_idx(str)
865
+ s1, s2 = _compile_term(str)
866
+ %Q`<span class="index" title="#{s2}">#{s1}</span>`
867
+ end
868
+ def inline_hidx(str)
869
+ _, s2 = _compile_term(str)
870
+ %Q`<span class="index" title="#{s2}"></span>`
871
+ end
872
+ def inline_term(str)
873
+ s1, s2 = _compile_term(str)
874
+ %Q`<span class="index term" title="#{s2}">#{s1}</span>`
875
+ end
876
+ def on_inline_termnoidx(str)
877
+ %Q`<span class="term">#{yield}</span>`
878
+ end
879
+
880
+ def _compile_term(str)
881
+ arr = []
882
+ placeholder = "---"
883
+ display_str, see = parse_term(str, placeholder) do |term, term_e, yomi|
884
+ if yomi
885
+ arr << escape(yomi)
886
+ else
887
+ arr << term_e
888
+ end
889
+ end
890
+ title_attr = arr.join()
891
+ title_attr += " → see: #{escape(see)}" if see
892
+ return display_str, title_attr
893
+ end
894
+ private :_compile_term
895
+
612
896
  end
613
897
 
614
898
 
615
899
  class TEXTBuilder
616
900
 
901
+ def target_name
902
+ "text"
903
+ end
904
+
617
905
  ## nestable inline commands
618
906
 
619
907
  def on_inline_i() ; "<i>#{yield}</i>" ; end