Skip to content

Commit 32b620c

Browse files
authored
Merge pull request #21 from timholy/teh/sigsat_base_stdlibs_repl
signatures_at support for Base, stdlibs, and methods defined at the REPL
2 parents c94c5fb + 712f197 commit 32b620c

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

src/CodeTracking.jl

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,25 @@ const method_info = IdDict{Type,Union{Missing,Tuple{LineNumberNode,Expr}}}()
1818

1919
const _pkgfiles = Dict{PkgId,PkgFiles}()
2020

21+
# Callback for method-lookup. `lookupfunc = method_lookup_callback[]` must have the form
22+
# ret = lookupfunc(method)
23+
# where `ret` is either `nothing` or `(lnn, def)`. `lnn` is a LineNumberNode (or any valid
24+
# input to `CodeTracking.fileline`) and `def` is the expression defining the method.
2125
const method_lookup_callback = Ref{Any}(nothing)
22-
const expressions_callback = Ref{Any}(nothing)
26+
27+
# Callback for `signatures_at` (lookup by file/lineno). `lookupfunc = expressions_callback[]`
28+
# must have the form
29+
# mod, exsigs = lookupfunc(id, relpath)
30+
# where
31+
# id is the PkgId of the corresponding package
32+
# relpath is the path of the file from the basedir of `id`
33+
# mod is the "active" module at that point in the source
34+
# exsigs is a ex=>sigs dictionary, where `ex` is the source expression and `sigs`
35+
# a list of method-signatures defined by that expression.
36+
const expressions_callback = Ref{Any}(nothing)
37+
38+
const juliabase = joinpath("julia", "base")
39+
const juliastdlib = joinpath("julia", "stdlib", "v$(VERSION.major).$(VERSION.minor)")
2340

2441
### Public API
2542

@@ -97,6 +114,22 @@ Return the signatures of all methods whose definition spans the specified locati
97114
Returns `nothing` if there are no methods at that location.
98115
"""
99116
function signatures_at(filename::AbstractString, line::Integer)
117+
if occursin(juliabase, filename)
118+
rpath = postpath(filename, juliabase)
119+
id = PkgId(Base)
120+
return signatures_at(id, rpath, line)
121+
elseif occursin(juliastdlib, filename)
122+
rpath = postpath(filename, juliastdlib)
123+
spath = splitpath(rpath)
124+
libname = spath[1]
125+
project = Base.active_project()
126+
id = PkgId(Base.project_deps_get(project, libname), libname)
127+
return signatures_at(id, joinpath(spath[2:end]...), line)
128+
end
129+
if startswith(filename, "REPL[")
130+
id = PkgId("@REPL")
131+
return signatures_at(id, filename, line)
132+
end
100133
for (id, pkgfls) in _pkgfiles
101134
if startswith(filename, basedir(pkgfls)) || id.name == "Main"
102135
bdir = basedir(pkgfls)

src/utils.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,11 @@ function maybe_fixup_stdlib_path(path)
8181
end
8282
return path
8383
end
84+
85+
function postpath(filename, pre)
86+
idx = findfirst(pre, filename)
87+
idx === nothing && error(pre, " not found in ", filename)
88+
post = filename[first(idx) + length(pre) : end]
89+
post[1:1] == Base.Filesystem.path_separator && return post[2:end]
90+
return post
91+
end

test/runtests.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,17 @@ include("script.jl")
7575
file, line = whereis(lin, m)
7676
@test endswith(file, String(lin.file))
7777
end
78+
79+
@testset "With Revise" begin
80+
if isdefined(Main, :Revise)
81+
m = @which gcd(10, 20)
82+
sigs = signatures_at(Base.find_source_file(String(m.file)), m.line)
83+
@test !isempty(sigs)
84+
85+
m = first(methods(edit))
86+
sigs = signatures_at(String(m.file), m.line)
87+
@test !isempty(sigs)
88+
sigs = signatures_at(Base.find_source_file(String(m.file)), m.line)
89+
@test !isempty(sigs)
90+
end
91+
end

0 commit comments

Comments
 (0)