bitclust-core 1.3.0 → 1.6.0
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.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/README.md +65 -0
- data/Rakefile +32 -0
- data/data/bitclust/catalog/ja_JP.UTF-8 +19 -1
- data/data/bitclust/searchpage/index.html +90 -0
- data/data/bitclust/template/class +69 -8
- data/data/bitclust/template/function +2 -2
- data/data/bitclust/template/layout +11 -3
- data/data/bitclust/template/method +2 -2
- data/data/bitclust/template/search +1 -1
- data/data/bitclust/template.epub/class +22 -1
- data/data/bitclust/template.epub/function +2 -2
- data/data/bitclust/template.epub/layout +1 -3
- data/data/bitclust/template.epub/method +2 -2
- data/data/bitclust/template.lillia/class +26 -5
- data/data/bitclust/template.lillia/layout +1 -3
- data/data/bitclust/template.lillia/method +2 -2
- data/data/bitclust/template.offline/class +48 -4
- data/data/bitclust/template.offline/function +2 -2
- data/data/bitclust/template.offline/layout +27 -3
- data/data/bitclust/template.offline/method +2 -2
- data/lib/bitclust/app.rb +16 -17
- data/lib/bitclust/capi_converter.rb +20 -0
- data/lib/bitclust/classentry.rb +67 -17
- data/lib/bitclust/compat.rb +2 -2
- data/lib/bitclust/completion.rb +58 -27
- data/lib/bitclust/crossrubyutils.rb +8 -5
- data/lib/bitclust/database.rb +28 -8
- data/lib/bitclust/doc_converter.rb +63 -0
- data/lib/bitclust/docentry.rb +1 -1
- data/lib/bitclust/entity_splitter.rb +221 -0
- data/lib/bitclust/entry.rb +47 -7
- data/lib/bitclust/functiondatabase.rb +13 -1
- data/lib/bitclust/functionentry.rb +5 -1
- data/lib/bitclust/functionreferenceparser.rb +4 -4
- data/lib/bitclust/generators/epub.rb +10 -3
- data/lib/bitclust/htmlutils.rb +1 -1
- data/lib/bitclust/include_graph.rb +375 -0
- data/lib/bitclust/include_pruner.rb +144 -0
- data/lib/bitclust/interface.rb +1 -1
- data/lib/bitclust/libraryentry.rb +8 -7
- data/lib/bitclust/lineinput.rb +7 -5
- data/lib/bitclust/link_checker.rb +179 -0
- data/lib/bitclust/markdown_bridge.rb +186 -0
- data/lib/bitclust/markdown_orchestrator.rb +267 -0
- data/lib/bitclust/markdown_to_rrd.rb +824 -0
- data/lib/bitclust/markdown_tree.rb +217 -0
- data/lib/bitclust/mdcompiler.rb +883 -0
- data/lib/bitclust/mdparser.rb +347 -0
- data/lib/bitclust/messagecatalog.rb +3 -3
- data/lib/bitclust/method_since_calculator.rb +117 -0
- data/lib/bitclust/methoddatabase.rb +124 -14
- data/lib/bitclust/methodentry.rb +125 -7
- data/lib/bitclust/methodid.rb +12 -11
- data/lib/bitclust/methodsignature.rb +10 -4
- data/lib/bitclust/nameutils.rb +41 -22
- data/lib/bitclust/preprocessor.rb +66 -29
- data/lib/bitclust/rdcompiler.rb +195 -95
- data/lib/bitclust/refsdatabase.rb +23 -8
- data/lib/bitclust/reloadable_request_handler.rb +72 -0
- data/lib/bitclust/requesthandler.rb +21 -16
- data/lib/bitclust/ridatabase.rb +10 -4
- data/lib/bitclust/rrd_to_markdown.rb +925 -0
- data/lib/bitclust/rrdparser.rb +196 -30
- data/lib/bitclust/runner.rb +17 -2
- data/lib/bitclust/screen.rb +80 -11
- data/lib/bitclust/search_index_generator.rb +288 -0
- data/lib/bitclust/searcher.rb +69 -20
- data/lib/bitclust/simplesearcher.rb +24 -12
- data/lib/bitclust/subcommand.rb +7 -1
- data/lib/bitclust/subcommands/ancestors_command.rb +9 -2
- data/lib/bitclust/subcommands/checklink_command.rb +54 -0
- data/lib/bitclust/subcommands/chm_command.rb +15 -7
- data/lib/bitclust/subcommands/classes_command.rb +5 -0
- data/lib/bitclust/subcommands/extract_command.rb +5 -0
- data/lib/bitclust/subcommands/htmlfile_command.rb +21 -7
- data/lib/bitclust/subcommands/init_command.rb +4 -1
- data/lib/bitclust/subcommands/list_command.rb +12 -4
- data/lib/bitclust/subcommands/lookup_command.rb +28 -9
- data/lib/bitclust/subcommands/methods_command.rb +10 -2
- data/lib/bitclust/subcommands/methodsince_command.rb +80 -0
- data/lib/bitclust/subcommands/preproc_command.rb +5 -0
- data/lib/bitclust/subcommands/property_command.rb +2 -1
- data/lib/bitclust/subcommands/searchpage_command.rb +102 -0
- data/lib/bitclust/subcommands/server_command.rb +10 -8
- data/lib/bitclust/subcommands/setup_command.rb +24 -10
- data/lib/bitclust/subcommands/statichtml_command.rb +129 -6
- data/lib/bitclust/subcommands/update_command.rb +110 -2
- data/lib/bitclust/syntax_highlighter.rb +48 -4
- data/lib/bitclust/textutils.rb +3 -3
- data/lib/bitclust/version.rb +1 -1
- data/lib/bitclust/version_badges.rb +90 -0
- data/lib/bitclust/whole_file_gate.rb +137 -0
- data/test/test_app.rb +269 -0
- data/test/test_bitclust.rb +2 -0
- data/test/test_capi_converter.rb +91 -0
- data/test/test_class_screen.rb +413 -0
- data/test/test_copy_doc_md.rb +53 -0
- data/test/test_doc_converter.rb +78 -0
- data/test/test_entity_splitter.rb +231 -0
- data/test/test_entry.rb +207 -2
- data/test/test_eol_warning.rb +43 -0
- data/test/test_functionreferenceparser.rb +11 -0
- data/test/test_include_graph.rb +640 -0
- data/test/test_include_pruner.rb +133 -0
- data/test/test_link_checker.rb +114 -0
- data/test/test_lookup_command.rb +135 -0
- data/test/test_markdown_bridge.rb +217 -0
- data/test/test_markdown_orchestrator.rb +478 -0
- data/test/test_markdown_to_rrd.rb +757 -0
- data/test/test_markdown_tree.rb +369 -0
- data/test/test_mdcompiler.rb +1276 -0
- data/test/test_mdparser.rb +538 -0
- data/test/test_method_screen.rb +166 -0
- data/test/test_method_since_calculator.rb +290 -0
- data/test/test_methoddatabase.rb +16 -0
- data/test/test_methodentry.rb +328 -0
- data/test/test_methodsignature.rb +3 -1
- data/test/test_methodsince_command.rb +168 -0
- data/test/test_nameutils.rb +22 -0
- data/test/test_preprocessor.rb +215 -0
- data/test/test_rdcompiler.rb +401 -30
- data/test/test_refsdatabase.rb +32 -0
- data/test/test_rrd_to_markdown.rb +968 -0
- data/test/test_rrdparser.rb +295 -2
- data/test/test_run_ruby_wasm.rb +54 -0
- data/test/test_run_worker_prelude.rb +83 -0
- data/test/test_runner.rb +51 -0
- data/test/test_search_index_generator.rb +513 -0
- data/test/test_search_screen.rb +48 -0
- data/test/test_searcher.rb +132 -0
- data/test/test_searchpage_command.rb +167 -0
- data/test/test_simplesearcher.rb +28 -0
- data/test/test_statichtml_command.rb +204 -0
- data/test/test_syntax_highlighter.rb +60 -0
- data/test/test_whole_file_gate.rb +175 -0
- data/theme/default/js/NOTICE +42 -0
- data/theme/default/js/run-worker.js +111 -0
- data/theme/default/js/run.js +350 -0
- data/theme/default/js/search_controller.js +134 -0
- data/theme/default/js/search_init.js +176 -0
- data/theme/default/js/search_navigation.js +110 -0
- data/theme/default/js/search_page.js +202 -0
- data/theme/default/js/search_ranker.js +244 -0
- data/theme/default/script.js +91 -18
- data/theme/default/search.css +149 -0
- data/theme/default/style.css +193 -21
- data/theme/default/syntax-highlight.css +8 -0
- data/theme/lillia/style.css +45 -1
- metadata +161 -20
- data/README +0 -32
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bitclust/include_graph'
|
|
4
|
+
require 'bitclust/whole_file_gate'
|
|
5
|
+
|
|
6
|
+
module BitClust
|
|
7
|
+
# マルチエンティティ RD のエンティティ単位分割(O3)。
|
|
8
|
+
#
|
|
9
|
+
# 「ヘッダ関係(include/extend/alias)を持つエンティティは自分のファイルを持ち、
|
|
10
|
+
# 関係は front matter に一元化する」ため、関係を持つマルチエンティティファイルを
|
|
11
|
+
# エンティティ単位のセグメントへ分割する。関係を持たない束ね(Errno 族等)は
|
|
12
|
+
# 分割しない(判断はオーケストレータが行う。ここは純テキスト変換)。
|
|
13
|
+
#
|
|
14
|
+
# 分割の前処理として、スコープ定数(スコープ内で常に真/偽)の版ゲートのうち
|
|
15
|
+
# エンティティ H1 を包むものを解決する。版で改名されたエンティティ
|
|
16
|
+
# (thread/Mutex, Net::HTTPURITooLong 等の #@since/#@else H1 ペア)が
|
|
17
|
+
# スコープ内の単一 H1 に収束する(旧名は活き枝の alias 行として残っている)。
|
|
18
|
+
module EntitySplitter
|
|
19
|
+
H1_RE = /\A=(?!=)\s*(?:class|module|object|reopen|redefine)\s+(\S+)/
|
|
20
|
+
GATE_OPEN_RE = /\A\#@(since|until|if)\s*(.*)$/
|
|
21
|
+
BLOCK_OPEN_RE = /\A\#@(?:since|until|if|samplecode)\b/
|
|
22
|
+
BLANK_RE = /\A\s*\z/
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
# スコープ定数(スコープ内で常に真/偽)な版ゲートのうち、エンティティ H1 を
|
|
27
|
+
# 含むブロックを解決する。活きている枝の内容(再帰的に解決)を残し、
|
|
28
|
+
# ゲート行と死んだ枝を落とす。スコープ内で真偽が変わるゲートと、
|
|
29
|
+
# H1 を含まないゲート(散文の版分岐・gated relations)は触らない。
|
|
30
|
+
def resolve_header_gates(src, scope)
|
|
31
|
+
lines = src.lines
|
|
32
|
+
out = [] #: Array[String]
|
|
33
|
+
i = 0
|
|
34
|
+
while i < lines.length
|
|
35
|
+
line = lines[i]
|
|
36
|
+
truth = constant_truth(line, scope)
|
|
37
|
+
if !truth.nil? && (block = parse_block(lines, i)) &&
|
|
38
|
+
contains_entity_h1?(block[:body] + block[:else_body])
|
|
39
|
+
active = truth ? block[:body] : block[:else_body]
|
|
40
|
+
resolved = resolve_header_gates(active.join, scope).lines
|
|
41
|
+
if resolved.empty? && out.last =~ BLANK_RE && lines[block[:next]] =~ BLANK_RE
|
|
42
|
+
i = block[:next] + 1 # ブロックごと消えた場合は後続の空行を1つ畳む
|
|
43
|
+
else
|
|
44
|
+
i = block[:next]
|
|
45
|
+
end
|
|
46
|
+
out.concat(resolved)
|
|
47
|
+
else
|
|
48
|
+
out << line
|
|
49
|
+
i += 1
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
out.join
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# ゲート行のスコープ定数評価: 常真なら true、常偽なら false、
|
|
56
|
+
# 定数でない/ゲートでないなら nil。
|
|
57
|
+
# #@if は「version >= "X"(X <= 下限)」形のみ常真と証明できる
|
|
58
|
+
def constant_truth(line, scope)
|
|
59
|
+
cond = gate_condition(line)
|
|
60
|
+
return nil unless cond
|
|
61
|
+
if cond.kind == :if
|
|
62
|
+
WholeFileGate.provably_true_if?(cond.version, scope) ? true : nil
|
|
63
|
+
elsif scope.always?(cond)
|
|
64
|
+
true
|
|
65
|
+
elsif scope.never?(cond)
|
|
66
|
+
false
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# samplecode の内容を除いて、エンティティ H1 行を含むか
|
|
71
|
+
def contains_entity_h1?(lines)
|
|
72
|
+
code = 0
|
|
73
|
+
lines.each do |l|
|
|
74
|
+
case l
|
|
75
|
+
when /\A\#@samplecode\b/ then code += 1
|
|
76
|
+
when /\A\#@end\b/ then code -= 1 if code > 0
|
|
77
|
+
when H1_RE then return true if code.zero?
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
false
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# エンティティ単位のセグメント列 [[エンティティ名, テキスト], ...] を返す。
|
|
84
|
+
# 境界は深さ0の H1 行、または最初の内容行が H1 の版ゲートブロック
|
|
85
|
+
# (スコープ内ゲート付きエンティティ。ブロック全体が1セグメント)。
|
|
86
|
+
# 先頭に H1 以外の内容がある場合(ライブラリ概要部)は name=nil の
|
|
87
|
+
# ベースセグメントとして返す。連結すると入力に一致する。
|
|
88
|
+
def segments(src)
|
|
89
|
+
lines = src.lines
|
|
90
|
+
# [行index, エンティティ名, ゲート付きか]
|
|
91
|
+
boundaries = [] #: Array[[Integer, String?, bool]]
|
|
92
|
+
depth = 0
|
|
93
|
+
lines.each_with_index do |line, i|
|
|
94
|
+
case line
|
|
95
|
+
when BLOCK_OPEN_RE
|
|
96
|
+
if depth.zero? && line =~ /\A\#@(?:since|until|if)\b/ &&
|
|
97
|
+
(name = first_h1_name(lines, i + 1))
|
|
98
|
+
boundaries << [i, name, true]
|
|
99
|
+
end
|
|
100
|
+
depth += 1
|
|
101
|
+
when /\A\#@end\b/
|
|
102
|
+
depth -= 1
|
|
103
|
+
when H1_RE
|
|
104
|
+
boundaries << [i, $1, false] if depth.zero?
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
# ゲート付き H1 境界は、ゲートがセグメント全体を包む場合のみ分割境界にする。
|
|
108
|
+
# H1 と見出しだけがゲートされ内容がゲートの外にある形(syslog の旧構造)を
|
|
109
|
+
# 単独ファイル化すると、ゲートが偽の版で自立パースできない
|
|
110
|
+
# (旧世界では直前エンティティの内容として付く)ため、直前セグメントに残す
|
|
111
|
+
boundaries = boundaries.each_with_index.select { |(start, _, gated), idx|
|
|
112
|
+
next true unless gated
|
|
113
|
+
stop = idx + 1 < boundaries.length ? boundaries[idx + 1][0] : lines.length
|
|
114
|
+
gate_wraps_segment?(lines, start, stop)
|
|
115
|
+
}.map { |(start, name, _), _| [start, name] } #: Array[[Integer, String?]]
|
|
116
|
+
return nil if boundaries.empty?
|
|
117
|
+
if (lines[0...(boundaries.first || raise)[0]] || raise).all? { |l| l =~ BLANK_RE }
|
|
118
|
+
boundaries[0] = [0, boundaries[0][1]] # 先頭の空行は最初のセグメントへ
|
|
119
|
+
else
|
|
120
|
+
boundaries.unshift([0, nil]) # ライブラリ概要部(ベースセグメント)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
boundaries.each_with_index.map do |(start, name), idx|
|
|
124
|
+
stop = idx + 1 < boundaries.length ? boundaries[idx + 1][0] : lines.length
|
|
125
|
+
[name, (lines[start...stop] || raise).join]
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# start のゲート開き行に対応する #@end がセグメント終端(末尾の空行は許容)に
|
|
130
|
+
# あるか。ゲートがセグメント全体を包むときのみ真
|
|
131
|
+
def gate_wraps_segment?(lines, start, stop)
|
|
132
|
+
depth = 0
|
|
133
|
+
close = nil #: Integer?
|
|
134
|
+
(start...stop).each do |i|
|
|
135
|
+
case lines[i]
|
|
136
|
+
when BLOCK_OPEN_RE then depth += 1
|
|
137
|
+
when /\A\#@end\b/
|
|
138
|
+
depth -= 1
|
|
139
|
+
if depth.zero?
|
|
140
|
+
close = i
|
|
141
|
+
break
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
return false unless close
|
|
146
|
+
(lines[(close + 1)...stop] || raise).all? { |l| l =~ BLANK_RE }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# エンティティ名 → 出力ファイル名(拡張子なし)。既存の命名規約に合わせ :: → __
|
|
150
|
+
def entity_filename(name)
|
|
151
|
+
name.gsub('::', '__')
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# いずれかのエンティティの H1 直後のヘッダ領域(関係行・#@・空行が続く範囲)に
|
|
155
|
+
# include/extend/alias があるか。本文中やコード例の同名行は数えない
|
|
156
|
+
def header_relations?(src)
|
|
157
|
+
in_header = false
|
|
158
|
+
src.each_line do |line|
|
|
159
|
+
if line =~ H1_RE
|
|
160
|
+
in_header = true
|
|
161
|
+
elsif in_header
|
|
162
|
+
case line
|
|
163
|
+
when /\A(?:include|extend|alias)\s+\S/ then return true
|
|
164
|
+
when /\A\#@/, BLANK_RE then nil
|
|
165
|
+
else in_header = false
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
false
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def gate_condition(line)
|
|
173
|
+
return nil unless line =~ GATE_OPEN_RE
|
|
174
|
+
# Preprocessor は #@since "1.8.5" のクォート形式も受理する
|
|
175
|
+
IncludeGraph::Condition.new(($1 || raise).to_sym, ($2 || raise).strip.delete_prefix('"').delete_suffix('"'))
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# i のゲート開始行から対応を取り、{body:, else_body:, next:} を返す。
|
|
179
|
+
# body/else_body は枝の行列、next は #@end の次の行 index。対応が取れなければ nil
|
|
180
|
+
def parse_block(lines, i)
|
|
181
|
+
depth = 0
|
|
182
|
+
body = [] #: Array[String]
|
|
183
|
+
else_body = [] #: Array[String]
|
|
184
|
+
current = body
|
|
185
|
+
j = i
|
|
186
|
+
while j < lines.length
|
|
187
|
+
line = lines[j]
|
|
188
|
+
case line
|
|
189
|
+
when BLOCK_OPEN_RE
|
|
190
|
+
depth += 1
|
|
191
|
+
current << line unless j == i
|
|
192
|
+
when /\A\#@else\b/
|
|
193
|
+
if depth == 1
|
|
194
|
+
current = else_body
|
|
195
|
+
else
|
|
196
|
+
current << line
|
|
197
|
+
end
|
|
198
|
+
when /\A\#@end\b/
|
|
199
|
+
depth -= 1
|
|
200
|
+
return { body: body, else_body: else_body, next: j + 1 } if depth.zero?
|
|
201
|
+
current << line
|
|
202
|
+
else
|
|
203
|
+
current << line
|
|
204
|
+
end
|
|
205
|
+
j += 1
|
|
206
|
+
end
|
|
207
|
+
nil
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def first_content_is_h1?(branch_lines)
|
|
211
|
+
first = branch_lines.find { |l| l !~ BLANK_RE }
|
|
212
|
+
first =~ H1_RE ? true : false
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# i 以降の最初の非空行が H1 ならその名前を返す
|
|
216
|
+
def first_h1_name(lines, i)
|
|
217
|
+
first = (lines[i..] || raise).find { |l| l !~ BLANK_RE }
|
|
218
|
+
first =~ H1_RE ? $1 : nil
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
data/lib/bitclust/entry.rb
CHANGED
|
@@ -113,11 +113,11 @@ module BitClust
|
|
|
113
113
|
when 'LibraryEntry' then "restore_library(h['#{@name}'])"
|
|
114
114
|
when 'ClassEntry' then "restore_class(h['#{@name}'])"
|
|
115
115
|
when 'MethodEntry' then "restore_method(h['#{@name}'])"
|
|
116
|
-
when '[String]' then "h['#{@name}'].split(/,(?=.)/)"
|
|
116
|
+
when '[String]' then "(h['#{@name}'] || '').split(/,(?=.)/)"
|
|
117
117
|
when '[LibraryEntry]' then "restore_libraries(h['#{@name}'])"
|
|
118
118
|
when '[ClassEntry]' then "restore_classes(h['#{@name}'])"
|
|
119
119
|
when '[MethodEntry]' then "restore_methods(h['#{@name}'])"
|
|
120
|
-
when 'Location' then "h['#{@name}']&.tap { |loc| break if loc.empty?; break Location.new(
|
|
120
|
+
when 'Location' then "h['#{@name}']&.tap { |loc| break if loc.empty?; break Location.new(loc.split(?:).first, nil) }"
|
|
121
121
|
else
|
|
122
122
|
raise "must not happen: @type=#{@type.inspect}"
|
|
123
123
|
end
|
|
@@ -135,7 +135,7 @@ module BitClust
|
|
|
135
135
|
when '[LibraryEntry]' then "serialize_entries(@#{@name})"
|
|
136
136
|
when '[ClassEntry]' then "serialize_entries(@#{@name})"
|
|
137
137
|
when '[MethodEntry]' then "serialize_entries(@#{@name})"
|
|
138
|
-
when 'Location' then "
|
|
138
|
+
when 'Location' then "(@#{@name} && @#{@name}.file).to_s"
|
|
139
139
|
else
|
|
140
140
|
raise "must not happen: @type=#{@type.inspect}"
|
|
141
141
|
end
|
|
@@ -150,6 +150,46 @@ module BitClust
|
|
|
150
150
|
@db = db
|
|
151
151
|
end
|
|
152
152
|
|
|
153
|
+
# description 等、コンパイラを通さない表示テキスト。
|
|
154
|
+
# md ソースの DB では旧経路と同じ表示形(rd インライン形式)へ戻す
|
|
155
|
+
def display_text(text)
|
|
156
|
+
return text unless text
|
|
157
|
+
if @db.properties['source_format'] == 'markdown'
|
|
158
|
+
# LibraryEntry#require(ライブラリ関係の登録)が Kernel#require を
|
|
159
|
+
# 隠蔽するため、ファイルロードは Kernel を明示する
|
|
160
|
+
Kernel.require 'bitclust/markdown_to_rrd'
|
|
161
|
+
::BitClust::MarkdownToRRD.restore_description(text)
|
|
162
|
+
else
|
|
163
|
+
text
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
private :display_text
|
|
167
|
+
|
|
168
|
+
# BitClust::RDCompiler::BracketLink と同等の正規表現(/n なし)
|
|
169
|
+
BracketLink = /\[\[[\w-]+?:[!-~]+?(?:\[\] )?\]\]/
|
|
170
|
+
|
|
171
|
+
# meta description など、コンパイラを通さずマークアップも解釈されない
|
|
172
|
+
# 場所に使うテキスト。非 ASCII 文字間の改行は削除し(ブラウザでは
|
|
173
|
+
# 空白扱いになり日本語文中に不自然な空白が見えるため)、残りの改行は
|
|
174
|
+
# 空白に変換、ブラケットリンクはリンク先名のみにする
|
|
175
|
+
def description_text(text)
|
|
176
|
+
text = display_text(text)
|
|
177
|
+
return text unless text
|
|
178
|
+
# module function の ".#" は表示専用なので、DB バージョンが 4.0 以降なら
|
|
179
|
+
# "?." で表示する(RDCompiler#display_spec と同じ #250/#282 の規則。
|
|
180
|
+
# ここは可視ページを通さない meta description 用の経路なので、bracket_link
|
|
181
|
+
# と同じ変換を独立に適用する必要がある。spec・URL・アンカーキーは不変)
|
|
182
|
+
version = @db&.propget('version')
|
|
183
|
+
text = text.split("\n").map(&:strip).join("\n")
|
|
184
|
+
.gsub(/(\P{ascii})\n(?=\P{ascii})/) { $1 || raise }
|
|
185
|
+
.tr("\n", ' ')
|
|
186
|
+
text.gsub(BracketLink) {|link|
|
|
187
|
+
label = ((link[2..-3] || raise).split(':', 2).last || raise).rstrip
|
|
188
|
+
label.include?('.#') ? label.sub('.#', NameUtils.display_typemark('.#', version)) : label
|
|
189
|
+
}
|
|
190
|
+
end
|
|
191
|
+
private :description_text
|
|
192
|
+
|
|
153
193
|
def type_id
|
|
154
194
|
self.class.type_id
|
|
155
195
|
end
|
|
@@ -189,11 +229,11 @@ module BitClust
|
|
|
189
229
|
end
|
|
190
230
|
|
|
191
231
|
def restore_library(id)
|
|
192
|
-
LibraryEntry.load(@db, id)
|
|
232
|
+
LibraryEntry.load(@db, id) # steep:ignore
|
|
193
233
|
end
|
|
194
234
|
|
|
195
235
|
def restore_class(id)
|
|
196
|
-
id.empty? ? nil : ClassEntry.load(@db, id)
|
|
236
|
+
id.empty? ? nil : ClassEntry.load(@db, id) # steep:ignore
|
|
197
237
|
end
|
|
198
238
|
|
|
199
239
|
def restore_libraries(str)
|
|
@@ -210,7 +250,7 @@ module BitClust
|
|
|
210
250
|
|
|
211
251
|
def restore_entries(str, klass)
|
|
212
252
|
return [] if str.nil?
|
|
213
|
-
str.split(',').map {|id| klass.load(@db, id) }
|
|
253
|
+
str.split(',').map {|id| klass.load(@db, id) } # steep:ignore
|
|
214
254
|
end
|
|
215
255
|
|
|
216
256
|
def serialize_entry(x)
|
|
@@ -227,7 +267,7 @@ module BitClust
|
|
|
227
267
|
|
|
228
268
|
def path_string(path)
|
|
229
269
|
i = path.index(name())
|
|
230
|
-
(path[i..-1] + [name()]).join(' -> ')
|
|
270
|
+
((path[i..-1] || raise) + [name()]).join(' -> ')
|
|
231
271
|
end
|
|
232
272
|
private :path_string
|
|
233
273
|
|
|
@@ -53,6 +53,18 @@ module BitClust
|
|
|
53
53
|
@dirty_functions.clear
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
# C API の Markdown ツリー(manual/capi)を直接パースして更新する(M3)。
|
|
57
|
+
# filename は旧経路と同じ「eval.c」等(basename から .md を除いた形)
|
|
58
|
+
def update_by_markdowntree(md_root)
|
|
59
|
+
check_transaction
|
|
60
|
+
require 'bitclust/mdparser'
|
|
61
|
+
# 描画層(screen.rb)が MDCompiler を選択するためのマーカー
|
|
62
|
+
propset 'source_format', 'markdown'
|
|
63
|
+
Dir.glob(File.join(md_root, '*.md')).sort.each do |path|
|
|
64
|
+
MDFunctionParser.new(self).parse_file(path, File.basename(path, '.md'), properties())
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
56
68
|
def update_by_file(path, filename)
|
|
57
69
|
check_transaction
|
|
58
70
|
FunctionReferenceParser.new(self).parse_file(path, filename, properties())
|
|
@@ -69,7 +81,7 @@ module BitClust
|
|
|
69
81
|
def open_function(id)
|
|
70
82
|
check_transaction
|
|
71
83
|
if exist?("function/#{id}")
|
|
72
|
-
f = load_function(id)
|
|
84
|
+
f = load_function(id) || raise
|
|
73
85
|
f.clear
|
|
74
86
|
else
|
|
75
87
|
f = (@functionmap[id] ||= FunctionEntry.new(self, id))
|
|
@@ -52,6 +52,10 @@ module BitClust
|
|
|
52
52
|
remove_method :name
|
|
53
53
|
alias name id
|
|
54
54
|
alias label id
|
|
55
|
+
# bitclust#250: MethodEntry の display_label と同じインターフェースを
|
|
56
|
+
# 満たすためのエイリアス。関数には module function の概念(typemark)が
|
|
57
|
+
# ないので単に label と同じ(変換なし)
|
|
58
|
+
alias display_label label
|
|
55
59
|
|
|
56
60
|
alias macro? macro
|
|
57
61
|
alias private? private
|
|
@@ -79,7 +83,7 @@ module BitClust
|
|
|
79
83
|
end
|
|
80
84
|
|
|
81
85
|
def description
|
|
82
|
-
source.split(/\n\n+/, 2)[0].strip
|
|
86
|
+
description_text(source.split(/\n\n+/, 2)[0].strip)
|
|
83
87
|
end
|
|
84
88
|
end
|
|
85
89
|
end
|
|
@@ -61,7 +61,7 @@ module BitClust
|
|
|
61
61
|
f.name = h.name
|
|
62
62
|
f.params = h.params
|
|
63
63
|
f.source = body.join('')
|
|
64
|
-
f.source_location = body[0]&.location
|
|
64
|
+
f.source_location = body[0]&.location && Location.new(@path, nil)
|
|
65
65
|
}
|
|
66
66
|
end
|
|
67
67
|
|
|
@@ -71,9 +71,9 @@ module BitClust
|
|
|
71
71
|
raise ParseError, "syntax error: #{header.inspect}" unless m
|
|
72
72
|
h.macro = m[1] ? true : false
|
|
73
73
|
h.private = m[2] ? true : false
|
|
74
|
-
h.type = m[3]
|
|
75
|
-
h.name = m[4]
|
|
76
|
-
h.params = m[5]
|
|
74
|
+
h.type = m[3]&.strip || raise
|
|
75
|
+
h.name = m[4] || raise
|
|
76
|
+
h.params = m[5]&.strip if m[5]
|
|
77
77
|
h
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -61,6 +61,7 @@ module BitClust
|
|
|
61
61
|
]
|
|
62
62
|
argv << "--fs-casesensitive" if @fs_casesensitive
|
|
63
63
|
argv << "--quiet" unless @verbose
|
|
64
|
+
# @type var options: Subcommand::options
|
|
64
65
|
options = {
|
|
65
66
|
:prefix => @prefix,
|
|
66
67
|
:capi => @capi,
|
|
@@ -71,7 +72,7 @@ module BitClust
|
|
|
71
72
|
end
|
|
72
73
|
|
|
73
74
|
def generate_contents_opf(epub_directory)
|
|
74
|
-
items = []
|
|
75
|
+
items = [] #: Array[{:id => String, :path => Pathname}]
|
|
75
76
|
glob_relative_path(epub_directory, "#{CONTENTS_DIR_NAME}/class/*.xhtml").each do |path|
|
|
76
77
|
items << {
|
|
77
78
|
:id => decodename_package(path.basename(".*").to_s),
|
|
@@ -79,7 +80,13 @@ module BitClust
|
|
|
79
80
|
}
|
|
80
81
|
end
|
|
81
82
|
items.sort_by!{|item| item[:path] }
|
|
82
|
-
|
|
83
|
+
template = (@templatedir + "contents").read
|
|
84
|
+
if ::ERB.instance_method(:initialize).parameters.last.first == :key
|
|
85
|
+
erb = ::ERB.new(template, trim_mode: '-')
|
|
86
|
+
else
|
|
87
|
+
erb = ::ERB.new(template, nil, "-") # steep:ignore UnexpectedPositionalArgument
|
|
88
|
+
end
|
|
89
|
+
contents = erb.result(binding)
|
|
83
90
|
File.open(epub_directory + "contents.opf", "w") do |f|
|
|
84
91
|
f.write contents
|
|
85
92
|
end
|
|
@@ -94,7 +101,7 @@ module BitClust
|
|
|
94
101
|
end
|
|
95
102
|
|
|
96
103
|
def glob_relative_path(path, pattern)
|
|
97
|
-
relative_paths = []
|
|
104
|
+
relative_paths = [] #: Array[Pathname]
|
|
98
105
|
absolute_path_to_search = Pathname.new(path).realpath
|
|
99
106
|
Dir.glob(absolute_path_to_search + pattern) do |absolute_path|
|
|
100
107
|
absolute_path = Pathname.new(absolute_path)
|
data/lib/bitclust/htmlutils.rb
CHANGED
|
@@ -21,7 +21,7 @@ module BitClust
|
|
|
21
21
|
|
|
22
22
|
# make method anchor from MethodEntry
|
|
23
23
|
def link_to_method(m, specp = false)
|
|
24
|
-
label = specp ? m.
|
|
24
|
+
label = specp ? m.display_label : m.display_short_label
|
|
25
25
|
a_href(@urlmapper.method_url(methodid2specstring(m.id)), label)
|
|
26
26
|
end
|
|
27
27
|
|