diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 3e904b6391778..0d8665d0e54a4 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -18,22 +18,20 @@ module Docs Functions, methods and types can be documented by placing a string before the definition: - \""" + \"\"\" # The Foo Function `foo(x)`: Foo the living hell out of `x`. - \""" + \"\"\" foo(x) = ... -The `@doc` macro can be used directly to both set and retrieve documentation / metadata. By -default, documentation is written as Markdown, but any object can be placed before the -arrow. For example: +The `@doc` macro can be used directly to both set and retrieve documentation / metadata. +The macro has special parsing so that the documented object may occur on the next line: - @doc "blah" -> + @doc "blah" function foo() ... -The `->` is not required if the object is on the same line, e.g. - - @doc "foo" foo +By default, documentation is written as Markdown, but any object can be used as +the first argument. ## Documenting objects after they are defined You can document an object after its definition by diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 2b84727363aeb..b508c1ad4b222 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -317,6 +317,56 @@ julia> filter!(x -> x > 1, a) # in-place & thus more efficient than a = a[a .> 1 """ kw"=" +""" + .= + +Perform broadcasted assignment. The right-side argument is expanded as in +[`broadcast`](@ref) and then assigned into the left-side argument in-place. +Fuses with other dotted operators in the same expression; i.e. the whole +assignment expression is converted into a single loop. + +`A .= B` is similar to `broadcast!(identity, A, B)`. + +# Examples +```jldoctest +julia> A = zeros(4, 4); B = [1, 2, 3, 4]; + +julia> A .= B +4×4 Array{Float64,2}: + 1.0 1.0 1.0 1.0 + 2.0 2.0 2.0 2.0 + 3.0 3.0 3.0 3.0 + 4.0 4.0 4.0 4.0 + +julia> A +4×4 Array{Float64,2}: + 1.0 1.0 1.0 1.0 + 2.0 2.0 2.0 2.0 + 3.0 3.0 3.0 3.0 + 4.0 4.0 4.0 4.0 +``` +""" +kw".=" + +""" + . + +The dot operator is used to access fields or properties of objects and access +variables defined inside modules. + +In general, `a.b` calls `getproperty(a, :b)` (see [`getproperty`](@ref Base.getproperty)). + +# Examples +```jldoctest +julia> z = 1 + 2im; z.im +2 + +julia> Iterators.product +product (generic function with 1 method) +``` +""" +kw"." + """ let diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index b245330aabc5e..5479ea8f29e02 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -31,12 +31,21 @@ function _helpmode(io::IO, line::AbstractString) extended_help_on[] = nothing brief = true end + # interpret anything starting with # or #= as asking for help on comments + if startswith(line, "#") + if startswith(line, "#=") + line = "#=" + else + line = "#" + end + end x = Meta.parse(line, raise = false, depwarn = false) + assym = Symbol(line) expr = - if haskey(keywords, Symbol(line)) || isexpr(x, :error) || isexpr(x, :invalid) + if haskey(keywords, assym) || Base.isoperator(assym) || isexpr(x, :error) || isexpr(x, :invalid) # Docs for keywords must be treated separately since trying to parse a single # keyword such as `function` would throw a parse error due to the missing `end`. - Symbol(line) + assym elseif isexpr(x, (:using, :import)) x.head else @@ -185,20 +194,33 @@ doc(object, sig::Type = Union{}) = doc(aliasof(object, typeof(object)), sig) doc(object, sig...) = doc(object, Tuple{sig...}) function lookup_doc(ex) + if isa(ex, Expr) && ex.head !== :(.) && Base.isoperator(ex.head) + # handle syntactic operators, e.g. +=, ::, .= + ex = ex.head + end if haskey(keywords, ex) - parsedoc(keywords[ex]) + return parsedoc(keywords[ex]) elseif Meta.isexpr(ex, :incomplete) return :($(Markdown.md"No documentation found.")) - elseif isa(ex, Union{Expr, Symbol}) - binding = esc(bindingexpr(namify(ex))) - if isexpr(ex, :call) || isexpr(ex, :macrocall) - sig = esc(signature(ex)) - :($(doc)($binding, $sig)) - else - :($(doc)($binding)) + elseif !isa(ex, Expr) && !isa(ex, Symbol) + return :($(doc)($(typeof)($(esc(ex))))) + end + if isa(ex, Symbol) && Base.isoperator(ex) + str = string(ex) + if endswith(str, "=") + op = str[1:end-1] + return Markdown.parse("`x $op= y` is a synonym for `x = x $op y`") + elseif startswith(str, ".") + op = str[2:end] + return Markdown.parse("`x $ex y` is equivalent to `broadcast($op, x, y)`. See [`broadcast`](@ref).") end + end + binding = esc(bindingexpr(namify(ex))) + if isexpr(ex, :call) || isexpr(ex, :macrocall) + sig = esc(signature(ex)) + :($(doc)($binding, $sig)) else - :($(doc)($(typeof)($(esc(ex))))) + :($(doc)($binding)) end end @@ -335,7 +357,7 @@ function repl(io::IO, s::Symbol; brief::Bool=true) quote repl_latex($io, $str) repl_search($io, $str) - $(if !isdefined(Main, s) && !haskey(keywords, s) + $(if !isdefined(Main, s) && !haskey(keywords, s) && !Base.isoperator(s) :(repl_corrections($io, $str)) end) $(_repl(s, brief)) diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 7e97b88956eaa..3c391b616d800 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -1013,6 +1013,8 @@ fake_repl() do stdin_write, stdout_read, repl Base.wait(repltask) end +help_result(line) = Base.eval(REPL._helpmode(IOBuffer(), line)) + # Docs.helpmode tests: we test whether the correct expressions are being generated here, # rather than complete integration with Julia's REPL mode system. for (line, expr) in Pair[ @@ -1032,16 +1034,18 @@ for (line, expr) in Pair[ "import Foo" => :import, ] @test REPL._helpmode(line).args[4] == expr - buf = IOBuffer() - @test Base.eval(REPL._helpmode(buf, line)) isa Union{Markdown.MD,Nothing} + @test help_result(line) isa Union{Markdown.MD,Nothing} end # PR 30754, Issues #22013, #24871, #26933, #29282, #29361, #30348 -for line in ["′", "abstract", "type", "|=", ".="] +for line in ["′", "abstract", "type"] @test occursin("No documentation found.", - sprint(show, Base.eval(REPL._helpmode(IOBuffer(), line))::Union{Markdown.MD,Nothing})) + sprint(show, help_result(line)::Union{Markdown.MD,Nothing})) end +@test occursin("|=", sprint(show, help_result("|="))) +@test occursin("broadcast", sprint(show, help_result(".="))) + # Issue #25930 # Brief and extended docs (issue #25930)