yard 0.9.37 → 0.9.41
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/CHANGELOG.md +52 -1
- data/README.md +27 -30
- data/docs/GettingStarted.md +41 -15
- data/docs/Tags.md +5 -5
- data/docs/Templates.md +5 -4
- data/docs/WhatsNew.md +59 -7
- data/docs/templates/default/yard_tags/html/setup.rb +1 -1
- data/lib/yard/autoload.rb +17 -0
- data/lib/yard/cli/diff.rb +7 -2
- data/lib/yard/code_objects/base.rb +1 -1
- data/lib/yard/code_objects/extra_file_object.rb +1 -0
- data/lib/yard/code_objects/proxy.rb +1 -1
- data/lib/yard/handlers/base.rb +23 -1
- data/lib/yard/handlers/processor.rb +1 -0
- data/lib/yard/handlers/rbs/attribute_handler.rb +43 -0
- data/lib/yard/handlers/rbs/base.rb +38 -0
- data/lib/yard/handlers/rbs/constant_handler.rb +18 -0
- data/lib/yard/handlers/rbs/method_handler.rb +327 -0
- data/lib/yard/handlers/rbs/mixin_handler.rb +20 -0
- data/lib/yard/handlers/rbs/namespace_handler.rb +26 -0
- data/lib/yard/handlers/ruby/attribute_handler.rb +7 -4
- data/lib/yard/handlers/ruby/constant_handler.rb +24 -6
- data/lib/yard/handlers/ruby/legacy/visibility_handler.rb +2 -1
- data/lib/yard/handlers/ruby/visibility_handler.rb +1 -0
- data/lib/yard/i18n/locale.rb +1 -1
- data/lib/yard/i18n/pot_generator.rb +1 -1
- data/lib/yard/parser/rbs/rbs_parser.rb +325 -0
- data/lib/yard/parser/rbs/statement.rb +75 -0
- data/lib/yard/parser/ruby/ast_node.rb +5 -4
- data/lib/yard/parser/ruby/legacy/irb/slex.rb +19 -1
- data/lib/yard/parser/ruby/legacy/ruby_lex.rb +1 -1
- data/lib/yard/parser/ruby/ruby_parser.rb +109 -24
- data/lib/yard/parser/source_parser.rb +3 -2
- data/lib/yard/registry_resolver.rb +7 -0
- data/lib/yard/rubygems/specification.rb +1 -1
- data/lib/yard/server/library_version.rb +1 -1
- data/lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js +208 -12
- data/lib/yard/server/templates/default/layout/html/breadcrumb.erb +1 -17
- data/lib/yard/server/templates/default/method_details/html/permalink.erb +4 -2
- data/lib/yard/server/templates/doc_server/library_list/html/headers.erb +3 -3
- data/lib/yard/server/templates/doc_server/library_list/html/library_list.erb +2 -3
- data/lib/yard/server/templates/doc_server/processing/html/processing.erb +22 -16
- data/lib/yard/tags/directives.rb +7 -0
- data/lib/yard/tags/library.rb +3 -3
- data/lib/yard/tags/overload_tag.rb +2 -1
- data/lib/yard/tags/tag.rb +1 -1
- data/lib/yard/tags/types_explainer.rb +5 -4
- data/lib/yard/templates/helpers/base_helper.rb +1 -1
- data/lib/yard/templates/helpers/html_helper.rb +21 -6
- data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +6 -1
- data/lib/yard/templates/helpers/markup/hybrid_markdown.rb +2147 -0
- data/lib/yard/templates/helpers/markup/rdoc_markup.rb +2 -0
- data/lib/yard/templates/helpers/markup_helper.rb +4 -2
- data/lib/yard/version.rb +1 -1
- data/po/ja.po +82 -82
- data/templates/default/fulldoc/html/css/style.css +33 -15
- data/templates/default/fulldoc/html/full_list.erb +4 -4
- data/templates/default/fulldoc/html/js/app.js +567 -271
- data/templates/default/fulldoc/html/js/full_list.js +341 -211
- data/templates/default/layout/html/headers.erb +1 -1
- data/templates/default/layout/html/layout.erb +2 -1
- data/templates/default/method/html/header.erb +3 -3
- data/templates/default/module/html/defines.erb +3 -3
- data/templates/default/module/html/inherited_methods.erb +1 -0
- data/templates/default/module/html/method_summary.erb +8 -0
- data/templates/default/module/setup.rb +20 -0
- data/templates/default/onefile/html/layout.erb +3 -4
- data/templates/guide/fulldoc/html/js/app.js +57 -26
- data/templates/guide/layout/html/layout.erb +9 -11
- metadata +18 -8
|
@@ -236,14 +236,26 @@ module YARD
|
|
|
236
236
|
|
|
237
237
|
def visit_event(node)
|
|
238
238
|
map = @map[MAPPINGS[node.type]]
|
|
239
|
-
|
|
239
|
+
|
|
240
|
+
# Pattern matching and `in` syntax creates :case nodes without 'case' tokens,
|
|
241
|
+
# fall back to the first child node.
|
|
242
|
+
if node.type == :case && (!map || map.empty?) && (child_node = node[0])
|
|
243
|
+
lstart = child_node.line_range.first
|
|
244
|
+
sstart = child_node.source_range.first
|
|
245
|
+
else
|
|
246
|
+
lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1])
|
|
247
|
+
(@map[:rbrace] ||= []).shift if map && MAPPINGS[node.type] == :lbrace
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
raise "Cannot determine start of node #{node} around #{file}:#{lineno}" if lstart.nil? || sstart.nil?
|
|
251
|
+
|
|
240
252
|
node.source_range = Range.new(sstart, @ns_charno - 1)
|
|
241
253
|
node.line_range = Range.new(lstart, lineno)
|
|
242
254
|
if node.respond_to?(:block)
|
|
243
255
|
sr = node.block.source_range
|
|
244
256
|
lr = node.block.line_range
|
|
245
|
-
node.block.source_range = Range.new(sr.
|
|
246
|
-
node.block.line_range = Range.new(lr.
|
|
257
|
+
node.block.source_range = Range.new(sr.begin, @tokens.last[2][1] - 1)
|
|
258
|
+
node.block.line_range = Range.new(lr.begin, @tokens.last[2][0])
|
|
247
259
|
end
|
|
248
260
|
node
|
|
249
261
|
end
|
|
@@ -259,7 +271,10 @@ module YARD
|
|
|
259
271
|
def visit_ns_token(token, data, ast_token = false)
|
|
260
272
|
add_token(token, data)
|
|
261
273
|
ch = charno
|
|
262
|
-
|
|
274
|
+
|
|
275
|
+
# For purposes of tracking parsing state, don't treat keywords as such
|
|
276
|
+
# where used as a symbol identifier.
|
|
277
|
+
@last_ns_token = [@last_ns_token && @last_ns_token.first == :symbeg ? :symbol : token, data]
|
|
263
278
|
@charno += data.length
|
|
264
279
|
@ns_charno = charno
|
|
265
280
|
@newline = [:semicolon, :comment, :kw, :op, :lparen, :lbrace].include?(token)
|
|
@@ -272,14 +287,14 @@ module YARD
|
|
|
272
287
|
if @percent_ary
|
|
273
288
|
if token == :words_sep && data !~ /\s\z/
|
|
274
289
|
rng = @percent_ary.source_range
|
|
275
|
-
rng = Range.new(rng.
|
|
290
|
+
rng = Range.new(rng.begin, rng.end.to_i + data.length)
|
|
276
291
|
@percent_ary.source_range = rng
|
|
277
292
|
@tokens << [token, data, [lineno, charno]]
|
|
278
293
|
@percent_ary = nil
|
|
279
294
|
return
|
|
280
295
|
elsif token == :tstring_end && data =~ /\A\s/
|
|
281
296
|
rng = @percent_ary.source_range
|
|
282
|
-
rng = Range.new(rng.
|
|
297
|
+
rng = Range.new(rng.begin, rng.end.to_i + data.length)
|
|
283
298
|
@percent_ary.source_range = rng
|
|
284
299
|
@tokens << [token, data, [lineno, charno]]
|
|
285
300
|
@percent_ary = nil
|
|
@@ -294,7 +309,7 @@ module YARD
|
|
|
294
309
|
@heredoc_tokens << [token, data, [lineno, charno]]
|
|
295
310
|
|
|
296
311
|
# fix ripper encoding of heredoc bug
|
|
297
|
-
# (see
|
|
312
|
+
# (see https://bugs.ruby-lang.org/issues/6200)
|
|
298
313
|
data.force_encoding(file_encoding) if file_encoding
|
|
299
314
|
|
|
300
315
|
@heredoc_state = :ended if token == :heredoc_end
|
|
@@ -322,6 +337,7 @@ module YARD
|
|
|
322
337
|
undef on_aref_field
|
|
323
338
|
undef on_lbracket
|
|
324
339
|
undef on_rbracket
|
|
340
|
+
undef on_rbrace
|
|
325
341
|
undef on_string_literal
|
|
326
342
|
undef on_lambda
|
|
327
343
|
undef on_unary
|
|
@@ -357,6 +373,20 @@ module YARD
|
|
|
357
373
|
visit_event AstNode.new(:hash, args.first || [])
|
|
358
374
|
end
|
|
359
375
|
|
|
376
|
+
# Ruby 3.0+ pattern matching: braced hash patterns ({key: val} syntax) fire
|
|
377
|
+
# on_lbrace and on_rbrace scanner events. The corresponding parser event is
|
|
378
|
+
# on_hshptn (not on_hash), so we must clean up the brace maps to prevent stale
|
|
379
|
+
# entries from corrupting source ranges of later hash literals and brace blocks.
|
|
380
|
+
# Bare hash patterns (key: val without braces) fire no brace scanner events, so
|
|
381
|
+
# we only clean up when @map[:rbrace] confirms a closing brace was scanned.
|
|
382
|
+
def on_hshptn(*args)
|
|
383
|
+
if (@map[:rbrace] ||= []).any?
|
|
384
|
+
(@map[:lbrace] ||= []).pop
|
|
385
|
+
@map[:rbrace].shift
|
|
386
|
+
end
|
|
387
|
+
AstNode.new(:hshptn, args)
|
|
388
|
+
end
|
|
389
|
+
|
|
360
390
|
def on_bare_assoc_hash(*args)
|
|
361
391
|
AstNode.new(:list, args.first)
|
|
362
392
|
end
|
|
@@ -377,20 +407,22 @@ module YARD
|
|
|
377
407
|
def on_aref(*args)
|
|
378
408
|
@map[:lbracket].pop
|
|
379
409
|
ll, lc = *@map[:aref].shift
|
|
380
|
-
sr = args.first.source_range.
|
|
381
|
-
lr = args.first.line_range.
|
|
410
|
+
sr = args.first.source_range.begin..lc
|
|
411
|
+
lr = args.first.line_range.begin..ll
|
|
382
412
|
AstNode.new(:aref, args, :char => sr, :line => lr)
|
|
383
413
|
end
|
|
384
414
|
|
|
385
415
|
def on_aref_field(*args)
|
|
386
416
|
@map[:lbracket].pop
|
|
387
|
-
|
|
388
|
-
|
|
417
|
+
ll, lc = *@map[:aref].shift
|
|
418
|
+
sr = args.first.source_range.begin..lc
|
|
419
|
+
lr = args.first.line_range.begin..ll
|
|
420
|
+
AstNode.new(:aref_field, args, :char => sr, :line => lr)
|
|
389
421
|
end
|
|
390
422
|
|
|
391
423
|
def on_array(other)
|
|
392
424
|
node = AstNode.node_class_for(:array).new(:array, [other])
|
|
393
|
-
map = @map[MAPPINGS[node.type]]
|
|
425
|
+
map = @map[MAPPINGS[node.type]] if other.nil? || other.type == :list
|
|
394
426
|
if map && !map.empty?
|
|
395
427
|
lstart, sstart = *map.pop
|
|
396
428
|
node.source_range = Range.new(sstart, @ns_charno - 1)
|
|
@@ -406,6 +438,27 @@ module YARD
|
|
|
406
438
|
node
|
|
407
439
|
end
|
|
408
440
|
|
|
441
|
+
# Ruby 3.0+ pattern matching: array patterns (SomeClass[a, b]) and find patterns
|
|
442
|
+
# (SomeClass[*pre, val, *post]) use [...] brackets, which fire on_lbracket and
|
|
443
|
+
# on_rbracket scanner events. The corresponding parser events are on_aryptn/on_fndptn
|
|
444
|
+
# (not on_aref), so we must clean up the bracket maps to prevent stale entries from
|
|
445
|
+
# corrupting source ranges of later array indexing expressions.
|
|
446
|
+
def on_aryptn(*args)
|
|
447
|
+
(@map[:lbracket] ||= []).pop
|
|
448
|
+
(@map[:aref] ||= []).shift
|
|
449
|
+
# Source range is intentionally not set; no handler is registered for
|
|
450
|
+
# pattern-match nodes, so they produce no documentation output.
|
|
451
|
+
AstNode.new(:aryptn, args)
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def on_fndptn(*args)
|
|
455
|
+
(@map[:lbracket] ||= []).pop
|
|
456
|
+
(@map[:aref] ||= []).shift
|
|
457
|
+
# Source range is intentionally not set; no handler is registered for
|
|
458
|
+
# pattern-match nodes, so they produce no documentation output.
|
|
459
|
+
AstNode.new(:fndptn, args)
|
|
460
|
+
end
|
|
461
|
+
|
|
409
462
|
def on_lbracket(tok)
|
|
410
463
|
(@map[:lbracket] ||= []) << [lineno, charno]
|
|
411
464
|
visit_ns_token(:lbracket, tok, false)
|
|
@@ -416,6 +469,13 @@ module YARD
|
|
|
416
469
|
visit_ns_token(:rbracket, tok, false)
|
|
417
470
|
end
|
|
418
471
|
|
|
472
|
+
# Maintained explicitly (unlike on_lbracket/on_rbracket) so on_hshptn can
|
|
473
|
+
# distinguish braced from bare hash patterns in Ruby 3.0+ pattern matching.
|
|
474
|
+
def on_rbrace(tok)
|
|
475
|
+
(@map[:rbrace] ||= []) << [lineno, charno]
|
|
476
|
+
visit_ns_token(:rbrace, tok, false)
|
|
477
|
+
end
|
|
478
|
+
|
|
419
479
|
def on_dyna_symbol(sym)
|
|
420
480
|
rng = if sym.source_range.to_a.size == 0 # rubocop:disable Style/ZeroLengthPredicate
|
|
421
481
|
(sym.source_range.begin - 3)...sym.source_range.end
|
|
@@ -449,8 +509,8 @@ module YARD
|
|
|
449
509
|
def on_#{kw}(*args)
|
|
450
510
|
mapping = @map[#{kw.to_s.sub(/_mod$/, '').inspect}]
|
|
451
511
|
mapping.pop if mapping
|
|
452
|
-
sr = args.last.source_range.
|
|
453
|
-
lr = args.last.line_range.
|
|
512
|
+
sr = args.last.source_range.begin..args.first.source_range.end
|
|
513
|
+
lr = args.last.line_range.begin..args.first.line_range.end
|
|
454
514
|
#{node_class}.new(:#{kw}, args, :line => lr, :char => sr)
|
|
455
515
|
end
|
|
456
516
|
eof
|
|
@@ -473,8 +533,8 @@ module YARD
|
|
|
473
533
|
begin; undef on_#{kw}_add; rescue NameError; end
|
|
474
534
|
def on_#{kw}_add(list, item)
|
|
475
535
|
last = @source[@ns_charno,1] == "\n" ? @ns_charno - 1 : @ns_charno
|
|
476
|
-
list.source_range = (list.source_range.
|
|
477
|
-
list.line_range = (list.line_range.
|
|
536
|
+
list.source_range = (list.source_range.begin..last)
|
|
537
|
+
list.line_range = (list.line_range.begin..lineno)
|
|
478
538
|
list.push(item)
|
|
479
539
|
list
|
|
480
540
|
end
|
|
@@ -485,9 +545,9 @@ module YARD
|
|
|
485
545
|
node = visit_event_arr(LiteralNode.new(:string_literal, args))
|
|
486
546
|
if args.size == 1
|
|
487
547
|
r = args[0].source_range
|
|
488
|
-
if node.source_range != Range.new(r.
|
|
548
|
+
if node.source_range != Range.new(r.begin - 1, r.end + 1)
|
|
489
549
|
klass = AstNode.node_class_for(node[0].type)
|
|
490
|
-
r = Range.new(node.source_range.
|
|
550
|
+
r = Range.new(node.source_range.begin + 1, node.source_range.end - 1)
|
|
491
551
|
node[0] = klass.new(node[0].type, [@source[r]], :line => node.line_range, :char => r)
|
|
492
552
|
end
|
|
493
553
|
end
|
|
@@ -573,7 +633,7 @@ module YARD
|
|
|
573
633
|
@comments_flags[lineno] = @comments_flags[lineno - 1]
|
|
574
634
|
@comments_flags.delete(lineno - 1)
|
|
575
635
|
range = @comments_range.delete(lineno - 1)
|
|
576
|
-
source_range = range.
|
|
636
|
+
source_range = range.begin..source_range.end
|
|
577
637
|
comment = append_comment + "\n" + comment
|
|
578
638
|
end
|
|
579
639
|
|
|
@@ -609,6 +669,7 @@ module YARD
|
|
|
609
669
|
alias compile_error on_parse_error
|
|
610
670
|
|
|
611
671
|
def comment_starts_line?(charno)
|
|
672
|
+
return true if @source[charno] == "\n"
|
|
612
673
|
(charno - 1).downto(0) do |i|
|
|
613
674
|
ch = @source[i]
|
|
614
675
|
break if ch == "\n"
|
|
@@ -627,11 +688,13 @@ module YARD
|
|
|
627
688
|
end
|
|
628
689
|
|
|
629
690
|
# check upwards from line before node; check node's line at the end
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
691
|
+
if (n_l = node.line)
|
|
692
|
+
((n_l - 1).downto(n_l - 2).to_a + [n_l]).each do |line|
|
|
693
|
+
comment = @comments[line]
|
|
694
|
+
if comment && !comment.empty?
|
|
695
|
+
add_comment(line, node)
|
|
696
|
+
break
|
|
697
|
+
end
|
|
635
698
|
end
|
|
636
699
|
end
|
|
637
700
|
|
|
@@ -656,6 +719,23 @@ module YARD
|
|
|
656
719
|
end
|
|
657
720
|
end unless @comments.empty?
|
|
658
721
|
|
|
722
|
+
# Attach comments that fall within an otherwise empty
|
|
723
|
+
# class or module body. Without this step, a comment used
|
|
724
|
+
# solely for directives (like @!method) would be treated as
|
|
725
|
+
# a top-level comment and its directives would not be scoped
|
|
726
|
+
# to the namespace.
|
|
727
|
+
unless @comments.empty?
|
|
728
|
+
root.traverse do |node|
|
|
729
|
+
next unless [:class, :module, :sclass].include?(node.type)
|
|
730
|
+
body = node.children.last
|
|
731
|
+
next unless body && body.type == :list && body.empty?
|
|
732
|
+
@comments.keys.each do |line|
|
|
733
|
+
next unless node.line_range.include?(line)
|
|
734
|
+
add_comment(line, nil, body, true)
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
|
|
659
739
|
# insert all remaining comments
|
|
660
740
|
@comments.each do |line, _comment|
|
|
661
741
|
add_comment(line, nil, root, true)
|
|
@@ -667,6 +747,11 @@ module YARD
|
|
|
667
747
|
def add_comment(line, node = nil, before_node = nil, into = false)
|
|
668
748
|
comment = @comments[line]
|
|
669
749
|
source_range = @comments_range[line]
|
|
750
|
+
if comment && source_range
|
|
751
|
+
source = @source[source_range]
|
|
752
|
+
last_line = source.lines.to_a.last
|
|
753
|
+
return if last_line && last_line =~ /^\s*\#-\s*$/
|
|
754
|
+
end
|
|
670
755
|
line_range = ((line - comment.count("\n"))..line)
|
|
671
756
|
if node.nil?
|
|
672
757
|
node = CommentNode.new(:comment, [comment], :line => line_range, :char => source_range)
|
|
@@ -67,7 +67,7 @@ module YARD
|
|
|
67
67
|
|
|
68
68
|
# The default glob of files to be parsed.
|
|
69
69
|
# @since 0.9.0
|
|
70
|
-
DEFAULT_PATH_GLOB = ["{lib,app}/**/*.rb", "ext/**/*.{c,cc,cxx,cpp,rb}"]
|
|
70
|
+
DEFAULT_PATH_GLOB = ["{lib,app}/**/*.{rb,rbs}", "sig/**/*.rbs", "ext/**/*.{c,cc,cxx,cpp,rb}"]
|
|
71
71
|
|
|
72
72
|
# Byte order marks for various encodings
|
|
73
73
|
# @since 0.7.0
|
|
@@ -105,7 +105,7 @@ module YARD
|
|
|
105
105
|
end
|
|
106
106
|
end
|
|
107
107
|
files = [paths].flatten.
|
|
108
|
-
map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c,cc,cxx,cpp}" : p }.
|
|
108
|
+
map {|p| File.directory?(p) ? "#{p}/**/*.{rb,rbs,c,cc,cxx,cpp}" : p }.
|
|
109
109
|
map {|p| p.include?("*") ? Dir[p].sort_by {|d| [d.length, d] } : p }.flatten.
|
|
110
110
|
reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } }.
|
|
111
111
|
map {|p| p.encoding == Encoding.default_external ? p : p.dup.force_encoding(Encoding.default_external) }
|
|
@@ -379,6 +379,7 @@ module YARD
|
|
|
379
379
|
register_parser_type :ruby, Ruby::RubyParser
|
|
380
380
|
register_parser_type :ruby18, Ruby::Legacy::RubyParser
|
|
381
381
|
register_parser_type :c, C::CParser, ['c', 'cc', 'cxx', 'cpp']
|
|
382
|
+
register_parser_type :rbs, RBS::RbsParser, ['rbs']
|
|
382
383
|
|
|
383
384
|
self.parser_type = :ruby
|
|
384
385
|
|
|
@@ -75,6 +75,13 @@ module YARD
|
|
|
75
75
|
lexical_lookup = 0
|
|
76
76
|
while namespace && !resolved
|
|
77
77
|
resolved = lookup_path_direct(namespace, path, type)
|
|
78
|
+
# Prevent a bare name from resolving back to the namespace we started
|
|
79
|
+
# from when searching through a parent namespace. For example,
|
|
80
|
+
# `include Enumerable` inside `A::Enumerable` would walk up to namespace
|
|
81
|
+
# `A` and match `A::Enumerable`, creating a false self-referential mixin.
|
|
82
|
+
# Only skip when we have already moved to a parent (namespace != orignamespace).
|
|
83
|
+
# See https://github.com/lsegal/yard/issues/1116
|
|
84
|
+
resolved = nil if resolved.equal?(orignamespace) && !namespace.equal?(orignamespace)
|
|
78
85
|
resolved ||= lookup_path_inherited(namespace, path, type) if inheritance
|
|
79
86
|
break if resolved
|
|
80
87
|
namespace = namespace.parent
|
|
@@ -71,7 +71,7 @@ module YARD
|
|
|
71
71
|
# def load_yardoc_from_http
|
|
72
72
|
# Thread.new do
|
|
73
73
|
# # zip/unzip method implementations are not shown
|
|
74
|
-
# download_zip_file("
|
|
74
|
+
# download_zip_file("https://mysite.com/yardocs/#{self}.zip")
|
|
75
75
|
# unzip_file_to("/path/to/yardocs/#{self}")
|
|
76
76
|
# end
|
|
77
77
|
#
|
|
@@ -1,12 +1,208 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
(function() {
|
|
2
|
+
function query(selector, root) {
|
|
3
|
+
return (root || document).querySelector(selector);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function ready(callback) {
|
|
7
|
+
if (document.readyState === "loading") {
|
|
8
|
+
document.addEventListener("DOMContentLoaded", callback, { once: true });
|
|
9
|
+
} else {
|
|
10
|
+
callback();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function createAutocomplete(input) {
|
|
15
|
+
var form = input.form;
|
|
16
|
+
var results = document.createElement("div");
|
|
17
|
+
var list = document.createElement("ul");
|
|
18
|
+
var requestTimer = null;
|
|
19
|
+
var controller = null;
|
|
20
|
+
var items = [];
|
|
21
|
+
var activeIndex = -1;
|
|
22
|
+
var blurTimer = null;
|
|
23
|
+
|
|
24
|
+
if (!form) return;
|
|
25
|
+
|
|
26
|
+
results.className = "ac_results";
|
|
27
|
+
results.hidden = true;
|
|
28
|
+
results.setAttribute("role", "listbox");
|
|
29
|
+
results.id = input.id + "_results";
|
|
30
|
+
list.setAttribute("role", "presentation");
|
|
31
|
+
results.appendChild(list);
|
|
32
|
+
input.setAttribute("autocomplete", "off");
|
|
33
|
+
input.setAttribute("aria-autocomplete", "list");
|
|
34
|
+
input.setAttribute("aria-controls", results.id);
|
|
35
|
+
input.setAttribute("aria-expanded", "false");
|
|
36
|
+
form.appendChild(results);
|
|
37
|
+
|
|
38
|
+
function syncResultsWidth() {
|
|
39
|
+
results.style.width = input.offsetWidth + "px";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function hideResults() {
|
|
43
|
+
results.hidden = true;
|
|
44
|
+
input.setAttribute("aria-expanded", "false");
|
|
45
|
+
input.removeAttribute("aria-activedescendant");
|
|
46
|
+
activeIndex = -1;
|
|
47
|
+
items = [];
|
|
48
|
+
list.innerHTML = "";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function setActive(index) {
|
|
52
|
+
if (!items.length) return;
|
|
53
|
+
activeIndex = (index + items.length) % items.length;
|
|
54
|
+
items.forEach(function(item, itemIndex) {
|
|
55
|
+
item.element.classList.toggle("ac_over", itemIndex === activeIndex);
|
|
56
|
+
});
|
|
57
|
+
input.setAttribute("aria-activedescendant", items[activeIndex].element.id);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function selectItem(item) {
|
|
61
|
+
input.value = item.values[1];
|
|
62
|
+
window.location.href = item.values[3];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function renderItems(lines) {
|
|
66
|
+
syncResultsWidth();
|
|
67
|
+
list.innerHTML = "";
|
|
68
|
+
items = lines.map(function(line, index) {
|
|
69
|
+
var values = line.split(",");
|
|
70
|
+
var element = document.createElement("li");
|
|
71
|
+
var label = document.createElement("span");
|
|
72
|
+
var namespace = document.createElement("small");
|
|
73
|
+
|
|
74
|
+
element.id = results.id + "_item_" + index;
|
|
75
|
+
element.setAttribute("role", "option");
|
|
76
|
+
element.className = index % 2 === 0 ? "ac_even" : "ac_odd";
|
|
77
|
+
label.textContent = values[0];
|
|
78
|
+
element.appendChild(label);
|
|
79
|
+
|
|
80
|
+
if (values[1] !== "") {
|
|
81
|
+
namespace.textContent = "(" + values[1] + ")";
|
|
82
|
+
element.appendChild(document.createTextNode(" "));
|
|
83
|
+
element.appendChild(namespace);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
element.addEventListener("mouseenter", function() {
|
|
87
|
+
setActive(index);
|
|
88
|
+
});
|
|
89
|
+
element.addEventListener("mousedown", function(event) {
|
|
90
|
+
event.preventDefault();
|
|
91
|
+
selectItem(items[index]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
list.appendChild(element);
|
|
95
|
+
|
|
96
|
+
return { element: element, values: values };
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (items.length) {
|
|
100
|
+
results.hidden = false;
|
|
101
|
+
input.setAttribute("aria-expanded", "true");
|
|
102
|
+
setActive(0);
|
|
103
|
+
} else {
|
|
104
|
+
hideResults();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function fetchResults(term) {
|
|
109
|
+
if (controller) controller.abort();
|
|
110
|
+
controller = new AbortController();
|
|
111
|
+
input.classList.add("ac_loading");
|
|
112
|
+
|
|
113
|
+
fetch(
|
|
114
|
+
form.action +
|
|
115
|
+
"?q=" +
|
|
116
|
+
encodeURIComponent(term) +
|
|
117
|
+
"&_=" +
|
|
118
|
+
new Date().getTime(),
|
|
119
|
+
{
|
|
120
|
+
headers: {
|
|
121
|
+
"X-Requested-With": "XMLHttpRequest"
|
|
122
|
+
},
|
|
123
|
+
signal: controller.signal
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
.then(function(response) {
|
|
127
|
+
return response.text();
|
|
128
|
+
})
|
|
129
|
+
.then(function(text) {
|
|
130
|
+
var lines = text
|
|
131
|
+
.split("\n")
|
|
132
|
+
.map(function(line) {
|
|
133
|
+
return line.trim();
|
|
134
|
+
})
|
|
135
|
+
.filter(Boolean);
|
|
136
|
+
|
|
137
|
+
renderItems(lines);
|
|
138
|
+
})
|
|
139
|
+
.catch(function(error) {
|
|
140
|
+
if (error.name !== "AbortError") hideResults();
|
|
141
|
+
})
|
|
142
|
+
.finally(function() {
|
|
143
|
+
input.classList.remove("ac_loading");
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
input.addEventListener("input", function() {
|
|
148
|
+
clearTimeout(requestTimer);
|
|
149
|
+
if (blurTimer) clearTimeout(blurTimer);
|
|
150
|
+
|
|
151
|
+
if (!input.value.trim()) {
|
|
152
|
+
hideResults();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
requestTimer = setTimeout(function() {
|
|
157
|
+
fetchResults(input.value.trim());
|
|
158
|
+
}, 200);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
input.addEventListener("keydown", function(event) {
|
|
162
|
+
if (results.hidden && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
|
|
163
|
+
if (!input.value.trim()) return;
|
|
164
|
+
fetchResults(input.value.trim());
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (event.key === "ArrowDown") {
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
setActive(activeIndex + 1);
|
|
171
|
+
} else if (event.key === "ArrowUp") {
|
|
172
|
+
event.preventDefault();
|
|
173
|
+
setActive(activeIndex - 1);
|
|
174
|
+
} else if (event.key === "Enter") {
|
|
175
|
+
if (activeIndex >= 0 && items[activeIndex]) {
|
|
176
|
+
event.preventDefault();
|
|
177
|
+
selectItem(items[activeIndex]);
|
|
178
|
+
}
|
|
179
|
+
} else if (event.key === "Escape") {
|
|
180
|
+
hideResults();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
input.addEventListener("blur", function() {
|
|
185
|
+
blurTimer = setTimeout(hideResults, 150);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
input.addEventListener("focus", function() {
|
|
189
|
+
syncResultsWidth();
|
|
190
|
+
if (items.length) {
|
|
191
|
+
results.hidden = false;
|
|
192
|
+
input.setAttribute("aria-expanded", "true");
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
document.addEventListener("click", function(event) {
|
|
197
|
+
if (!form.contains(event.target)) hideResults();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
window.addEventListener("resize", syncResultsWidth);
|
|
201
|
+
syncResultsWidth();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
ready(function() {
|
|
205
|
+
var input = query("#search_box");
|
|
206
|
+
if (input) createAutocomplete(input);
|
|
207
|
+
});
|
|
208
|
+
})();
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
<form class="search" method="get" action="<%= abs_url base_path(router.search_prefix) %>">
|
|
2
|
-
<input name="q" type="search" placeholder="Search" id="search_box" size="30" value="<%= h @query %>"
|
|
2
|
+
<input name="q" type="search" placeholder="Search" id="search_box" size="30" value="<%= h @query %>">
|
|
3
3
|
</form>
|
|
4
|
-
<script type="text/javascript" charset="utf-8">
|
|
5
|
-
$(function() {
|
|
6
|
-
$('#search_box').autocomplete($('#search_box').parent().attr('action'), {
|
|
7
|
-
width: 200,
|
|
8
|
-
formatItem: function(item) {
|
|
9
|
-
var values = item[0].split(",");
|
|
10
|
-
return values[0] + (values[1] == '' ? "" : " <small>(" + values[1] + ")</small>");
|
|
11
|
-
}
|
|
12
|
-
}).result(function(event, item) {
|
|
13
|
-
var values = item[0].split(",")
|
|
14
|
-
$('#search_box').val(values[1]);
|
|
15
|
-
location.href = values[3];
|
|
16
|
-
return false;
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
</script>
|
|
20
4
|
|
|
21
5
|
<div id="menu">
|
|
22
6
|
<% unless @single_library %>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
document.getElementById("<%= anchor_for(object) %>").insertAdjacentHTML(
|
|
3
|
+
"afterbegin",
|
|
4
|
+
'<a class="permalink" href="<%= abs_url base_path(router.docs_prefix) %>/<%= urlencode serializer.serialized_path(object) %>">permalink</a>'
|
|
5
|
+
);
|
|
4
6
|
</script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<meta
|
|
1
|
+
<meta charset="UTF-8">
|
|
2
2
|
<title>YARD Documentation Server <%= YARD::VERSION %> - Library Listing</title>
|
|
3
|
-
<link rel="stylesheet" href="<%= abs_url('css', 'style.css') %>?<%= mtime('css/style.css') %>" type="text/css" media="screen" charset="utf-8"
|
|
4
|
-
<link rel="stylesheet" href="<%= abs_url('css', 'custom.css') %>?<%= mtime('css/custom.css') %>" type="text/css" media="screen" charset="utf-8"
|
|
3
|
+
<link rel="stylesheet" href="<%= abs_url('css', 'style.css') %>?<%= mtime('css/style.css') %>" type="text/css" media="screen" charset="utf-8">
|
|
4
|
+
<link rel="stylesheet" href="<%= abs_url('css', 'custom.css') %>?<%= mtime('css/custom.css') %>" type="text/css" media="screen" charset="utf-8">
|
|
5
5
|
<style type="text/css" media="screen">
|
|
6
6
|
ul { list-style: circle inside none; padding: 0; }
|
|
7
7
|
li { font-size: 1.2em; line-height: 1.4em; padding: 3px 5px; }
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
<!DOCTYPE html
|
|
2
|
-
|
|
3
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
4
3
|
<head>
|
|
5
4
|
<%= erb(:headers) %>
|
|
6
5
|
</head>
|