Skip to content

Commit

Permalink
Merge pull request #4991 from stevengj/methodshow
Browse files Browse the repository at this point in the history
add text/html writemime for MethodList and Method (fix #4952)
  • Loading branch information
stevengj committed Dec 23, 2013
2 parents 0d6eb45 + 4861ee2 commit d135a07
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 76 deletions.
138 changes: 138 additions & 0 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Method and method-table pretty-printing

function argtype_decl(n, t) # -> (argname, argtype)
if isa(n,Expr)
n = n.args[1] # handle n::T in arg list
end
s = string(n)
i = search(s,'#')
if i > 0
s = s[1:i-1]
end
if t === Any && !isempty(s)
return s, ""
end
if t <: Vararg && t !== None && t.parameters[1] === Any
return string(s, "..."), ""
end
return s, string(t)
end

function arg_decl_parts(m::Method)
tv = m.tvars
if !isa(tv,Tuple)
tv = (tv,)
end
li = m.func.code
e = uncompressed_ast(li)
argnames = e.args[1]
s = symbol("?")
decls = [argtype_decl(get(argnames,i,s), m.sig[i]) for i=1:length(m.sig)]
return tv, decls, li.file, li.line
end

function show(io::IO, m::Method)
tv, decls, file, line = arg_decl_parts(m)
if !isempty(tv)
show_delim_array(io, tv, '{', ',', '}', false)
end
print(io, "(")
print_joined(io, [isempty(d[2]) ? d[1] : d[1]*"::"*d[2] for d in decls],
",", ",")
print(io, ")")
if line > 0
print(io, " at ", file, ":", line)
end
end

function show_method_table(io::IO, mt::MethodTable, max::Int=-1, header::Bool=true)
name = mt.name
n = length(mt)
if header
m = n==1 ? "method" : "methods"
print(io, "# $n $m for generic function \"$name\":")
end
d = mt.defs
n = rest = 0
while !is(d,())
if max==-1 || n<max || (rest==0 && n==max && d.next === ())
println(io)
print(io, name)
show(io, d)
n += 1
else
rest += 1
end
d = d.next
end
if rest > 0
println(io)
print(io,"... $rest methods not shown (use methods($name) to see them all)")
end
end

show(io::IO, mt::MethodTable) = show_method_table(io, mt)

inbase(m::Module) = m == Base ? true : m == Main ? false : inbase(module_parent(m))
function url(m::Method)
M = m.func.code.module
file = string(m.func.code.file)
line = m.func.code.line
line <= 0 || ismatch(r"In\[[0-9]+\]", file) && return ""
if inbase(M)
return "https://github.com/JuliaLang/julia/tree/$(Base.BUILD_INFO.commit)/base/$file#L$line"
else
try
d = dirname(file)
u = Git.readchomp(`config remote.origin.url`, dir=d)
u = match(Git.GITHUB_REGEX,u).captures[1]
root = cd(d) do # dir=d confuses --show-toplevel, apparently
Git.readchomp(`rev-parse --show-toplevel`)
end
if beginswith(file, root)
commit = Git.readchomp(`rev-parse HEAD`, dir=d)
return "https://github.com/$u/tree/$commit/"*file[length(root)+2:end]*"#L$line"
else
return "file://"*find_source_file(file)
end
catch
return "file://"*find_source_file(file)
end
end
end

function writemime(io::IO, ::MIME"text/html", m::Method)
tv, decls, file, line = arg_decl_parts(m)
if !isempty(tv)
print(io,"<i>")
show_delim_array(io, tv, '{', ',', '}', false)
print(io,"</i>")
end
print(io, "(")
print_joined(io, [isempty(d[2]) ? d[1] : d[1]*"::<b>"*d[2]*"</b>"
for d in decls], ",", ",")
print(io, ")")
if line > 0
u = url(m)
if isempty(u)
print(io, " at ", file, ":", line)
else
print(io, """ at <a href="$u" target="_blank">""",
file, ":", line, "</a>")
end
end
end

function writemime(io::IO, mime::MIME"text/html", mt::MethodTable)
name = mt.name
n = length(mt)
meths = n==1 ? "method" : "methods"
print(io, "$n $meths for generic function <b>$name</b>:<ul>")
d = mt.defs
while !is(d,())
print(io, "<li> ", name)
writemime(io, mime, d)
d = d.next
end
print(io, "</ul>")
end
76 changes: 0 additions & 76 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -388,82 +388,6 @@ function show_unquoted(io::IO, ex::SymbolNode)
show_expr_type(io, ex.typ)
end

function clean_gensym(s::Symbol)
s = string(s)
i = search(s,'#')
if i > 0
return s[1:i-1]
end
return s
end

function argtype_decl_string(n, t)
if isa(n,Expr)
n = n.args[1] # handle n::T in arg list
end
n = clean_gensym(n)
if t === Any && !isempty(n)
return n
end
if t <: Vararg && t !== None && t.parameters[1] === Any
return string(n, "...")
end
return string(n, "::", t)
end

function show(io::IO, m::Method)
tv = m.tvars
if !isa(tv,Tuple)
tv = (tv,)
end
if !isempty(tv)
show_delim_array(io, tv, '{', ',', '}', false)
end
li = m.func.code
e = uncompressed_ast(li)
argnames = e.args[1]
if length(argnames) != length(m.sig)
s = symbol("?")
decls = map(argtype_decl_string, { s for i=1:length(m.sig) }, {m.sig...})
else
decls = map(argtype_decl_string, argnames, {m.sig...})
end
print(io, "(")
print_joined(io, decls, ",", ",")
print(io, ")")
if li.line > 0
print(io, " at ", li.file, ":", li.line)
end
end

function show_method_table(io::IO, mt::MethodTable, max::Int=-1, header::Bool=true)
name = mt.name
n = length(mt)
if header
m = n==1 ? "method" : "methods"
print(io, "# $n $m for generic function \"$name\":")
end
d = mt.defs
n = rest = 0
while !is(d,())
if max==-1 || n<max || (rest==0 && n==max && d.next === ())
println(io)
print(io, name)
show(io, d)
n += 1
else
rest += 1
end
d = d.next
end
if rest > 0
println(io)
print(io,"... $rest methods not shown (use methods($name) to see them all)")
end
end

show(io::IO, mt::MethodTable) = show_method_table(io, mt)

# dump & xdump - structured tree representation like R's str()
# - dump is for the user-facing structure
# - xdump is for the internal structure
Expand Down
1 change: 1 addition & 0 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ import .Grisu.print_shortest
include("printf.jl")
importall .Printf
include("file.jl")
include("methodshow.jl")

# core math functions
include("floatfuncs.jl")
Expand Down

0 comments on commit d135a07

Please sign in to comment.