* Rename useCalc * Move CommandBar so it has access to settings and kcl * Create codemirror variable mention extension * Make project path a dep of TextEditor useMemo * Add incomplete KCL input for CommandBar to replace current number arg type * Add previous variables autocompletion to kcl input * Fix missed typos from merge * Working AST mods, not working variable additions * Add ability to create a new variable * Add icon and tooltip to command arg tag if a variable is added * Polish variable naming logic, preserve when going back * Allow stepping back from KCL input * Don't prevent keydown of enter, it's used by autocomplete * Round the variable value in cmd bar header * Add Playwright test * Formatting, polish TS types * More type wrangling * Needed to fmt after above type wrangling * Update snapshot tests to account for new variable name autogeneration * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Merge branch 'main' into cmd-bar-make-variable * Update all test instances of var name with number index after merge with main * Partial revert of "Polish variable naming logic, preserve when going back" This reverts commitdddcb13c36
. * Revert "Update all test instances of var name with number index after merge with main" This reverts commit8c4b63b523
. * Revert "Update snapshot tests to account for new variable name autogeneration" This reverts commit11bfce3832
. * Retry a refactoring of findUniqueName * minor feedback from @jgomez720 - better highlighting of kcl input - consistent hotkeys - disallow invalid var names * Polish stepping back state logic * Fix tests now that keyboard shortcut changed * Remove unused imports * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Fix tests * Trigger CI * Update src/components/ProjectSidebarMenu.test.tsx * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * re-trigger CI --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
127 lines
4.0 KiB
TypeScript
127 lines
4.0 KiB
TypeScript
import { useModelingContext } from 'hooks/useModelingContext'
|
|
import { kclManager, useKclContext } from 'lang/KclSingleton'
|
|
import { findUniqueName } from 'lang/modifyAst'
|
|
import { PrevVariable, findAllPreviousVariables } from 'lang/queryAst'
|
|
import { engineCommandManager } from '../lang/std/engineConnection'
|
|
import { Value, parse } from 'lang/wasm'
|
|
import { useEffect, useRef, useState } from 'react'
|
|
import { executeAst } from 'useStore'
|
|
|
|
const isValidVariableName = (name: string) =>
|
|
/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)
|
|
|
|
/**
|
|
* Given a value and a possible variablename,
|
|
* return helpers for calculating the value and inserting it into the code
|
|
* as well as information about the variables that are available
|
|
*/
|
|
export function useCalculateKclExpression({
|
|
value,
|
|
initialVariableName: valueName = '',
|
|
}: {
|
|
value: string
|
|
initialVariableName?: string
|
|
}): {
|
|
inputRef: React.RefObject<HTMLInputElement>
|
|
valueNode: Value | null
|
|
calcResult: string
|
|
prevVariables: PrevVariable<unknown>[]
|
|
newVariableName: string
|
|
isNewVariableNameUnique: boolean
|
|
newVariableInsertIndex: number
|
|
setNewVariableName: (a: string) => void
|
|
} {
|
|
const { programMemory } = useKclContext()
|
|
const { context } = useModelingContext()
|
|
const selectionRange = context.selectionRanges.codeBasedSelections[0].range
|
|
const inputRef = useRef<HTMLInputElement>(null)
|
|
const [availableVarInfo, setAvailableVarInfo] = useState<
|
|
ReturnType<typeof findAllPreviousVariables>
|
|
>({
|
|
variables: [],
|
|
insertIndex: 0,
|
|
bodyPath: [],
|
|
})
|
|
const [valueNode, setValueNode] = useState<Value | null>(null)
|
|
const [calcResult, setCalcResult] = useState('NAN')
|
|
const [newVariableName, setNewVariableName] = useState('')
|
|
const [isNewVariableNameUnique, setIsNewVariableNameUnique] = useState(true)
|
|
|
|
useEffect(() => {
|
|
setTimeout(() => {
|
|
inputRef.current && inputRef.current.focus()
|
|
inputRef.current &&
|
|
inputRef.current.setSelectionRange(0, String(value).length)
|
|
}, 100)
|
|
setNewVariableName(findUniqueName(kclManager.ast, valueName))
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
const allVarNames = Object.keys(programMemory.root)
|
|
if (
|
|
allVarNames.includes(newVariableName) ||
|
|
newVariableName === '' ||
|
|
!isValidVariableName(newVariableName)
|
|
) {
|
|
setIsNewVariableNameUnique(false)
|
|
} else {
|
|
setIsNewVariableNameUnique(true)
|
|
}
|
|
}, [newVariableName])
|
|
|
|
useEffect(() => {
|
|
if (!programMemory || !selectionRange) return
|
|
const varInfo = findAllPreviousVariables(
|
|
kclManager.ast,
|
|
kclManager.programMemory,
|
|
selectionRange
|
|
)
|
|
setAvailableVarInfo(varInfo)
|
|
}, [kclManager.ast, kclManager.programMemory, selectionRange])
|
|
|
|
useEffect(() => {
|
|
const execAstAndSetResult = async () => {
|
|
const code = `const __result__ = ${value}`
|
|
const ast = parse(code)
|
|
const _programMem: any = { root: {}, return: null }
|
|
availableVarInfo.variables.forEach(({ key, value }) => {
|
|
_programMem.root[key] = { type: 'userVal', value, __meta: [] }
|
|
})
|
|
const { programMemory } = await executeAst({
|
|
ast,
|
|
engineCommandManager,
|
|
useFakeExecutor: true,
|
|
programMemoryOverride: JSON.parse(
|
|
JSON.stringify(kclManager.programMemory)
|
|
),
|
|
})
|
|
const resultDeclaration = ast.body.find(
|
|
(a) =>
|
|
a.type === 'VariableDeclaration' &&
|
|
a.declarations?.[0]?.id?.name === '__result__'
|
|
)
|
|
const init =
|
|
resultDeclaration?.type === 'VariableDeclaration' &&
|
|
resultDeclaration?.declarations?.[0]?.init
|
|
const result = programMemory?.root?.__result__?.value
|
|
setCalcResult(typeof result === 'number' ? String(result) : 'NAN')
|
|
init && setValueNode(init)
|
|
}
|
|
execAstAndSetResult().catch(() => {
|
|
setCalcResult('NAN')
|
|
setValueNode(null)
|
|
})
|
|
}, [value, availableVarInfo])
|
|
|
|
return {
|
|
valueNode,
|
|
calcResult,
|
|
prevVariables: availableVarInfo.variables,
|
|
newVariableInsertIndex: availableVarInfo.insertIndex,
|
|
newVariableName,
|
|
isNewVariableNameUnique,
|
|
setNewVariableName,
|
|
inputRef,
|
|
}
|
|
}
|