UI and a Lisp experiment
This commit is contained in:
parent
38ff06ea45
commit
f55b437037
24 changed files with 2746 additions and 89 deletions
127
src/ui/App.tsx
Normal file
127
src/ui/App.tsx
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
import { createMemo, createSignal, Show } from 'solid-js';
|
||||
import { sourceText } from 'source-region';
|
||||
import type { CodePointSpan, SourceRegion, SourceText } from 'source-region';
|
||||
import { parseDocument } from '../parser';
|
||||
import type { ParseError } from '../parser';
|
||||
import type { ConcreteSyntax } from '../syntax';
|
||||
import { spanLabel } from './format';
|
||||
import { PaneHeader, PaneSplitter } from './Pane';
|
||||
import { SourceGrid } from './SourceGrid';
|
||||
import type { SourceGridAnnotation } from './SourceGrid';
|
||||
import { ErrorList, ExpressionList } from './SyntaxPane';
|
||||
import type { HoverTarget } from './types';
|
||||
|
||||
type ParsedDocument = {
|
||||
source: SourceText;
|
||||
region: SourceRegion;
|
||||
values: ConcreteSyntax[];
|
||||
errors: ParseError[];
|
||||
};
|
||||
|
||||
const SAMPLE_INPUT = `(define square (_ x) (mul x x))
|
||||
|
||||
(add 1 2)
|
||||
|
||||
(define pyth (_ x y) (+ (square x) (square y)))
|
||||
|
||||
foo ) @@@ (bar 1)
|
||||
(nested (list 123 abc_9 name-with-dash))`;
|
||||
|
||||
export function App() {
|
||||
const [input, setInput] = createSignal(SAMPLE_INPUT);
|
||||
const [hovered, setHovered] = createSignal<HoverTarget | undefined>();
|
||||
const [leftWidth, setLeftWidth] = createSignal(420);
|
||||
const [middleWidth, setMiddleWidth] = createSignal(420);
|
||||
|
||||
const parsed = createMemo<ParsedDocument>(() => {
|
||||
const source = sourceText(input());
|
||||
const region = source.fullRegion();
|
||||
const result = parseDocument(region);
|
||||
return { source, region, values: result.values, errors: result.errors };
|
||||
});
|
||||
|
||||
return (
|
||||
<main
|
||||
class="app-shell"
|
||||
style={{
|
||||
"--left-width": `${leftWidth()}px`,
|
||||
"--middle-width": `${middleWidth()}px`,
|
||||
}}
|
||||
>
|
||||
<section class="pane input-pane">
|
||||
<PaneHeader title="Source" detail={`${input().length} UTF-16 units`} />
|
||||
<textarea
|
||||
class="source-input"
|
||||
spellcheck={false}
|
||||
value={input()}
|
||||
onInput={(event) => {
|
||||
setInput(event.currentTarget.value);
|
||||
setHovered(undefined);
|
||||
}}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<PaneSplitter
|
||||
label="Resize source and structure panes"
|
||||
onDrag={(delta) => {
|
||||
setLeftWidth((width) => clamp(width + delta, 280, 760));
|
||||
}}
|
||||
/>
|
||||
|
||||
<section class="pane structure-pane">
|
||||
<PaneHeader
|
||||
title="Structure"
|
||||
detail={`${parsed().values.length} expressions, ${parsed().errors.length} errors`}
|
||||
/>
|
||||
<Show
|
||||
when={parsed().errors.length > 0}
|
||||
fallback={
|
||||
<ExpressionList
|
||||
values={parsed().values}
|
||||
onHover={setHovered}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ErrorList
|
||||
errors={parsed().errors}
|
||||
values={parsed().values}
|
||||
onHover={setHovered}
|
||||
/>
|
||||
</Show>
|
||||
</section>
|
||||
|
||||
<PaneSplitter
|
||||
label="Resize structure and source grid panes"
|
||||
onDrag={(delta) => {
|
||||
setMiddleWidth((width) => clamp(width + delta, 260, 760));
|
||||
}}
|
||||
/>
|
||||
|
||||
<section class="pane source-pane">
|
||||
<PaneHeader
|
||||
title="Source Grid"
|
||||
detail={hovered() ? spanLabel(hovered()!.span) : "nothing hovered"}
|
||||
/>
|
||||
<SourceGrid
|
||||
source={parsed().source}
|
||||
region={parsed().region}
|
||||
annotations={hovered() ? [hoverAnnotation(hovered()!)] : []}
|
||||
/>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
function hoverAnnotation(target: HoverTarget): SourceGridAnnotation {
|
||||
return {
|
||||
id: "hovered",
|
||||
span: target.span,
|
||||
label: target.label,
|
||||
cellClass: "annotation-hovered",
|
||||
markerClass: "annotation-hovered-marker",
|
||||
};
|
||||
}
|
||||
|
||||
function clamp(value: number, min: number, max: number): number {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue