import { Completion } from '@codemirror/autocomplete' import { EditorView, ViewUpdate } from '@codemirror/view' import { CustomIcon } from 'components/CustomIcon' import { useCommandsContext } from 'hooks/useCommandsContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { CommandArgument, KclCommandValue } from 'lib/commandTypes' import { getSystemTheme } from 'lib/theme' import { useCalculateKclExpression } from 'lib/useCalculateKclExpression' import { roundOff } from 'lib/utils' import { varMentions } from 'lib/varCompletionExtension' import { useEffect, useRef, useState } from 'react' import { useHotkeys } from 'react-hotkeys-hook' import styles from './CommandBarKclInput.module.css' import { createIdentifier, createVariableDeclaration } from 'lang/modifyAst' import { useCodeMirror } from 'components/ModelingSidebar/ModelingPanes/CodeEditor' function CommandBarKclInput({ arg, stepBack, onSubmit, }: { arg: CommandArgument & { inputType: 'kcl' name: string } stepBack: () => void onSubmit: (event: unknown) => void }) { const { commandBarSend, commandBarState } = useCommandsContext() const previouslySetValue = commandBarState.context.argumentsToSubmit[ arg.name ] as KclCommandValue | undefined const { settings } = useSettingsAuthContext() const defaultValue = (arg.defaultValue as string) || '' const [value, setValue] = useState( previouslySetValue?.valueText || defaultValue || '' ) const [createNewVariable, setCreateNewVariable] = useState( previouslySetValue && 'variableName' in previouslySetValue ) const [canSubmit, setCanSubmit] = useState(true) useHotkeys('mod + k, mod + /', () => commandBarSend({ type: 'Close' })) const editorRef = useRef(null) const { prevVariables, calcResult, newVariableInsertIndex, valueNode, newVariableName, setNewVariableName, isNewVariableNameUnique, } = useCalculateKclExpression({ value, initialVariableName: previouslySetValue && 'variableName' in previouslySetValue ? previouslySetValue.variableName : arg.name, }) const varMentionData: Completion[] = prevVariables.map((v) => ({ label: v.key, detail: String(roundOff(v.value as number)), })) const { setContainer } = useCodeMirror({ container: editorRef.current, initialDocValue: value, autoFocus: true, selection: { anchor: 0, head: previouslySetValue && 'valueText' in previouslySetValue ? previouslySetValue.valueText.length : defaultValue.length, }, theme: settings.context.app.theme.current === 'system' ? getSystemTheme() : settings.context.app.theme.current, extensions: [ EditorView.domEventHandlers({ keydown: (event) => { if (event.key === 'Backspace' && value === '') { event.preventDefault() stepBack() } else if (event.key === 'Enter') { event.preventDefault() handleSubmit() } }, }), varMentions(varMentionData), EditorView.updateListener.of((vu: ViewUpdate) => { if (vu.docChanged) { setValue(vu.state.doc.toString()) } }), ], }) useEffect(() => { if (editorRef.current) { setContainer(editorRef.current) } }, [arg, editorRef]) useEffect(() => { setCanSubmit( calcResult !== 'NAN' && (!createNewVariable || isNewVariableNameUnique) ) }, [calcResult, createNewVariable, isNewVariableNameUnique]) function handleSubmit(e?: React.FormEvent) { e?.preventDefault() if (!canSubmit || valueNode === null) return onSubmit( createNewVariable ? ({ valueAst: valueNode, valueText: value, valueCalculated: calcResult, variableName: newVariableName, insertIndex: newVariableInsertIndex, variableIdentifierAst: createIdentifier(newVariableName), variableDeclarationAst: createVariableDeclaration( newVariableName, valueNode ), } satisfies KclCommandValue) : ({ valueAst: valueNode, valueText: value, valueCalculated: calcResult, } satisfies KclCommandValue) ) } return (