import type { Diagnostic } from '@codemirror/lint' import { useMachine, useSelector } from '@xstate/react' import type { ComponentProps } from 'react' import { useEffect, useMemo, useRef, useState } from 'react' import type { Actor, Prop } from 'xstate' import type { Operation } from '@rust/kcl-lib/bindings/Operation' import { ContextMenu, ContextMenuItem } from '@src/components/ContextMenu' import type { CustomIconName } from '@src/components/CustomIcon' import { CustomIcon } from '@src/components/CustomIcon' import Loading from '@src/components/Loading' import { useModelingContext } from '@src/hooks/useModelingContext' import { useKclContext } from '@src/lang/KclProvider' import { codeRefFromRange, getArtifactFromRange, } from '@src/lang/std/artifactGraph' import { sourceRangeFromRust } from '@src/lang/wasm' import { filterOperations, getOperationIcon, getOperationLabel, stdLibMap, } from '@src/lib/operations' import { editorManager, kclManager } from '@src/lib/singletons' import { featureTreeMachine, featureTreeMachineDefaultContext, } from '@src/machines/featureTreeMachine' import { editorIsMountedSelector, kclEditorActor, selectionEventSelector, } from '@src/machines/kclEditorMachine' export const FeatureTreePane = () => { const isEditorMounted = useSelector(kclEditorActor, editorIsMountedSelector) const lastSelectionEvent = useSelector(kclEditorActor, selectionEventSelector) const { send: modelingSend, state: modelingState } = useModelingContext() // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_featureTreeState, featureTreeSend] = useMachine( featureTreeMachine.provide({ guards: { codePaneIsOpen: () => modelingState.context.store.openPanes.includes('code') && editorManager.editorView !== null, }, actions: { openCodePane: () => { modelingSend({ type: 'Set context', data: { openPanes: [...modelingState.context.store.openPanes, 'code'], }, }) }, sendEditFlowStart: () => { modelingSend({ type: 'Enter sketch' }) }, scrollToError: () => { editorManager.scrollToFirstErrorDiagnosticIfExists() }, sendSelectionEvent: ({ context }) => { if (!context.targetSourceRange) { return } const artifact = context.targetSourceRange ? getArtifactFromRange( context.targetSourceRange, kclManager.artifactGraph ) : null if (!artifact) { modelingSend({ type: 'Set selection', data: { selectionType: 'singleCodeCursor', selection: { codeRef: codeRefFromRange( context.targetSourceRange, kclManager.ast ), }, scrollIntoView: true, }, }) } else { modelingSend({ type: 'Set selection', data: { selectionType: 'singleCodeCursor', selection: { artifact: artifact, codeRef: codeRefFromRange( context.targetSourceRange, kclManager.ast ), }, scrollIntoView: true, }, }) } }, }, }), { input: { ...featureTreeMachineDefaultContext, }, // devTools: true, } ) // If there are parse errors we show the last successful operations // and overlay a message on top of the pane const parseErrors = kclManager.errors.filter((e) => e.kind !== 'engine') // If there are engine errors we show the successful operations // Errors return an operation list, so use the longest one if there are multiple const longestErrorOperationList = kclManager.errors.reduce((acc, error) => { return error.operations && error.operations.length > acc.length ? error.operations : acc }, [] as Operation[]) const unfilteredOperationList = !parseErrors.length ? !kclManager.errors.length ? kclManager.execState.operations : longestErrorOperationList : kclManager.lastSuccessfulOperations // We filter out operations that are not useful to show in the feature tree const operationList = filterOperations(unfilteredOperationList) // Watch for changes in the open panes and send an event to the feature tree machine useEffect(() => { const codeOpen = modelingState.context.store.openPanes.includes('code') if (codeOpen && isEditorMounted) { featureTreeSend({ type: 'codePaneOpened' }) } }, [modelingState.context.store.openPanes, isEditorMounted]) // Watch for changes in the selection and send an event to the feature tree machine useEffect(() => { featureTreeSend({ type: 'selected' }) }, [lastSelectionEvent]) function goToError() { featureTreeSend({ type: 'goToError' }) } return (
Errors found in KCL code.
Please fix them before continuing.