narou 1.5.11 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of narou might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/ChangeLog.md +619 -432
- data/Gemfile +9 -0
- data/README.md +101 -76
- data/lib/color.rb +62 -22
- data/lib/command.rb +21 -19
- data/lib/command/alias.rb +9 -9
- data/lib/command/backup.rb +11 -4
- data/lib/command/browser.rb +8 -7
- data/lib/command/convert.rb +25 -77
- data/lib/command/diff.rb +67 -36
- data/lib/command/download.rb +5 -4
- data/lib/command/flag.rb +32 -6
- data/lib/command/folder.rb +7 -5
- data/lib/command/freeze.rb +21 -11
- data/lib/command/help.rb +29 -17
- data/lib/command/init.rb +7 -7
- data/lib/command/inspect.rb +6 -5
- data/lib/command/list.rb +106 -25
- data/lib/command/mail.rb +6 -7
- data/lib/command/remove.rb +9 -7
- data/lib/command/send.rb +6 -5
- data/lib/command/setting.rb +51 -16
- data/lib/command/tag.rb +179 -0
- data/lib/command/update.rb +9 -8
- data/lib/command/version.rb +4 -4
- data/lib/commandbase.rb +79 -8
- data/lib/commandline.rb +14 -8
- data/lib/converterbase.rb +78 -28
- data/lib/database.rb +3 -3
- data/lib/device.rb +26 -13
- data/lib/device/ibooks.rb +116 -0
- data/lib/device/ibunko.rb +45 -0
- data/lib/device/kindle.rb +4 -0
- data/lib/device/kobo.rb +4 -0
- data/lib/device/library/windows.rb +12 -4
- data/lib/device/reader.rb +9 -0
- data/lib/diffviewer.rb +147 -0
- data/lib/downloader.rb +195 -80
- data/lib/extensions/jruby.rb +33 -0
- data/lib/extensions/windows.rb +8 -9
- data/lib/helper.rb +79 -37
- data/lib/illustration.rb +1 -1
- data/lib/inspector.rb +2 -2
- data/lib/inventory.rb +48 -0
- data/lib/logger.rb +28 -4
- data/lib/narou.rb +9 -7
- data/lib/narou/api.rb +7 -2
- data/lib/novelconverter.rb +46 -19
- data/lib/novelinfo.rb +13 -3
- data/lib/novelsetting.rb +17 -9
- data/lib/version.rb +1 -1
- data/narou.gemspec +106 -27
- data/narou.rb +2 -2
- data/spec/convert_spec.rb +102 -0
- data/spec/data/convert_test/auto_indent/correct_test_auto_indent.txt +18 -0
- data/spec/data/convert_test/auto_indent/test_auto_indent.txt +21 -0
- data/spec/data/convert_test/auto_join_bracket/correct_test_auto_join_bracket.txt +12 -0
- data/spec/data/convert_test/auto_join_bracket/test_auto_join_bracket.txt +16 -0
- data/spec/data/convert_test/auto_join_line/correct_test_auto_join_line.txt +36 -0
- data/spec/data/convert_test/auto_join_line/test_auto_join_line.txt +51 -0
- data/spec/data/convert_test/convert_page_break/correct_test_convert_page_break.txt +21 -0
- data/spec/data/convert_test/convert_page_break/setting.ini +5 -0
- data/spec/data/convert_test/convert_page_break/test_convert_page_break.txt +60 -0
- data/spec/data/convert_test/force_indent_special_chapter/correct_test_force_indent_special_chapter.txt +64 -0
- data/spec/data/convert_test/force_indent_special_chapter/test_force_indent_special_chapter.txt +61 -0
- data/spec/data/convert_test/horizontal_ellipsis/correct_test_horizontal_ellipsis.txt +52 -0
- data/spec/data/convert_test/horizontal_ellipsis/test_horizontal_ellipsis.txt +57 -0
- data/spec/data/convert_test/kanji_num/correct_test_kanji_num.txt +49 -0
- data/spec/data/convert_test/kanji_num/test_kanji_num.txt +56 -0
- data/spec/data/convert_test/nonokagi/correct_test_nonokagi.txt +29 -0
- data/spec/data/convert_test/nonokagi/test_nonokagi.txt +34 -0
- data/spec/data/convert_test/replace/correct_test_replace.txt +12 -0
- data/spec/data/convert_test/replace/replace.txt +7 -0
- data/spec/data/convert_test/replace/test_replace.txt +14 -0
- data/spec/data/convert_test/ruby/correct_test_ruby.txt +131 -0
- data/spec/data/convert_test/ruby/test_ruby.txt +170 -0
- data/spec/data/convert_test/ruby_youon/correct_test_ruby_youon.txt +12 -0
- data/spec/data/convert_test/ruby_youon/setting.ini +2 -0
- data/spec/data/convert_test/ruby_youon/test_ruby_youon.txt +14 -0
- data/spec/data/convert_test/sesame/correct_test_sesame.txt +40 -0
- data/spec/data/convert_test/sesame/test_sesame.txt +52 -0
- data/spec/data/convert_test/to_odd_leader/correct_test_to_odd_leader.txt +20 -0
- data/spec/data/convert_test/to_odd_leader/test_to_odd_leader.txt +21 -0
- data/spec/device_spec.rb +3 -3
- data/spec/generator/convert_spec_gen.rb +95 -0
- data/spec/html_spec.rb +9 -8
- data/spec/ini_spec.rb +31 -31
- data/spec/novelinfo_spec.rb +2 -2
- data/spec/num_to_kanji_spec.rb +2 -2
- data/template/diff.txt.erb +5 -2
- data/template/ibunko_novel.txt.erb +2 -1
- data/template/novel.txt.erb +16 -3
- data/template/setting.ini.erb +1 -1
- data/webnovel/ncode.syosetu.com.yaml +7 -7
- data/webnovel/novel18.syosetu.com.yaml +7 -7
- data/webnovel/syosetu.org.yaml +8 -11
- metadata +193 -23
- data/lib/globalsetting.rb +0 -64
- data/lib/localsetting.rb +0 -63
data/lib/command/update.rb
CHANGED
@@ -8,8 +8,12 @@ require_relative "../downloader"
|
|
8
8
|
|
9
9
|
module Command
|
10
10
|
class Update < CommandBase
|
11
|
+
def self.oneline_help
|
12
|
+
"小説を更新します"
|
13
|
+
end
|
14
|
+
|
11
15
|
def initialize
|
12
|
-
super("[<target>
|
16
|
+
super("[<target> ...] [options]")
|
13
17
|
@opt.separator <<-EOS
|
14
18
|
|
15
19
|
・管理対象の小説を更新します。
|
@@ -19,8 +23,9 @@ module Command
|
|
19
23
|
・一度に複数の小説を指定する場合は空白で区切って下さい。
|
20
24
|
・全て更新する場合、convert.no-openが設定されていなくても保存フォルダは開きません。
|
21
25
|
|
22
|
-
|
26
|
+
Examples:
|
23
27
|
narou update # 全て更新
|
28
|
+
narou u # 短縮コマンド
|
24
29
|
narou update 0 1 2 4
|
25
30
|
narou update n9669bk 異世界迷宮で奴隷ハーレムを
|
26
31
|
narou update http://ncode.syosetu.com/n9669bk/
|
@@ -45,11 +50,12 @@ module Command
|
|
45
50
|
end
|
46
51
|
no_open = true
|
47
52
|
end
|
53
|
+
tagname_to_ids(update_target_list)
|
48
54
|
update_target_list.each_with_index do |target, i|
|
49
55
|
display_message = nil
|
50
56
|
data = Downloader.get_data_by_target(target)
|
51
57
|
if !data
|
52
|
-
display_message = "<red>[ERROR]</red> #{target} は管理小説の中に存在しません".termcolor
|
58
|
+
display_message = "<bold><red>[ERROR]</red></bold> #{target} は管理小説の中に存在しません".termcolor
|
53
59
|
elsif Narou.novel_frozen?(target)
|
54
60
|
if argv.length > 0
|
55
61
|
display_message = "ID:#{data["id"]} #{data["title"]} は凍結中です"
|
@@ -73,7 +79,6 @@ module Command
|
|
73
79
|
end
|
74
80
|
when :failed
|
75
81
|
puts "ID:#{data["id"]} #{data["title"]} の更新は失敗しました"
|
76
|
-
Freeze.execute!([target])
|
77
82
|
when :canceled
|
78
83
|
puts "ID:#{data["id"]} #{data["title"]} の更新はキャンセルされました"
|
79
84
|
when :none
|
@@ -84,9 +89,5 @@ module Command
|
|
84
89
|
puts "アップデートを中断しました"
|
85
90
|
exit 1
|
86
91
|
end
|
87
|
-
|
88
|
-
def oneline_help
|
89
|
-
"小説を更新します"
|
90
|
-
end
|
91
92
|
end
|
92
93
|
end
|
data/lib/command/version.rb
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
module Command
|
7
7
|
class Version < CommandBase
|
8
|
-
def
|
9
|
-
|
8
|
+
def self.oneline_help
|
9
|
+
"バージョンを表示します"
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
"
|
12
|
+
def execute(argv)
|
13
|
+
puts ::Version + " build " + ::CommitVersion
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/commandbase.rb
CHANGED
@@ -7,27 +7,49 @@ require "optparse"
|
|
7
7
|
|
8
8
|
module Command
|
9
9
|
class CommandBase
|
10
|
-
|
10
|
+
# postfixies は改行で区切ることで2パターン以上記述できる
|
11
|
+
def initialize(postfixies = "")
|
11
12
|
@opt = OptionParser.new(nil, 20)
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
command_name = self.class.to_s.scan(/::(.+)$/)[0][0].downcase
|
14
|
+
banner = postfixies.split("\n").map.with_index { |postfix, i|
|
15
|
+
(i == 0 ? "Usage: " : " or: ") + "narou #{command_name} #{postfix}"
|
16
|
+
}.join("\n")
|
17
|
+
@opt.banner = "<bold><green>#{TermColor.escape(banner)}</green></bold>".termcolor
|
15
18
|
@options = {}
|
19
|
+
# ヘルプを見やすく色付け
|
20
|
+
def @opt.help
|
21
|
+
msg = super
|
22
|
+
# 見出し部分
|
23
|
+
msg.gsub!(/((?:Examples|Options|Configuration|[^\s]+? Variable List):)/) do
|
24
|
+
"<underline><bold>#{$1}</bold></underline>".termcolor
|
25
|
+
end
|
26
|
+
# Examples のコメント部分
|
27
|
+
msg.gsub!(/(#.+)$/) do
|
28
|
+
"<cyan>#{TermColor.escape($1)}</cyan>".termcolor
|
29
|
+
end
|
30
|
+
# 文字列部分
|
31
|
+
msg.gsub!(/(".+?")/) do
|
32
|
+
"<yellow>#{TermColor.escape($1)}</yellow>".termcolor
|
33
|
+
end
|
34
|
+
msg
|
35
|
+
end
|
16
36
|
end
|
17
37
|
|
18
38
|
def execute(argv)
|
39
|
+
@options.clear
|
40
|
+
load_local_settings
|
19
41
|
@opt.parse!(argv)
|
20
42
|
rescue OptionParser::InvalidOption => e
|
21
|
-
error "
|
43
|
+
error "不明なオプションです(#{e})"
|
22
44
|
exit 1
|
23
45
|
rescue OptionParser::MissingArgument => e
|
24
|
-
error "
|
46
|
+
error "オプションの引数が指定されていないか正しくありません(#{e})"
|
25
47
|
exit 1
|
26
48
|
end
|
27
49
|
|
28
50
|
def load_local_settings
|
29
51
|
command_prefix = self.class.to_s.scan(/[^:]+$/)[0].downcase
|
30
|
-
local_settings =
|
52
|
+
local_settings = Inventory.load("local_setting", :local)
|
31
53
|
local_settings.each do |name, value|
|
32
54
|
if name =~ /^#{command_prefix}\.(.+)$/
|
33
55
|
@options[$1] = value
|
@@ -35,6 +57,24 @@ module Command
|
|
35
57
|
end
|
36
58
|
end
|
37
59
|
|
60
|
+
#
|
61
|
+
# タグ情報をID情報に展開する
|
62
|
+
#
|
63
|
+
def tagname_to_ids(array)
|
64
|
+
database = Database.instance
|
65
|
+
tag_index = Hash.new { [] }
|
66
|
+
database.each do |id, data|
|
67
|
+
tags = data["tags"] || []
|
68
|
+
tags.each do |tag|
|
69
|
+
tag_index[tag] |= [id]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
array.map! { |arg|
|
73
|
+
ids = tag_index[arg]
|
74
|
+
ids.empty? ? arg : ids
|
75
|
+
}.flatten!
|
76
|
+
end
|
77
|
+
|
38
78
|
#
|
39
79
|
# 普通にコマンドを実行するけど、exit(2) を補足してexitstatus を返す
|
40
80
|
# 正常終了なら0
|
@@ -47,8 +87,39 @@ module Command
|
|
47
87
|
0
|
48
88
|
end
|
49
89
|
|
50
|
-
def oneline_help(msg)
|
90
|
+
def self.oneline_help(msg)
|
51
91
|
""
|
52
92
|
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# 指定したメソッドを呼び出す際に、フック関数があればそれ経由で呼ぶ
|
96
|
+
#
|
97
|
+
# 指定したメソッドは存在しなくてもいい。存在しなければ空のProcが作られる
|
98
|
+
#
|
99
|
+
def hook_call(target_method, *argv)
|
100
|
+
hook = "hook_#{target_method}"
|
101
|
+
target_method_proc = self.method(target_method) rescue ->{}
|
102
|
+
if respond_to?(hook)
|
103
|
+
self.__send__(hook, *argv, &target_method_proc)
|
104
|
+
else
|
105
|
+
target_method_proc.call(*argv)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
# 設定の強制設定
|
111
|
+
#
|
112
|
+
def force_change_settings_function(pairs)
|
113
|
+
settings = Inventory.load("local_setting", :local)
|
114
|
+
modified = false
|
115
|
+
pairs.each do |name, value|
|
116
|
+
if settings[name].nil? || settings[name] != value
|
117
|
+
settings[name] = value
|
118
|
+
puts "<bold><cyan>#{name} を #{value} に強制変更しました</cyan></bold>".termcolor
|
119
|
+
modified = true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
settings.save if modified
|
123
|
+
end
|
53
124
|
end
|
54
125
|
end
|
data/lib/commandline.rb
CHANGED
@@ -6,10 +6,12 @@
|
|
6
6
|
require_relative "narou"
|
7
7
|
require_relative "command"
|
8
8
|
require_relative "helper"
|
9
|
-
require_relative "
|
9
|
+
require_relative "inventory"
|
10
10
|
|
11
11
|
module CommandLine
|
12
|
-
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def run(argv)
|
13
15
|
if Helper.os_windows?
|
14
16
|
argv.map! do |arg|
|
15
17
|
arg.encode(Encoding::UTF_8)
|
@@ -30,25 +32,29 @@ module CommandLine
|
|
30
32
|
puts
|
31
33
|
arg = "help"
|
32
34
|
end
|
33
|
-
if argv.empty?
|
35
|
+
if argv.empty? && STDIN.tty?
|
34
36
|
argv += load_default_arguments(arg)
|
35
37
|
end
|
36
38
|
if argv.delete("--multiple")
|
37
39
|
multiple_argument_extract(argv)
|
38
40
|
end
|
39
|
-
|
41
|
+
unless STDIN.tty?
|
42
|
+
# pipeで接続された場合、標準入力からIDリストを受け取って引数に繋げる
|
43
|
+
argv += STDIN.gets.split
|
44
|
+
end
|
45
|
+
Command.get_list[arg].new.execute(argv)
|
40
46
|
end
|
41
47
|
|
42
|
-
def
|
43
|
-
default_arguments_list =
|
48
|
+
def load_default_arguments(cmd)
|
49
|
+
default_arguments_list = Inventory.load("local_setting", :local)
|
44
50
|
(default_arguments_list["default_args.#{cmd}"] || "").split
|
45
51
|
end
|
46
52
|
|
47
53
|
#
|
48
54
|
# 引数をスペース以外による区切り文字で展開する
|
49
55
|
#
|
50
|
-
def
|
51
|
-
delimiter =
|
56
|
+
def multiple_argument_extract(argv)
|
57
|
+
delimiter = Inventory.load("local_setting", :local)["multiple-delimiter"] || ","
|
52
58
|
argv.map! { |arg|
|
53
59
|
arg.split(delimiter)
|
54
60
|
}.flatten!
|
data/lib/converterbase.rb
CHANGED
@@ -17,10 +17,10 @@ class ConverterBase
|
|
17
17
|
|
18
18
|
def before(io, text_type)
|
19
19
|
data = io.string
|
20
|
-
convert_page_break(data) if @text_type == "body"
|
21
|
-
if @text_type != "story"
|
20
|
+
convert_page_break(data) if @text_type == "body" || @text_type == "textfile"
|
21
|
+
if @text_type != "story" && @setting.enable_pack_blank_line
|
22
22
|
data.gsub!("\n\n", "\n")
|
23
|
-
data.gsub!(
|
23
|
+
data.gsub!(/(^\n){3}/m, "\n\n") # 改行のみの行3つを2つに削減
|
24
24
|
end
|
25
25
|
io
|
26
26
|
end
|
@@ -48,6 +48,7 @@ class ConverterBase
|
|
48
48
|
@illust_chuki_list = []
|
49
49
|
@kanji_num_list = {}
|
50
50
|
@num_and_comma_list = {}
|
51
|
+
@force_indent_special_chapter_list = {}
|
51
52
|
@in_author_comment_block = nil
|
52
53
|
end
|
53
54
|
|
@@ -187,6 +188,7 @@ class ConverterBase
|
|
187
188
|
def convert_kanji_num_with_unit(data, lower_digit_zero = 0)
|
188
189
|
data.gsub!(/([#{KANJI_NUM}十百千万億兆京]+)/) do |match|
|
189
190
|
total = kanji_num_to_integer($1)
|
191
|
+
next match if total.to_s.length > KANJI_NUM_UNITS_DIGIT["京"] + 4
|
190
192
|
m1 = total.to_s.tr("0-9", KANJI_NUM)
|
191
193
|
if m1 =~ /〇{#{lower_digit_zero},}$/
|
192
194
|
digits = m1.reverse.scan(/.{1,4}/).map(&:reverse).reverse # 下の桁から4桁ずつ区切った配列を作成
|
@@ -327,16 +329,21 @@ class ConverterBase
|
|
327
329
|
data.replace(NKF.nkf("-wWX", data).tr("\u2014", "―"))
|
328
330
|
end
|
329
331
|
|
332
|
+
# ミュート(ノノカギ)化する記号定義
|
333
|
+
SINGLE_MINUTE_FAMILY = %!‘’'!
|
334
|
+
DOUBLE_MINUTE_FAMILY = %!“”〝〟"!
|
335
|
+
|
330
336
|
#
|
331
337
|
# 半角記号を全角に変換
|
332
338
|
#
|
333
339
|
def symbols_to_zenkaku(data)
|
334
|
-
data.
|
335
|
-
|
336
|
-
data.gsub!(/
|
340
|
+
data.gsub!(/[#{SINGLE_MINUTE_FAMILY}]([^"\n]+)[#{SINGLE_MINUTE_FAMILY}]/, "〝\\1〟")
|
341
|
+
# MEMO: シングルミュートを表示出来るフォントはほとんど無いためダブルにする
|
342
|
+
data.gsub!(/[#{DOUBLE_MINUTE_FAMILY}]([^"\n]+)[#{DOUBLE_MINUTE_FAMILY}]/, "〝\\1〟")
|
337
343
|
data.tr!("-=+/*《》'\"%$#&!?<><>()|‐,._;:[]",
|
338
344
|
"-=+/*≪≫’”%$#&!?〈〉〈〉()|-,._;:[]")
|
339
345
|
data.gsub!("\\", "¥")
|
346
|
+
data
|
340
347
|
end
|
341
348
|
|
342
349
|
#
|
@@ -511,7 +518,7 @@ class ConverterBase
|
|
511
518
|
end
|
512
519
|
|
513
520
|
#
|
514
|
-
#
|
521
|
+
# 全角数字(漢数字含む)を半角アラビア数字に
|
515
522
|
#
|
516
523
|
def zenkaku_num_to_hankaku_num(num)
|
517
524
|
num.tr("0-9#{KANJI_NUM}", "0-90-9")
|
@@ -536,7 +543,7 @@ class ConverterBase
|
|
536
543
|
data
|
537
544
|
end
|
538
545
|
|
539
|
-
HALF_INDENT_TARGET = /^[ \t]*([〔「『((【〈《≪〝])/
|
546
|
+
HALF_INDENT_TARGET = /^[ \t]*((?:[〔「『((【〈《≪〝])|(?:※[#始め二重山括弧]))/
|
540
547
|
FULL_INDENT_TARGET = /^[ \t]*(――)/
|
541
548
|
AUTO_INDENT_IGNORE_INDENT_CHAR = Inspector::IGNORE_INDENT_CHAR.sub("・", "")
|
542
549
|
#
|
@@ -546,7 +553,13 @@ class ConverterBase
|
|
546
553
|
# kindle paperwhite で鍵括弧のインデントがおかしいことへの対応
|
547
554
|
#
|
548
555
|
def half_indent_bracket(data)
|
549
|
-
data.gsub!(HALF_INDENT_TARGET
|
556
|
+
data.gsub!(HALF_INDENT_TARGET) do
|
557
|
+
if @setting.enable_half_indent_bracket
|
558
|
+
"[#二分アキ]#{$1}"
|
559
|
+
else
|
560
|
+
$1
|
561
|
+
end
|
562
|
+
end
|
550
563
|
end
|
551
564
|
|
552
565
|
#
|
@@ -572,23 +585,46 @@ class ConverterBase
|
|
572
585
|
end
|
573
586
|
|
574
587
|
#
|
575
|
-
#
|
576
|
-
#
|
577
|
-
# TODO: 半角数字の縦中横注記をいれた影響で、2桁の半角数字が認識されてないのをどうにかする
|
588
|
+
# 章見出しっぽい文字列を字下げする
|
578
589
|
#
|
579
|
-
def force_indent_special_chapter(
|
580
|
-
|
581
|
-
|
590
|
+
def force_indent_special_chapter(data)
|
591
|
+
return unless @text_type == "body" || @text_type == "textfile"
|
592
|
+
@@count_of_rebuild_container ||= 0
|
593
|
+
data.gsub!(/^[ \t]*([-―<<〈-]*)([0-90-9#{KANJI_NUM}]{1,3})([-―>>〉-]*)$/) do
|
582
594
|
top, chapter, bottom = $1, $2, $3
|
583
|
-
|
595
|
+
pre, post = $`, $'
|
596
|
+
if top != "" && "―--".include?(top) # include?は空文字("")だとtrueなのでチェック必須
|
584
597
|
top = "― "
|
585
598
|
bottom = " ―"
|
586
599
|
end
|
587
|
-
|
588
|
-
|
600
|
+
str = " [#ゴシック体]#{top}"
|
601
|
+
str += hankaku_num_to_zenkaku_num(chapter.tr("0-9", "0-9"))
|
602
|
+
str += "#{bottom}[#ゴシック体終わり]"
|
603
|
+
# 前後に空行を入れたいが、それは行処理ループ中に行う
|
604
|
+
symbols_to_zenkaku(str)
|
605
|
+
index = @@count_of_rebuild_container += 1
|
606
|
+
@force_indent_special_chapter_list[convert_numbers(index.to_s)] = str
|
607
|
+
"[#章見出しっぽい文=#{index}]"
|
589
608
|
end
|
590
609
|
end
|
591
610
|
|
611
|
+
def rebuild_force_indent_special_chapter(data)
|
612
|
+
data.gsub!(/[#章見出しっぽい文=(.+?)]/) do
|
613
|
+
@force_indent_special_chapter_list[$1]
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
def insert_blank_before_line_and_behind_to_special_chapter(line)
|
618
|
+
result = ""
|
619
|
+
if line =~ /[#章見出しっぽい文=/
|
620
|
+
unless blank_line?(@before_line)
|
621
|
+
result << "\n"
|
622
|
+
end
|
623
|
+
@request_insert_blank_next_line = true
|
624
|
+
end
|
625
|
+
line.sub!(/\A/, result)
|
626
|
+
end
|
627
|
+
|
592
628
|
#
|
593
629
|
# 行頭空白を考慮した字下げ
|
594
630
|
#
|
@@ -800,7 +836,7 @@ class ConverterBase
|
|
800
836
|
to_ruby(match, $1, $2, ["≪", "≫"])
|
801
837
|
end
|
802
838
|
# ()なルビの対処
|
803
|
-
data.gsub!(/(.+?)(([ぁ-んァ-ヶーゝゞ・A-Za-zA-Za-z
|
839
|
+
data.gsub!(/(.+?)(([ぁ-んァ-ヶーゝゞ・A-Za-zA-Za-z ]{,20}))/) do |match|
|
804
840
|
to_ruby(match, $1, $2, ["(", ")"])
|
805
841
|
end
|
806
842
|
end
|
@@ -849,7 +885,8 @@ class ConverterBase
|
|
849
885
|
"#{m1.sub(/|([^|]*)$/, "[#ルビ用縦線]\\1")}《#{m2}》"
|
850
886
|
when object_of_ruby?(last_char)
|
851
887
|
# なろうのルビ対象文字を辿って|を挿入する(青空文庫となろうのルビ仕様の差異吸収のため)
|
852
|
-
|
888
|
+
# 空白もルビ対象文字に含むのはなろうの仕様である
|
889
|
+
m1.sub(/([#{CHARACTER_OF_RUBY} ]+)$/) {
|
853
890
|
match_target = $1
|
854
891
|
if match_target =~ /^( +)/
|
855
892
|
"#{$1}[#ルビ用縦線]#{match_target[$1.length..-1]}"
|
@@ -894,7 +931,7 @@ class ConverterBase
|
|
894
931
|
def rebuild_url(data)
|
895
932
|
@url_list.each_with_index do |url, id|
|
896
933
|
data.sub!("[#URL=#{convert_numbers(id.to_s)}]",
|
897
|
-
"<a href=\"#{url}\">#{url}</a>")
|
934
|
+
"<a href=\"#{Helper.ampersand_to_entity(url)}\">#{url}</a>")
|
898
935
|
end
|
899
936
|
end
|
900
937
|
|
@@ -920,8 +957,9 @@ class ConverterBase
|
|
920
957
|
# 中黒(・)や句読点を並べて三点リーダーもどきにしているのを三点リーダーに変換
|
921
958
|
#
|
922
959
|
def convert_horizontal_ellipsis(data)
|
923
|
-
return if !@setting.enable_convert_horizontal_ellipsis ||
|
924
|
-
|
960
|
+
return if !@setting.enable_convert_horizontal_ellipsis || \
|
961
|
+
@text_type == "subtitle" || @text_type == "chapter"
|
962
|
+
%w(・ 。 、 .).each do |char|
|
925
963
|
data.gsub!(/#{char}{3,}/) do |match|
|
926
964
|
pre_char, post_char = $`[-1], $'[0]
|
927
965
|
if pre_char == "―" || post_char == "―"
|
@@ -952,21 +990,30 @@ class ConverterBase
|
|
952
990
|
"[#3字下げ][#ここから中見出し]#{midashi_title}[#ここで中見出し終わり]"
|
953
991
|
end
|
954
992
|
|
993
|
+
def calc_cr_count(str)
|
994
|
+
head_cr_count = str.index(/[^\n]/)
|
995
|
+
head_cr_count > 2 ? 2 : head_cr_count
|
996
|
+
end
|
997
|
+
|
998
|
+
# 実際に見出しを付与する
|
955
999
|
data.gsub!(/[#改ページ]\n(.+?)\n/) do |match|
|
956
1000
|
m1 = $1
|
957
1001
|
rest = $'
|
1002
|
+
# 前書きがある場合は今回は保留して、次の処理で見出しを付与する
|
958
1003
|
if $1 =~ /#{AUTHOR_COMMENT_CHUKI[:introduction][:open]}/
|
959
1004
|
match
|
960
1005
|
else
|
961
1006
|
# 見出しの次の行が空行ではない場合空行を追加する
|
962
|
-
add_tail =
|
1007
|
+
add_tail = "\n" * (2 - calc_cr_count(rest))
|
1008
|
+
# 見出しと本文の間には空行を2行挟む
|
963
1009
|
"[#改ページ]\n#{midashi(m1)}\n#{add_tail}"
|
964
1010
|
end
|
965
1011
|
end
|
1012
|
+
# 前書きがある場合は、前書き→見出しの順番を見出し→前書きに入れ替えて置換
|
966
1013
|
data.gsub!(/([#改ページ]\n)(#{AUTHOR_COMMENT_CHUKI[:introduction][:open]}.+?#{AUTHOR_COMMENT_CHUKI[:introduction][:close]}\n)(.+?\n)/m) do
|
967
1014
|
m1, m2, m3 = $1, $2, $3
|
968
1015
|
add_tail = $' =~ /\A$/ ? "" : "\n"
|
969
|
-
"#{m1 + midashi(m3) + m2}#{add_tail}"
|
1016
|
+
"#{m1 + midashi(m3) + m2}#{add_tail}"
|
970
1017
|
end
|
971
1018
|
end
|
972
1019
|
|
@@ -1003,9 +1050,9 @@ class ConverterBase
|
|
1003
1050
|
#
|
1004
1051
|
def convert_page_break(data)
|
1005
1052
|
if @setting.enable_convert_page_break
|
1006
|
-
threshold = @setting.to_page_break_threshold
|
1053
|
+
threshold = @setting.to_page_break_threshold
|
1007
1054
|
# `改ページ' を使うと見出し付与等で混乱するので自動生成したものは区別する
|
1008
|
-
data.gsub!(
|
1055
|
+
data.gsub!(/(^\n){#{threshold},}/, "[#改頁]\n")
|
1009
1056
|
end
|
1010
1057
|
end
|
1011
1058
|
|
@@ -1030,6 +1077,7 @@ class ConverterBase
|
|
1030
1077
|
replace_narou_tag(data)
|
1031
1078
|
convert_rome_numeric(data)
|
1032
1079
|
alphabet_to_zenkaku(data, @setting.enable_alphabet_force_zenkaku)
|
1080
|
+
force_indent_special_chapter(data)
|
1033
1081
|
convert_numbers(data)
|
1034
1082
|
exception_reconvert_kanji_to_num(data)
|
1035
1083
|
if @setting.enable_convert_num_to_kanji && @text_type != "subtitle" && @text_type != "chapter" \
|
@@ -1105,10 +1153,11 @@ class ConverterBase
|
|
1105
1153
|
if @request_insert_blank_next_line
|
1106
1154
|
outputs unless blank_line?(line)
|
1107
1155
|
@request_insert_blank_next_line = false
|
1156
|
+
@before_line = ""
|
1108
1157
|
end
|
1109
1158
|
process_author_comment(line) if @text_type == "textfile"
|
1159
|
+
insert_blank_before_line_and_behind_to_special_chapter(line)
|
1110
1160
|
insert_blank_line_to_border_symbol(line)
|
1111
|
-
force_indent_special_chapter(line)
|
1112
1161
|
|
1113
1162
|
outputs(line)
|
1114
1163
|
unless @delay_outputs_buffer.empty?
|
@@ -1138,6 +1187,7 @@ class ConverterBase
|
|
1138
1187
|
rebuild_english_sentences(data)
|
1139
1188
|
rebuild_hankaku_num_and_comma(data)
|
1140
1189
|
rebuild_kome_to_gaiji(data)
|
1190
|
+
rebuild_force_indent_special_chapter(data)
|
1141
1191
|
# 再構築された文章にルビがふられる可能性を考慮して、
|
1142
1192
|
# この位置でルビの処理を行う
|
1143
1193
|
narou_ruby(data) if @setting.enable_ruby
|