diff --git a/src/app/components/generator/McdocRenderer.tsx b/src/app/components/generator/McdocRenderer.tsx index fb914301..d053a90b 100644 --- a/src/app/components/generator/McdocRenderer.tsx +++ b/src/app/components/generator/McdocRenderer.tsx @@ -2,26 +2,27 @@ import type { JsonNode } from '@spyglassmc/json' import { JsonArrayNode, JsonBooleanNode, JsonNumberNode, JsonObjectNode, JsonStringNode } from '@spyglassmc/json' import type { ListType, LiteralType, McdocType } from '@spyglassmc/mcdoc' import type { SimplifiedStructType } from '@spyglassmc/mcdoc/lib/runtime/checker/index.js' +import { useCallback } from 'preact/hooks' import { useLocale } from '../../contexts/Locale.jsx' -import type { Edit } from '../../services/Spyglass.js' +import type { AstEdit } from '../../services/Spyglass.js' import { Octicon } from '../Octicon.jsx' interface Props { node: JsonNode | undefined - makeEdits: (edits: Edit[]) => void + makeEdit: (edit: AstEdit) => void } -export function McdocRoot({ node, makeEdits } : Props) { +export function McdocRoot({ node, makeEdit } : Props) { const type = node?.typeDef ?? { kind: 'unsafe' } if (type.kind === 'struct') { - return + return } return <>
- +
- + } @@ -91,14 +92,14 @@ function Head({ simpleType, optional, node }: HeadProps) { interface BodyProps extends Props { simpleType: McdocType } -function Body({ simpleType, node, makeEdits }: BodyProps) { +function Body({ simpleType, node, makeEdit }: BodyProps) { const type = node?.typeDef ?? simpleType if (node?.typeDef?.kind === 'struct') { if (node.typeDef.fields.length === 0) { return <> } return
- +
} if (node?.typeDef?.kind === 'list') { @@ -107,7 +108,7 @@ function Body({ simpleType, node, makeEdits }: BodyProps) { return <> } return
- +
} if (type.kind === 'byte' || type.kind === 'short' || type.kind === 'int' || type.kind === 'boolean') { @@ -120,7 +121,7 @@ function Body({ simpleType, node, makeEdits }: BodyProps) { interface StructBodyProps extends Props { type: SimplifiedStructType } -function StructBody({ type, node, makeEdits }: StructBodyProps) { +function StructBody({ type, node, makeEdit }: StructBodyProps) { if (!JsonObjectNode.is(node)) { return <> } @@ -139,9 +140,9 @@ function StructBody({ type, node, makeEdits }: StructBodyProps) { return
- +
- +
})} @@ -156,17 +157,22 @@ function Key({ label }: { label: string | number | boolean }) { interface ListBodyProps extends Props { type: ListType } -function ListBody({ type, node, makeEdits }: ListBodyProps) { +function ListBody({ type, node, makeEdit }: ListBodyProps) { const { locale } = useLocale() if (!JsonArrayNode.is(node)) { return <> } + const onRemoveItem = useCallback((index: number) => { + makeEdit(() => { + node.children.splice(index, 1) + }) + }, [makeEdit, node]) return <> {node.children.map((item, index) => { const child = item.value return
- {node.children.length > 1 &&
@@ -178,9 +184,9 @@ function ListBody({ type, node, makeEdits }: ListBodyProps) {
} - +
- +
})} diff --git a/src/app/components/generator/SchemaGenerator.tsx b/src/app/components/generator/SchemaGenerator.tsx index 94c4ea49..34b6cc4b 100644 --- a/src/app/components/generator/SchemaGenerator.tsx +++ b/src/app/components/generator/SchemaGenerator.tsx @@ -119,7 +119,7 @@ export function SchemaGenerator({ gen, allowedVersions }: Props) { return } Analytics.undoGenerator(gen.id, 1, 'menu') - await service.undoEdits(uri) + await service.undoEdit(uri) } const redo = async (e: MouseEvent) => { e.stopPropagation() @@ -127,7 +127,7 @@ export function SchemaGenerator({ gen, allowedVersions }: Props) { return } Analytics.redoGenerator(gen.id, 1, 'menu') - await service?.redoEdits(uri) + await service?.redoEdit(uri) } useEffect(() => { @@ -137,10 +137,10 @@ export function SchemaGenerator({ gen, allowedVersions }: Props) { } if (e.ctrlKey && e.key === 'z') { Analytics.undoGenerator(gen.id, 1, 'hotkey') - await service.undoEdits(uri) + await service.undoEdit(uri) } else if (e.ctrlKey && e.key === 'y') { Analytics.redoGenerator(gen.id, 1, 'hotkey') - await service.redoEdits(uri) + await service.redoEdit(uri) } } const onKeyDown = (e: KeyboardEvent) => { diff --git a/src/app/components/generator/Tree.tsx b/src/app/components/generator/Tree.tsx index 99f86580..c9ec44df 100644 --- a/src/app/components/generator/Tree.tsx +++ b/src/app/components/generator/Tree.tsx @@ -3,7 +3,7 @@ import { JsonFileNode } from '@spyglassmc/json' import { useCallback, useErrorBoundary } from 'preact/hooks' import { useLocale } from '../../contexts/index.js' import { useDocAndNode, useSpyglass } from '../../contexts/Spyglass.jsx' -import type { Edit } from '../../services/Spyglass.js' +import type { AstEdit } from '../../services/Spyglass.js' import { McdocRoot } from './McdocRenderer.jsx' type TreePanelProps = { @@ -27,14 +27,14 @@ export function Tree({ docAndNode, onError }: TreePanelProps) { }) if (error) return <> - const makeEdits = useCallback((edits: Edit[]) => { + const makeEdit = useCallback((edit: AstEdit) => { if (!service) { return } - service.applyEdits(docAndNode.doc.uri, edits) + service.applyEdit(docAndNode.doc.uri, edit) }, [service, docAndNode]) return
- +
} diff --git a/src/app/contexts/Spyglass.tsx b/src/app/contexts/Spyglass.tsx index 6d85602c..c8931a59 100644 --- a/src/app/contexts/Spyglass.tsx +++ b/src/app/contexts/Spyglass.tsx @@ -59,18 +59,10 @@ export function SpyglassProvider({ children }: { children: ComponentChildren }) const { version } = useVersion() const [client] = useState(new SpyglassClient()) - const { value: service, error } = useAsync(() => { + const { value: service } = useAsync(() => { return client.createService(version) }, [client, version]) - useEffect(() => { - if (error) { - console.warn(error) - } - }, [error]) - - console.log('->', service) - const value: SpyglassContext = { client, service, diff --git a/src/app/services/Spyglass.ts b/src/app/services/Spyglass.ts index a464af8d..293febb1 100644 --- a/src/app/services/Spyglass.ts +++ b/src/app/services/Spyglass.ts @@ -4,6 +4,7 @@ import type { McmetaSummary } from '@spyglassmc/java-edition/lib/dependency/inde import { Fluids, ReleaseVersion, symbolRegistrar } from '@spyglassmc/java-edition/lib/dependency/index.js' import * as jeJson from '@spyglassmc/java-edition/lib/json/index.js' import * as jeMcf from '@spyglassmc/java-edition/lib/mcfunction/index.js' +import type { JsonFileNode } from '@spyglassmc/json' import * as json from '@spyglassmc/json' import { localize } from '@spyglassmc/locales' import * as mcdoc from '@spyglassmc/mcdoc' @@ -17,10 +18,7 @@ import { computeIfAbsent, genPath } from '../Utils.js' import { fetchBlockStates, fetchRegistries, fetchVanillaMcdoc, getVersionChecksum } from './DataFetcher.js' import type { VersionId } from './Versions.js' -export interface Edit { - range?: core.Range - text: string -} +export type AstEdit = (docAndNode: core.DocAndNode) => void interface ClientDocument { doc: TextDocument @@ -63,7 +61,6 @@ export class SpyglassService { public async getFile(uri: string, emptyContent?: () => string) { let docAndNode = this.service.project.getClientManaged(uri) if (docAndNode === undefined) { - console.info(`[Spyglass#openFile] Opening file with content from fs: ${uri}`) const content = await this.readFile(uri) const doc = TextDocument.create(uri, 'json', 1, content ?? (emptyContent ? emptyContent() : '')) await this.service.project.onDidOpen(doc.uri, doc.languageId, doc.version, doc.getText()) @@ -110,21 +107,24 @@ export class SpyglassService { } } - public async applyEdits(uri: string, edits: Edit[]) { + public async applyEdit(uri: string, edit: AstEdit) { const document = this.client.documents.get(uri) if (document !== undefined) { document.undoStack.push(document.doc.getText()) document.redoStack = [] - TextDocument.update(document.doc, edits.map(e => ({ - range: e.range ? getLsRange(e.range, document.doc) : undefined, - text: e.text, - })), document.doc.version + 1) + const docAndNode = this.service.project.getClientManaged(uri) + if (!docAndNode) { + throw new Error(`[Spyglass#openFile] Cannot get doc and node: ${uri}`) + } + edit(docAndNode) + const newText = this.service.format(docAndNode.node, docAndNode.doc, 2, true) + TextDocument.update(document.doc, [{ text: newText }], document.doc.version + 1) await this.service.project.externals.fs.writeFile(uri, document.doc.getText()) await this.notifyChange(document.doc) } } - public async undoEdits(uri: string) { + public async undoEdit(uri: string) { const document = this.client.documents.get(uri) if (document === undefined) { throw new Error(`[Spyglass#undoEdits] Document doesn't exist: ${uri}`) @@ -139,7 +139,7 @@ export class SpyglassService { await this.notifyChange(document.doc) } - public async redoEdits(uri: string) { + public async redoEdit(uri: string) { const document = this.client.documents.get(uri) if (document === undefined) { throw new Error(`[Spyglass#redoEdits] Document doesn't exist: ${uri}`) @@ -250,6 +250,10 @@ const initialize: core.ProjectInitializer = async (ctx) => { jeMcf.initialize(ctx, summary.commands, release) nbt.initialize(ctx) + meta.registerFormatter('json:file', (node, ctx) => { + return ctx.meta.getFormatter(node.children[0].type)(node.children[0], ctx) + }) + return { loadedVersion: release } }