review-retrovert 0.9.7 → 0.9.8

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 (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