Skip to content

Commit

Permalink
Stack trace: bracket-matched hiding and expanding and more (#3045)
Browse files Browse the repository at this point in the history
  • Loading branch information
fonsp authored Oct 4, 2024
1 parent a724359 commit 4190ad0
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 27 deletions.
88 changes: 62 additions & 26 deletions frontend/components/ErrorMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const DocLink = ({ frame }) => {
if (frame.parent_module == null) return null
if (ignore_funccall(frame)) return null

const funcname = frame.call.split("(")[0]
const funcname = frame.func
if (funcname === "") return null

const nb = pluto_actions.get_notebook()
Expand Down Expand Up @@ -88,39 +88,62 @@ const at = html`<span> from </span>`
const ignore_funccall = (frame) => frame.call === "top-level scope"
const ignore_location = (frame) => frame.file === "none"

const funcname_args = (call) => {
const anon_match = call.indexOf(")(")
if (anon_match != -1) {
return [call.substring(0, anon_match + 1), call.substring(anon_match + 1)]
} else {
const bracket_index = call.indexOf("(")
if (bracket_index != -1) {
return [call.substring(0, bracket_index), call.substring(bracket_index)]
} else {
return [call, ""]
}
}
}

const Funccall = ({ frame }) => {
if (ignore_funccall(frame)) return null
let [expanded_state, set_expanded] = useState(false)
useEffect(() => {
set_expanded(false)
}, [frame])

const bracket_index = frame.call.indexOf("(")
const silly_to_hide = (frame.call_short.match(//g) ?? "").length <= 1 && frame.call.length < frame.call_short.length + 7

let inner =
bracket_index != -1
? html`<strong>${frame.call.substr(0, bracket_index)}</strong><${ClickToExpandIfLong} text=${frame.call.substr(bracket_index)} />`
: html`<strong>${frame.call}</strong>`
const expanded = expanded_state || (frame.call === frame.call_short && frame.func === funcname_args(frame.call)[0]) || silly_to_hide

return html`<mark>${inner}</mark>`
}
if (ignore_funccall(frame)) return null

const LIMIT_LONG = 200,
LIMIT_PREVIEW = 100
const call = expanded ? frame.call : frame.call_short

const ClickToExpandIfLong = ({ text }) => {
let [expanded, set_expanded] = useState(false)
const call_funcname_args = funcname_args(call)
const funcname = expanded ? call_funcname_args[0] : frame.func

useEffect(() => {
set_expanded(false)
}, [text])
// if function name is #12 or #15#16 then it is an anonymous function

const collaped_text = html`${text.slice(0, LIMIT_PREVIEW)}<a
href="#"
onClick=${(e) => {
e.preventDefault()
set_expanded(true)
}}
>...Show more...</a
>${text.slice(-1)}`
const funcname_display = funcname.match(/^#\d+(#\d+)?$/)
? html`<abbr title="A (mini-)function that is defined without the 'function' keyword, but using -> or 'do'.">anonymous function</abbr>`
: funcname
console.log(funcname, funcname.match(/^#\d+(#\d+)?$/), funcname_display)

let inner = html`<strong>${funcname_display}</strong><${HighlightCallArgumentNames} code=${call_funcname_args[1]} />`

const id = useMemo(() => Math.random().toString(36).substring(7), [frame])

return html`<span>${expanded ? text : text.length < LIMIT_LONG ? text : collaped_text}</span>`
return html`<mark id=${id}>${inner}</mark> ${!expanded
? html`<a
aria-expanded=${expanded}
aria-controls=${id}
title="Display the complete type information of this function call"
role="button"
href="#"
onClick=${(e) => {
e.preventDefault()
set_expanded(true)
}}
>...show types...</a
>`
: null}`
}

const LinePreview = ({ frame, num_context_lines = 2 }) => {
Expand Down Expand Up @@ -172,6 +195,19 @@ const JuliaHighlightedLine = ({ code, frameLine, i }) => {
></code>`
}

const HighlightCallArgumentNames = ({ code }) => {
const code_ref = useRef(/** @type {HTMLPreElement?} */ (null))
useLayoutEffect(() => {
if (code_ref.current) {
const html = code.replaceAll(/([^():{},; ]*)::/g, "<span class='argument_name'>$1</span>::")

code_ref.current.innerHTML = html
}
}, [code_ref.current, code])

return html`<s-span ref=${code_ref} class="language-julia"></s-span>`
}

const insert_commas_and_and = (/** @type {any[]} */ xs) => xs.flatMap((x, i) => (i === xs.length - 1 ? [x] : i === xs.length - 2 ? [x, " and "] : [x, ", "]))

export const ParseError = ({ cell_id, diagnostics }) => {
Expand Down Expand Up @@ -218,7 +254,7 @@ export const ParseError = ({ cell_id, diagnostics }) => {
const frame_is_important_heuristic = (frame, frame_index, limited_stacktrace, frame_cell_id) => {
if (frame_cell_id != null) return true

const [funcname, params] = frame.call.split("(", 2)
const [funcname, params] = funcname_args(frame.call)

if (["_collect", "collect_similar", "iterate", "error", "macro expansion"].includes(funcname)) {
return false
Expand Down
8 changes: 8 additions & 0 deletions frontend/treeview.css
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,14 @@ jlerror > section .classical-frame > mark {
jlerror > section .classical-frame > mark > strong {
color: var(--black);
}
jlerror > section .classical-frame s-span {
/* color: var(--cm-color-type); */
}
jlerror > section .classical-frame s-span .argument_name {
color: var(--jlerror-mark-color);
color: var(--cm-color-var);
color: var(--cm-color-type);
}
jlerror > section .frame-source {
display: flex;
flex-direction: row;
Expand Down
16 changes: 15 additions & 1 deletion src/runner/PlutoRunner/src/display/Exception.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,16 @@ function format_output(val::CapturedException; context=default_iocontext)
stack_relevant = stack[1:something(limit, end)]

pretty = map(stack_relevant) do s
func = s.func === nothing ? nothing : s.func isa Symbol ? String(s.func) : repr(s.func)
method = method_from_frame(s)
sp = source_package(method)
pm = VERSION >= v"1.9" && method isa Method ? parentmodule(method) : nothing
call = replace(pretty_stackcall(s, s.linfo), r"Main\.var\"workspace#\d+\"\." => "")

Dict(
:call => replace(pretty_stackcall(s, s.linfo), r"Main\.var\"workspace#\d+\"\." => ""),
:call => call,
:call_short => type_depth_limit(call, 0),
:func => func,
:inlined => s.inlined,
:from_c => s.from_c,
:file => basename(String(s.file)),
Expand Down Expand Up @@ -124,6 +128,16 @@ function pretty_stackcall(frame::Base.StackFrame, linfo::Module)
end


function type_depth_limit(call::String, n::Int)
!occursin("{" , call) && return call
@static if isdefined(Base, :type_depth_limit) && hasmethod(Base.type_depth_limit, Tuple{String, Int})
Base.type_depth_limit(call, n)
else
call
end
end


"Because even showerror can error... 👀"
function try_showerror(io::IO, e, args...)
try
Expand Down

0 comments on commit 4190ad0

Please sign in to comment.