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.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/README.md +65 -0
  4. data/Rakefile +32 -0
  5. data/data/bitclust/catalog/ja_JP.UTF-8 +19 -1
  6. data/data/bitclust/searchpage/index.html +90 -0
  7. data/data/bitclust/template/class +69 -8
  8. data/data/bitclust/template/function +2 -2
  9. data/data/bitclust/template/layout +11 -3
  10. data/data/bitclust/template/method +2 -2
  11. data/data/bitclust/template/search +1 -1
  12. data/data/bitclust/template.epub/class +22 -1
  13. data/data/bitclust/template.epub/function +2 -2
  14. data/data/bitclust/template.epub/layout +1 -3
  15. data/data/bitclust/template.epub/method +2 -2
  16. data/data/bitclust/template.lillia/class +26 -5
  17. data/data/bitclust/template.lillia/layout +1 -3
  18. data/data/bitclust/template.lillia/method +2 -2
  19. data/data/bitclust/template.offline/class +48 -4
  20. data/data/bitclust/template.offline/function +2 -2
  21. data/data/bitclust/template.offline/layout +27 -3
  22. data/data/bitclust/template.offline/method +2 -2
  23. data/lib/bitclust/app.rb +16 -17
  24. data/lib/bitclust/capi_converter.rb +20 -0
  25. data/lib/bitclust/classentry.rb +67 -17
  26. data/lib/bitclust/compat.rb +2 -2
  27. data/lib/bitclust/completion.rb +58 -27
  28. data/lib/bitclust/crossrubyutils.rb +8 -5
  29. data/lib/bitclust/database.rb +28 -8
  30. data/lib/bitclust/doc_converter.rb +63 -0
  31. data/lib/bitclust/docentry.rb +1 -1
  32. data/lib/bitclust/entity_splitter.rb +221 -0
  33. data/lib/bitclust/entry.rb +47 -7
  34. data/lib/bitclust/functiondatabase.rb +13 -1
  35. data/lib/bitclust/functionentry.rb +5 -1
  36. data/lib/bitclust/functionreferenceparser.rb +4 -4
  37. data/lib/bitclust/generators/epub.rb +10 -3
  38. data/lib/bitclust/htmlutils.rb +1 -1
  39. data/lib/bitclust/include_graph.rb +375 -0
  40. data/lib/bitclust/include_pruner.rb +144 -0
  41. data/lib/bitclust/interface.rb +1 -1
  42. data/lib/bitclust/libraryentry.rb +8 -7
  43. data/lib/bitclust/lineinput.rb +7 -5
  44. data/lib/bitclust/link_checker.rb +179 -0
  45. data/lib/bitclust/markdown_bridge.rb +186 -0
  46. data/lib/bitclust/markdown_orchestrator.rb +267 -0
  47. data/lib/bitclust/markdown_to_rrd.rb +824 -0
  48. data/lib/bitclust/markdown_tree.rb +217 -0
  49. data/lib/bitclust/mdcompiler.rb +883 -0
  50. data/lib/bitclust/mdparser.rb +347 -0
  51. data/lib/bitclust/messagecatalog.rb +3 -3
  52. data/lib/bitclust/method_since_calculator.rb +117 -0
  53. data/lib/bitclust/methoddatabase.rb +124 -14
  54. data/lib/bitclust/methodentry.rb +125 -7
  55. data/lib/bitclust/methodid.rb +12 -11
  56. data/lib/bitclust/methodsignature.rb +10 -4
  57. data/lib/bitclust/nameutils.rb +41 -22
  58. data/lib/bitclust/preprocessor.rb +66 -29
  59. data/lib/bitclust/rdcompiler.rb +195 -95
  60. data/lib/bitclust/refsdatabase.rb +23 -8
  61. data/lib/bitclust/reloadable_request_handler.rb +72 -0
  62. data/lib/bitclust/requesthandler.rb +21 -16
  63. data/lib/bitclust/ridatabase.rb +10 -4
  64. data/lib/bitclust/rrd_to_markdown.rb +925 -0
  65. data/lib/bitclust/rrdparser.rb +196 -30
  66. data/lib/bitclust/runner.rb +17 -2
  67. data/lib/bitclust/screen.rb +80 -11
  68. data/lib/bitclust/search_index_generator.rb +288 -0
  69. data/lib/bitclust/searcher.rb +69 -20
  70. data/lib/bitclust/simplesearcher.rb +24 -12
  71. data/lib/bitclust/subcommand.rb +7 -1
  72. data/lib/bitclust/subcommands/ancestors_command.rb +9 -2
  73. data/lib/bitclust/subcommands/checklink_command.rb +54 -0
  74. data/lib/bitclust/subcommands/chm_command.rb +15 -7
  75. data/lib/bitclust/subcommands/classes_command.rb +5 -0
  76. data/lib/bitclust/subcommands/extract_command.rb +5 -0
  77. data/lib/bitclust/subcommands/htmlfile_command.rb +21 -7
  78. data/lib/bitclust/subcommands/init_command.rb +4 -1
  79. data/lib/bitclust/subcommands/list_command.rb +12 -4
  80. data/lib/bitclust/subcommands/lookup_command.rb +28 -9
  81. data/lib/bitclust/subcommands/methods_command.rb +10 -2
  82. data/lib/bitclust/subcommands/methodsince_command.rb +80 -0
  83. data/lib/bitclust/subcommands/preproc_command.rb +5 -0
  84. data/lib/bitclust/subcommands/property_command.rb +2 -1
  85. data/lib/bitclust/subcommands/searchpage_command.rb +102 -0
  86. data/lib/bitclust/subcommands/server_command.rb +10 -8
  87. data/lib/bitclust/subcommands/setup_command.rb +24 -10
  88. data/lib/bitclust/subcommands/statichtml_command.rb +129 -6
  89. data/lib/bitclust/subcommands/update_command.rb +110 -2
  90. data/lib/bitclust/syntax_highlighter.rb +48 -4
  91. data/lib/bitclust/textutils.rb +3 -3
  92. data/lib/bitclust/version.rb +1 -1
  93. data/lib/bitclust/version_badges.rb +90 -0
  94. data/lib/bitclust/whole_file_gate.rb +137 -0
  95. data/test/test_app.rb +269 -0
  96. data/test/test_bitclust.rb +2 -0
  97. data/test/test_capi_converter.rb +91 -0
  98. data/test/test_class_screen.rb +413 -0
  99. data/test/test_copy_doc_md.rb +53 -0
  100. data/test/test_doc_converter.rb +78 -0
  101. data/test/test_entity_splitter.rb +231 -0
  102. data/test/test_entry.rb +207 -2
  103. data/test/test_eol_warning.rb +43 -0
  104. data/test/test_functionreferenceparser.rb +11 -0
  105. data/test/test_include_graph.rb +640 -0
  106. data/test/test_include_pruner.rb +133 -0
  107. data/test/test_link_checker.rb +114 -0
  108. data/test/test_lookup_command.rb +135 -0
  109. data/test/test_markdown_bridge.rb +217 -0
  110. data/test/test_markdown_orchestrator.rb +478 -0
  111. data/test/test_markdown_to_rrd.rb +757 -0
  112. data/test/test_markdown_tree.rb +369 -0
  113. data/test/test_mdcompiler.rb +1276 -0
  114. data/test/test_mdparser.rb +538 -0
  115. data/test/test_method_screen.rb +166 -0
  116. data/test/test_method_since_calculator.rb +290 -0
  117. data/test/test_methoddatabase.rb +16 -0
  118. data/test/test_methodentry.rb +328 -0
  119. data/test/test_methodsignature.rb +3 -1
  120. data/test/test_methodsince_command.rb +168 -0
  121. data/test/test_nameutils.rb +22 -0
  122. data/test/test_preprocessor.rb +215 -0
  123. data/test/test_rdcompiler.rb +401 -30
  124. data/test/test_refsdatabase.rb +32 -0
  125. data/test/test_rrd_to_markdown.rb +968 -0
  126. data/test/test_rrdparser.rb +295 -2
  127. data/test/test_run_ruby_wasm.rb +54 -0
  128. data/test/test_run_worker_prelude.rb +83 -0
  129. data/test/test_runner.rb +51 -0
  130. data/test/test_search_index_generator.rb +513 -0
  131. data/test/test_search_screen.rb +48 -0
  132. data/test/test_searcher.rb +132 -0
  133. data/test/test_searchpage_command.rb +167 -0
  134. data/test/test_simplesearcher.rb +28 -0
  135. data/test/test_statichtml_command.rb +204 -0
  136. data/test/test_syntax_highlighter.rb +60 -0
  137. data/test/test_whole_file_gate.rb +175 -0
  138. data/theme/default/js/NOTICE +42 -0
  139. data/theme/default/js/run-worker.js +111 -0
  140. data/theme/default/js/run.js +350 -0
  141. data/theme/default/js/search_controller.js +134 -0
  142. data/theme/default/js/search_init.js +176 -0
  143. data/theme/default/js/search_navigation.js +110 -0
  144. data/theme/default/js/search_page.js +202 -0
  145. data/theme/default/js/search_ranker.js +244 -0
  146. data/theme/default/script.js +91 -18
  147. data/theme/default/search.css +149 -0
  148. data/theme/default/style.css +193 -21
  149. data/theme/default/syntax-highlight.css +8 -0
  150. data/theme/lillia/style.css +45 -1
  151. metadata +161 -20
  152. 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
@@ -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(*loc.split(?:)) }"
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 "@#@name.to_s"
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&.tap {|loc| break Location.new(@path, loc.line - 1) }
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].strip
75
- h.name = m[4]
76
- h.params = m[5].strip if 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
- contents = ERB.new(File.read(@templatedir + "contents"), nil, "-").result(binding)
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)
@@ -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.label : m.short_label
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