testdata/mybook/lib/ruby/review-latexbuilder.rb in review-retrovert-0.9.7 vs testdata/mybook/lib/ruby/review-latexbuilder.rb in review-retrovert-0.9.8
- old
+ new
@@ -12,28 +12,39 @@
defined?(LATEXBuilder) or raise "internal error: LATEXBuilder not found."
class LATEXBuilder
+ public :print, :puts
+
+ def target_name
+ "latex"
+ end
+
## 章や節や項や目のタイトル
def headline(level, label, caption)
with_context(:headline) do
_, anchor = headline_prefix(level)
headname = _headline_name(level) # 'chapter', 'section', 'subsection', ...
headstar = _headline_star(level) # '*' or nil
- blank unless @output.pos == 0
+ blank() unless @output.pos == 0
with_context(:caption) do
print macro("#{headname}#{headstar}", compile_inline(caption))
print "\n" unless level >= 5 # \paragraphと\subpararaphでは改行しない
end
if headstar && _headline_toc?(level) # 番号はつかないけど目次には出す場合
## starter-heading.sty を使っているときは \addcontentsline が必要ない
#puts "\\@ifundefined{Chapter}{\\addcontentsline{toc}{#{headname}}{#{compile_inline(caption)}}}{}"
puts "\\ifx\\Chapter\\undefined{\\addcontentsline{toc}{#{headname}}{#{compile_inline(caption)}}}\\fi"
end
if _headline_chapter?(level)
- puts macro('label', chapter_label)
+ ## \Chapter直後の\addvspaceが効くように、
+ ## \lastskipをいったん保存し、\labelのあとで復元する。
+ puts "\\keeplastskip{"
+ puts " \\label{#{chapter_label()}}"
+ puts " \\par\\nobreak"
+ puts "}"
elsif level >= 5 # 段(Paragraph)と小段(Subparagraph)では
nil # 何もしない、\labelもつけない
else
## \Section最後と\Subsection最初の\addvspaceが効くように、
## \lastskipをいったん保存し、\labelのあとで復元する。
@@ -70,11 +81,11 @@
end
public
def nonum_begin(level, _label, caption)
- blank unless @output.pos == 0
+ blank() unless @output.pos == 0
with_context(:headline) do
with_context(:caption) do
puts macro(HEADLINE[level] + '*', compile_inline(caption))
puts "\\ifx\\Chapter\\undefined"
puts macro('addcontentsline', 'toc', HEADLINE[level], compile_inline(caption))
@@ -82,11 +93,11 @@
end
end
end
def notoc_begin(level, _label, caption)
- blank unless @output.pos == 0
+ blank() unless @output.pos == 0
with_context(:headline) do
with_context(:caption) do
puts "\\ifx\\Chapter\\undefined"
puts macro(HEADLINE[level] + '*', compile_inline(caption))
puts "\\else"
@@ -94,24 +105,57 @@
puts "\\fi"
end
end
end
- ## テーブルヘッダー
- ## (TODO: 第3引数にpos=htbpを指定)
- def table_header(id, caption)
- if caption.present?
+ ## テーブル
+ def table(lines, id=nil, caption=nil, option=nil)
+ super
+ end
+
+ def table_header(id, caption, options)
+ if id.present? || caption.present?
@table_caption = true
+ pos = options[:pos] || 'h'
star = id.present? ? '' : '*'
- s = with_context(:caption) { compile_inline(caption) }
- puts "\\begin{table}[h]%%#{id}"
+ s = with_context(:caption) { compile_inline(caption || '') }
+ puts "\\begin{table}[#{pos}]%%#{id}"
puts "\\centering%"
puts macro("reviewtablecaption#{star}", s)
end
- puts macro('label', table_label(id)) if id.present?
+ begin
+ puts macro('label', table_label(id)) if id.present?
+ rescue KeyError
+ error "no such table: #{id}"
+ end
end
+ alias __original_table_begin table_begin
+
+ def table_begin(ncols, fontsize: nil)
+ if fontsize
+ font = FONTSIZES[fontsize]
+ puts "\\def\\startertablefont{\\#{font}}" if font
+ end
+ __original_table_begin(ncols)
+ end
+
+ ## CSVテーブル
+ def _table_hline()
+ "\\hline"
+ end
+
+ def _table_bottom(hline: false)
+ puts "\\hline" if hline
+ end
+
+ def _table_tr(cells, hline: false)
+ s = "#{cells.join(' & ')} \\\\"
+ s << " \\hline" if hline
+ return s
+ end
+
## 改行命令「\\」のあとに改行文字「\n」を置かない。
##
## 「\n」が置かれると、たとえば
##
## foo@<br>{}
@@ -129,149 +173,242 @@
#"\\\\\n" # original
#"\\\\{}" # これだと後続行の先頭に1/4空白が入ってしまう
"\\\\[0pt]" # これなら後続行の先頭に1/4空白が入らない
end
+ protected
- ## コードブロック(//program, //terminal)
- def program(lines, id=nil, caption=nil, optionstr=nil)
- _codeblock('program', lines, id, caption, optionstr)
- end
+ ## コードブロック(//program, //terminal, //output)
- def terminal(lines, id=nil, caption=nil, optionstr=nil)
- _codeblock('terminal', lines, id, caption, optionstr)
- end
-
- protected
-
FONTSIZES = {
"small" => "small",
"x-small" => "footnotesize",
"xx-small" => "scriptsize",
"large" => "large",
"x-large" => "Large",
"xx-large" => "LARGE",
+ "medium" => "normalsize",
}
- ## コードブロック(//program, //terminal)
- def _codeblock(blockname, lines, id, caption, optionstr)
- ## ブロックコマンドのオプション引数はCompilerクラスでパースすべき。
- ## しかしCompilerクラスがそのような設計になってないので、
- ## 仕方ないのでBuilderクラスでパースする。
- opts = _parse_codeblock_optionstr(optionstr, blockname)
- CODEBLOCK_OPTIONS.each {|k, v| opts[k] = v unless opts.key?(k) }
- #
+ def _codeblock_eolmark()
+ "{\\startereolmark}"
+ end
+
+ def _codeblock_indentmark()
+ "{\\starterindentchar}"
+ end
+
+ LATEX_ESCAPE_TABLE = {
+ '{' => '\{',
+ '}' => '\}',
+ '%' => '\%',
+ '$' => '\$',
+ '#' => '\#',
+ '&' => '\&',
+ '_' => '\_',
+ '\\' => '{\textbackslash}',
+ '^' => '{\textasciicircum}',
+ '~' => '{\textasciitilde}',
+ }
+
+ def _render_codeblock(blockname, lines, id, caption_str, opts)
if opts['eolmark']
- lines = lines.map {|line| "#{detab(line)}\\startereolmark{}" }
+ eolmark = _codeblock_eolmark() # ex: '{\startereolmark}'
else
- lines = lines.map {|line| detab(line) }
+ eolmark = nil
end
#
- if opts['indentwidth'] && opts['indentwidth'] > 0
- indent_w = opts['indentwidth']
- indent_str = " " * (indent_w - 1) + "{\\starterindentchar}"
- lines = lines.map {|line|
- line.sub(/\A( +)/) {
- m, n = ($1.length - 1).divmod indent_w
- " " << indent_str * m << " " * n
- }
+ eol = eolmark ? "#{eolmark}\\par\n" : "\\par\n"
+ lines = lines.map {|line|
+ line = _parse_inline(line) {|text|
+ _convert_and_escape_str(text)
}
- end
+ if line =~ /\A\n/
+ "\\mbox{}#{eol}\n"
+ else
+ line.gsub(/(?:\\-)?\n/, eol)
+ end
+ }
#
- if id.present? || caption.present?
- caption_str = _build_caption_str(id, caption)
- else
- caption_str = nil
+ indent_width = opts['indent']
+ if indent_width && indent_width > 0
+ lines = _add_indent_mark(lines, indent_width)
end
#
+ default_opts = _codeblock_default_options(blockname)
+ opts2 = {}
+ opts.each do |k, v|
+ opts2[k] = v unless v == default_opts[k]
+ end
fontsize = FONTSIZES[opts['fontsize']]
- print "\\def\\startercodeblockfontsize{#{fontsize}}\n"
#
environ = "starter#{blockname}"
+ puts "\\begingroup"
+ puts " \\makeatletter" if fontsize
+ puts " \\def\\starter@#{blockname}@fontsize{#{fontsize}}" if fontsize
+ puts " \\makeatother" if fontsize
+ puts " \\makeatletter" unless opts2.empty?
+ opts2.each do |k, v|
+ x = k.gsub(/[^a-zA-Z]/, '_')
+ v = v == true ? 'Y' : v == false ? '' : v #escape(v.to_s)
+ puts " \\edef\\starter@#{blockname}@#{x}{#{v}}"
+ #puts " \\edef\\starter@codeblock@#{x}{#{v}}"
+ end
+ puts " \\makeatother" unless opts2.empty?
print "\\begin{#{environ}}[#{id}]{#{caption_str}}"
print "\\startersetfoldmark{}" unless opts['foldmark']
- if opts['eolmark']
- print "\\startereolmarkdark{}" if blockname == 'terminal'
- print "\\startereolmarklight{}" if blockname != 'terminal'
- end
if opts['lineno']
gen = LineNumberGenerator.new(opts['lineno'])
- width = opts['linenowidth']
+ width = opts['linenowidth'] || -1
if width && width >= 0
if width == 0
last_lineno = gen.each.take(lines.length).compact.last
width = last_lineno.to_s.length
end
print "\\startersetfoldindentwidth{#{'9'*(width+2)}}"
- format = "\\textcolor{gray}{%#{width}s:} "
+ format = "\\starterinnerlineno{%#{width}s:} "
else
- format = "\\starterlineno{%s}"
+ format = "\\starterouterlineno{%s}"
end
buf = []
- opt_fold = opts['fold']
lines.zip(gen).each do |x, n|
- buf << ( opt_fold \
- ? "#{format % n.to_s}\\seqsplit{#{x}}" \
- : "#{format % n.to_s}#{x}" )
+ buf << "#{(format % n.to_s).gsub(' ', '~')}#{x}"
end
- print buf.join("\n")
+ print buf.join()
else
- print "\\seqsplit{" if opts['fold']
- print lines.join("\n")
- print "}" if opts['fold']
+ print lines.join()
end
puts "\\end{#{environ}}"
+ puts "\\endgroup"
nil
end
+ def _convert_and_escape_str(str)
+ #str.gsub(/[\{\}\\\%\^\_\$\&\~]/, LATEX_ESCAPE_TABLE)
+ rexp = /[\{\}\\\#\%\^\_\$\&\~]/
+ cs = []
+ zenkaku_rexp = ZENKAKU_CHAR_REXP
+ str.each_char do |c|
+ cs << (
+ case c
+ when / / ; '~'
+ when /\n/ ; "\n"
+ when rexp ; LATEX_ESCAPE_TABLE[c]
+ when zenkaku_rexp ; "\\ZC{#{c}}" # 全角文字
+ else ; c # 半角文字
+ end
+ )
+ end
+ cs << "" unless cs[-1] == "\n"
+ return cs.join('\\-')
+ end
+
+ ZENKAKU_CHAR_REXP = /\A[^\000-\177]\z/
+
+ def _add_indent_mark(lines, indent_width)
+ space = "~\\-"
+ rexp = /\A((?:~\\-)+)/
+ #
+ width = indent_width
+ mark = _codeblock_indentmark() # ex: '{\starterindentmark}'
+ indent = space * (width - 1) + mark
+ nchar = space.length
+ return lines.map {|line|
+ line.sub(rexp) {
+ m, n = ($1.length / nchar - 1).divmod width
+ "#{space}#{indent * m}#{space * n}"
+ }
+ }
+ end
+
public
## ・\caption{} のかわりに \reviewimagecaption{} を使うよう修正
## ・「scale=X」に加えて「pos=X」も受け付けるように拡張
- def image_image(id, caption, option_str)
- pos = nil; border = nil; arr = []
- _each_block_option(option_str) do |k, v|
- case k
- when 'pos'
- v =~ /\A[Hhtb]+\z/ or # H: Here, h: here, t: top, b: bottom
- raise "//image[][][pos=#{v}]: expected 'pos=H' or 'pos=h'."
- pos = v # detect 'pos=H' or 'pos=h'
- when 'border', 'draft'
- case v
- when nil ; flag = true
- when 'on' ; flag = true
- when 'off'; flag = false
- else
- raise "//image[][][#{k}=#{v}]: expected '#{k}=on' or '#{k}=off'"
- end
- border = flag if k == 'border'
- arr << "draft=#{flag}" if k == 'draft'
+ def _render_image(id, image_filepath, caption, opts)
+ width = "\\maxwidth"
+ if opts[:scale]
+ case (scale = opts[:scale])
+ when /\A\d+\z/, /\A\d\.\d*\z/, /\A\.\d+\z/
+ when /\A\d+(\.\d+)?%\z/
+ scale = scale.sub(/%\z/, '').to_f / 100.0
else
- arr << (v.nil? ? k : "#{k}=#{v}")
+ error "scale=#{scale}: invalid scale value."
end
+ width = "#{scale}\\maxwidth" # not '\textwidth'
end
#
- metrics = parse_metric('latex', arr.join(","))
- puts "\\begin{reviewimage}[#{pos}]%%#{id}" if pos
- puts "\\begin{reviewimage}%%#{id}" unless pos
- metrics = "width=\\maxwidth" unless metrics.present?
- puts "\\starterimageframe{%" if border
- puts "\\includegraphics[#{metrics}]{#{@chapter.image(id).path}}%"
- puts "}%" if border
+ if opts[:width]
+ case opts[:width]
+ when /\A\d+\z/, /\A\d\.\d*\z/, /\A\.\d+\z/
+ width = "#{opts[:width]}\\textwidth" # not '\maxwidth'
+ when /\A(\d+(\.\d+)?)%\z/
+ width = "#{$1.to_f/100.0}\\textwidth" # not '\maxwidth'
+ when /\A(\d+(?:\.\d*)?)(mm|cm)\z/
+ width = "#{$1}true#{$2}" # 'mm'->'truemm', 'cm'->'truecm'
+ else
+ width = opts[:width]
+ end
+ end
+ #
+ metrics = ["width=#{width}"]
+ metrics << "draft=#{opts[:draft]}" if opts[:draft] != nil
+ #
+ pos = opts[:pos] || config_starter()['image_position']
+ puts "\\begin{reviewimage}[#{pos}]%%#{id}"
+ puts "\\starterimageframe{%" if opts[:border]
+ puts "\\includegraphics[#{metrics.join(',')}]{#{image_filepath}}%"
+ puts "}%" if opts[:border]
with_context(:caption) do
#puts macro('caption', compile_inline(caption)) if caption.present? # original
- puts macro('reviewimagecaption', compile_inline(caption)) if caption.present?
+ puts "\\reviewimagecaption{#{compile_inline(caption)}}" if caption.present?
end
- puts macro('label', image_label(id))
+ puts "\\label{#{image_label(id)}}"
puts "\\end{reviewimage}"
end
+ ## //imgtable
+ def imgtable(lines, id, caption=nil, option=nil)
+ super
+ end
+
+ def _render_imgtable(id, caption, opts)
+ pos = opts['pos'] || 'h'
+ puts "\\begin{table}[#{pos}]%%#{id}"
+ puts "\\centering"
+ yield
+ puts "\\end{table}"
+ blank()
+ end
+
+ def _render_imgtable_caption(caption)
+ puts macro('reviewimgtablecaption', compile_inline(caption))
+ end
+
+ def _render_imgtable_label(id)
+ puts macro('label', table_label(id))
+ rescue ReVIEW::KeyError
+ error "no such table: #{id}"
+ end
+
+ def imgtable_image(id, _caption, metric)
+ metrics = parse_metric('latex', metric)
+ # image is always bound here
+ #puts "\\begin{reviewimage}%%#{id}" #-
+ metrics = "width=\\maxwidth" unless metrics.present?
+ imagefile = @chapter.image(id).path
+ puts "\\includegraphics[#{metrics}]{#{imagefile}}"
+ #puts '\end{reviewimage}' #-
+ end
+
+ ##
+
def _build_secref(chap, num, title, parent_title)
s = ""
## 親セクションのタイトルがあれば使う
- if parent_title && @book.config['starter']['secref_parenttitle']
+ if parent_title && self.config_starter['secref_parenttitle']
s << "「%s」内の" % parent_title # TODO: I18n化
end
## 対象セクションへのリンクを作成する
if @book.config['chapterlink']
label = "sec:" + num.gsub('.', '-')
@@ -292,32 +429,32 @@
###
public
def ul_begin
- blank
+ blank()
puts '\begin{starteritemize}' # instead of 'itemize'
end
def ul_end
puts '\end{starteritemize}' # instead of 'itemize'
- blank
+ blank()
end
def ol_begin(start_num=nil)
- blank
+ blank()
puts '\begin{starterenumerate}' # instead of 'enumerate'
if start_num.nil?
return true unless @ol_num
puts "\\setcounter{enumi}{#{@ol_num - 1}}"
@ol_num = nil
end
end
def ol_end
puts '\end{starterenumerate}' # instead of 'enumerate'
- blank
+ blank()
end
def ol_item_begin(lines, num)
str = lines.join
num = escape(num).sub(']', '\rbrack{}')
@@ -325,14 +462,24 @@
end
def ol_item_end()
end
+ def dt(str)
+ puts "\\starterdt{#{str}}%"
+ end
+
+ def dl_dd_begin()
+ end
+
+ def dl_dd_end()
+ end
+
## コラム
def column_begin(level, label, caption)
- blank
+ blank()
@doc_status[:column] = true
puts "\\begin{reviewcolumn}\n"
puts "\\phantomsection % for hyperref" #+
if label
puts "\\hypertarget{#{column_label(label)}}{}"
@@ -365,16 +512,89 @@
## 章 (Chapter) の概要
## (導入文 //lead{ ... //} と似ているが、導入文では詩や物語を
## 引用するのが普通らしく、概要 (abstract) とは違うみたいなので、
## 概要を表すブロックを用意した。)
- def abstract(lines)
+ def on_abstract_block()
puts '\begin{starterabstract}'
- puts lines
+ yield
puts '\end{starterabstract}'
end
+ ## 章 (Chapter) の著者
+ def on_chapterauthor_block(name)
+ puts "\\starterchapterauthor{#{escape(name)}}"
+ end
+
+ ## 会話リスト
+ def _render_talklist(opts, &b)
+ puts '\begingroup'
+ puts ' \makeatletter' unless opts.empty?
+ opts.each do |k, v|
+ puts " \\def\\starter@talklist@#{k}{#{v}}"
+ end
+ puts ' \makeatother' unless opts.empty?
+ puts '\begin{startertalklist}'
+ yield
+ puts '\end{startertalklist}'
+ puts '\endgroup'
+ end
+
+ ## 会話項目
+ def _render_talk(image_filepath=nil, name=nil, &b)
+ s = name ? compile_inline(name) : nil
+ print "\\startertalk{#{image_filepath}}{#{s}}{%"
+ yield
+ @blank_needed = false
+ puts "}"
+ end
+
+ ## キーと説明文のリスト
+ def _render_desclist(opts, &b)
+ bkup = @_desclist_opts
+ @_desclist_opts = opts
+ star = opts[:compact] ? '*' : ''
+ puts "\\begingroup"
+ puts " \\makeatletter" unless opts.empty?
+ opts.each do |k, v|
+ k_ = k.to_s.gsub('_', '@')
+ v_ = v == true ? 'Y' : v == false ? '' : escape(v.to_s)
+ puts " \\def\\starter@desclist@#{k_}{#{v_}}"
+ end
+ puts " \\makeatother" unless opts.empty?
+ puts "\\begin{starterdesclist}"
+ yield
+ puts "\\end{starterdesclist}"
+ puts "\\endgroup"
+ @_desclist_opts = bkup
+ end
+
+ ## キーと説明文
+ def on_desc_block(key, text=nil, &b)
+ text = "\n" + text if text
+ super(key, text, &b)
+ end
+ def _render_desc(key, &b)
+ opts = @_desclist_opts
+ s = compile_inline(key)
+ #print "\\begin{starterdesc}{#{s}}"
+ #print "\\begin{starterdesc}{#{s}}%"
+ print "\\begin{starterdesc}{#{s}}\\ignorespaces "
+ yield
+ @blank_needed = false
+ puts "\\end{starterdesc}"
+ end
+
+ ## 縦方向の空きを入れる
+ def _render_vspace(size)
+ puts "\\vspace{#{size}}"
+ end
+
+ def _render_addvspace(size)
+ puts "\\addvspace{#{size}}"
+ end
+
## 章タイトルを独立したページに
def makechaptitlepage(option=nil)
case option
when nil, "" ;
when 'toc=section', 'toc=subsection' ;
@@ -385,14 +605,12 @@
end
puts "\\makechaptitlepage{#{option}}"
end
## 縦方向のスペースがなければ改ページ
- def needvspace(builder_name, height)
- if builder_name == 'latex'
- puts "\\needvspace{#{height}}"
- end
+ def _render_needvspace(height)
+ puts "\\needvspace{#{height}}"
end
## 段(Paragraph)の終わりにスペースを入れる
def paragraphend()
puts "\\ParagraphEnd"
@@ -426,15 +644,17 @@
end
## ノート(//note[caption]{ ... //})
## (入れ子対応なので、中に箇条書きや別のブロックを入れられる)
def on_note_block(label=nil, caption=nil)
- caption, label = label, nil if caption.nil?
- s = compile_inline(caption || "")
- puts "\\begin{starternote}[#{label}]{#{s}}"
- yield
- puts "\\end{starternote}"
+ with_context(:minicolumn) do
+ caption, label = label, nil if caption.nil?
+ s = compile_inline(caption || "")
+ puts "\\begin{starternote}[#{label}]{#{s}}"
+ yield
+ puts "\\end{starternote}"
+ end
end
def note(lines, label=nil, caption=nil)
on_note_block(label, caption) do
puts lines
end
@@ -474,36 +694,24 @@
end
def _codeblock_optstr(lang, lineno_flag)
arr = []
arr << lang if lang
if lineno_flag
- first_line_num = line_num
+ first_line_num = line_num()
arr << "lineno=#{first_line_num}"
arr << "linenowidth=0"
end
return arr.join(",")
end
private :_codeblock_optstr
-
- ## 入れ子可能なブロック命令
-
- def on_minicolumn(type, caption, &b)
- s = with_context(:caption) { compile_inline(caption) }
- puts "\\begin{starter#{type}}{#{s}}"
- yield
- puts "\\end{starter#{type}}\n"
- end
- protected :on_minicolumn
-
- def on_sideimage_block(imagefile, imagewidth, option_str=nil, &b)
- imagefile, imagewidth, opts = validate_sideimage_args(imagefile, imagewidth, option_str)
- filepath = find_image_filepath(imagefile)
- side = opts['side'] || 'L'
+ ## 画像横に文章
+ def _render_sideimage(filepath, imagewidth, opts, &b)
+ side = opts['side'] || 'L'
normalize = proc {|s|
- s =~ /\A(\d+(?:\.\d+)?)(%|mm|cm)\z/
- if $2.nil? ; s
+ rexp = /\A(\d+(?:\.\d+)?)(%|mm|cm)\z/
+ if s !~ rexp ; s
elsif $2 == '%' ; "#{$1.to_f/100.0}\\textwidth"
else ; "#{$1}true#{$2}"
end
}
imgwidth = normalize.call(imagewidth)
@@ -515,10 +723,24 @@
yield
puts " \\end{startersideimage}\n"
puts "}\n"
end
+ ## 入れ子可能なブロック命令
+
+ def on_minicolumn(type, caption=nil, &b)
+ with_context(:minicolumn) do
+ s = caption ? with_context(:caption) { compile_inline(caption) } : nil
+ puts "\\begin{starter#{type}}{#{s}}"
+ yield
+ puts "\\end{starter#{type}}\n"
+ end
+ end
+ protected :on_minicolumn
+
+ ## 数式
+
def texequation(lines, label=nil, caption=nil)
blank()
#
if label.present?
puts macro("begin", "reviewequationblock")
@@ -559,10 +781,15 @@
blank()
end
#### インライン命令
+ ## 改段落(箇条書き内では空行を入れられないため)
+ def inline_par(arg)
+ "\\starterpar{#{arg}}"
+ end
+
## ファイル名
def inline_file(str)
on_inline_file { escape(str) }
end
def on_inline_file
@@ -572,15 +799,15 @@
## ユーザ入力
def inline_userinput(str)
on_inline_userinput { escape(str) }
end
def on_inline_userinput
- if within_codeblock?()
- "{\\starteruserinput{\\seqsplit{#{yield}}}}"
- else
+ #if within_codeblock?()
+ # "{\\starteruserinput{\\seqsplit{#{yield}}}}"
+ #else
"\\starteruserinput{#{yield}}"
- end
+ #end
end
## 引数をそのまま表示
## 例:
## //emlist{
@@ -595,15 +822,15 @@
## 目立たせない(@<strong>{} の反対)
def inline_weak(str)
on_inline_weak { escape(str) }
end
def on_inline_weak
- if within_codeblock?()
- "{\\starterweak{\\seqsplit{#{yield}}}}"
- else
+ #if within_codeblock?()
+ # "{\\starterweak{\\seqsplit{#{yield}}}}"
+ #else
"\\starterweak{#{yield}}"
- end
+ #end
end
## 文字を小さくする
def inline_small(str) ; on_inline_small { escape(str) } ; end
def inline_xsmall(str) ; on_inline_xsmall { escape(str) } ; end
@@ -670,23 +897,21 @@
def on_inline_u() ; "{\\reviewunderline{#{yield}}}"; end
def on_inline_ami() ; "{\\reviewami{#{yield}}}" ; end
def on_inline_balloon(); "{\\reviewballoon{#{yield}}}" ; end
def on_inline_tt()
- ## LaTeXでは、'\texttt{}' 中の '!?:.' の直後の空白が2文字分で表示される。
- ## その問題を回避するために、' ' を '\ ' にする。
- s = yield
- s = s.gsub(/([!?:.]) /, '\\1\\ ')
- return "{\\reviewtt{#{s}}}"
+ return "{\\reviewtt{#{yield}}}"
end
def on_inline_code()
with_context(:inline_code) {
- ## LaTeXでは、'\texttt{}' 中の '!?:.' の直後の空白が2文字分で表示される。
- ## その問題を回避するために、' ' を '\ ' にする。
+ ## 連続した空白が1つの空白として扱われるのを防ぐ
s = yield
- s = s.gsub(/([!?:.]) /, '\\1\\ ')
+ s = s.gsub(/ /, '{\\starterspacechar}')
+ ## 連続した「`」や「'」はエスケープする必要がある
+ s = s.gsub(/\'\'/, "{'}{'}")
+ s = s.gsub(/\`\`/, '{`}{`}')
## コンテキストによって、背景色をつけないことがある
if false
elsif within_context?(:headline) # 章タイトルや節タイトルでは
"{\\reviewcode[headline]{#{s}}}" # 背景色をつけない(かも)
elsif within_context?(:caption) # リストや画像のキャプションでも
@@ -717,39 +942,47 @@
end
def on_inline_del()
if within_codeblock?()
#"\\reviewstrike{#{yield}}" # \seqsplit{} 内でエラーになる
#"{\\reviewstrike{#{yield}}}" # \seqsplit{} 内でもエラーにならないが折り返しされない
- "{\\reviewstrike{\\seqsplit{#{yield}}}}" # エラーにならないし、折り返しもされる
+ #"{\\reviewstrike{\\seqsplit{#{yield}}}}" # エラーにならないし、折り返しもされる
+ "{\\reviewstrike{#{yield}}}"
else
macro('reviewstrike', yield)
end
end
def build_inline_href(url, escaped_label) # compile_href()をベースに改造
- flag_footnote = @book.config['starter']['linkurl_footnote']
+ flag_footnote = self.config_starter['linkurl_footnote']
return _inline_hyperlink(url, escaped_label, flag_footnote)
end
## @<href>{} の代わり
def inline_hlink(str)
url, label = str.split(/, /, 2)
- flag_footnote = @book.config['starter']['hyperlink_footnote']
- return _inline_hyperlink(url, escape(label), flag_footnote)
+ flag_footnote = self.config_starter['hyperlink_footnote']
+ label_ = label.present? ? escape(label) : nil
+ return _inline_hyperlink(url, label_, flag_footnote)
end
def _inline_hyperlink(url, escaped_label, flag_footnote)
if /\A[a-z]+:/ !~ url
"\\ref{#{url}}"
elsif ! escaped_label.present?
- "\\url{#{escape_url(url)}}"
+ #"\\url{#{escape_url(url)}}"
+ "\\starterurl{#{escape_url(url)}}{#{escape(url)}}"
elsif ! flag_footnote
"\\href{#{escape_url(url)}}{#{escaped_label}}"
elsif within_context?(:footnote)
- "#{escaped_label}(\\url{#{escape_url(url)}})"
+ #"#{escaped_label}(\\url{#{escape_url(url)}})"
+ "#{escaped_label}(\\starterurl{#{escape_url(url)}}{#{escape(url)}})"
else
- "#{escaped_label}\\footnote{\\url{#{escape_url(url)}}}"
+ #"#{escaped_label}\\footnote{\\url{#{escape_url(url)}}}"
+ #"#{escaped_label}\\footnote{\\starterurl{#{escape_url(url)}}{#{escape(url)}}}"
+ url1 = escape_url(url)
+ url2 = escape(url)
+ "\\href{#{url1}}{#{escaped_label}}\\footnote{\\starterurl{#{url1}}{#{url2}}}"
end
end
private :_inline_hyperlink
def build_inline_ruby(escaped_word, escaped_yomi) # compile_ruby()をベースに改造
@@ -773,9 +1006,59 @@
## 数式を参照する
def build_eq(chapter, label, number)
#"\\reviewequationref{#{chapter.number}.#{number}}"
escape("#{I18n.t('equation')}#{chapter.number}.#{number}")
end
+
+ public
+
+ ## 数式を $...$ から \(...\) に変更する。
+ ## これで //list の中でも @<m>$...$ が使えるようになる。
+ ## ただし '^' や '_' がエスケープされるので、実用性はイマイチ。
+ def inline_m(str)
+ #" $#{str}$ " # original
+ "\\(#{str}\\)"
+ end
+
+ ## 「``」と「''」で囲む
+ def on_inline_qq()
+ "``#{yield}''"
+ end
+
+ ## 索引に載せる語句 (@<idx>{}, @<term>{})
+ def inline_idx(str)
+ s1, s2 = _compile_term(str)
+ "#{s1}\\index{#{s2}}"
+ end
+ def inline_hidx(str)
+ _, s2 = _compile_term(str)
+ "\\index{#{s2}}"
+ end
+ def inline_term(str)
+ s1, s2 = _compile_term(str)
+ "\\starterterm{#{s1}}\\index{#{s2}}"
+ end
+ def on_inline_termnoidx()
+ "\\starterterm{#{yield}}"
+ end
+
+ def _compile_term(str)
+ arr = []
+ placeholder = "\\starterindexplaceholder{}"
+ display_str, see = parse_term(str, placeholder) do |term, term_e, yomi|
+ if yomi
+ arr << "#{escape_index(escape_latex(yomi))}@#{term_e}"
+ elsif escape_index(term) != term_e
+ arr << "#{escape_index(term)}@#{term_e}"
+ else
+ arr << term_e
+ end
+ end
+ argstr = arr.join('!')
+ argstr += "|see{#{escape_latex(see)}}" if see
+ return display_str, argstr
+ end
+ private :_compile_term
end
end