bitclust-core 1.2.1 → 1.2.6

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/data/bitclust/catalog/ja_JP.UTF-8 +4 -0
  3. data/data/bitclust/template.lillia/layout +1 -1
  4. data/data/bitclust/template.offline/class +127 -34
  5. data/data/bitclust/template.offline/class-index +33 -6
  6. data/data/bitclust/template.offline/doc +41 -8
  7. data/data/bitclust/template.offline/function +42 -9
  8. data/data/bitclust/template.offline/function-index +33 -7
  9. data/data/bitclust/template.offline/layout +21 -14
  10. data/data/bitclust/template.offline/library +48 -12
  11. data/data/bitclust/template.offline/library-index +33 -6
  12. data/data/bitclust/template.offline/method +56 -11
  13. data/lib/bitclust/classentry.rb +13 -2
  14. data/lib/bitclust/compat.rb +8 -0
  15. data/lib/bitclust/completion.rb +1 -0
  16. data/lib/bitclust/docentry.rb +4 -2
  17. data/lib/bitclust/entry.rb +3 -0
  18. data/lib/bitclust/functionentry.rb +8 -7
  19. data/lib/bitclust/functionreferenceparser.rb +2 -0
  20. data/lib/bitclust/libraryentry.rb +4 -1
  21. data/lib/bitclust/lineinput.rb +6 -2
  22. data/lib/bitclust/methoddatabase.rb +3 -0
  23. data/lib/bitclust/methodentry.rb +10 -8
  24. data/lib/bitclust/methodid.rb +1 -0
  25. data/lib/bitclust/nameutils.rb +15 -11
  26. data/lib/bitclust/preprocessor.rb +26 -21
  27. data/lib/bitclust/rdcompiler.rb +29 -19
  28. data/lib/bitclust/requesthandler.rb +3 -3
  29. data/lib/bitclust/ridatabase.rb +2 -1
  30. data/lib/bitclust/rrdparser.rb +19 -20
  31. data/lib/bitclust/screen.rb +39 -4
  32. data/lib/bitclust/silent_progress_bar.rb +8 -4
  33. data/lib/bitclust/simplesearcher.rb +1 -1
  34. data/lib/bitclust/subcommand.rb +9 -0
  35. data/lib/bitclust/subcommands/chm_command.rb +3 -3
  36. data/lib/bitclust/subcommands/methods_command.rb +1 -1
  37. data/lib/bitclust/subcommands/server_command.rb +6 -1
  38. data/lib/bitclust/subcommands/setup_command.rb +2 -2
  39. data/lib/bitclust/subcommands/statichtml_command.rb +44 -21
  40. data/lib/bitclust/syntax_highlighter.rb +5 -3
  41. data/lib/bitclust/version.rb +1 -1
  42. data/test/test_bitclust.rb +1 -1
  43. data/test/test_entry.rb +14 -1
  44. data/test/test_functionreferenceparser.rb +4 -4
  45. data/test/test_preprocessor.rb +21 -0
  46. data/test/test_rdcompiler.rb +240 -0
  47. data/test/test_rrdparser.rb +16 -0
  48. data/test/test_syntax_highlighter.rb +22 -4
  49. data/theme/default/rurema.png +0 -0
  50. data/theme/default/rurema.svg +31 -0
  51. data/theme/default/script.js +34 -0
  52. data/theme/default/style.css +112 -8
  53. metadata +32 -19
@@ -9,6 +9,7 @@
9
9
  #
10
10
 
11
11
  require 'stringio'
12
+ require 'bitclust/parseutils'
12
13
 
13
14
  # Utility class for line-wise file parsing
14
15
  class LineInput
@@ -34,7 +35,7 @@ class LineInput
34
35
  end
35
36
 
36
37
  def path
37
- @input.path
38
+ @input.path if @input.respond_to?(:path)
38
39
  end
39
40
 
40
41
  def name
@@ -52,12 +53,15 @@ class LineInput
52
53
  def gets
53
54
  unless @buf.empty?
54
55
  @lineno += 1
55
- return @buf.pop
56
+ line = @buf.pop
57
+ line&.location ||= BitClust::Location.new(path, @lineno)
58
+ return line
56
59
  end
57
60
  return nil if @eof_p # to avoid ARGF blocking.
58
61
  line = @input.gets
59
62
  @eof_p = true unless line
60
63
  @lineno += 1
64
+ line&.location ||= BitClust::Location.new(path, @lineno)
61
65
  line
62
66
  end
63
67
 
@@ -175,14 +175,17 @@ module BitClust
175
175
  end
176
176
 
177
177
  def copy_doc
178
+ root_path = Pathname.new(@root).expand_path
178
179
  Dir.glob("#{@root}/../../doc/**/*.rd").each do |f|
179
180
  if %r!\A#{Regexp.escape(@root)}/\.\./\.\./doc/([-\./\w]+)\.rd\z! =~ f
180
181
  id = libname2id($1)
181
182
  se = DocEntry.new(self, id)
182
183
  s = Preprocessor.read(f, properties)
183
184
  title, source = RRDParser.split_doc(s)
185
+ relative_path = Pathname.new(f).expand_path(@root).relative_path_from(root_path)
184
186
  se.title = title
185
187
  se.source = source
188
+ se.source_location = Location.new(relative_path, 1)
186
189
  se.save
187
190
  end
188
191
  end
@@ -29,6 +29,7 @@ module BitClust
29
29
  attr_reader :id
30
30
 
31
31
  def ==(other)
32
+ return false if self.class != other.class
32
33
  @id == other.id
33
34
  end
34
35
 
@@ -94,14 +95,15 @@ module BitClust
94
95
  attr_writer :klass
95
96
 
96
97
  persistent_properties {
97
- property :names, '[String]'
98
- property :visibility, 'Symbol' # :public | :private | :protected
99
- property :kind, 'Symbol' # :defined | :added | :redefined
100
- property :source, 'String'
98
+ property :names, '[String]'
99
+ property :visibility, 'Symbol' # :public | :private | :protected
100
+ property :kind, 'Symbol' # :defined | :added | :redefined
101
+ property :source, 'String'
102
+ property :source_location, 'Location'
101
103
  }
102
104
 
103
105
  def inspect
104
- c, t, m, lib = methodid2specparts(@id)
106
+ c, t, _m, _lib = methodid2specparts(@id)
105
107
  "\#<method #{c}#{t}#{names().join(',')}>"
106
108
  end
107
109
 
@@ -114,12 +116,12 @@ module BitClust
114
116
  end
115
117
 
116
118
  def label
117
- c, t, m, lib = methodid2specparts(@id)
119
+ c, t, m, _lib = methodid2specparts(@id)
118
120
  "#{t == '$' ? '' : c}#{t}#{m}"
119
121
  end
120
122
 
121
123
  def short_label
122
- c, t, m, lib = methodid2specparts(@id)
124
+ _c, t, m, _lib = methodid2specparts(@id)
123
125
  "#{t == '#' ? '' : t}#{m}"
124
126
  end
125
127
 
@@ -128,7 +130,7 @@ module BitClust
128
130
  end
129
131
 
130
132
  def labels
131
- c, t, m, lib = methodid2specparts(@id)
133
+ c, t, _m, _lib = methodid2specparts(@id)
132
134
  names().map {|name| "#{c}#{t}#{name}" }
133
135
  end
134
136
 
@@ -93,6 +93,7 @@ module BitClust
93
93
  end
94
94
 
95
95
  def ==(other)
96
+ return false if self.class != other.class
96
97
  @klass == other.klass and
97
98
  @type == other.type and
98
99
  @method == other.method
@@ -19,8 +19,8 @@ module BitClust
19
19
  LIBNAME_RE = %r<[\w\-]+(/[\w\-]+)*>
20
20
  CONST_RE = /[A-Z]\w*/
21
21
  CONST_PATH_RE = /#{CONST_RE}(?:::#{CONST_RE})*/
22
- CLASS_NAME_RE = /(?:#{CONST_RE}(?:::compatible)?|fatal|ARGF.class|main)/
23
- CLASS_PATH_RE = /(?:#{CONST_PATH_RE}(?:::compatible)?|fatal|ARGF.class|main)/
22
+ CLASS_NAME_RE = /(?:#{CONST_RE}(?:::compatible)?|fatal|ARGF\.class|main)/
23
+ CLASS_PATH_RE = /(?:#{CONST_PATH_RE}(?:::compatible)?|fatal|ARGF\.class|main)/
24
24
  METHOD_NAME_RE = /\w+[?!=]?|===|==|=~|<=>|<=|>=|!=|!~|!@|!|\[\]=|\[\]|\*\*|>>|<<|\+@|\-@|[~+\-*\/%&|^<>`]/
25
25
  TYPEMARK_RE = /(?:\.|\#|\.\#|::|\$)/
26
26
  METHOD_SPEC_RE = /#{CLASS_PATH_RE}#{TYPEMARK_RE}#{METHOD_NAME_RE}/
@@ -67,7 +67,7 @@ module BitClust
67
67
  end
68
68
 
69
69
  def methodid2specstring(id)
70
- c, t, m, lib = *split_method_id(id)
70
+ c, t, m, _lib = *split_method_id(id)
71
71
  classid2name(c) + typechar2mark(t) + decodename_url(m)
72
72
  end
73
73
 
@@ -77,32 +77,32 @@ module BitClust
77
77
  end
78
78
 
79
79
  def methodid2libid(id)
80
- c, t, m, lib = *split_method_id(id)
80
+ _c, _t, _m, lib = *split_method_id(id)
81
81
  lib
82
82
  end
83
83
 
84
84
  def methodid2classid(id)
85
- c, t, m, lib = *split_method_id(id)
85
+ c, _t, _m, _lib = *split_method_id(id)
86
86
  c
87
87
  end
88
88
 
89
89
  def methodid2typechar(id)
90
- c, t, m, lib = *split_method_id(id)
90
+ _c, t, _m, _lib = *split_method_id(id)
91
91
  t
92
92
  end
93
93
 
94
94
  def methodid2typename(id)
95
- c, t, m, lib = *split_method_id(id)
95
+ _c, t, _m, _lib = *split_method_id(id)
96
96
  typechar2name(t)
97
97
  end
98
98
 
99
99
  def methodid2typemark(id)
100
- c, t, m, lib = *split_method_id(id)
100
+ _c, t, _m, _lib = *split_method_id(id)
101
101
  typechar2mark(t)
102
102
  end
103
103
 
104
104
  def methodid2mname(id)
105
- c, t, m, lib = *split_method_id(id)
105
+ _c, _t, m, _lib = *split_method_id(id)
106
106
  decodename_url(m)
107
107
  end
108
108
 
@@ -120,10 +120,14 @@ module BitClust
120
120
  "#{cid}/#{typename2char(t)}.#{encodename_url(name)}.#{libid}"
121
121
  end
122
122
 
123
+ @@split_method_id = {}
124
+
123
125
  # private module function
124
126
  def split_method_id(id)
125
- c, rest = id.split("/")
126
- return *[c, *rest.split(%r<[/\.]>, 3)]
127
+ @@split_method_id[id] ||= begin
128
+ c, rest = id.split("/")
129
+ [c, *rest.split(%r<[/\.]>, 3)]
130
+ end
127
131
  end
128
132
 
129
133
  NAME_TO_MARK = {
@@ -71,11 +71,20 @@ module BitClust
71
71
  cond_init
72
72
  end
73
73
 
74
+ def path
75
+ @f.path if @f.respond_to?(:path)
76
+ end
77
+
74
78
  private
75
79
 
76
80
  def next_line(f)
77
81
  while line = f.gets
78
82
  case line
83
+ when /\A(?!\#@)/
84
+ if current_cond.processing?
85
+ @buf.push line
86
+ break
87
+ end
79
88
  when /\A\#@\#/ # preprocessor comment
80
89
  ;
81
90
  when /\A\#@todo/i
@@ -86,7 +95,7 @@ module BitClust
86
95
  file = $1.strip
87
96
  basedir = File.dirname(line.location.file)
88
97
  @buf.concat Preprocessor.process("#{basedir}/#{file}", @params)
89
- rescue Errno::ENOENT => err
98
+ rescue Errno::ENOENT => _err
90
99
  raise WrongInclude, "#{line.location}: \#@include'ed file not exist: #{file}"
91
100
  end
92
101
  when /\A\#@since\b/
@@ -107,13 +116,8 @@ module BitClust
107
116
  parse_error "no matching \#@if", line if cond_toplevel?
108
117
  cond_pop
109
118
  end
110
- when /\A\#@/
111
- parse_error "unknown preprocessor directive", line
112
119
  else
113
- if current_cond.processing?
114
- @buf.push line
115
- break
116
- end
120
+ parse_error "unknown preprocessor directive", line
117
121
  end
118
122
  end
119
123
  if @buf.empty?
@@ -149,7 +153,7 @@ module BitClust
149
153
  end
150
154
 
151
155
  def cond_init
152
- @state_stack = [State.new(nil, :toplevel)]
156
+ @state_stack = [State.new(true, :toplevel)]
153
157
  end
154
158
 
155
159
  def cond_toplevel?
@@ -158,13 +162,13 @@ module BitClust
158
162
 
159
163
  def cond_push(bool)
160
164
  last = @state_stack.last
161
- @state_stack.push(State.new(last.current, bool))
165
+ @state_stack.push(last.next(bool, :condition))
162
166
  end
163
167
 
164
168
  def cond_invert
165
169
  b = @state_stack.pop.processing?
166
170
  last = @state_stack.last
167
- @state_stack.push(State.new(last.current, !b))
171
+ @state_stack.push(last.next(!b, :condition))
168
172
  end
169
173
 
170
174
  def cond_pop
@@ -254,7 +258,7 @@ module BitClust
254
258
 
255
259
  def samplecode_push(description)
256
260
  last = @state_stack.last
257
- @state_stack.push(State.new(last.current, :samplecode))
261
+ @state_stack.push(last.next(true, :samplecode))
258
262
  end
259
263
 
260
264
  def samplecode_pop
@@ -276,24 +280,25 @@ module BitClust
276
280
  class State
277
281
  attr_reader :current
278
282
 
279
- def initialize(previous, current)
280
- @previous = previous
281
- @current = current
283
+ def initialize(is_processing, label)
284
+ @is_processing = is_processing
285
+ @label = label
286
+ end
287
+
288
+ def next(is_processing, label)
289
+ State.new(@is_processing && is_processing, label)
282
290
  end
283
291
 
284
292
  def toplevel?
285
- @current == :toplevel
293
+ @label == :toplevel
286
294
  end
287
295
 
288
296
  def processing?
289
- toplevel? ||
290
- (@current == true && @previous != false) ||
291
- (@current == :samplecode && @previous == true) ||
292
- (@current == :samplecode && @previous == :toplevel)
297
+ @is_processing
293
298
  end
294
299
 
295
300
  def samplecode?
296
- @current == :samplecode
301
+ @label == :samplecode
297
302
  end
298
303
  end
299
304
  end
@@ -320,7 +325,7 @@ module BitClust
320
325
  file = $1.strip
321
326
  basedir = File.dirname(line.location.file)
322
327
  @buf.concat LineCollector.process("#{basedir}/#{file}")
323
- rescue Errno::ENOENT => err
328
+ rescue Errno::ENOENT => _err
324
329
  raise WrongInclude, "#{line.location}: \#@include'ed file not exist: #{file}"
325
330
  end
326
331
  else
@@ -229,11 +229,9 @@ module BitClust
229
229
  case @f.peek
230
230
  when /\A$/
231
231
  @f.gets
232
- when /\A[ \t\z]/
232
+ when /\A[ \t]/
233
233
  line '<p>'
234
- @f.while_match(/\A[ \t\z]/) do |line|
235
- line compile_text(line.strip)
236
- end
234
+ line compile_text(text_node_from_lines(@f.span(/\A[ \t]/)))
237
235
  line '</p>'
238
236
  when %r!\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{!
239
237
  emlist
@@ -249,10 +247,8 @@ module BitClust
249
247
  line '<dd>'
250
248
  while /\A[ \t]/ =~ @f.peek or %r!\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{! =~ @f.peek
251
249
  case @f.peek
252
- when /\A[ \t\z]/
253
- @f.while_match(/\A[ \t\z]/) do |line|
254
- line compile_text(line.strip)
255
- end
250
+ when /\A[ \t]/
251
+ line compile_text(text_node_from_lines(@f.span(/\A[ \t]/)))
256
252
  when %r!\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{!
257
253
  emlist
258
254
  end
@@ -264,6 +260,11 @@ module BitClust
264
260
  "<dt>#{s}</dt>"
265
261
  end
266
262
 
263
+ def stop_on_syntax_error?
264
+ return true unless @option.key?(:stop_on_syntax_error)
265
+ @option[:stop_on_syntax_error]
266
+ end
267
+
267
268
  def emlist
268
269
  command = @f.gets
269
270
  if %r!\A//emlist\[(?<caption>[^\[\]]+?)?\]\[(?<lang>\w+?)\]! =~ command
@@ -280,7 +281,11 @@ module BitClust
280
281
  string BitClust::SyntaxHighlighter.new(src, filename).highlight
281
282
  rescue BitClust::SyntaxHighlighter::Error => ex
282
283
  $stderr.puts ex.message
283
- exit(false)
284
+ if stop_on_syntax_error?
285
+ exit(false)
286
+ else
287
+ string src
288
+ end
284
289
  end
285
290
  else
286
291
  string src
@@ -313,9 +318,7 @@ module BitClust
313
318
 
314
319
  def paragraph
315
320
  line '<p>'
316
- read_paragraph(@f).each do |line|
317
- line compile_text(line.strip)
318
- end
321
+ line compile_text(text_node_from_lines(read_paragraph(@f)))
319
322
  line '</p>'
320
323
  end
321
324
 
@@ -325,16 +328,16 @@ module BitClust
325
328
 
326
329
  def see
327
330
  header = @f.gets
328
- cmd = header.slice!(/\A\@\w+/)
331
+ header.slice!(/\A\@\w+/)
329
332
  body = [header] + @f.span(/\A\s+\S/)
330
333
  line '<p>'
331
- line '[SEE_ALSO] ' + compile_text(body.join('').strip)
334
+ line '[SEE_ALSO] ' + compile_text(text_node_from_lines(body))
332
335
  line '</p>'
333
336
  end
334
337
 
335
338
  def todo
336
339
  header = @f.gets
337
- cmd = header.slice!(/\A\@\w+/)
340
+ header.slice!(/\A\@\w+/)
338
341
  body = header
339
342
  line '<p class="todo">'
340
343
  line '[TODO]' + body
@@ -368,9 +371,7 @@ module BitClust
368
371
  # FIXME: parse @param, @return, ...
369
372
  def entry_paragraph
370
373
  line '<p>'
371
- read_entry_paragraph(@f).each do |line|
372
- line compile_text(line.strip)
373
- end
374
+ line compile_text(text_node_from_lines(read_entry_paragraph(@f)))
374
375
  line '</p>'
375
376
  end
376
377
 
@@ -392,6 +393,10 @@ module BitClust
392
393
  string a_href(@urlmapper.method_url(methodid2specstring(@method.id)), "permalink")
393
394
  string ']['
394
395
  string rdoc_link(@method.id, @option[:database].properties["version"])
396
+ if @option[:edit_base_url] && @method.source_location
397
+ string ']['
398
+ string a_href(@urlmapper.edit_url(@method.source_location), 'edit')
399
+ end
395
400
  string ']</span>'
396
401
  end
397
402
  if @method and not @method.defined?
@@ -552,7 +557,7 @@ module BitClust
552
557
  end
553
558
 
554
559
  def rdoc_url(method_id, version)
555
- cname, tmark, mname, libname = methodid2specparts(method_id)
560
+ cname, tmark, mname, _libname = methodid2specparts(method_id)
556
561
  tchar = typemark2char(tmark) == 'i' ? 'i' : 'c'
557
562
  cname = cname.split(".").first
558
563
  cname = cname.gsub('::', '/')
@@ -591,6 +596,11 @@ module BitClust
591
596
  @out.puts
592
597
  end
593
598
 
599
+ def text_node_from_lines(lines)
600
+ lines.map(&:strip).join("\n").gsub(/(\P{ascii})\n(\P{ascii})/) do
601
+ "#{::Regexp.last_match(1)}#{::Regexp.last_match(2)}"
602
+ end
603
+ end
594
604
  end
595
605
 
596
606
  end
@@ -207,7 +207,7 @@ module BitClust
207
207
  end
208
208
 
209
209
  def defined_type?
210
- type, param = parse_path_info()
210
+ type, _param = parse_path_info()
211
211
  case type
212
212
  when 'library', 'class', 'method', 'function', 'search', 'opensearchdescription'
213
213
  true
@@ -217,7 +217,7 @@ module BitClust
217
217
  end
218
218
 
219
219
  def type_id
220
- type, param = parse_path_info()
220
+ type, _param = parse_path_info()
221
221
  type.intern if type
222
222
  end
223
223
 
@@ -256,7 +256,7 @@ module BitClust
256
256
  private
257
257
 
258
258
  def type_param
259
- type, param = parse_path_info()
259
+ _type, param = parse_path_info()
260
260
  return nil unless param
261
261
  return nil if param.empty?
262
262
  param