module Help
export help, apropos, @help
CATEGORY_LIST = nothing
CATEGORY_DICT = nothing
MODULE_DICT = nothing
FUNCTION_DICT = nothing
function clear_cache()
global CATEGORY_LIST = nothing
global CATEGORY_DICT = nothing
global MODULE_DICT = nothing
global FUNCTION_DICT = nothing
end
function decor_help_desc(func::String, mfunc::String, desc::String)
sd = split(desc, '\n')
for i = 1:length(sd)
if beginswith(sd[i], func)
sd[i] = mfunc * sd[i][length(func)+1:end]
else
break
end
end
return join(sd, '\n')
end
function helpdb_filename()
root = "$JULIA_HOME/../share/julia"
file = "helpdb.jl"
for loc in [Base.locale()]
fn = joinpath(root, loc, file)
if isfile(fn)
return fn
end
end
joinpath(root, file)
end
function init_help()
global CATEGORY_LIST, CATEGORY_DICT,
MODULE_DICT, FUNCTION_DICT
if CATEGORY_DICT == nothing
println("Loading help data...")
helpdb = evalfile(helpdb_filename())
CATEGORY_LIST = {}
CATEGORY_DICT = Dict()
MODULE_DICT = Dict()
FUNCTION_DICT = Dict()
for (cat,mod,func,desc) in helpdb
if !haskey(CATEGORY_DICT, cat)
push!(CATEGORY_LIST, cat)
CATEGORY_DICT[cat] = {}
end
if !isempty(mod)
mfunc = mod * "." * func
desc = decor_help_desc(func, mfunc, desc)
else
mfunc = func
end
push!(CATEGORY_DICT[cat], mfunc)
if !haskey(FUNCTION_DICT, mfunc)
FUNCTION_DICT[mfunc] = {}
end
push!(FUNCTION_DICT[mfunc], desc)
if !haskey(MODULE_DICT, func)
MODULE_DICT[func] = {}
end
if !in(mod, MODULE_DICT[func])
push!(MODULE_DICT[func], mod)
end
end
end
end
function help()
init_help()
print(
"""
Welcome to Julia. The full manual is available at
http://docs.julialang.org
To get help, try help(function), help("@macro"), or help("variable").
To search all help text, try apropos("string"). To see available functions,
try help(category), for one of the following categories:
""")
for cat = CATEGORY_LIST
if !isempty(CATEGORY_DICT[cat])
print(" ")
show(cat); println()
end
end
end
function help(cat::String)
init_help()
if !haskey(CATEGORY_DICT, cat)
# if it's not a category, try another named thing
return help_for(cat)
end
println("Help is available for the following items:")
for func = CATEGORY_DICT[cat]
print(func, " ")
end
println()
end
function print_help_entries(entries)
first = true
for desc in entries
if !first
println()
end
println(strip(desc))
first = false
end
end
func_expr_from_symbols(s::Vector{Symbol}) = length(s) == 1 ? s[1] : Expr(:., func_expr_from_symbols(s[1:end-1]), Expr(:quote, s[end]))
help_for(s::String) = help_for(s, 0)
function help_for(fname::String, obj)
init_help()
found = false
if haskey(FUNCTION_DICT, fname)
print_help_entries(FUNCTION_DICT[fname])
found = true
elseif haskey(MODULE_DICT, fname)
allmods = MODULE_DICT[fname]
alldesc = {}
for mod in allmods
mfname = isempty(mod) ? fname : mod * "." * fname
if isgeneric(obj)
mf = eval(func_expr_from_symbols(map(symbol, split(mfname, "."))))
if mf === obj
append!(alldesc, FUNCTION_DICT[mfname])
found = true
end
else
append!(alldesc, FUNCTION_DICT[mfname])
found = true
end
end
found && print_help_entries(alldesc)
elseif haskey(FUNCTION_DICT, "Base." * fname)
print_help_entries(FUNCTION_DICT["Base." * fname])
found = true
end
if !found
if isa(obj, DataType)
print("DataType : ")
writemime(STDOUT, "text/plain", obj)
println()
println(" supertype: ", super(obj))
if obj.abstract
st = subtypes(obj)
if length(st) > 0
print(" subtypes : ")
showcompact(st)
println()
end
end
if length(obj.names) > 0
println(" fields : ", obj.names)
end
elseif isgeneric(obj)
writemime(STDOUT, "text/plain", obj); println()
else
println("No help information found.")
end
end
end
function apropos(txt::String)
init_help()
n = 0
r = Regex("\\Q$txt", Base.PCRE.CASELESS)
for (cat, _) in CATEGORY_DICT
if ismatch(r, cat)
println("Category: \"$cat\"")
end
end
for (func, entries) in FUNCTION_DICT
if ismatch(r, func) || any(e->ismatch(r,e), entries)
for desc in entries
nl = search(desc,'\n')
if nl != 0
println(desc[1:(nl-1)])
else
println(desc)
end
end
n+=1
end
end
if n == 0
println("No help information found.")
end
end
function help(f::Function)
if is(f,help)
return help()
end
help_for(string(f), f)
end
help(t::DataType) = help_for(string(t.name),t)
help(t::Module) = help(string(t))
function help(x)
show(x)
t = typeof(x)
if isa(t,DataType)
println(" is of type")
help(t)
else
println(" is of type $t")
end
end
# check whether an expression is a qualified name, e.g. Base.FFTW.FORWARD
isname(n::Symbol) = true
isname(ex::Expr) = ((ex.head == :. && isname(ex.args[1]) && isname(ex.args[2]))
|| (ex.head == :quote && isname(ex.args[1])))
macro help(ex)
if !isa(ex, Expr) || isname(ex)
return Expr(:call, :help, esc(ex))
elseif ex.head == :macrocall && length(ex.args) == 1
# e.g., "julia> @help @printf"
return Expr(:call, :help, string(ex.args[1]))
else
return Expr(:macrocall, symbol("@which"), esc(ex))
end
end
end # module