lib/review/tocprinter.rb in review-5.0.0 vs lib/review/tocprinter.rb in review-5.1.0
- old
+ new
@@ -1,6 +1,6 @@
-# Copyright (c) 2008-2020 Minero Aoki, Kenshi Muto
+# Copyright (c) 2008-2021 Minero Aoki, Kenshi Muto
# 1999-2007 Minero Aoki
#
# This program is free software.
# You can distribute or modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.1.
@@ -34,38 +34,49 @@
@blank_seen = true
end
end
class TOCPrinter
- def self.execute(*args)
- Signal.trap(:INT) { exit 1 }
- if RUBY_PLATFORM !~ /mswin(?!ce)|mingw|cygwin|bccwin/
- Signal.trap(:PIPE, 'IGNORE')
+ class Counter
+ def initialize(name: nil, level: nil, headline: nil, lines: nil, chars: nil, list_lines: nil, text_lines: nil, part: nil)
+ @name = name
+ @level = level
+ @headline = headline
+ @lines = lines
+ @chars = chars
+ @list_lines = list_lines
+ @text_lines = text_lines
+ @part = part
end
+
+ attr_accessor :name, :level, :headline, :lines, :chars, :list_lines, :text_lines, :part
+ end
+
+ def self.execute(*args)
new.execute(*args)
- rescue Errno::EPIPE
- exit 0
end
def initialize
@logger = ReVIEW.logger
- @config = ReVIEW::Configure.values
@yamlfile = 'config.yml'
- @book = ReVIEW::Book::Base.new('.', config: @config)
@upper = 4
@indent = true
@buildonly = nil
@detail = nil
+ @calc_char_width = nil
end
+ attr_accessor :calc_char_width
+
def execute(*args)
parse_options(args)
+ @config = ReVIEW::Configure.create(yamlfile: @yamlfile)
+ @book = ReVIEW::Book::Base.new('.', config: @config)
unless File.readable?(@yamlfile)
@logger.error("No such fiile or can't open #{@yamlfile}.")
exit 1
end
- @book.load_config(@yamlfile)
I18n.setup(@config['language'])
if @detail
begin
require 'unicode/eaw'
@@ -82,31 +93,31 @@
def build_result_array
result_array = []
begin
@book.parts.each do |part|
if part.name.present? && (@buildonly.nil? || @buildonly.include?(part.name))
- result_array.push({ part: 'start' })
+ result_array.push(Counter.new(part: 'start'))
if part.file?
- result = build_chap(part)
- result_array += parse_contents(part.name, @upper, result)
+ content = build_chap(part)
+ result_array.concat(parse_contents(part.name, @upper, content))
else
title = part.format_number + I18n.t('chapter_postfix') + part.title
- result_array += [
- { name: '', lines: 1, chars: title.size, list_lines: 0, text_lines: 1 },
- { level: 0, headline: title, lines: 1, chars: title.size, list_lines: 0, text_lines: 1 }
- ]
+ result_array.push(
+ Counter.new(name: '', lines: 1, chars: title.size, list_lines: 0, text_lines: 1),
+ Counter.new(level: 0, headline: title, lines: 1, chars: title.size, list_lines: 0, text_lines: 1)
+ )
end
end
part.chapters.each do |chap|
if @buildonly.nil? || @buildonly.include?(chap.name)
- result = build_chap(chap)
- result_array += parse_contents(chap.name, @upper, result)
+ content = build_chap(chap)
+ result_array.concat(parse_contents(chap.name, @upper, content))
end
end
if part.name.present? && (@buildonly.nil? || @buildonly.include?(part.name))
- result_array.push({ part: 'end' })
+ result_array.push(Counter.new(part: 'end'))
end
end
rescue ReVIEW::FileNotFound, ReVIEW::CompileError => e
@logger.error e
exit 1
@@ -115,62 +126,59 @@
result_array
end
def print_result(result_array)
result_array.each do |result|
- if result[:part]
+ if result.part
next
end
- if result[:name]
+ if result.name
# file information
if @detail
puts '============================='
- printf("%6dC %5dL %5dP %s\n", result[:chars], result[:lines], calc_pages(result).ceil, result[:name])
+ printf("%6dC %5dL %5dP %s\n", result.chars, result.lines, calc_pages(result).ceil, result.name)
puts '-----------------------------'
end
next
end
# section information
if @detail
- printf('%6dC %5dL %5.1fP ', result[:chars], result[:lines], calc_pages(result))
+ printf('%6dC %5dL %5.1fP ', result.chars, result.lines, calc_pages(result))
end
- if @indent && result[:level]
- print ' ' * (result[:level] == 0 ? 0 : result[:level] - 1)
+ if @indent && result.level
+ print ' ' * (result.level == 0 ? 0 : result.level - 1)
end
- puts result[:headline]
+ puts result.headline
end
end
def calc_pages(result)
- p = 0
- p += result[:list_lines].to_f / @book.page_metric.list.n_lines
- p += result[:text_lines].to_f / @book.page_metric.text.n_lines
- p
+ (result.list_lines.to_f / @book.page_metric.list.n_lines) +
+ (result.text_lines.to_f / @book.page_metric.text.n_lines)
end
- def calc_linesize(l)
- return l.size unless @calc_char_width
- w = 0
- l.split('').each do |c|
+ def calc_linesize(line)
+ return line.size unless @calc_char_width
+
+ line.each_char.inject(0) do |result, char|
# XXX: should include A also?
- if %i[Na H N].include?(Unicode::Eaw.property(c))
- w += 0.5 # halfwidth
+ if %i[Na H N].include?(Unicode::Eaw.property(char))
+ result + 0.5 # halfwidth
else
- w += 1
+ result + 1
end
end
- w
end
def parse_contents(name, upper, content)
headline_array = []
- counter = { lines: 0, chars: 0, list_lines: 0, text_lines: 0 }
+ counter = Counter.new(lines: 0, chars: 0, list_lines: 0, text_lines: 0)
listmode = nil
- content.split("\n").each do |l|
+ content.each_line(chomp: true) do |l|
if l.start_with?("\x01STARTLIST\x01")
listmode = true
next
elsif l.start_with?("\x01ENDLIST\x01")
listmode = nil
@@ -178,69 +186,78 @@
elsif l =~ /\A\x01H(\d)\x01/
# headline
level = $1.to_i
l = $'
if level <= upper
- if counter[:chars] > 0
+ if counter.chars > 0
headline_array.push(counter)
end
headline = l
- counter = {
+ counter = Counter.new(
level: level,
headline: headline,
lines: 1,
chars: headline.size,
list_lines: 0,
text_lines: 1
- }
+ )
next
end
end
- counter[:lines] += 1
- counter[:chars] += l.size
+ counter.lines += 1
+ counter.chars += l.size
if listmode
# code list: calculate line wrapping
- if l.size == 0
- counter[:list_lines] += 1
- else
- counter[:list_lines] += (calc_linesize(l) - 1) / @book.page_metric.list.n_columns + 1
- end
+ counter.list_lines += calc_line_wrapping(l, mode: :list)
else
# normal paragraph: calculate line wrapping
- if l.size == 0
- counter[:text_lines] += 1
- else
- counter[:text_lines] += (calc_linesize(l) - 1) / @book.page_metric.text.n_columns + 1
- end
+ counter.text_lines += calc_line_wrapping(l, mode: :text)
end
end
headline_array.push(counter)
- total_lines = 0
- total_chars = 0
- total_list_lines = 0
- total_text_lines = 0
+ total = calc_total_count(name, headline_array)
+ headline_array.unshift(total)
+ end
+ def calc_line_wrapping(line, mode:)
+ return 1 if line.size == 0
+
+ case mode
+ when :list
+ (calc_linesize(line) - 1) / @book.page_metric.list.n_columns + 1
+ else # mode == :text
+ (calc_linesize(line) - 1) / @book.page_metric.text.n_columns + 1
+ end
+ end
+
+ def calc_total_count(name, headline_array)
+ total = Counter.new(name: name,
+ lines: 0,
+ chars: 0,
+ list_lines: 0,
+ text_lines: 0)
+
headline_array.each do |h|
- next unless h[:lines]
- total_lines += h[:lines]
- total_chars += h[:chars]
- total_list_lines += h[:list_lines]
- total_text_lines += h[:text_lines]
+ next unless h.lines
+
+ total.lines += h.lines
+ total.chars += h.chars
+ total.list_lines += h.list_lines
+ total.text_lines += h.text_lines
end
- headline_array.delete_if(&:empty?).
- unshift({ name: name, lines: total_lines, chars: total_chars, list_lines: total_list_lines, text_lines: total_text_lines })
+ total
end
def build_chap(chap)
compiler = ReVIEW::Compiler.new(ReVIEW::PLAINTEXTTocBuilder.new)
begin
compiler.compile(@book.chapter(chap.name))
rescue ReVIEW::ApplicationError => e
- @logger.error e
+ @logger.error e.message
exit 1
end
end
def parse_options(args)