Skip to content

Commit f4e920a

Browse files
committed
fix #54664, make at-doc not change when REPL is loaded
1 parent a31a880 commit f4e920a

File tree

3 files changed

+110
-107
lines changed

3 files changed

+110
-107
lines changed

base/docs/Docs.jl

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ docstr(object, data = Dict{Symbol,Any}()) = _docstr(object, data)
178178
_docstr(vec::Core.SimpleVector, data::Dict{Symbol,Any}) = DocStr(vec, nothing, data)
179179
_docstr(str::AbstractString, data::Dict{Symbol,Any}) = DocStr(Core.svec(str), nothing, data)
180180
_docstr(object, data::Dict{Symbol,Any}) = DocStr(Core.svec(), object, data)
181+
_docstr(strs::Vector{DocStr}, data::Dict{Symbol,Any}) = error("Cannot apply multiple docstrings to a single object.")
181182

182183
_docstr(doc::DocStr, data::Dict{Symbol,Any}) = (doc.data = merge(data, doc.data); doc)
183184

@@ -563,33 +564,51 @@ isquotedmacrocall(@nospecialize x) =
563564
isbasicdoc(@nospecialize x) = isexpr(x, :.) || isa(x, Union{QuoteNode, Symbol})
564565
is_signature(@nospecialize x) = isexpr(x, :call) || (isexpr(x, :(::), 2) && isexpr(x.args[1], :call)) || isexpr(x, :where)
565566

566-
function _doc(binding::Binding, sig::Type = Union{})
567+
function doc(binding::Binding, sig::Type = Union{})
567568
if defined(binding)
568569
result = getdoc(resolve(binding), sig)
569570
result === nothing || return result
570571
end
571-
# Lookup first match for `binding` and `sig` in all modules of the docsystem.
572+
results, groups = DocStr[], MultiDoc[]
573+
# Lookup `binding` and `sig` for matches in all modules of the docsystem.
572574
for mod in modules
573575
dict = meta(mod; autoinit=false)
574576
isnothing(dict) && continue
575577
if haskey(dict, binding)
576578
multidoc = dict[binding]
579+
push!(groups, multidoc)
577580
for msig in multidoc.order
578-
sig <: msig && return multidoc.docs[msig]
581+
sig <: msig && push!(results, multidoc.docs[msig])
579582
end
580-
# if no matching signatures, return first
581-
if !isempty(multidoc.docs)
582-
return first(values(multidoc.docs))
583+
end
584+
end
585+
if isempty(groups)
586+
# When no `MultiDoc`s are found that match `binding` then we check whether `binding`
587+
# is an alias of some other `Binding`. When it is we then re-run `doc` with that
588+
# `Binding`, otherwise we return nothing and the front end will decide what to
589+
# display, usually a brief description of the binding.
590+
alias = aliasof(binding)
591+
alias == binding ? nothing : doc(alias, sig)
592+
else
593+
# There was at least one match for `binding` while searching. If there weren't any
594+
# matches for `sig` then we concatenate *all* the docs from the matching `Binding`s.
595+
if isempty(results)
596+
for group in groups, each in group.order
597+
push!(results, group.docs[each])
583598
end
584599
end
600+
if length(results) == 1
601+
return results[1]
602+
else
603+
return results
604+
end
585605
end
586-
return nothing
587606
end
588607

589608
# Some additional convenience `doc` methods that take objects rather than `Binding`s.
590-
_doc(obj::UnionAll) = _doc(Base.unwrap_unionall(obj))
591-
_doc(object, sig::Type = Union{}) = _doc(aliasof(object, typeof(object)), sig)
592-
_doc(object, sig...) = _doc(object, Tuple{sig...})
609+
doc(obj::UnionAll) = doc(Base.unwrap_unionall(obj))
610+
doc(object, sig::Type = Union{}) = doc(aliasof(object, typeof(object)), sig)
611+
doc(object, sig...) = doc(object, Tuple{sig...})
593612

594613
function simple_lookup_doc(ex)
595614
if isa(ex, Expr) && ex.head !== :(.) && Base.isoperator(ex.head)
@@ -599,24 +618,23 @@ function simple_lookup_doc(ex)
599618
if haskey(keywords, ex)
600619
return keywords[ex]
601620
elseif !isa(ex, Expr) && !isa(ex, Symbol)
602-
return :($(_doc)($(typeof)($(esc(ex)))))
621+
return :($(doc)($(typeof)($(esc(ex)))))
622+
elseif isexpr(ex, :incomplete)
623+
return nothing
603624
end
604625
binding = esc(bindingexpr(namify(ex)))
605626
if isexpr(ex, :call) || isexpr(ex, :macrocall) || isexpr(ex, :where)
606627
sig = esc(signature(ex))
607-
:($(_doc)($binding, $sig))
628+
:($(doc)($binding, $sig))
608629
else
609-
:($(_doc)($binding))
630+
:($(doc)($binding))
610631
end
611632
end
612633

613634
function docm(source::LineNumberNode, mod::Module, ex)
614635
@nospecialize ex
615636
if isexpr(ex, :->) && length(ex.args) > 1
616637
return docm(source, mod, ex.args...)
617-
elseif (REPL = Base.REPL_MODULE_REF[]) !== Base
618-
# TODO: this is a shim to continue to allow `@doc` for looking up docstrings
619-
return invokelatest(REPL.lookup_doc, ex)
620638
else
621639
return simple_lookup_doc(ex)
622640
end

stdlib/REPL/src/docview.jl

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ using Markdown
77
using Base.Docs: catdoc, modules, DocStr, Binding, MultiDoc, keywords, isfield, namify, bindingexpr,
88
defined, resolve, getdoc, meta, aliasof, signature
99

10-
import Base.Docs: doc, formatdoc, parsedoc, apropos
10+
import Base.Docs: formatdoc, parsedoc, apropos
1111

1212
using Base: with_output_color, mapany, isdeprecated, isexported
1313

@@ -206,55 +206,31 @@ function insert_internal_warning(other, internal_access::Set{Pair{Module,Symbol}
206206
other
207207
end
208208

209-
function doc(binding::Binding, sig::Type = Union{})
209+
function doc_as_md(binding::Binding, sig::Type = Union{})
210210
if defined(binding)
211211
result = getdoc(resolve(binding), sig)
212212
result === nothing || return result
213213
end
214-
results, groups = DocStr[], MultiDoc[]
215-
# Lookup `binding` and `sig` for matches in all modules of the docsystem.
216-
for mod in modules
217-
dict = meta(mod; autoinit=false)
218-
isnothing(dict) && continue
219-
if haskey(dict, binding)
220-
multidoc = dict[binding]
221-
push!(groups, multidoc)
222-
for msig in multidoc.order
223-
sig <: msig && push!(results, multidoc.docs[msig])
224-
end
225-
end
226-
end
227-
if isempty(groups)
228-
# When no `MultiDoc`s are found that match `binding` then we check whether `binding`
229-
# is an alias of some other `Binding`. When it is we then re-run `doc` with that
230-
# `Binding`, otherwise if it's not an alias then we generate a summary for the
231-
# `binding` and display that to the user instead.
232-
alias = aliasof(binding)
233-
alias == binding ? summarize(alias, sig) : doc(alias, sig)
214+
result = Base.Docs.doc(binding, sig)
215+
if result === nothing
216+
return summarize(binding, sig)
234217
else
235-
# There was at least one match for `binding` while searching. If there weren't any
236-
# matches for `sig` then we concatenate *all* the docs from the matching `Binding`s.
237-
if isempty(results)
238-
for group in groups, each in group.order
239-
push!(results, group.docs[each])
240-
end
218+
if !(result isa Vector)
219+
result = [result]
241220
end
242-
# Get parsed docs and concatenate them.
243-
md = catdoc(mapany(parsedoc, results)...)
221+
md = catdoc(mapany(parsedoc, result)...)
244222
# Save metadata in the generated markdown.
245223
if isa(md, Markdown.MD)
246-
md.meta[:results] = results
224+
md.meta[:results] = result
247225
md.meta[:binding] = binding
248226
md.meta[:typesig] = sig
249227
end
250228
return md
251229
end
252230
end
253231

254-
# Some additional convenience `doc` methods that take objects rather than `Binding`s.
255-
doc(obj::UnionAll) = doc(Base.unwrap_unionall(obj))
256-
doc(object, sig::Type = Union{}) = doc(aliasof(object, typeof(object)), sig)
257-
doc(object, sig...) = doc(object, Tuple{sig...})
232+
doc_as_md(obj::UnionAll) = doc_as_md(Base.unwrap_unionall(obj))
233+
doc_as_md(object, sig::Type = Union{}) = doc_as_md(aliasof(object, typeof(object)), sig)
258234

259235
function lookup_doc(ex)
260236
if isa(ex, Expr) && ex.head !== :(.) && Base.isoperator(ex.head)
@@ -266,7 +242,7 @@ function lookup_doc(ex)
266242
elseif Meta.isexpr(ex, :incomplete)
267243
return :($(Markdown.md"No documentation found."))
268244
elseif !isa(ex, Expr) && !isa(ex, Symbol)
269-
return :($(doc)($(typeof)($(esc(ex)))))
245+
return :($(doc_as_md)($(typeof)($(esc(ex)))))
270246
end
271247
if isa(ex, Symbol) && Base.isoperator(ex)
272248
str = string(ex)
@@ -287,12 +263,16 @@ function lookup_doc(ex)
287263
binding = esc(bindingexpr(namify(ex)))
288264
if isexpr(ex, :call) || isexpr(ex, :macrocall) || isexpr(ex, :where)
289265
sig = esc(signature(ex))
290-
:($(doc)($binding, $sig))
266+
:($(doc_as_md)($binding, $sig))
291267
else
292-
:($(doc)($binding))
268+
:($(doc_as_md)($binding))
293269
end
294270
end
295271

272+
macro showdoc(ex)
273+
lookup_doc(ex)
274+
end
275+
296276
# Object Summaries.
297277
# =================
298278

@@ -570,7 +550,7 @@ isregex(x) = isexpr(x, :macrocall, 3) && x.args[1] === Symbol("@r_str") && !isem
570550

571551
repl(io::IO, ex::Expr; brief::Bool=true, mod::Module=Main, internal_accesses::Union{Nothing, Set{Pair{Module,Symbol}}}=nothing) = isregex(ex) ? :(apropos($io, $ex)) : _repl(ex, brief, mod, internal_accesses)
572552
repl(io::IO, str::AbstractString; brief::Bool=true, mod::Module=Main, internal_accesses::Union{Nothing, Set{Pair{Module,Symbol}}}=nothing) = :(apropos($io, $str))
573-
repl(io::IO, other; brief::Bool=true, mod::Module=Main, internal_accesses::Union{Nothing, Set{Pair{Module,Symbol}}}=nothing) = esc(:(@doc $other)) # TODO: track internal_accesses
553+
repl(io::IO, other; brief::Bool=true, mod::Module=Main, internal_accesses::Union{Nothing, Set{Pair{Module,Symbol}}}=nothing) = esc(:(REPL.@showdoc $other)) # TODO: track internal_accesses
574554
#repl(io::IO, other) = lookup_doc(other) # TODO
575555

576556
repl(x; brief::Bool=true, mod::Module=Main) = repl(stdout, x; brief, mod)
@@ -629,7 +609,7 @@ function _repl(x, brief::Bool=true, mod::Module=Main, internal_accesses::Union{N
629609
end
630610
end
631611
#docs = lookup_doc(x) # TODO
632-
docs = esc(:(@doc $x))
612+
docs = esc(:($REPL.@showdoc $x))
633613
docs = if isfield(x)
634614
quote
635615
if isa($(esc(x.args[1])), DataType)
@@ -983,7 +963,7 @@ apropos(io::IO, string) = apropos(io, Regex("\\Q$string", "i"))
983963
function apropos(io::IO, needle::Regex)
984964
for mod in modules
985965
# Module doc might be in README.md instead of the META dict
986-
docsearch(doc(mod), needle) && println(io, mod)
966+
docsearch(doc_as_md(mod), needle) && println(io, mod)
987967
dict = meta(mod; autoinit=false)
988968
isnothing(dict) && continue
989969
for (k, v) in dict

0 commit comments

Comments
 (0)