Skip to content

Instantly share code, notes, and snippets.

@ashleysommer
Created July 23, 2020 14:26
Show Gist options
  • Save ashleysommer/b85982f191b1c0baab5c4d353cdcc814 to your computer and use it in GitHub Desktop.
Save ashleysommer/b85982f191b1c0baab5c4d353cdcc814 to your computer and use it in GitHub Desktop.
Fixed Julia include file for Intellij-Julia
using Debugger
using JuliaInterpreter
using Sockets
using REPL
using JSON
import Debugger: Debugger, locdesc, locinfo, print_sourcecode, print_next_expr, print_locals, maybe_quote, pattern_match_kw_call, pattern_match_apply_call, breakpoint_linenumbers, repr_limited
import JuliaInterpreter: JuliaInterpreter, Frame, @lookup, caller, pc_expr, isexpr
_intellij_debug_mode = true
_intellij_current_stack = []
_intellij_debug_port = 0
function _intellij_send_to(rows)
if _intellij_debug_port != 0
f = connect(getipaddr(), _intellij_debug_port)
write(f,json(rows) * "\n")
end
end
const MAX_BYTES_REPR = Ref(1024)
function Debugger.print_var(var::JuliaInterpreter.Variable)::Dict
T = typeof(var.value)
val = repr_limited(var.value, MAX_BYTES_REPR[])
Dict("name" => string(var.name), "type" => string(T), "value" => val)
end
const _print_full_path = Ref(true)
function Debugger.locdesc(frame::Frame; current_line=false)::Dict
func = ""
file = ""
framecode = frame.framecode
meth = framecode.scope
@assert meth isa Method
argnames = framecode.src.slotnames[2:meth.nargs]
spectypes = Any[Any for i=1:length(argnames)]
is_kw = false
if frame.caller !== nothing
is_kw = occursin("#kw##", string(frame.caller.framecode.scope))
end
if is_kw
i = 0
for arg in argnames
if arg == Symbol("")
break
end
i += 1
end
kw_indices = 1:i
positional_indices = i+2:length(argnames)
else
kw_indices = 1:0
positional_indices = 1:length(argnames)
end
methname = string(meth.name)
if is_kw
m = match(r"#(.*?)#(?:[0-9]*)$", methname)
m === nothing || (methname = m.captures[1])
end
func *= "$methname("
function print_indices(indices)
first = true
for (argname, argT) in zip(argnames[indices], spectypes[indices])
first || (func *= ", ")
first = false
func *= "$argname"
!(argT === Any) && (func *= "::$argT")
end
end
print_indices(positional_indices)
if !isempty(kw_indices)
func *= "; "
print_indices(kw_indices)
end
func *= ")"
line = current_line ? JuliaInterpreter.linenumber(frame) : meth.line
#path = string(_print_full_path[] ? meth.file : basename(String(meth.file)), ":", line)
path = string(_print_full_path[] ? meth.file : basename(String(meth.file)))
#path = CodeTracking.replace_buildbot_stdlibpath(String(path)) # TODO: CodeTracking
Dict("function" => func, "file" => path, "line" => line)
end
# function Debugger.print_status(io, state, frame)
# # Buffer to avoid flickering
# outbuf = IOContext(IOBuffer(), io)
# # printstyled(outbuf, "In ", locdesc(frame), "\n"; color=:bold)
# # println("location: $fl")
# loc = locinfo(frame)
#
# currentLine = loc.line
# fileInfo::Dict = locdesc(frame)
# !_intellij_debug_mode &&
# if loc !== nothing
# data = if isa(loc, BufferLocInfo)
# loc.data
# else
# VERSION < v"0.7" ? read(loc.filepath, String) :
# read(loc.filepath, String)
# end
# print_sourcecode(outbuf, data,
# loc.line, loc.defline)
# else
# buf = IOBuffer()
# active_line = print_status_synthtic(buf, state, frame, 2, 5)::Int
# code = split(String(take!(buf)),'\n')
# @assert active_line <= length(code)
# for (lineno, line) in enumerate(code)
# if lineno == active_line
# printstyled(outbuf, "=> ", bold = true, color = :yellow); println(outbuf, line)
# else
# printstyled(outbuf, "? ", bold = true); println(outbuf, line)
# end
# end
# end
# print_next_expr(outbuf, state, frame)
# # print(io, String(take!(outbuf.io)))
# about_to_run = String(take!(outbuf.io))
#
# arr = print_backtrace(state)
# _intellij_send_to(Dict("next" => Dict("line" => currentLine, "expr" => about_to_run, "file" => fileInfo["file"]),"frames" => arr))
# end
function Debugger.print_status(io::IO, frame::Frame; force_lowered=false)
# Buffer to avoid flickering
outbuf = IOContext(IOBuffer(), io)
loc = locinfo(frame)
fileInfo::Dict = locdesc(frame)
if _intellij_debug_mode
_, current_line, _ = loc
else
if loc !== nothing && !force_lowered
defline, current_line, body = loc
breakpoint_lines = breakpoint_linenumbers(frame)
ok = print_sourcecode(outbuf, body, current_line, defline, breakpoint_lines)
if !ok
printstyled(io, "failed to lookup source code, showing lowered code:\n"; color=Base.warn_color())
print_codeinfo(outbuf, frame)
end
else
current_line = 0
print_codeinfo(outbuf, frame)
end
end
print_next_expr(outbuf, frame)
about_to_run = String(take!(outbuf.io))
arr = print_backtrace(frame)
_intellij_send_to(Dict("next" => Dict("line" => current_line, "expr" => about_to_run, "file" => fileInfo["file"]),"frames" => arr))
end
function Debugger.print_next_expr(io::IO, frame::Frame)
expr = pc_expr(frame)
@assert expr !== nothing
#print(io, "About to run: ")
isa(expr, Expr) && (expr = copy(expr))
if isexpr(expr, :(=))
expr = expr.args[2]
end
if isexpr(expr, :call) || isexpr(expr, :return)
for i in 1:length(expr.args)
val = try
@lookup(frame, expr.args[i])
catch err
err isa UndefVarError || rethrow(err)
expr.args[i]
end
expr.args[i] = maybe_quote(val)
end
end
expr = pattern_match_kw_call(expr)
expr = pattern_match_apply_call(expr, frame)
limit_expr = repr_limited(expr, MAX_BYTES_REPR[], print)
print(io, limit_expr)
#print(io, highlight_code(limit_expr; context=io))
#println(io)
end
function print_locdesc(frame::Frame; current_line=False)
sprint() do io
Debugger.locdesc(io, frame; current_line=current_line)
end
end
function print_locdesc(io::IO, frame::Frame; current_line=False)
Debugger.locdesc(io, frame; current_line=current_line)
end
function Debugger.print_frame(io::IO, num::Integer, frame::Frame; current_line=false)::Dict
#print(io, "[$num] ")
#println(io, locdesc(frame; current_line=current_line))
stackInfo::Dict = Debugger.locdesc(frame; current_line=current_line)
global _intellij_current_stack
varinfo = _intellij_current_stack = []
print_locals(frame)
Dict("stack" => stackInfo, "vars" => varinfo)
end
function print_backtrace(frame::Frame)::Array
num = 0
arr = []
sprint() do io
while frame !== nothing
num += 1
frame_info::Dict = Debugger.print_frame(io, num, frame; current_line=true)
push!(arr, frame_info)
frame = caller(frame)
end
end
arr
end
function print_backtrace(state)::Array
io = Base.pipe_writer(state.terminal)
iob = IOContext(IOBuffer(), io)
num = 0
arr = []
frame = state.frame
while frame !== nothing
num += 1
frame_info::Dict = Debugger.print_frame(iob, num, frame; current_line=true)
push!(arr, frame_info)
frame = caller(frame)
end
arr
end
function Debugger.print_locals(frame::Frame)
global _intellij_current_stack
vars = JuliaInterpreter.locals(frame)
for var in vars
# Hide gensymmed variables
if var.name == Symbol("#self#")
val = var.value
(isa(val, Type) || sizeof(val) == 0) && continue
else
startswith(string(var.name), "#") && continue
end
ret = Debugger.print_var(var)
push!(_intellij_current_stack,ret)
end
#TODO: Do sparams?
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment