From a5baf0d33a226956123cf4db5123684349267ea8 Mon Sep 17 00:00:00 2001 From: Yura Dupyn <2153100+omedusyo@users.noreply.github.com> Date: Sat, 25 Apr 2026 18:20:26 +0200 Subject: [PATCH] JSON UI --- src/ui/App.tsx | 7 +- src/ui/languages/json/App.tsx | 116 +++++++ src/ui/languages/json/StructurePane.tsx | 407 ++++++++++++++++++++++++ src/ui/languages/json/format.ts | 57 ++++ 4 files changed, 586 insertions(+), 1 deletion(-) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 1e58f6a..fddf812 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -1,7 +1,8 @@ import { createSignal, Switch, Match } from 'solid-js'; import { App as LispApp } from './languages/lisp/App'; +import { App as JsonApp } from './languages/json/App'; -type LanguageId = "lisp"; +type LanguageId = "lisp" | "json"; export function App() { const [language, setLanguage] = createSignal("lisp"); @@ -16,6 +17,7 @@ export function App() { onChange={(event) => setLanguage(event.currentTarget.value as LanguageId)} > + @@ -23,6 +25,9 @@ export function App() { + + + ); diff --git a/src/ui/languages/json/App.tsx b/src/ui/languages/json/App.tsx index e69de29..6424e06 100644 --- a/src/ui/languages/json/App.tsx +++ b/src/ui/languages/json/App.tsx @@ -0,0 +1,116 @@ +import { createMemo, createSignal } from 'solid-js'; +import { sourceText } from 'source-region'; +import type { CodePointSpan, SourceRegion, SourceText } from 'source-region'; +import { + parseDocument, + programOf, +} from '../../../languages/json'; +import type { + ConcreteSyntaxResult, + ParseError, + PartialConcreteSyntax, +} from '../../../languages/json'; +import { hoverAnnotation } from '../../annotations'; +import { spanLabel } from '../../format'; +import { PaneHeader, PaneSplitter } from '../../Pane'; +import { SourceGrid } from '../../SourceGrid'; +import type { HoverTarget } from '../../types'; +import { clamp } from '../../utils'; +import { StructureTree } from './StructurePane'; + +type ParsedDocument = { + source: SourceText; + region: SourceRegion; + syntax: ConcreteSyntaxResult; + program: PartialConcreteSyntax; + errors: ParseError[]; +}; + +const SAMPLE_INPUT = `{ + "name": "Ada", + "scores": [1, 2, 3], + "active": true, + "nested": { "ok": null } +} + +[1 2, 3] +{"x" 1, "y": 2} +{"bad": "escape \\x"} +01 - 1. 1e+ 123abc +@@@ {"recovered": true}`; + +export function App() { + const [input, setInput] = createSignal(SAMPLE_INPUT); + const [hovered, setHovered] = createSignal(); + const [leftWidth, setLeftWidth] = createSignal(420); + const [middleWidth, setMiddleWidth] = createSignal(480); + + const parsed = createMemo(() => { + const source = sourceText(input()); + const region = source.fullRegion(); + const result = parseDocument(region); + return { source, region, syntax: result.syntax, program: programOf(result.syntax), errors: result.errors }; + }); + + return ( +
+
+ +