diff --git a/src/CodeTracking.jl b/src/CodeTracking.jl index f1bcea9..8b43754 100644 --- a/src/CodeTracking.jl +++ b/src/CodeTracking.jl @@ -245,36 +245,40 @@ function definition(::Type{String}, method::Method) # Step forward to the definition of this method, keeping track of positions of newlines # Issue: in-code `'\n'`. To fix, presumably we'd have to parse the entire file. eol = isequal('\n') - linestarts = Int[] + slop = 20 + linestarts = zeros(Int, slop) istart = 1 - for _ = 1:line-1 - push!(linestarts, istart) + lineindex = 1 + for i in 1:line-1 + if i > line - slop + linestarts[lineindex] = istart + lineindex += 1 + end istart = findnext(eol, src, istart) + 1 end - push!(linestarts, length(src) + 1) - # Parse the function definition (hoping that we've found the right location to start) - ex, iend = Meta.parse(src, istart; raise=false) + linestarts[lineindex] = istart # The function declaration may have been on a previous line, # allow some slop - lineindex = lastindex(linestarts) - linestop = max(0, lineindex - 20) - while !is_func_expr(ex, method) && lineindex > linestop - if isexpr(ex, :call) && length(ex.args) > 1 && first(ex.args) == :eval && isexpr(last(ex.args), :quote) && length(last(ex.args).args) > 0 - actual_ex = first(last(ex.args).args) - if is_func_expr(actual_ex, method) - return clean_source(string(actual_ex)), line - end - end + while lineindex > 0 istart = linestarts[lineindex] - try - ex, iend = Meta.parse(src, istart) + # Parse the function definition (hoping that we've found the right location to start) + ex, iend = try + Meta.parse(src, istart) catch + nothing, nothing + end + + is_func_expr(ex, method) && return clean_source(src[istart:prevind(src, iend)]), line + + if isexpr(ex, :call) && length(ex.args) > 1 && first(ex.args) == :eval && isexpr(last(ex.args), :quote) && length(last(ex.args).args) > 0 + ex = first(last(ex.args).args) + is_func_expr(ex, method) && return clean_source(string(ex)), line end + lineindex -= 1 line -= 1 end - lineindex <= linestop && return nothing - return clean_source(src[istart:prevind(src, iend)]), line + return nothing end function clean_source(src)