Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
754
julia-0.6.2/share/julia/base/docs/Docs.jl
Normal file
754
julia-0.6.2/share/julia/base/docs/Docs.jl
Normal file
@@ -0,0 +1,754 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
"""
|
||||
Docs
|
||||
|
||||
The `Docs` module provides the `@doc` macro which can be used to set and retrieve
|
||||
documentation metadata for Julia objects.
|
||||
|
||||
Please see the manual section on documentation for more
|
||||
information.
|
||||
"""
|
||||
module Docs
|
||||
|
||||
"""
|
||||
# Documentation
|
||||
|
||||
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:
|
||||
|
||||
@doc "blah" ->
|
||||
function foo() ...
|
||||
|
||||
The `->` is not required if the object is on the same line, e.g.
|
||||
|
||||
@doc "foo" foo
|
||||
|
||||
## Documenting objects after they are defined
|
||||
You can document an object after its definition by
|
||||
|
||||
@doc "foo" function_to_doc
|
||||
@doc "bar" TypeToDoc
|
||||
|
||||
For macros, the syntax is `@doc "macro doc" :(@Module.macro)` or `@doc "macro doc"
|
||||
:(string_macro"")` for string macros. Without the quote `:()` the expansion of the macro
|
||||
will be documented.
|
||||
|
||||
## Retrieving Documentation
|
||||
You can retrieve docs for functions, macros and other objects as follows:
|
||||
|
||||
@doc foo
|
||||
@doc @time
|
||||
@doc md""
|
||||
|
||||
## Functions & Methods
|
||||
Placing documentation before a method definition (e.g. `function foo() ...` or `foo() = ...`)
|
||||
will cause that specific method to be documented, as opposed to the whole function. Method
|
||||
docs are concatenated together in the order they were defined to provide docs for the
|
||||
function.
|
||||
"""
|
||||
:(Core.@doc)
|
||||
|
||||
include("bindings.jl")
|
||||
|
||||
import Base.Markdown: @doc_str, MD
|
||||
import Base.Meta: quot, isexpr
|
||||
import Base: Callable
|
||||
import ..CoreDocs: lazy_iterpolate
|
||||
|
||||
export doc
|
||||
|
||||
# Basic API / Storage
|
||||
|
||||
const modules = Module[]
|
||||
const META = gensym(:meta)
|
||||
|
||||
meta(m::Module = current_module()) = isdefined(m, META) ? getfield(m, META) : ObjectIdDict()
|
||||
|
||||
function initmeta(m::Module = current_module())
|
||||
if !isdefined(m, META)
|
||||
eval(m, :(const $META = $(ObjectIdDict())))
|
||||
push!(modules, m)
|
||||
end
|
||||
nothing
|
||||
end
|
||||
|
||||
function signature!(tv, expr::Expr)
|
||||
if isexpr(expr, (:call, :macrocall))
|
||||
sig = :(Union{Tuple{}})
|
||||
for arg in expr.args[2:end]
|
||||
isexpr(arg, :parameters) && continue
|
||||
if isexpr(arg, :kw) # optional arg
|
||||
push!(sig.args, :(Tuple{$(sig.args[end].args[2:end]...)}))
|
||||
end
|
||||
push!(sig.args[end].args, argtype(arg))
|
||||
end
|
||||
if isexpr(expr.args[1], :curly) && isempty(tv)
|
||||
append!(tv, tvar.(expr.args[1].args[2:end]))
|
||||
end
|
||||
for i = length(tv):-1:1
|
||||
push!(sig.args, :(Tuple{$(tv[i].args[1])}))
|
||||
end
|
||||
for i = length(tv):-1:1
|
||||
sig = Expr(:where, sig, tv[i])
|
||||
end
|
||||
sig
|
||||
elseif isexpr(expr, :where)
|
||||
append!(tv, tvar.(expr.args[2:end]))
|
||||
signature!(tv, expr.args[1])
|
||||
else
|
||||
signature!(tv, expr.args[1])
|
||||
end
|
||||
end
|
||||
signature!(tv, other) = :(Union{})
|
||||
signature(expr::Expr) = signature!([], expr)
|
||||
signature(other) = signature!([], other)
|
||||
|
||||
function argtype(expr::Expr)
|
||||
isexpr(expr, :(::)) && return expr.args[end]
|
||||
isexpr(expr, :(...)) && return :(Vararg{$(argtype(expr.args[1]))})
|
||||
argtype(expr.args[1])
|
||||
end
|
||||
argtype(other) = :Any
|
||||
|
||||
tvar(x::Expr) = x
|
||||
tvar(s::Symbol) = :($s <: Any)
|
||||
|
||||
# Docsystem types.
|
||||
# ================
|
||||
|
||||
"""
|
||||
Docs.DocStr
|
||||
|
||||
Stores the contents of a single docstring as well as related metadata.
|
||||
|
||||
Both the raw text, `.text`, and the parsed markdown, `.object`, are tracked by this type.
|
||||
Parsing of the raw text is done lazily when a request is made to render the docstring,
|
||||
which helps to reduce total precompiled image size.
|
||||
|
||||
The `.data` fields stores several values related to the docstring, such as: path,
|
||||
linenumber, source code, and fielddocs.
|
||||
"""
|
||||
mutable struct DocStr
|
||||
text :: Core.SimpleVector
|
||||
object :: Nullable
|
||||
data :: Dict{Symbol, Any}
|
||||
end
|
||||
|
||||
function docstr(binding::Binding, typesig::ANY = Union{})
|
||||
for m in modules
|
||||
dict = meta(m)
|
||||
if haskey(dict, binding)
|
||||
docs = dict[binding].docs
|
||||
if haskey(docs, typesig)
|
||||
return docs[typesig]
|
||||
end
|
||||
end
|
||||
end
|
||||
error("could not find matching docstring for '$binding :: $typesig'.")
|
||||
end
|
||||
docstr(object, data = Dict()) = _docstr(object, data)
|
||||
|
||||
_docstr(vec::Core.SimpleVector, data) = DocStr(vec, Nullable(), data)
|
||||
_docstr(str::AbstractString, data) = DocStr(Core.svec(str), Nullable(), data)
|
||||
_docstr(object, data) = DocStr(Core.svec(), Nullable(object), data)
|
||||
|
||||
_docstr(doc::DocStr, data) = (doc.data = merge(data, doc.data); doc)
|
||||
|
||||
macro ref(x)
|
||||
binding = bindingexpr(namify(x))
|
||||
typesig = signature(x)
|
||||
esc(docexpr(binding, typesig))
|
||||
end
|
||||
|
||||
docexpr(args...) = Expr(:call, docstr, args...)
|
||||
|
||||
function formatdoc(d::DocStr)
|
||||
buffer = IOBuffer()
|
||||
for part in d.text
|
||||
formatdoc(buffer, d, part)
|
||||
end
|
||||
Markdown.parse(seekstart(buffer))
|
||||
end
|
||||
@noinline formatdoc(buffer, d, part) = print(buffer, part)
|
||||
|
||||
function parsedoc(d::DocStr)
|
||||
if isnull(d.object)
|
||||
md = formatdoc(d)
|
||||
md.meta[:module] = d.data[:module]
|
||||
md.meta[:path] = d.data[:path]
|
||||
d.object = Nullable(md)
|
||||
end
|
||||
get(d.object)
|
||||
end
|
||||
|
||||
"""
|
||||
MultiDoc
|
||||
|
||||
Stores a collection of docstrings for related objects, ie. a `Function`/`DataType` and
|
||||
associated `Method` objects.
|
||||
|
||||
Each documented object in a `MultiDoc` is referred to by it's signature which is represented
|
||||
by a `Union` of `Tuple` types. For example the following `Method` definition
|
||||
|
||||
f(x, y) = ...
|
||||
|
||||
is stored as `Tuple{Any, Any}` in the `MultiDoc` while
|
||||
|
||||
f{T}(x::T, y = ?) = ...
|
||||
|
||||
is stored as `Union{Tuple{T, Any}, Tuple{T}} where T`.
|
||||
|
||||
Note: The `Function`/`DataType` object's signature is always `Union{}`.
|
||||
"""
|
||||
mutable struct MultiDoc
|
||||
"Ordered (via definition order) vector of object signatures."
|
||||
order::Vector{Type}
|
||||
"Documentation for each object. Keys are signatures."
|
||||
docs::ObjectIdDict
|
||||
|
||||
MultiDoc() = new(Type[], ObjectIdDict())
|
||||
end
|
||||
|
||||
# Docstring registration.
|
||||
# =======================
|
||||
|
||||
"""
|
||||
Docs.doc!(binding, str, sig)
|
||||
|
||||
Adds a new docstring `str` to the docsystem for `binding` and signature `sig`.
|
||||
"""
|
||||
function doc!(b::Binding, str::DocStr, sig::ANY = Union{})
|
||||
initmeta()
|
||||
m = get!(meta(), b, MultiDoc())
|
||||
if haskey(m.docs, sig)
|
||||
# We allow for docstrings to be updated, but print a warning since it is possible
|
||||
# that over-writing a docstring *may* have been accidental. The warning
|
||||
# is suppressed for symbols in Main, for interactive use (#23011).
|
||||
current_module() == Main || warn("replacing docs for '$b :: $sig' in module '$(current_module())'.")
|
||||
else
|
||||
# The ordering of docstrings for each Binding is defined by the order in which they
|
||||
# are initially added. Replacing a specific docstring does not change it's ordering.
|
||||
push!(m.order, sig)
|
||||
end
|
||||
m.docs[sig] = str
|
||||
str.data[:binding] = b
|
||||
str.data[:typesig] = sig
|
||||
return b
|
||||
end
|
||||
|
||||
# Docstring lookup.
|
||||
# =================
|
||||
|
||||
"""
|
||||
getdoc(obj)
|
||||
getdoc(obj, sig)
|
||||
|
||||
Return a custom docstring object associated with the object `obj` and, optionally, the tuple
|
||||
type signature `sig`. See `MultiDoc` docs for an explanation of the possible values of `sig`.
|
||||
|
||||
The returned object can either be a markdown object generated by `Markdown.parse` or some
|
||||
other custom type used to display non-markdown formatted documentation.
|
||||
|
||||
A return value of `nothing` can be used to signify to the docsystem that no documentation
|
||||
was found for `obj`, in which case the docsystem will fall back to searching for the
|
||||
`Binding` associated with `obj` instead.
|
||||
"""
|
||||
function getdoc end
|
||||
|
||||
getdoc(x, sig) = getdoc(x)
|
||||
getdoc(x) = nothing
|
||||
|
||||
"""
|
||||
Docs.doc(binding, sig)
|
||||
|
||||
Returns all documentation that matches both `binding` and `sig`.
|
||||
|
||||
If `getdoc` returns a non-`nothing` result on the value of the binding, then a
|
||||
dynamic docstring is returned instead of one based on the binding itself.
|
||||
"""
|
||||
function doc(binding::Binding, sig::Type = Union{})
|
||||
if defined(binding)
|
||||
result = getdoc(resolve(binding), sig)
|
||||
result === nothing || return result
|
||||
end
|
||||
results, groups = DocStr[], MultiDoc[]
|
||||
# Lookup `binding` and `sig` for matches in all modules of the docsystem.
|
||||
for mod in modules
|
||||
dict = meta(mod)
|
||||
if haskey(dict, binding)
|
||||
multidoc = dict[binding]
|
||||
push!(groups, multidoc)
|
||||
for msig in multidoc.order
|
||||
sig <: msig && push!(results, multidoc.docs[msig])
|
||||
end
|
||||
end
|
||||
end
|
||||
if isempty(groups)
|
||||
# When no `MultiDoc`s are found that match `binding` then we check whether `binding`
|
||||
# is an alias of some other `Binding`. When it is we then re-run `doc` with that
|
||||
# `Binding`, otherwise if it's not an alias then we generate a summary for the
|
||||
# `binding` and display that to the user instead.
|
||||
alias = aliasof(binding)
|
||||
alias == binding ? summarize(alias, sig) : doc(alias, sig)
|
||||
else
|
||||
# There was at least one match for `binding` while searching. If there weren't any
|
||||
# matches for `sig` then we concatenate *all* the docs from the matching `Binding`s.
|
||||
if isempty(results)
|
||||
for group in groups, each in group.order
|
||||
push!(results, group.docs[each])
|
||||
end
|
||||
end
|
||||
# Get parsed docs and concatenate them.
|
||||
md = catdoc(map(parsedoc, results)...)
|
||||
# Save metadata in the generated markdown.
|
||||
if isa(md, Markdown.MD)
|
||||
md.meta[:results] = results
|
||||
md.meta[:binding] = binding
|
||||
md.meta[:typesig] = sig
|
||||
end
|
||||
return md
|
||||
end
|
||||
end
|
||||
|
||||
# Some additional convenience `doc` methods that take objects rather than `Binding`s.
|
||||
doc(obj::UnionAll) = doc(Base.unwrap_unionall(obj))
|
||||
doc(object, sig::Type = Union{}) = doc(aliasof(object, typeof(object)), sig)
|
||||
doc(object, sig...) = doc(object, Tuple{sig...})
|
||||
|
||||
"""
|
||||
Docs.fielddoc(binding, field)
|
||||
|
||||
Returns documentation for a particular `field` of a type if it exists.
|
||||
"""
|
||||
function fielddoc(binding::Binding, field::Symbol)
|
||||
for mod in modules
|
||||
dict = meta(mod)
|
||||
if haskey(dict, binding)
|
||||
multidoc = dict[binding]
|
||||
if haskey(multidoc.docs, Union{})
|
||||
fields = multidoc.docs[Union{}].data[:fields]
|
||||
if haskey(fields, field)
|
||||
doc = fields[field]
|
||||
return isa(doc, Markdown.MD) ? doc : Markdown.parse(doc)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
fields = join(["`$f`" for f in fieldnames(resolve(binding))], ", ", ", and ")
|
||||
fields = isempty(fields) ? "no fields" : "fields $fields"
|
||||
Markdown.parse("`$(resolve(binding))` has $fields.")
|
||||
end
|
||||
|
||||
# As with the additional `doc` methods, this converts an object to a `Binding` first.
|
||||
fielddoc(object, field::Symbol) = fielddoc(aliasof(object, typeof(object)), field)
|
||||
|
||||
# Object Summaries.
|
||||
# =================
|
||||
|
||||
function summarize(binding::Binding, sig)
|
||||
io = IOBuffer()
|
||||
println(io, "No documentation found.\n")
|
||||
if defined(binding)
|
||||
summarize(io, resolve(binding), binding)
|
||||
else
|
||||
println(io, "Binding `", binding, "` does not exist.")
|
||||
end
|
||||
md = Markdown.parse(seekstart(io))
|
||||
# Save metadata in the generated markdown.
|
||||
md.meta[:results] = DocStr[]
|
||||
md.meta[:binding] = binding
|
||||
md.meta[:typesig] = sig
|
||||
return md
|
||||
end
|
||||
|
||||
function summarize(io::IO, λ::Function, binding)
|
||||
kind = startswith(string(binding.var), '@') ? "macro" : "`Function`"
|
||||
println(io, "`", binding, "` is a ", kind, ".")
|
||||
println(io, "```\n", methods(λ), "\n```")
|
||||
end
|
||||
|
||||
function summarize(io::IO, T::DataType, binding)
|
||||
println(io, "**Summary:**")
|
||||
println(io, "```")
|
||||
println(io,
|
||||
T.abstract ? "abstract type" :
|
||||
T.mutable ? "mutable struct" :
|
||||
Base.isstructtype(T) ? "struct" : "primitive type",
|
||||
" ", T, " <: ", supertype(T)
|
||||
)
|
||||
println(io, "```")
|
||||
if !isempty(fieldnames(T))
|
||||
println(io, "**Fields:**")
|
||||
println(io, "```")
|
||||
pad = maximum(length(string(f)) for f in fieldnames(T))
|
||||
for (f, t) in zip(fieldnames(T), T.types)
|
||||
println(io, rpad(f, pad), " :: ", t)
|
||||
end
|
||||
println(io, "```")
|
||||
end
|
||||
if !isempty(subtypes(T))
|
||||
println(io, "**Subtypes:**")
|
||||
println(io, "```")
|
||||
for t in subtypes(T)
|
||||
println(io, t)
|
||||
end
|
||||
println(io, "```")
|
||||
end
|
||||
end
|
||||
|
||||
function summarize(io::IO, m::Module, binding)
|
||||
readme = Pkg.dir(string(m), "README.md")
|
||||
if isfile(readme)
|
||||
println(io, "Displaying the `README.md` for the module instead.\n")
|
||||
println(io, "---\n")
|
||||
println(io, readstring(readme))
|
||||
else
|
||||
println(io, "No docstring or `README.md` found for module `", m, "`.\n")
|
||||
end
|
||||
end
|
||||
|
||||
function summarize{T}(io::IO, ::T, binding)
|
||||
println(io, "`", binding, "` is of type `", T, "`.\n")
|
||||
summarize(io, T, binding)
|
||||
end
|
||||
|
||||
# Utilities.
|
||||
# ==========
|
||||
|
||||
"""
|
||||
`catdoc(xs...)`: Combine the documentation metadata `xs` into a single meta object.
|
||||
"""
|
||||
catdoc() = nothing
|
||||
catdoc(xs...) = vcat(xs...)
|
||||
|
||||
const keywords = Dict{Symbol, DocStr}()
|
||||
|
||||
isdoc(s::AbstractString) = true
|
||||
|
||||
isdoc(x) = isexpr(x, :string) ||
|
||||
(isexpr(x, :macrocall) && x.args[1] === Symbol("@doc_str")) ||
|
||||
(isexpr(x, :call) && x.args[1] === Base.Markdown.doc_str)
|
||||
|
||||
function unblock(ex)
|
||||
isexpr(ex, :block) || return ex
|
||||
exs = filter(ex -> !(isa(ex, LineNumberNode) || isexpr(ex, :line)), ex.args)
|
||||
length(exs) == 1 || return ex
|
||||
return unblock(exs[1])
|
||||
end
|
||||
|
||||
uncurly(ex) = isexpr(ex, :curly) ? ex.args[1] : ex
|
||||
|
||||
namify(x) = nameof(x, isexpr(x, :macro))
|
||||
|
||||
function nameof(x::Expr, ismacro)
|
||||
if isexpr(x, :.)
|
||||
ismacro ? macroname(x) : x
|
||||
else
|
||||
n = isexpr(x, (:module, :type, :bitstype)) ? 2 : 1
|
||||
nameof(x.args[n], ismacro)
|
||||
end
|
||||
end
|
||||
nameof(q::QuoteNode, ismacro) = nameof(q.value, ismacro)
|
||||
nameof(s::Symbol, ismacro) = ismacro ? macroname(s) : s
|
||||
nameof(other, ismacro) = other
|
||||
|
||||
macroname(s::Symbol) = Symbol('@', s)
|
||||
macroname(x::Expr) = Expr(x.head, x.args[1], macroname(x.args[end].value))
|
||||
|
||||
isfield(x) = isexpr(x, :.) &&
|
||||
(isa(x.args[1], Symbol) || isfield(x.args[1])) &&
|
||||
(isa(x.args[2], QuoteNode) || isexpr(x.args[2], :quote))
|
||||
|
||||
# @doc expression builders.
|
||||
# =========================
|
||||
|
||||
"""
|
||||
Docs.metadata(expr)
|
||||
|
||||
Build a `Dict` expression containing metadata captured from the expression `expr`.
|
||||
|
||||
Fields that may be included in the returned `Dict`:
|
||||
|
||||
- `:path`: String representing the file where `expr` is defined.
|
||||
- `:linenumber`: Linenumber where `expr` is defined.
|
||||
- `:module`: Module where the docstring is defined.
|
||||
- `:fields`: `Dict` of all field docs found in `expr`. Only for concrete types.
|
||||
"""
|
||||
function metadata(expr)
|
||||
args = []
|
||||
# Filename and linenumber of the docstring.
|
||||
push!(args, :($(Pair)(:path, $(Base).@__FILE__)))
|
||||
push!(args, :($(Pair)(:linenumber, $(unsafe_load(cglobal(:jl_lineno, Cint))))))
|
||||
# Module in which the docstring is defined.
|
||||
push!(args, :($(Pair)(:module, $(current_module)())))
|
||||
# Field docs for concrete types.
|
||||
if isexpr(expr, :type)
|
||||
fields = []
|
||||
tmp = nothing
|
||||
for each in expr.args[3].args
|
||||
if isdoc(each)
|
||||
tmp = each
|
||||
elseif tmp !== nothing && (isa(each, Symbol) || isexpr(each, :(::)))
|
||||
push!(fields, (namify(each), tmp))
|
||||
tmp = nothing
|
||||
end
|
||||
end
|
||||
dict = :($(Dict)($([:($(Pair)($(quot(f)), $d)) for (f, d) in fields]...)))
|
||||
push!(args, :($(Pair)(:fields, $dict)))
|
||||
end
|
||||
:($(Dict)($(args...)))
|
||||
end
|
||||
|
||||
function keyworddoc(str, def)
|
||||
docstr = esc(docexpr(lazy_iterpolate(str), metadata(def)))
|
||||
:($(keywords)[$(esc(quot(def.name)))] = $docstr)
|
||||
end
|
||||
|
||||
function objectdoc(str, def, expr, sig = :(Union{}))
|
||||
binding = esc(bindingexpr(namify(expr)))
|
||||
docstr = esc(docexpr(lazy_iterpolate(str), metadata(expr)))
|
||||
quote
|
||||
$(esc(def))
|
||||
$(doc!)($binding, $docstr, $(esc(sig)))
|
||||
end
|
||||
end
|
||||
|
||||
function calldoc(str, def)
|
||||
args = def.args[2:end]
|
||||
if isempty(args) || all(validcall, args)
|
||||
objectdoc(str, nothing, def, signature(def))
|
||||
else
|
||||
docerror(def)
|
||||
end
|
||||
end
|
||||
validcall(x) = isa(x, Symbol) || isexpr(x, (:(::), :..., :kw, :parameters))
|
||||
|
||||
function moduledoc(meta, def, def′)
|
||||
name = namify(def′)
|
||||
docex = Expr(:call, doc!, bindingexpr(name),
|
||||
docexpr(lazy_iterpolate(meta), metadata(name))
|
||||
)
|
||||
if def === nothing
|
||||
esc(:(eval($name, $(quot(docex)))))
|
||||
else
|
||||
def = unblock(def)
|
||||
block = def.args[3].args
|
||||
if !def.args[1]
|
||||
isempty(block) && error("empty baremodules are not documentable.")
|
||||
insert!(block, 2, :(import Base: @doc))
|
||||
end
|
||||
push!(block, docex)
|
||||
esc(Expr(:toplevel, def))
|
||||
end
|
||||
end
|
||||
|
||||
# Shares a single doc, `meta`, between several expressions from the tuple expression `ex`.
|
||||
function multidoc(meta, ex, define)
|
||||
out = Expr(:toplevel)
|
||||
str = docexpr(lazy_iterpolate(meta), metadata(ex))
|
||||
ref = Ref{DocStr}()
|
||||
for (n, arg) in enumerate(ex.args)
|
||||
# The first `arg` to be documented needs to also create the docstring for the group.
|
||||
# Subsequent `arg`s just need `ref` to be able to find the docstring without having
|
||||
# to create an entirely new one each.
|
||||
docstr = n === 1 ? :($(ref)[] = $str) : :($(ref)[])
|
||||
push!(out.args, :(@doc($docstr, $arg, $define)))
|
||||
end
|
||||
esc(out)
|
||||
end
|
||||
|
||||
"""
|
||||
@__doc__(ex)
|
||||
|
||||
Low-level macro used to mark expressions returned by a macro that should be documented. If
|
||||
more than one expression is marked then the same docstring is applied to each expression.
|
||||
|
||||
macro example(f)
|
||||
quote
|
||||
\$(f)() = 0
|
||||
@__doc__ \$(f)(x) = 1
|
||||
\$(f)(x, y) = 2
|
||||
end |> esc
|
||||
end
|
||||
|
||||
`@__doc__` has no effect when a macro that uses it is not documented.
|
||||
"""
|
||||
:(Core.@__doc__)
|
||||
|
||||
function __doc__!(meta, def, define)
|
||||
# Two cases must be handled here to avoid redefining all definitions contained in `def`:
|
||||
if define
|
||||
# `def` has not been defined yet (this is the common case, i.e. when not generating
|
||||
# the Base image). We just need to convert each `@__doc__` marker to an `@doc`.
|
||||
finddoc(def) do each
|
||||
each.head = :macrocall
|
||||
each.args = [Symbol("@doc"), meta, each.args[end], define]
|
||||
end
|
||||
else
|
||||
# `def` has already been defined during Base image gen so we just need to find and
|
||||
# document any subexpressions marked with `@__doc__`.
|
||||
docs = []
|
||||
found = finddoc(def) do each
|
||||
push!(docs, :(@doc($meta, $(each.args[end]), $define)))
|
||||
end
|
||||
# If any subexpressions have been documented then replace the entire expression with
|
||||
# just those documented subexpressions to avoid redefining any definitions.
|
||||
if found
|
||||
def.head = :toplevel
|
||||
def.args = docs
|
||||
end
|
||||
found
|
||||
end
|
||||
end
|
||||
# Walk expression tree `def` and call `λ` when any `@__doc__` markers are found. Returns
|
||||
# `true` to signify that at least one `@__doc__` has been found, and `false` otherwise.
|
||||
function finddoc(λ, def::Expr)
|
||||
if isexpr(def, :block, 2) && isexpr(def.args[1], :meta, 1) && def.args[1].args[1] === :doc
|
||||
# Found the macroexpansion of an `@__doc__` expression.
|
||||
λ(def)
|
||||
true
|
||||
else
|
||||
found = false
|
||||
for each in def.args
|
||||
found |= finddoc(λ, each)
|
||||
end
|
||||
found
|
||||
end
|
||||
end
|
||||
finddoc(λ, def) = false
|
||||
|
||||
# Predicates and helpers for `docm` expression selection:
|
||||
|
||||
const FUNC_HEADS = [:function, :stagedfunction, :macro, :(=)]
|
||||
const BINDING_HEADS = [:typealias, :const, :global, :(=)] # deprecation: remove `typealias` post-0.6
|
||||
# For the special `:@mac` / `:(Base.@mac)` syntax for documenting a macro after definition.
|
||||
isquotedmacrocall(x) =
|
||||
isexpr(x, :copyast, 1) &&
|
||||
isa(x.args[1], QuoteNode) &&
|
||||
isexpr(x.args[1].value, :macrocall, 1)
|
||||
# Simple expressions / atoms the may be documented.
|
||||
isbasicdoc(x) = isexpr(x, :.) || isa(x, Union{QuoteNode, Symbol})
|
||||
is_signature(x) = isexpr(x, :call) || (isexpr(x, :(::), 2) && isexpr(x.args[1], :call)) || isexpr(x, :where)
|
||||
|
||||
function docm(meta, ex, define = true)
|
||||
# Some documented expressions may be decorated with macro calls which obscure the actual
|
||||
# expression. Expand the macro calls and remove extra blocks.
|
||||
x = unblock(macroexpand(ex))
|
||||
# Don't try to redefine expressions. This is only needed for `Base` img gen since
|
||||
# otherwise calling `loaddocs` would redefine all documented functions and types.
|
||||
def = define ? x : nothing
|
||||
if isa(x, GlobalRef) && (x::GlobalRef).mod == current_module()
|
||||
x = (x::GlobalRef).name
|
||||
end
|
||||
|
||||
# Keywords using the `@kw_str` macro in `base/docs/basedocs.jl`.
|
||||
#
|
||||
# "..."
|
||||
# kw"if", kw"else"
|
||||
#
|
||||
isa(x, Base.BaseDocs.Keyword) ? keyworddoc(meta, x) :
|
||||
|
||||
# Method / macro definitions and "call" syntax.
|
||||
#
|
||||
# function f(...) ... end
|
||||
# f(...) = ...
|
||||
# macro m(...) end
|
||||
# function f end
|
||||
# f(...)
|
||||
#
|
||||
isexpr(x, FUNC_HEADS) && is_signature(x.args[1]) ? objectdoc(meta, def, x, signature(x)) :
|
||||
isexpr(x, :function) && !isexpr(x.args[1], :call) ? objectdoc(meta, def, x) :
|
||||
isexpr(x, :call) ? calldoc(meta, x) :
|
||||
|
||||
# Type definitions.
|
||||
#
|
||||
# type T ... end
|
||||
# abstract T
|
||||
# bitstype N T
|
||||
#
|
||||
isexpr(x, [:type, :abstract, :bitstype]) ? objectdoc(meta, def, x) :
|
||||
|
||||
# "Bindings". Names that resolve to objects with different names, ie.
|
||||
#
|
||||
# const T = S
|
||||
# T = S
|
||||
# global T = S
|
||||
#
|
||||
isexpr(x, BINDING_HEADS) && !isexpr(x.args[1], :call) ? objectdoc(meta, def, x) :
|
||||
|
||||
# Quoted macrocall syntax. `:@time` / `:(Base.@time)`.
|
||||
isquotedmacrocall(x) ? objectdoc(meta, def, x) :
|
||||
# Modules and baremodules.
|
||||
isexpr(x, :module) ? moduledoc(meta, def, x) :
|
||||
# Document several expressions with the same docstring. `a, b, c`.
|
||||
isexpr(x, :tuple) ? multidoc(meta, x, define) :
|
||||
# Errors generated by calling `macroexpand` are passed back to the call site.
|
||||
isexpr(x, :error) ? esc(x) :
|
||||
# When documenting macro-generated code we look for embedded `@__doc__` calls.
|
||||
__doc__!(meta, x, define) ? esc(x) :
|
||||
# Any "basic" expression such as a bare function or module name or numeric literal.
|
||||
isbasicdoc(x) ? objectdoc(meta, nothing, x) :
|
||||
|
||||
# All other expressions are undocumentable and should be handled on a case-by-case basis
|
||||
# with `@__doc__`. Unbound string literals are also undocumentable since they cannot be
|
||||
# retrieved from the module's metadata `ObjectIdDict` without a reference to the string.
|
||||
docerror(ex)
|
||||
end
|
||||
|
||||
function docerror(ex)
|
||||
txt = """
|
||||
cannot document the following expression:
|
||||
|
||||
$(isa(ex, AbstractString) ? repr(ex) : ex)"""
|
||||
if isexpr(ex, :macrocall)
|
||||
txt *= "\n\n'$(ex.args[1])' not documentable. See 'Base.@__doc__' docs for details."
|
||||
end
|
||||
:($(error)($txt, "\n"))
|
||||
end
|
||||
|
||||
function docm(ex)
|
||||
if isexpr(ex, :->)
|
||||
docm(ex.args...)
|
||||
elseif haskey(keywords, ex)
|
||||
parsedoc(keywords[ex])
|
||||
elseif isa(ex, Union{Expr, Symbol})
|
||||
binding = esc(bindingexpr(namify(ex)))
|
||||
if isexpr(ex, [:call, :macrocall])
|
||||
sig = esc(signature(ex))
|
||||
:($(doc)($binding, $sig))
|
||||
else
|
||||
:($(doc)($binding))
|
||||
end
|
||||
else
|
||||
:($(doc)($(typeof)($(esc(ex)))))
|
||||
end
|
||||
end
|
||||
|
||||
# MD support
|
||||
catdoc(md::MD...) = MD(md...)
|
||||
|
||||
include("utils.jl")
|
||||
|
||||
# Swap out the bootstrap macro with the real one.
|
||||
Core.atdoc!(docm)
|
||||
|
||||
function loaddocs(docs)
|
||||
for (mod, ex, str, file, line) in docs
|
||||
data = Dict(:path => string(file), :linenumber => line)
|
||||
doc = docstr(str, data)
|
||||
eval(mod, :(@doc($doc, $ex, false)))
|
||||
end
|
||||
empty!(docs)
|
||||
end
|
||||
|
||||
end
|
||||
744
julia-0.6.2/share/julia/base/docs/basedocs.jl
Normal file
744
julia-0.6.2/share/julia/base/docs/basedocs.jl
Normal file
@@ -0,0 +1,744 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module BaseDocs
|
||||
|
||||
struct Keyword
|
||||
name :: Symbol
|
||||
end
|
||||
macro kw_str(text) Keyword(Symbol(text)) end
|
||||
|
||||
"""
|
||||
**Welcome to Julia $(string(VERSION)).** The full manual is available at
|
||||
|
||||
https://docs.julialang.org/
|
||||
|
||||
as well many great tutorials and learning resources:
|
||||
|
||||
https://julialang.org/learning/
|
||||
|
||||
For help on a specific function or macro, type `?` followed
|
||||
by its name, e.g. `?fft`, or `?@time`, and press enter.
|
||||
"""
|
||||
kw"help", kw"?", kw"julia"
|
||||
|
||||
"""
|
||||
`using` will load the given module or package and make some of its names available for
|
||||
use (see also `export`). For example:
|
||||
|
||||
using Gadfly
|
||||
|
||||
loads the plotting package, Gadfly, so that the `plot` function can be used.
|
||||
|
||||
Names can be used via dot syntax, whether they are exported or not:
|
||||
|
||||
Gadfly.plot(...)
|
||||
|
||||
If you don't want to use the packages exports directly, see also `import`. If you're not
|
||||
sure, `using` is almost definitely what you want.
|
||||
"""
|
||||
kw"using"
|
||||
|
||||
"""
|
||||
import Gadfly
|
||||
|
||||
`import`, like `using`, will load modules and packages for use. Unlike `using`, however,
|
||||
it will *not* make any `export`ed names available for use. To use Gadfly's `plot`
|
||||
function after importing it, for example, you have to write:
|
||||
|
||||
Gadfly.plot(...)
|
||||
|
||||
Import can also be used with specific names, for example
|
||||
|
||||
import Gadfly: plot, render
|
||||
|
||||
This syntax is used when you want to extend the modules functions with new methods.
|
||||
"""
|
||||
kw"import"
|
||||
|
||||
"""
|
||||
`export` is used within modules and packages to tell Julia which functions should be
|
||||
made available to the user. For example:
|
||||
|
||||
module Test
|
||||
export foo # foo is exported, but bar isn't
|
||||
foo(x) = x
|
||||
bar(y) = y
|
||||
end
|
||||
|
||||
using Test
|
||||
foo(1) # 1
|
||||
bar(1) # Error: bar not defined
|
||||
Test.bar(1) # 1
|
||||
"""
|
||||
kw"export"
|
||||
|
||||
"""
|
||||
`abstract type` declares a type that cannot be instantiated, and serves only as a node in the
|
||||
type graph, thereby describing sets of related concrete types: those concrete types
|
||||
which are their descendants. Abstract types form the conceptual hierarchy which makes
|
||||
Julia’s type system more than just a collection of object implementations. For example:
|
||||
|
||||
abstract type Number end
|
||||
abstract type Real <: Number end
|
||||
|
||||
[`Number`](@ref) has no supertype, whereas [`Real`](@ref) is an abstract subtype of `Number`.
|
||||
"""
|
||||
kw"abstract type"
|
||||
|
||||
"""
|
||||
`module` declares a Module, which is a separate global variable workspace. Within a
|
||||
module, you can control which names from other modules are visible (via importing), and
|
||||
specify which of your names are intended to be public (via exporting). For example:
|
||||
|
||||
module
|
||||
import Base.show
|
||||
export MyType, foo
|
||||
|
||||
type MyType
|
||||
x
|
||||
end
|
||||
|
||||
bar(x) = 2x
|
||||
foo(a::MyType) = bar(a.x) + 1
|
||||
show(io, a::MyType) = print(io, "MyType \$(a.x)")
|
||||
end
|
||||
|
||||
Modules allow you to create top-level definitions without worrying about name conflicts
|
||||
when your code is used together with somebody else’s.
|
||||
"""
|
||||
kw"module"
|
||||
|
||||
"""
|
||||
`baremodule` declares a module that does not contain `using Base`
|
||||
or a definition of `eval`. It does still import `Core`.
|
||||
"""
|
||||
kw"baremodule"
|
||||
|
||||
"""
|
||||
`primitive type` declares a concrete type whose data consists only of a series of bits. Classic
|
||||
examples of primitive types are integers and floating-point values. Some example built-in
|
||||
primitive type declarations:
|
||||
|
||||
primitive type Char 32 end
|
||||
primitive type Bool <: Integer 8 end
|
||||
|
||||
The number after the name indicates how many bits of storage the type requires. Currently,
|
||||
only sizes that are multiples of 8 bits are supported.
|
||||
The [`Bool`](@ref) declaration shows how a primitive type can be optionally
|
||||
declared to be a subtype of some supertype.
|
||||
"""
|
||||
kw"primitive type"
|
||||
|
||||
"""
|
||||
`macro` defines a method to include generated code in the final body of a program. A
|
||||
macro maps a tuple of arguments to a returned expression, and the resulting expression
|
||||
is compiled directly rather than requiring a runtime `eval()` call. Macro arguments may
|
||||
include expressions, literal values, and symbols. For example:
|
||||
|
||||
macro sayhello(name)
|
||||
return :( println("Hello, ", \$name) )
|
||||
end
|
||||
|
||||
This macro takes one argument: `name`. When `@sayhello` is encountered, the quoted
|
||||
expression is expanded to interpolate the value of the argument into the final
|
||||
expression.
|
||||
"""
|
||||
kw"macro"
|
||||
|
||||
"""
|
||||
`importall` imports all names exported by the specified module, as if `import` were used
|
||||
individually on all of them. For example:
|
||||
|
||||
importall Distributions
|
||||
|
||||
As with `import`, functions imported by `importall` can be extended.
|
||||
"""
|
||||
kw"importall"
|
||||
|
||||
"""
|
||||
`local` introduces a new local variable. For example:
|
||||
|
||||
function foo(n)
|
||||
x = 0
|
||||
for i = 1:n
|
||||
local x
|
||||
x = i
|
||||
end
|
||||
x
|
||||
end
|
||||
|
||||
julia> foo(10)
|
||||
0
|
||||
|
||||
Here `local x` introduces a separate `x` inside the loop, so the function returns `0`.
|
||||
"""
|
||||
kw"local"
|
||||
|
||||
"""
|
||||
`global x` makes `x` in the current scope and its inner scopes refer to the global
|
||||
variable of that name. In the example below, `global` is needed so the function can
|
||||
modify the global variable `z`:
|
||||
|
||||
z=3
|
||||
function foo()
|
||||
global z=6
|
||||
end
|
||||
|
||||
julia> foo()
|
||||
6
|
||||
julia> z
|
||||
6
|
||||
|
||||
Without the `global` declaration in `foo()`, a new local variable would have been
|
||||
created inside foo(), and the `z` in the global scope would have remained equal to `3`.
|
||||
"""
|
||||
kw"global"
|
||||
|
||||
"""
|
||||
`let` statements allocate new variable bindings each time they run. Whereas an
|
||||
assignment modifies an existing value location, `let` creates new locations. This
|
||||
difference is only detectable in the case of variables that outlive their scope via
|
||||
closures. The `let` syntax accepts a comma-separated series of assignments and variable
|
||||
names:
|
||||
|
||||
let var1 = value1, var2, var3 = value3
|
||||
code
|
||||
end
|
||||
|
||||
The assignments are evaluated in order, with each right-hand side evaluated in the scope
|
||||
before the new variable on the left-hand side has been introduced. Therefore it makes
|
||||
sense to write something like `let x = x`, since the two `x` variables are distinct and
|
||||
have separate storage.
|
||||
"""
|
||||
kw"let"
|
||||
|
||||
"""
|
||||
`quote` creates multiple expression objects in a block without using the explicit `Expr`
|
||||
constructor. For example:
|
||||
|
||||
ex = quote
|
||||
x = 1
|
||||
y = 2
|
||||
x + y
|
||||
end
|
||||
|
||||
Unlike the other means of quoting, `:( ... )`, this form introduces `QuoteNode` elements
|
||||
to the expression tree, which must be considered when directly manipulating the tree.
|
||||
For other purposes, `:( ... )` and `quote .. end` blocks are treated identically.
|
||||
"""
|
||||
kw"quote"
|
||||
|
||||
"""
|
||||
`'` is the conjugate transposition operator:
|
||||
|
||||
julia> A = reshape(1:4, 2,2)
|
||||
2×2 Array{Int64,2}:
|
||||
1 3
|
||||
2 4
|
||||
|
||||
julia> A'
|
||||
2×2 Array{Int64,2}:
|
||||
1 2
|
||||
3 4
|
||||
|
||||
julia> B = A + im
|
||||
2×2 Array{Complex{Int64},2}:
|
||||
1+1im 3+1im
|
||||
2+1im 4+1im
|
||||
|
||||
julia> B'
|
||||
2×2 Array{Complex{Int64},2}:
|
||||
1-1im 2-1im
|
||||
3-1im 4-1im
|
||||
|
||||
"""
|
||||
kw"'"
|
||||
|
||||
|
||||
"""
|
||||
`.'` is the transposition operator:
|
||||
|
||||
julia> A = reshape(1:4, 2,2)
|
||||
2×2 Array{Int64,2}:
|
||||
1 3
|
||||
2 4
|
||||
|
||||
julia> A.'
|
||||
2×2 Array{Int64,2}:
|
||||
1 2
|
||||
3 4
|
||||
|
||||
julia> B = A + im
|
||||
2×2 Array{Complex{Int64},2}:
|
||||
1+1im 3+1im
|
||||
2+1im 4+1im
|
||||
|
||||
julia> B.'
|
||||
2×2 Array{Complex{Int64},2}:
|
||||
1+1im 2+1im
|
||||
3+1im 4+1im
|
||||
|
||||
julia> v = [1,2,3]
|
||||
3-element Array{Int64,1}:
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
julia> v.'
|
||||
1×3 RowVector{Int64,Array{Int64,1}}:
|
||||
1 2 3
|
||||
|
||||
"""
|
||||
kw".'"
|
||||
|
||||
"""
|
||||
`const` is used to declare global variables which are also constant. In almost all code
|
||||
(and particularly performance sensitive code) global variables should be declared
|
||||
constant in this way.
|
||||
|
||||
const x = 5
|
||||
|
||||
Note that "constant-ness" is not enforced inside containers, so if `x` is an array or
|
||||
dictionary (for example) you can still add and remove elements.
|
||||
|
||||
Technically, you can even redefine `const` variables, although this will generate a
|
||||
warning from the compiler. The only strict requirement is that the *type* of the
|
||||
variable does not change, which is why `const` variables are much faster than regular
|
||||
globals.
|
||||
"""
|
||||
kw"const"
|
||||
|
||||
"""
|
||||
Functions are defined with the `function` keyword:
|
||||
|
||||
function add(a, b)
|
||||
return a + b
|
||||
end
|
||||
|
||||
Or the short form notation:
|
||||
|
||||
add(a, b) = a + b
|
||||
|
||||
The use of the `return` keyword is exactly the same as in other languages, but is often
|
||||
optional. When it's not used, the last expression in the function body will be returned
|
||||
by default:
|
||||
|
||||
function compare(a, b)
|
||||
a == b && return "equal to"
|
||||
a < b ? "less than" : "greater than"
|
||||
end
|
||||
"""
|
||||
kw"function"
|
||||
|
||||
"""
|
||||
`return` can be used function bodies to exit early and return a given value, e.g.
|
||||
|
||||
function compare(a, b)
|
||||
a == b && return "equal to"
|
||||
a < b ? "less than" : "greater than"
|
||||
end
|
||||
|
||||
In general you can place a `return` statement anywhere within a function body, including
|
||||
within deeply nested loops or conditionals, but be careful with `do` blocks. For
|
||||
example:
|
||||
|
||||
function test1(xs)
|
||||
for x in xs
|
||||
iseven(x) && return 2x
|
||||
end
|
||||
end
|
||||
|
||||
function test2(xs)
|
||||
map(xs) do x
|
||||
iseven(x) && return 2x
|
||||
x
|
||||
end
|
||||
end
|
||||
|
||||
In the first example, the return breaks out of its enclosing function as soon as it hits
|
||||
an even number, so `test1([5,6,7])` returns `12`.
|
||||
|
||||
You might expect the second example to behave the same way, but in fact the `return`
|
||||
there only breaks out of the *inner* function (inside the `do` block) and gives a value
|
||||
back to `map`. `test2([5,6,7])` then returns `[5,12,7]`.
|
||||
"""
|
||||
kw"return"
|
||||
|
||||
"""
|
||||
`if`-`elseif`-`else` performs conditional evaluation, which allows portions of code to
|
||||
be evaluated or not evaluated depending on the value of a boolean expression. Here is
|
||||
the anatomy of the `if`-`elseif`-`else` conditional syntax:
|
||||
|
||||
if x < y
|
||||
println("x is less than y")
|
||||
elseif x > y
|
||||
println("x is greater than y")
|
||||
else
|
||||
println("x is equal to y")
|
||||
end
|
||||
|
||||
If the condition expression `x < y` is true, then the corresponding block is evaluated;
|
||||
otherwise the condition expression `x > y` is evaluated, and if it is true, the
|
||||
corresponding block is evaluated; if neither expression is true, the `else` block is
|
||||
evaluated. The `elseif` and `else` blocks are optional, and as many `elseif` blocks as
|
||||
desired can be used.
|
||||
"""
|
||||
kw"if", kw"elseif", kw"else"
|
||||
|
||||
"""
|
||||
`for` loops repeatedly evaluate the body of the loop by iterating over a sequence of
|
||||
values. For example:
|
||||
|
||||
for i in [1,4,0]
|
||||
println(i)
|
||||
end
|
||||
"""
|
||||
kw"for"
|
||||
|
||||
"""
|
||||
`while` loops repeatedly evaluate a conditional expression, and continues evaluating the
|
||||
body of the while loop so long as the expression remains `true`. If the condition
|
||||
expression is false when the while loop is first reached, the body is never evaluated.
|
||||
For example:
|
||||
|
||||
while i <= 5
|
||||
println(i)
|
||||
i += 1
|
||||
end
|
||||
"""
|
||||
kw"while"
|
||||
|
||||
"""
|
||||
`end` marks the conclusion of a block of expressions. In the example below, `end` marks
|
||||
the conclusion of a `function`.
|
||||
|
||||
function foo()
|
||||
println("hello, world")
|
||||
end
|
||||
|
||||
`end` marks the conclusion of all kinds of expression blocks: `module`, `type`, `begin`,
|
||||
`let`, `for`, etc.
|
||||
|
||||
In addition, `end` may be used when indexing into an array to represent the last index
|
||||
of each dimension:
|
||||
|
||||
x[1:end, 2:end-1]
|
||||
"""
|
||||
kw"end"
|
||||
|
||||
"""
|
||||
A `try/catch` statement allows for `Exception`s to be tested for. For example, a
|
||||
customized square root function can be written to automatically call either the real or
|
||||
complex square root method on demand using `Exception`s:
|
||||
|
||||
f(x) = try
|
||||
sqrt(x)
|
||||
catch
|
||||
sqrt(complex(x, 0))
|
||||
end
|
||||
|
||||
`try/catch` statements also allow the `Exception` to be saved in a variable, e.g. `catch y`.
|
||||
|
||||
The `catch` clause is not strictly necessary; when omitted, the default return value is
|
||||
`nothing`. The power of the `try/catch` construct lies in the ability to unwind a deeply
|
||||
nested computation immediately to a much higher level in the stack of calling functions.
|
||||
"""
|
||||
kw"try", kw"catch"
|
||||
|
||||
"""
|
||||
`finally` provides a way to run some code when a given block of code exits, regardless
|
||||
of how it exits. For example, here is how we can guarantee that an opened file is
|
||||
closed:
|
||||
|
||||
f = open("file")
|
||||
try
|
||||
operate_on_file(f)
|
||||
finally
|
||||
close(f)
|
||||
end
|
||||
|
||||
When control leaves the `try` block (for example due to a `return`, or just finishing
|
||||
normally), `close(f)` will be executed. If the `try` block exits due to an exception,
|
||||
the exception will continue propagating. A `catch` block may be combined with `try` and
|
||||
`finally` as well. In this case the `finally` block will run after `catch` has handled
|
||||
the error.
|
||||
"""
|
||||
kw"finally"
|
||||
|
||||
"""
|
||||
`break` breaks out of a loop immediately. For example
|
||||
|
||||
i = 0
|
||||
while true
|
||||
i += 1
|
||||
i > 10 && break
|
||||
println(i)
|
||||
end
|
||||
|
||||
prints the numbers 1 to 10.
|
||||
"""
|
||||
kw"break"
|
||||
|
||||
"""
|
||||
`continue` skips the rest of the current loop, then carries on looping. For example
|
||||
|
||||
for i = 1:10
|
||||
iseven(i) && continue
|
||||
println(i)
|
||||
end
|
||||
|
||||
prints the numbers 1, 3, 5..., skipping the even numbers.
|
||||
"""
|
||||
kw"continue"
|
||||
|
||||
"""
|
||||
The `do` keyword creates an anonymous function. For example
|
||||
|
||||
map(1:10) do x
|
||||
2x
|
||||
end
|
||||
|
||||
is equivalent to `map(x->2x, 1:10)`.
|
||||
|
||||
Use multiple arguments like so:
|
||||
|
||||
map(1:10, 11:20) do x, y
|
||||
x + y
|
||||
end
|
||||
"""
|
||||
kw"do"
|
||||
|
||||
"""
|
||||
The "splat" operator, `...`, represents a sequence of arguments. For example
|
||||
|
||||
add(xs...) = reduce(+, xs)
|
||||
|
||||
can take any number of arguments:
|
||||
|
||||
add(1, 2, 3, 4, 5)
|
||||
|
||||
`...` can also be used to apply a function to a sequence of arguments like so:
|
||||
|
||||
add([1, 2, 3]...) # 6
|
||||
add(7, 1:100..., 1000:1100...) # 111107
|
||||
"""
|
||||
kw"..."
|
||||
|
||||
"""
|
||||
`;` has a similar role in Julia as in many C-like languages, and is used to delimit the
|
||||
end of the previous statement. `;` is not necessary after new lines, but can be used to
|
||||
separate statements on a single line or to join statements into a single expression:
|
||||
|
||||
function foo()
|
||||
println("Hello, "); println("World!")
|
||||
return true
|
||||
end
|
||||
|
||||
foo() = (println("Hello, World!"); true)
|
||||
|
||||
`;` is also used to suppress output in the REPL and similar interfaces.
|
||||
"""
|
||||
kw";"
|
||||
|
||||
"""
|
||||
x && y
|
||||
|
||||
Short-circuiting boolean AND.
|
||||
"""
|
||||
kw"&&"
|
||||
|
||||
"""
|
||||
x || y
|
||||
|
||||
Short-circuiting boolean OR.
|
||||
"""
|
||||
kw"||"
|
||||
|
||||
"""
|
||||
ccall((symbol, library) or function_pointer, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)
|
||||
|
||||
Call function in C-exported shared library, specified by `(function name, library)`
|
||||
tuple, where each component is a string or symbol.
|
||||
|
||||
Note that the argument type tuple must be a literal tuple, and not a tuple-valued
|
||||
variable or expression. Alternatively, `ccall` may also be used to call a function
|
||||
pointer, such as one returned by `dlsym`.
|
||||
|
||||
Each `ArgumentValue` to the `ccall` will be converted to the corresponding
|
||||
`ArgumentType`, by automatic insertion of calls to `unsafe_convert(ArgumentType,
|
||||
cconvert(ArgumentType, ArgumentValue))`. (See also the documentation for each of these
|
||||
functions for further details.) In most cases, this simply results in a call to
|
||||
`convert(ArgumentType, ArgumentValue)`.
|
||||
"""
|
||||
kw"ccall"
|
||||
|
||||
"""
|
||||
llvmcall(IR::String, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)
|
||||
llvmcall((declarations::String, IR::String), ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)
|
||||
|
||||
Call LLVM IR string in the first argument. Similar to an LLVM function `define` block,
|
||||
arguments are available as consecutive unnamed SSA variables (%0, %1, etc.).
|
||||
|
||||
The optional declarations string contains external functions declarations that are
|
||||
necessary for llvm to compile the IR string. Multiple declarations can be passed in by
|
||||
separating them with line breaks.
|
||||
|
||||
Note that the argument type tuple must be a literal tuple, and not a tuple-valued
|
||||
variable or expression.
|
||||
|
||||
Each `ArgumentValue` to `llvmcall` will be converted to the corresponding
|
||||
`ArgumentType`, by automatic insertion of calls to `unsafe_convert(ArgumentType,
|
||||
cconvert(ArgumentType, ArgumentValue))`. (see also the documentation for each of these
|
||||
functions for further details). In most cases, this simply results in a call to
|
||||
`convert(ArgumentType, ArgumentValue)`.
|
||||
|
||||
See `test/llvmcall.jl` for usage examples.
|
||||
"""
|
||||
Core.Intrinsics.llvmcall
|
||||
|
||||
"""
|
||||
`begin...end` denotes a block of code.
|
||||
|
||||
begin
|
||||
println("Hello, ")
|
||||
println("World!")
|
||||
end
|
||||
|
||||
Usually `begin` will not be necessary, since keywords such as `function` and `let`
|
||||
implicitly begin blocks of code. See also `;`.
|
||||
"""
|
||||
kw"begin"
|
||||
|
||||
"""
|
||||
The most commonly used kind of type in Julia is a struct, specified as a name and a
|
||||
set of fields.
|
||||
|
||||
struct Point
|
||||
x
|
||||
y
|
||||
end
|
||||
|
||||
Fields can have type restrictions, which may be parameterized:
|
||||
|
||||
struct Point{X}
|
||||
x::X
|
||||
y::Float64
|
||||
end
|
||||
|
||||
A struct can also declare an abstract super type via `<:` syntax:
|
||||
|
||||
struct Point <: AbstractPoint
|
||||
...
|
||||
|
||||
Structs are immutable by default; an instance of one of these types cannot
|
||||
be modified after construction. Use `mutable struct` instead to declare a
|
||||
type whose instances can be modified.
|
||||
|
||||
See the manual for more details, such as how to define constructors.
|
||||
"""
|
||||
kw"struct"
|
||||
|
||||
"""
|
||||
`mutable struct` is similar to `struct`, but additionally allows the fields of the type
|
||||
to be set after construction. See `struct` and the manual for more information.
|
||||
"""
|
||||
kw"mutable struct"
|
||||
|
||||
"""
|
||||
@__LINE__ -> Int
|
||||
|
||||
`@__LINE__` expands to the line number of the call-site.
|
||||
"""
|
||||
kw"@__LINE__"
|
||||
|
||||
"""
|
||||
The `where` keyword creates a type that is an iterated union of other types, over all
|
||||
values of some variable. For example `Vector{T} where T<:Real` includes all `Vector`s
|
||||
where the element type is some kind of `Real` number.
|
||||
|
||||
The variable bound defaults to `Any` if it is omitted:
|
||||
|
||||
Vector{T} where T # short for `where T<:Any`
|
||||
|
||||
Variables can also have lower bounds:
|
||||
|
||||
Vector{T} where T>:Int
|
||||
Vector{T} where Int<:T<:Real
|
||||
|
||||
There is also a concise syntax for nested `where` expressions. For example, this:
|
||||
|
||||
Pair{T, S} where S<:Array{T} where T<:Number
|
||||
|
||||
can be shortened to:
|
||||
|
||||
Pair{T, S} where {T<:Number, S<:Array{T}}
|
||||
|
||||
This form is often found on method signatures.
|
||||
|
||||
Note that in this form, the variables are listed outermost-first. This matches the
|
||||
order in which variables are substituted when a type is "applied" to parameter values
|
||||
using the syntax `T{p1, p2, ...}`.
|
||||
"""
|
||||
kw"where"
|
||||
|
||||
"""
|
||||
ans
|
||||
|
||||
A variable referring to the last computed value, automatically set at the interactive prompt.
|
||||
"""
|
||||
kw"ans"
|
||||
|
||||
"""
|
||||
nothing
|
||||
|
||||
The singleton instance of type `Void`, used by convention when there is no value to return
|
||||
(as in a C `void` function). Can be converted to an empty `Nullable` value.
|
||||
"""
|
||||
nothing
|
||||
|
||||
"""
|
||||
ANY
|
||||
|
||||
Equivalent to `Any` for dispatch purposes, but signals the compiler to skip code
|
||||
generation specialization for that field.
|
||||
"""
|
||||
ANY
|
||||
|
||||
"""
|
||||
Core.TypeofBottom
|
||||
|
||||
The singleton type containing only the value `Union{}`.
|
||||
"""
|
||||
Core.TypeofBottom
|
||||
|
||||
"""
|
||||
DevNull
|
||||
|
||||
Used in a stream redirect to discard all data written to it. Essentially equivalent to
|
||||
/dev/null on Unix or NUL on Windows. Usage:
|
||||
|
||||
```julia
|
||||
run(pipeline(`cat test.txt`, DevNull))
|
||||
```
|
||||
"""
|
||||
DevNull
|
||||
|
||||
"""
|
||||
Function
|
||||
|
||||
Abstract type of all functions.
|
||||
|
||||
```jldoctest
|
||||
julia> isa(+, Function)
|
||||
true
|
||||
|
||||
julia> typeof(sin)
|
||||
Base.#sin
|
||||
|
||||
julia> ans <: Function
|
||||
true
|
||||
```
|
||||
"""
|
||||
Function
|
||||
|
||||
end
|
||||
46
julia-0.6.2/share/julia/base/docs/bindings.jl
Normal file
46
julia-0.6.2/share/julia/base/docs/bindings.jl
Normal file
@@ -0,0 +1,46 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
export @var
|
||||
|
||||
struct Binding
|
||||
mod::Module
|
||||
var::Symbol
|
||||
|
||||
function Binding(m::Module, v::Symbol)
|
||||
# Normalise the binding module for module symbols so that:
|
||||
# Binding(Base, :Base) === Binding(Main, :Base)
|
||||
m = module_name(m) === v ? module_parent(m) : m
|
||||
new(Base.binding_module(m, v), v)
|
||||
end
|
||||
end
|
||||
|
||||
bindingexpr(x) = Expr(:call, Binding, splitexpr(x)...)
|
||||
|
||||
defined(b::Binding) = isdefined(b.mod, b.var)
|
||||
resolve(b::Binding) = getfield(b.mod, b.var)
|
||||
|
||||
function splitexpr(x::Expr)
|
||||
isexpr(x, :macrocall) ? splitexpr(x.args[1]) :
|
||||
isexpr(x, :.) ? (x.args[1], x.args[2]) :
|
||||
error("Invalid @var syntax `$x`.")
|
||||
end
|
||||
splitexpr(s::Symbol) = Expr(:call, current_module), quot(s)
|
||||
splitexpr(other) = error("Invalid @var syntax `$other`.")
|
||||
|
||||
macro var(x)
|
||||
esc(bindingexpr(x))
|
||||
end
|
||||
|
||||
function Base.show(io::IO, b::Binding)
|
||||
if b.mod === Main
|
||||
print(io, b.var)
|
||||
else
|
||||
print(io, b.mod, '.', Base.isoperator(b.var) ? ":" : "", b.var)
|
||||
end
|
||||
end
|
||||
|
||||
aliasof(b::Binding) = defined(b) ? (a = aliasof(resolve(b), b); defined(a) ? a : b) : b
|
||||
aliasof(d::DataType, b) = Binding(d.name.module, d.name.name)
|
||||
aliasof(λ::Function, b) = (m = typeof(λ).name.mt; Binding(m.module, m.name))
|
||||
aliasof(m::Module, b) = Binding(m, module_name(m))
|
||||
aliasof(other, b) = b
|
||||
28
julia-0.6.2/share/julia/base/docs/core.jl
Normal file
28
julia-0.6.2/share/julia/base/docs/core.jl
Normal file
@@ -0,0 +1,28 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module CoreDocs
|
||||
|
||||
import ..esc, ..push!, ..getindex, ..current_module, ..unsafe_load, ..Csize_t
|
||||
|
||||
function doc!(str, ex)
|
||||
ptr = unsafe_load(Core.Intrinsics.cglobal(:jl_filename, Ptr{UInt8}))
|
||||
len = ccall(:strlen, Csize_t, (Ptr{UInt8},), ptr)
|
||||
file = ccall(:jl_symbol_n, Any, (Ptr{UInt8}, Csize_t), ptr, len)
|
||||
line = unsafe_load(Core.Intrinsics.cglobal(:jl_lineno, Int32)) # Cint
|
||||
push!(DOCS, (current_module(), ex, str, file, line))
|
||||
end
|
||||
const DOCS = Array{Any, 1}()
|
||||
|
||||
isexpr(x, h) = isa(x, Expr) && x.head === h
|
||||
|
||||
lazy_iterpolate(s::AbstractString) = Expr(:call, Core.svec, s)
|
||||
lazy_iterpolate(x) = isexpr(x, :string) ? Expr(:call, Core.svec, x.args...) : x
|
||||
|
||||
function docm(str, x)
|
||||
out = esc(Expr(:call, doc!, lazy_iterpolate(str), Expr(:quote, x)))
|
||||
isexpr(x, :module) ? Expr(:toplevel, out, esc(x)) :
|
||||
isexpr(x, :call) ? out : Expr(:block, esc(x), out)
|
||||
end
|
||||
docm(x) = isexpr(x, :->) ? docm(x.args[1], x.args[2].args[2]) : error("invalid '@doc'.")
|
||||
|
||||
end
|
||||
3
julia-0.6.2/share/julia/base/docs/helpdb.jl
Normal file
3
julia-0.6.2/share/julia/base/docs/helpdb.jl
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include(joinpath("helpdb", "Base.jl"))
|
||||
2744
julia-0.6.2/share/julia/base/docs/helpdb/Base.jl
Normal file
2744
julia-0.6.2/share/julia/base/docs/helpdb/Base.jl
Normal file
File diff suppressed because it is too large
Load Diff
455
julia-0.6.2/share/julia/base/docs/utils.jl
Normal file
455
julia-0.6.2/share/julia/base/docs/utils.jl
Normal file
@@ -0,0 +1,455 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# Text / HTML objects
|
||||
|
||||
import Base: print, show, ==, hash
|
||||
|
||||
export HTML, @html_str
|
||||
|
||||
export HTML, Text, apropos
|
||||
|
||||
"""
|
||||
`HTML(s)`: Create an object that renders `s` as html.
|
||||
|
||||
HTML("<div>foo</div>")
|
||||
|
||||
You can also use a stream for large amounts of data:
|
||||
|
||||
HTML() do io
|
||||
println(io, "<div>foo</div>")
|
||||
end
|
||||
"""
|
||||
mutable struct HTML{T}
|
||||
content::T
|
||||
end
|
||||
|
||||
function HTML(xs...)
|
||||
HTML() do io
|
||||
for x in xs
|
||||
show(io, MIME"text/html"(), x)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
show(io::IO, ::MIME"text/html", h::HTML) = print(io, h.content)
|
||||
show(io::IO, ::MIME"text/html", h::HTML{<:Function}) = h.content(io)
|
||||
|
||||
"""
|
||||
@html_str -> Docs.HTML
|
||||
|
||||
Create an `HTML` object from a literal string.
|
||||
"""
|
||||
macro html_str(s)
|
||||
:(HTML($s))
|
||||
end
|
||||
|
||||
function catdoc(xs::HTML...)
|
||||
HTML() do io
|
||||
for x in xs
|
||||
show(io, MIME"text/html"(), x)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
export Text, @text_str
|
||||
|
||||
"""
|
||||
`Text(s)`: Create an object that renders `s` as plain text.
|
||||
|
||||
Text("foo")
|
||||
|
||||
You can also use a stream for large amounts of data:
|
||||
|
||||
Text() do io
|
||||
println(io, "foo")
|
||||
end
|
||||
"""
|
||||
mutable struct Text{T}
|
||||
content::T
|
||||
end
|
||||
|
||||
print(io::IO, t::Text) = print(io, t.content)
|
||||
print(io::IO, t::Text{<:Function}) = t.content(io)
|
||||
show(io::IO, t::Text) = print(io, t)
|
||||
|
||||
==(t1::T, t2::T) where {T<:Union{HTML,Text}} = t1.content == t2.content
|
||||
hash(t::T, h::UInt) where {T<:Union{HTML,Text}} = hash(T, hash(t.content, h))
|
||||
|
||||
"""
|
||||
@text_str -> Docs.Text
|
||||
|
||||
Create a `Text` object from a literal string.
|
||||
"""
|
||||
macro text_str(s)
|
||||
:(Text($s))
|
||||
end
|
||||
|
||||
function catdoc(xs::Text...)
|
||||
Text() do io
|
||||
for x in xs
|
||||
show(io, MIME"text/plain"(), x)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# REPL help
|
||||
|
||||
function helpmode(io::IO, line::AbstractString)
|
||||
line = strip(line)
|
||||
expr =
|
||||
if haskey(keywords, Symbol(line))
|
||||
# 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)
|
||||
else
|
||||
x = Base.syntax_deprecation_warnings(false) do
|
||||
parse(line, raise = false)
|
||||
end
|
||||
# Retrieving docs for macros requires us to make a distinction between the text
|
||||
# `@macroname` and `@macroname()`. These both parse the same, but are used by
|
||||
# the docsystem to return different results. The first returns all documentation
|
||||
# for `@macroname`, while the second returns *only* the docs for the 0-arg
|
||||
# definition if it exists.
|
||||
(isexpr(x, :macrocall, 1) && !endswith(line, "()")) ? quot(x) : x
|
||||
end
|
||||
# the following must call repl(io, expr) via the @repl macro
|
||||
# so that the resulting expressions are evaluated in the Base.Docs namespace
|
||||
:(Base.Docs.@repl $io $expr)
|
||||
end
|
||||
helpmode(line::AbstractString) = helpmode(STDOUT, line)
|
||||
|
||||
function repl_search(io::IO, s)
|
||||
pre = "search:"
|
||||
print(io, pre)
|
||||
printmatches(io, s, completions(s), cols = displaysize(io)[2] - length(pre))
|
||||
println(io, "\n")
|
||||
end
|
||||
repl_search(s) = repl_search(STDOUT, s)
|
||||
|
||||
function repl_corrections(io::IO, s)
|
||||
print(io, "Couldn't find ")
|
||||
Markdown.with_output_format(:cyan, io) do io
|
||||
println(io, s)
|
||||
end
|
||||
print_correction(io, s)
|
||||
end
|
||||
repl_corrections(s) = repl_corrections(STDOUT, s)
|
||||
|
||||
# inverse of latex_symbols Dict, lazily created as needed
|
||||
const symbols_latex = Dict{String,String}()
|
||||
function symbol_latex(s::String)
|
||||
if isempty(symbols_latex)
|
||||
for (k,v) in Base.REPLCompletions.latex_symbols
|
||||
symbols_latex[v] = k
|
||||
end
|
||||
end
|
||||
return get(symbols_latex, s, "")
|
||||
end
|
||||
function repl_latex(io::IO, s::String)
|
||||
latex = symbol_latex(s)
|
||||
if !isempty(latex)
|
||||
print(io, "\"")
|
||||
Markdown.with_output_format(:cyan, io) do io
|
||||
print(io, s)
|
||||
end
|
||||
print(io, "\" can be typed by ")
|
||||
Markdown.with_output_format(:cyan, io) do io
|
||||
print(io, latex, "<tab>")
|
||||
end
|
||||
println(io, '\n')
|
||||
elseif any(c -> haskey(symbols_latex, string(c)), s)
|
||||
print(io, "\"")
|
||||
Markdown.with_output_format(:cyan, io) do io
|
||||
print(io, s)
|
||||
end
|
||||
print(io, "\" can be typed by ")
|
||||
Markdown.with_output_format(:cyan, io) do io
|
||||
for c in s
|
||||
cstr = string(c)
|
||||
if haskey(symbols_latex, cstr)
|
||||
print(io, symbols_latex[cstr], "<tab>")
|
||||
else
|
||||
print(io, c)
|
||||
end
|
||||
end
|
||||
end
|
||||
println(io, '\n')
|
||||
end
|
||||
end
|
||||
repl_latex(s::String) = repl_latex(STDOUT, s)
|
||||
|
||||
macro repl(ex) repl(ex) end
|
||||
macro repl(io, ex) repl(io, ex) end
|
||||
|
||||
function repl(io::IO, s::Symbol)
|
||||
str = string(s)
|
||||
quote
|
||||
repl_latex($io, $str)
|
||||
repl_search($io, $str)
|
||||
($(isdefined(s) || haskey(keywords, s))) || repl_corrections($io, $str)
|
||||
$(_repl(s))
|
||||
end
|
||||
end
|
||||
isregex(x) = isexpr(x, :macrocall, 2) && x.args[1] === Symbol("@r_str") && !isempty(x.args[2])
|
||||
repl(io::IO, ex::Expr) = isregex(ex) ? :(apropos($io, $ex)) : _repl(ex)
|
||||
repl(io::IO, str::AbstractString) = :(apropos($io, $str))
|
||||
repl(io::IO, other) = :(@doc $(esc(other)))
|
||||
|
||||
repl(x) = repl(STDOUT, x)
|
||||
|
||||
function _repl(x)
|
||||
if (isexpr(x, :call) && !any(isexpr(x, :(::)) for x in x.args))
|
||||
x.args[2:end] = [:(::typeof($arg)) for arg in x.args[2:end]]
|
||||
end
|
||||
docs = :(@doc $(esc(x)))
|
||||
if isfield(x)
|
||||
quote
|
||||
if isa($(esc(x.args[1])), DataType)
|
||||
fielddoc($(esc(x.args[1])), $(esc(x.args[2])))
|
||||
else
|
||||
$docs
|
||||
end
|
||||
end
|
||||
else
|
||||
docs
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Search & Rescue
|
||||
# Utilities for correcting user mistakes and (eventually)
|
||||
# doing full documentation searches from the repl.
|
||||
|
||||
# Fuzzy Search Algorithm
|
||||
|
||||
function matchinds(needle, haystack; acronym = false)
|
||||
chars = collect(needle)
|
||||
is = Int[]
|
||||
lastc = '\0'
|
||||
for (i, char) in enumerate(haystack)
|
||||
isempty(chars) && break
|
||||
while chars[1] == ' ' shift!(chars) end # skip spaces
|
||||
if lowercase(char) == lowercase(chars[1]) && (!acronym || !isalpha(lastc))
|
||||
push!(is, i)
|
||||
shift!(chars)
|
||||
end
|
||||
lastc = char
|
||||
end
|
||||
return is
|
||||
end
|
||||
|
||||
longer(x, y) = length(x) ≥ length(y) ? (x, true) : (y, false)
|
||||
|
||||
bestmatch(needle, haystack) =
|
||||
longer(matchinds(needle, haystack, acronym = true),
|
||||
matchinds(needle, haystack))
|
||||
|
||||
avgdistance(xs) =
|
||||
isempty(xs) ? 0 :
|
||||
(xs[end] - xs[1] - length(xs)+1)/length(xs)
|
||||
|
||||
function fuzzyscore(needle, haystack)
|
||||
score = 0.
|
||||
is, acro = bestmatch(needle, haystack)
|
||||
score += (acro?2:1)*length(is) # Matched characters
|
||||
score -= 2(length(needle)-length(is)) # Missing characters
|
||||
!acro && (score -= avgdistance(is)/10) # Contiguous
|
||||
!isempty(is) && (score -= mean(is)/100) # Closer to beginning
|
||||
return score
|
||||
end
|
||||
|
||||
function fuzzysort(search, candidates)
|
||||
scores = map(cand -> (fuzzyscore(search, cand), -levenshtein(search, cand)), candidates)
|
||||
candidates[sortperm(scores)] |> reverse
|
||||
end
|
||||
|
||||
# Levenshtein Distance
|
||||
|
||||
function levenshtein(s1, s2)
|
||||
a, b = collect(s1), collect(s2)
|
||||
m = length(a)
|
||||
n = length(b)
|
||||
d = Matrix{Int}(m+1, n+1)
|
||||
|
||||
d[1:m+1, 1] = 0:m
|
||||
d[1, 1:n+1] = 0:n
|
||||
|
||||
for i = 1:m, j = 1:n
|
||||
d[i+1,j+1] = min(d[i , j+1] + 1,
|
||||
d[i+1, j ] + 1,
|
||||
d[i , j ] + (a[i] != b[j]))
|
||||
end
|
||||
|
||||
return d[m+1, n+1]
|
||||
end
|
||||
|
||||
function levsort(search, candidates)
|
||||
scores = map(cand -> (levenshtein(search, cand), -fuzzyscore(search, cand)), candidates)
|
||||
candidates = candidates[sortperm(scores)]
|
||||
i = 0
|
||||
for i = 1:length(candidates)
|
||||
levenshtein(search, candidates[i]) > 3 && break
|
||||
end
|
||||
return candidates[1:i]
|
||||
end
|
||||
|
||||
# Result printing
|
||||
|
||||
function printmatch(io::IO, word, match)
|
||||
is, _ = bestmatch(word, match)
|
||||
Markdown.with_output_format(:fade, io) do io
|
||||
for (i, char) = enumerate(match)
|
||||
if i in is
|
||||
Markdown.with_output_format(print, :bold, io, char)
|
||||
else
|
||||
print(io, char)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
printmatch(args...) = printfuzzy(STDOUT, args...)
|
||||
|
||||
function printmatches(io::IO, word, matches; cols = displaysize(io)[2])
|
||||
total = 0
|
||||
for match in matches
|
||||
total + length(match) + 1 > cols && break
|
||||
fuzzyscore(word, match) < 0 && break
|
||||
print(io, " ")
|
||||
printmatch(io, word, match)
|
||||
total += length(match) + 1
|
||||
end
|
||||
end
|
||||
|
||||
printmatches(args...; cols = displaysize(STDOUT)[2]) = printmatches(STDOUT, args..., cols = cols)
|
||||
|
||||
function print_joined_cols(io::IO, ss, delim = "", last = delim; cols = displaysize(io)[2])
|
||||
i = 0
|
||||
total = 0
|
||||
for i = 1:length(ss)
|
||||
total += length(ss[i])
|
||||
total + max(i-2,0)*length(delim) + (i>1?1:0)*length(last) > cols && (i-=1; break)
|
||||
end
|
||||
join(io, ss[1:i], delim, last)
|
||||
end
|
||||
|
||||
print_joined_cols(args...; cols = displaysize(STDOUT)[2]) = print_joined_cols(STDOUT, args...; cols=cols)
|
||||
|
||||
function print_correction(io, word)
|
||||
cors = levsort(word, accessible(current_module()))
|
||||
pre = "Perhaps you meant "
|
||||
print(io, pre)
|
||||
print_joined_cols(io, cors, ", ", " or "; cols = displaysize(io)[2] - length(pre))
|
||||
println(io)
|
||||
return
|
||||
end
|
||||
|
||||
print_correction(word) = print_correction(STDOUT, word)
|
||||
|
||||
# Completion data
|
||||
|
||||
const builtins = ["abstract type", "baremodule", "begin", "break",
|
||||
"catch", "ccall", "const", "continue", "do", "else",
|
||||
"elseif", "end", "export", "finally", "for", "function",
|
||||
"global", "if", "import", "importall", "let",
|
||||
"local", "macro", "module", "mutable struct", "primitive type",
|
||||
"quote", "return", "struct", "try", "using", "while"]
|
||||
|
||||
moduleusings(mod) = ccall(:jl_module_usings, Any, (Any,), mod)
|
||||
|
||||
filtervalid(names) = filter(x->!ismatch(r"#", x), map(string, names))
|
||||
|
||||
accessible(mod::Module) =
|
||||
[filter!(s->Base.isdeprecated(mod, s), names(mod, true, true));
|
||||
map(names, moduleusings(mod))...;
|
||||
builtins] |> unique |> filtervalid
|
||||
|
||||
completions(name) = fuzzysort(name, accessible(current_module()))
|
||||
completions(name::Symbol) = completions(string(name))
|
||||
|
||||
|
||||
# Searching and apropos
|
||||
|
||||
# Docsearch simply returns true or false if an object contains the given needle
|
||||
docsearch(haystack::AbstractString, needle) = !isempty(search(haystack, needle))
|
||||
docsearch(haystack::Symbol, needle) = docsearch(string(haystack), needle)
|
||||
docsearch(::Void, needle) = false
|
||||
function docsearch(haystack::Array, needle)
|
||||
for elt in haystack
|
||||
docsearch(elt, needle) && return true
|
||||
end
|
||||
false
|
||||
end
|
||||
function docsearch(haystack, needle)
|
||||
Base.warn_once("unable to search documentation of type $(typeof(haystack))")
|
||||
false
|
||||
end
|
||||
|
||||
## Searching specific documentation objects
|
||||
function docsearch(haystack::MultiDoc, needle)
|
||||
for v in values(haystack.docs)
|
||||
docsearch(v, needle) && return true
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
function docsearch(haystack::DocStr, needle)
|
||||
docsearch(parsedoc(haystack), needle) && return true
|
||||
if haskey(haystack.data, :fields)
|
||||
for doc in values(haystack.data[:fields])
|
||||
docsearch(doc, needle) && return true
|
||||
end
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
## Markdown search simply strips all markup and searches plain text version
|
||||
docsearch(haystack::Markdown.MD, needle) =
|
||||
docsearch(stripmd(haystack.content), needle)
|
||||
|
||||
"""
|
||||
stripmd(x)
|
||||
|
||||
Strip all Markdown markup from x, leaving the result in plain text. Used
|
||||
internally by apropos to make docstrings containing more than one markdown
|
||||
element searchable.
|
||||
"""
|
||||
stripmd(x::ANY) = string(x) # for random objects interpolated into the docstring
|
||||
stripmd(x::AbstractString) = x # base case
|
||||
stripmd(x::Void) = " "
|
||||
stripmd(x::Vector) = string(map(stripmd, x)...)
|
||||
stripmd(x::Markdown.BlockQuote) = "$(stripmd(x.content))"
|
||||
stripmd(x::Markdown.Admonition) = "$(stripmd(x.content))"
|
||||
stripmd(x::Markdown.Bold) = "$(stripmd(x.text))"
|
||||
stripmd(x::Markdown.Code) = "$(stripmd(x.code))"
|
||||
stripmd(x::Markdown.Header) = stripmd(x.text)
|
||||
stripmd(x::Markdown.HorizontalRule) = " "
|
||||
stripmd(x::Markdown.Image) = "$(stripmd(x.alt)) $(x.url)"
|
||||
stripmd(x::Markdown.Italic) = "$(stripmd(x.text))"
|
||||
stripmd(x::Markdown.LaTeX) = "$(x.formula)"
|
||||
stripmd(x::Markdown.LineBreak) = " "
|
||||
stripmd(x::Markdown.Link) = "$(stripmd(x.text)) $(x.url)"
|
||||
stripmd(x::Markdown.List) = join(map(stripmd, x.items), " ")
|
||||
stripmd(x::Markdown.MD) = join(map(stripmd, x.content), " ")
|
||||
stripmd(x::Markdown.Paragraph) = stripmd(x.content)
|
||||
stripmd(x::Markdown.Footnote) = "$(stripmd(x.id)) $(stripmd(x.text))"
|
||||
stripmd(x::Markdown.Table) =
|
||||
join([join(map(stripmd, r), " ") for r in x.rows], " ")
|
||||
|
||||
# Apropos searches through all available documentation for some string or regex
|
||||
"""
|
||||
apropos(string)
|
||||
|
||||
Search through all documentation for a string, ignoring case.
|
||||
"""
|
||||
apropos(string) = apropos(STDOUT, string)
|
||||
apropos(io::IO, string) = apropos(io, Regex("\\Q$string", "i"))
|
||||
function apropos(io::IO, needle::Regex)
|
||||
for mod in modules
|
||||
# Module doc might be in README.md instead of the META dict
|
||||
docsearch(doc(mod), needle) && println(io, mod)
|
||||
for (k, v) in meta(mod)
|
||||
docsearch(v, needle) && println(io, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user