Skip to content

Commit

Permalink
several improvements to help and docs for operators (JuliaLang#35154)
Browse files Browse the repository at this point in the history
- add docstrings for .= and .
- improve help prompt behavior on comment syntax
- add help text for dotted and updating operators
- remove `->` syntax from docstring for doc macro

Fixes JuliaLang#33301.
  • Loading branch information
JeffBezanson authored and oxinabox committed Apr 8, 2020
1 parent 2187c65 commit 7a62009
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 25 deletions.
16 changes: 7 additions & 9 deletions base/docs/Docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 50 additions & 0 deletions base/docs/basedocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 34 additions & 12 deletions stdlib/REPL/src/docview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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))
Expand Down
12 changes: 8 additions & 4 deletions stdlib/REPL/test/repl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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[
Expand All @@ -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)
Expand Down

0 comments on commit 7a62009

Please sign in to comment.