UI and a Lisp experiment
This commit is contained in:
parent
38ff06ea45
commit
f55b437037
24 changed files with 2746 additions and 89 deletions
126
src/ui/SyntaxPane.tsx
Normal file
126
src/ui/SyntaxPane.tsx
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
import { For, Show } from 'solid-js';
|
||||
import type { JSX } from 'solid-js';
|
||||
import type { CodePointSpan } from 'source-region';
|
||||
import type { ParseError } from '../parser';
|
||||
import type { ConcreteSyntax } from '../syntax';
|
||||
import { Expr } from '../syntax';
|
||||
import { errorDetail, errorLabel, errorTitle } from './format';
|
||||
import type { HoverTarget } from './types';
|
||||
|
||||
export function ErrorList(props: {
|
||||
errors: ParseError[];
|
||||
values: ConcreteSyntax[];
|
||||
onHover: (target: HoverTarget | undefined) => void;
|
||||
}) {
|
||||
return (
|
||||
<div class="scroll-stack">
|
||||
<div class="section-label">Errors</div>
|
||||
<div class="error-list">
|
||||
<For each={props.errors}>
|
||||
{(error) => (
|
||||
<HoverBlock
|
||||
class="error-card"
|
||||
label={errorLabel(error)}
|
||||
span={error.span}
|
||||
onHover={props.onHover}
|
||||
>
|
||||
<div class="item-title">{errorTitle(error)}</div>
|
||||
<div class="item-meta">{errorDetail(error)}</div>
|
||||
</HoverBlock>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
|
||||
<Show when={props.values.length > 0}>
|
||||
<div class="section-label">Recovered Expressions</div>
|
||||
<ExpressionList values={props.values} onHover={props.onHover} />
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ExpressionList(props: {
|
||||
values: ConcreteSyntax[];
|
||||
onHover: (target: HoverTarget | undefined) => void;
|
||||
}) {
|
||||
return (
|
||||
<div class="expr-list">
|
||||
<For each={props.values}>
|
||||
{(value, index) => (
|
||||
<ExprView
|
||||
expr={value}
|
||||
label={`expression ${index() + 1}`}
|
||||
onHover={props.onHover}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ExprView(props: {
|
||||
expr: ConcreteSyntax;
|
||||
label: string;
|
||||
onHover: (target: HoverTarget | undefined) => void;
|
||||
}) {
|
||||
if (props.expr.tag === "literal") {
|
||||
return (
|
||||
<HoverBlock
|
||||
class="expr-node literal-node"
|
||||
label={`${props.label}: ${props.expr.value.tag}`}
|
||||
span={props.expr.span}
|
||||
onHover={props.onHover}
|
||||
>
|
||||
<span class="node-kind">{props.expr.value.tag}</span>
|
||||
<span class="node-value">{literalValue(props.expr)}</span>
|
||||
</HoverBlock>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<HoverBlock
|
||||
class="expr-node list-node"
|
||||
label={`${props.label}: list`}
|
||||
span={props.expr.span}
|
||||
onHover={props.onHover}
|
||||
>
|
||||
<div class="list-node-header">
|
||||
<span class="node-kind">list</span>
|
||||
<span class="item-meta">{props.expr.values.length} children</span>
|
||||
</div>
|
||||
<div class="list-children">
|
||||
<For each={props.expr.values}>
|
||||
{(child, index) => (
|
||||
<ExprView
|
||||
expr={child}
|
||||
label={`${props.label}.${index() + 1}`}
|
||||
onHover={props.onHover}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</HoverBlock>
|
||||
);
|
||||
}
|
||||
|
||||
function HoverBlock(props: {
|
||||
class: string;
|
||||
label: string;
|
||||
span: CodePointSpan;
|
||||
onHover: (target: HoverTarget | undefined) => void;
|
||||
children: JSX.Element;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
class={props.class}
|
||||
onMouseEnter={() => props.onHover({ label: props.label, span: props.span })}
|
||||
onMouseLeave={() => props.onHover(undefined)}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function literalValue(expr: ConcreteSyntax): string {
|
||||
return expr.tag === "literal" ? Expr.show(expr) : "";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue