diff --git a/base/help.jl b/base/help.jl new file mode 100644 index 0000000000000..39517ad454911 --- /dev/null +++ b/base/help.jl @@ -0,0 +1,207 @@ +module Help + +export help, apropos + +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 begins_with(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 !has(CATEGORY_DICT, cat) + push!(CATEGORY_LIST, cat) + CATEGORY_DICT[cat] = {} + end + if !isempty(mod) + if begins_with(func, '@') + mfunc = "@" * mod * "." * func[2:] + else + mfunc = mod * "." * func + end + desc = decor_help_desc(func, mfunc, desc) + else + mfunc = func + end + push!(CATEGORY_DICT[cat], mfunc) + if !has(FUNCTION_DICT, mfunc) + FUNCTION_DICT[mfunc] = {} + end + push!(FUNCTION_DICT[mfunc], desc) + if !has(MODULE_DICT, func) + MODULE_DICT[func] = {} + end + if !contains(MODULE_DICT[func], mod) + 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 !has(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 + +help_for(s::String) = help_for(s, 0) +function help_for(fname::String, obj) + init_help() + found = false + if has(FUNCTION_DICT, fname) + print_help_entries(FUNCTION_DICT[fname]) + found = true + else + macrocall = "" + if begins_with(fname, '@') + sfname = fname[2:] + macrocall = "@" + else + sfname = fname + end + if has(MODULE_DICT, fname) + allmods = MODULE_DICT[fname] + alldesc = {} + for mod in allmods + mod_prefix = isempty(mod) ? "" : mod * "." + append!(alldesc, FUNCTION_DICT[macrocall * mod_prefix * sfname]) + end + print_help_entries(alldesc) + found = true + end + end + if !found + if isgeneric(obj) + repl_show(obj); println() + else + println("No help information found.") + end + end +end + +function apropos(txt::String) + init_help() + n = 0 + r = Regex("\\Q$txt", 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) + +function help(x) + show(x) + t = typeof(x) + println(" is of type $t") + if isa(t,DataType) && length(t.names)>0 + println(" which has fields $(t.names)") + end +end + +end # module diff --git a/base/i18n.jl b/base/i18n.jl new file mode 100644 index 0000000000000..8b9cf7e2e49c0 --- /dev/null +++ b/base/i18n.jl @@ -0,0 +1,24 @@ +module I18n + +export locale + +LOCALE = nothing +CALLBACKS = Function[] + +function locale() + if LOCALE === nothing + # XXX:TBD return default locale + return "" + end + LOCALE +end + +function locale(s::ByteString) + global LOCALE = s + # XXX:TBD call setlocale + for cb in CALLBACKS + cb() + end +end + +end # module diff --git a/base/sysimg.jl b/base/sysimg.jl index 0edd24fcdfec7..fdbc0cb389654 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -148,6 +148,11 @@ include("deepcopy.jl") include("util.jl") include("test.jl") include("meta.jl") +include("i18n.jl") +include("help.jl") +using I18n +using Help +push!(I18n.CALLBACKS, Help.clear_cache) # sparse matrices and linear algebra include("sparse.jl") diff --git a/base/util.jl b/base/util.jl index 981a44ec92655..866080a9587c1 100644 --- a/base/util.jl +++ b/base/util.jl @@ -195,228 +195,6 @@ end methods(t::DataType) = (methods(t,Tuple); # force constructor creation t.env) -# locale - -let LOCALE = nothing - global locale - function locale() - if LOCALE === nothing - # XXX:TBD return default locale - return "" - end - LOCALE - end - function locale(s::ByteString) - global help_category_list, help_category_dict, - help_module_dict, help_function_dict - help_category_list = nothing - help_category_dict = nothing - help_module_dict = nothing - help_function_dict = nothing - LOCALE = s - # XXX:TBD call setlocale - end -end - -# help - -help_category_list = nothing -help_category_dict = nothing -help_module_dict = nothing -help_function_dict = nothing - -function decor_help_desc(func::String, mfunc::String, desc::String) - sd = split(desc, '\n') - for i = 1:length(sd) - if begins_with(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 [locale()] - fn = joinpath(root, loc, file) - if isfile(fn) - return fn - end - end - joinpath(root, file) -end - -function init_help() - global help_category_list, help_category_dict, - help_module_dict, help_function_dict - if help_category_dict == nothing - println("Loading help data...") - helpdb = evalfile(helpdb_filename()) - help_category_list = {} - help_category_dict = Dict() - help_module_dict = Dict() - help_function_dict = Dict() - for (cat,mod,func,desc) in helpdb - if !has(help_category_dict, cat) - push!(help_category_list, cat) - help_category_dict[cat] = {} - end - if !isempty(mod) - if begins_with(func, '@') - mfunc = "@" * mod * "." * func[2:] - else - mfunc = mod * "." * func - end - desc = decor_help_desc(func, mfunc, desc) - else - mfunc = func - end - push!(help_category_dict[cat], mfunc) - if !has(help_function_dict, mfunc) - help_function_dict[mfunc] = {} - end - push!(help_function_dict[mfunc], desc) - if !has(help_module_dict, func) - help_module_dict[func] = {} - end - if !contains(help_module_dict[func], mod) - push!(help_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 = help_category_list - if !isempty(help_category_dict[cat]) - print(" ") - show(cat); println() - end - end -end - -function help(cat::String) - init_help() - if !has(help_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 = help_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 - -help_for(s::String) = help_for(s, 0) -function help_for(fname::String, obj) - init_help() - found = false - if !begins_with(fname,'.') && contains(fname, '.') - if has(help_function_dict, fname) - print_help_entries(help_function_dict[fname]) - found = true - end - else - macrocall = "" - if begins_with(fname, '@') - sfname = fname[2:] - macrocall = "@" - else - sfname = fname - end - if has(help_module_dict, fname) - allmods = help_module_dict[fname] - alldesc = {} - for mod in allmods - mod_prefix = isempty(mod) ? "" : mod * "." - append!(alldesc, help_function_dict[macrocall * mod_prefix * sfname]) - end - print_help_entries(alldesc) - found = true - end - end - if !found - if isgeneric(obj) - repl_show(obj); println() - else - println("No help information found.") - end - end -end - -function apropos(txt::String) - init_help() - n = 0 - r = Regex("\\Q$txt", PCRE.CASELESS) - for (cat, _) in help_category_dict - if ismatch(r, cat) - println("Category: \"$cat\"") - end - end - for (func, entries) in help_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) - -function help(x) - show(x) - t = typeof(x) - println(" is of type $t") - if isa(t,DataType) && length(t.names)>0 - println(" which has fields $(t.names)") - end -end - # print a warning only once const have_warned = (ByteString=>Bool)[] @@ -427,7 +205,6 @@ function warn_once(msg::String...) warn(msg) end - # system information versioninfo() = versioninfo(false)