start of fixing changing files and cleaning up after execute (#897)

* start of fixing changing files and cleaning up after execute

* stop constraints from leaving artifacts

* don't write file on initial load
This commit is contained in:
Kurt Hutten
2023-11-06 11:49:13 +11:00
committed by GitHub
parent 7c22bac638
commit 34163da361
15 changed files with 106 additions and 90 deletions

View File

@ -31,7 +31,6 @@ import { TextEditor } from 'components/TextEditor'
import { Themes, getSystemTheme } from 'lib/theme' import { Themes, getSystemTheme } from 'lib/theme'
import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions' import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions'
import { engineCommandManager } from './lang/std/engineConnection' import { engineCommandManager } from './lang/std/engineConnection'
import { kclManager } from 'lang/KclSinglton'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
export function App() { export function App() {
@ -82,26 +81,6 @@ export function App() {
? 'opacity-40' ? 'opacity-40'
: '' : ''
// Use file code loaded from disk
// on mount, and overwrite any locally-stored code
useEffect(() => {
if (isTauri() && loadedCode !== null) {
if (kclManager.engineCommandManager.engineConnection?.isReady()) {
// If the engine is ready, promptly execute the loaded code
kclManager.setCodeAndExecute(loadedCode)
} else {
// Otherwise, just set the code and wait for the connection to complete
kclManager.setCode(loadedCode)
}
}
return () => {
// Clear code on unmount if in desktop app
if (isTauri()) {
kclManager.setCode('')
}
}
}, [loadedCode])
useEngineConnectionSubscriptions() useEngineConnectionSubscriptions()
const debounceSocketSend = throttle<EngineCommand>((message) => { const debounceSocketSend = throttle<EngineCommand>((message) => {

View File

@ -42,7 +42,7 @@ import CommandBarProvider from 'components/CommandBar'
import { TEST, VITE_KC_SENTRY_DSN } from './env' import { TEST, VITE_KC_SENTRY_DSN } from './env'
import * as Sentry from '@sentry/react' import * as Sentry from '@sentry/react'
import ModelingMachineProvider from 'components/ModelingMachineProvider' import ModelingMachineProvider from 'components/ModelingMachineProvider'
import { KclContextProvider } from 'lang/KclSinglton' import { KclContextProvider, kclManager } from 'lang/KclSinglton'
import FileMachineProvider from 'components/FileMachineProvider' import FileMachineProvider from 'components/FileMachineProvider'
import { sep } from '@tauri-apps/api/path' import { sep } from '@tauri-apps/api/path'
@ -207,6 +207,7 @@ const router = createBrowserRouter(
projectPath + sep + PROJECT_ENTRYPOINT projectPath + sep + PROJECT_ENTRYPOINT
) )
const children = await readDir(projectPath, { recursive: true }) const children = await readDir(projectPath, { recursive: true })
kclManager.setCodeAndExecute(code, false)
return { return {
code, code,

View File

@ -1,5 +1,5 @@
import { useEffect, useState, useRef } from 'react' import { useEffect, useState, useRef } from 'react'
import { parse, BinaryPart, Value, executor } from '../lang/wasm' import { parse, BinaryPart, Value } from '../lang/wasm'
import { import {
createIdentifier, createIdentifier,
createLiteral, createLiteral,
@ -10,6 +10,7 @@ import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst'
import { engineCommandManager } from '../lang/std/engineConnection' import { engineCommandManager } from '../lang/std/engineConnection'
import { kclManager, useKclContext } from 'lang/KclSinglton' import { kclManager, useKclContext } from 'lang/KclSinglton'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { executeAst } from 'useStore'
export const AvailableVars = ({ export const AvailableVars = ({
onVarClick, onVarClick,
@ -130,27 +131,29 @@ export function useCalc({
if (!programMemory || !selectionRange) return if (!programMemory || !selectionRange) return
const varInfo = findAllPreviousVariables( const varInfo = findAllPreviousVariables(
kclManager.ast, kclManager.ast,
programMemory, kclManager.programMemory,
selectionRange selectionRange
) )
setAvailableVarInfo(varInfo) setAvailableVarInfo(varInfo)
}, [kclManager.ast, programMemory, selectionRange]) }, [kclManager.ast, kclManager.programMemory, selectionRange])
useEffect(() => { useEffect(() => {
try { try {
const code = `const __result__ = ${value}\nshow(__result__)` const code = `const __result__ = ${value}`
const ast = parse(code) const ast = parse(code)
const _programMem: any = { root: {}, return: null } const _programMem: any = { root: {}, return: null }
availableVarInfo.variables.forEach(({ key, value }) => { availableVarInfo.variables.forEach(({ key, value }) => {
_programMem.root[key] = { type: 'userVal', value, __meta: [] } _programMem.root[key] = { type: 'userVal', value, __meta: [] }
}) })
executeAst({
executor(
ast, ast,
_programMem,
engineCommandManager, engineCommandManager,
kclManager.defaultPlanes defaultPlanes: kclManager.defaultPlanes,
).then((programMemory) => { useFakeExecutor: true,
programMemoryOverride: JSON.parse(
JSON.stringify(kclManager.programMemory)
),
}).then(({ programMemory }) => {
const resultDeclaration = ast.body.find( const resultDeclaration = ast.body.find(
(a) => (a) =>
a.type === 'VariableDeclaration' && a.type === 'VariableDeclaration' &&
@ -167,7 +170,7 @@ export function useCalc({
setCalcResult('NAN') setCalcResult('NAN')
setValueNode(null) setValueNode(null)
} }
}, [value]) }, [value, availableVarInfo])
return { return {
valueNode, valueNode,
@ -212,7 +215,10 @@ export const CreateNewVariable = ({
}) => { }) => {
return ( return (
<> <>
<label htmlFor="create-new-variable" className="block mt-3 font-mono"> <label
htmlFor="create-new-variable"
className="block mt-3 font-mono text-gray-900"
>
Create new variable Create new variable
</label> </label>
<div className="mt-1 flex gap-2 items-center"> <div className="mt-1 flex gap-2 items-center">
@ -223,6 +229,7 @@ export const CreateNewVariable = ({
onChange={(e) => { onChange={(e) => {
setShouldCreateVariable(e.target.checked) setShouldCreateVariable(e.target.checked)
}} }}
className="bg-white text-gray-900"
/> />
)} )}
<input <input

View File

@ -163,7 +163,6 @@ const FileTreeItem = ({
function openFile() { function openFile() {
if (fileOrDir.children !== undefined) return // Don't open directories if (fileOrDir.children !== undefined) return // Don't open directories
kclManager.setCode('')
navigate(`${paths.FILE}/${encodeURIComponent(fileOrDir.path)}`) navigate(`${paths.FILE}/${encodeURIComponent(fileOrDir.path)}`)
closePanel() closePanel()
} }

View File

@ -147,7 +147,7 @@ export const ModelingMachineProvider = ({
engineCommandManager.artifactMap[sketchEnginePathId] = { engineCommandManager.artifactMap[sketchEnginePathId] = {
type: 'result', type: 'result',
range: [startProfileAtCallExp.start, startProfileAtCallExp.end], range: [startProfileAtCallExp.start, startProfileAtCallExp.end],
commandType: 'extend_path', commandType: 'start_path',
data: null, data: null,
raw: {} as any, raw: {} as any,
} }

View File

@ -108,7 +108,7 @@ export const SetAngleLengthModal = ({
</label> </label>
<div className="mt-1 flex"> <div className="mt-1 flex">
<button <button
className="border border-gray-300 px-2" className="border border-gray-300 px-2 text-gray-900"
onClick={() => setSign(-sign)} onClick={() => setSign(-sign)}
> >
{sign > 0 ? '+' : '-'} {sign > 0 ? '+' : '-'}
@ -118,7 +118,7 @@ export const SetAngleLengthModal = ({
type="text" type="text"
name="val" name="val"
id="val" id="val"
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono pl-1" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono pl-1 text-gray-900"
value={value} value={value}
onChange={(e) => { onChange={(e) => {
setValue(e.target.value) setValue(e.target.value)

View File

@ -87,7 +87,7 @@ export const GetInfoModal = ({
leaveFrom="opacity-100 scale-100" leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95" leaveTo="opacity-0 scale-95"
> >
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all"> <Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white/90 p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title <Dialog.Title
as="h3" as="h3"
className="text-lg font-medium leading-6 text-gray-900" className="text-lg font-medium leading-6 text-gray-900"
@ -109,7 +109,7 @@ export const GetInfoModal = ({
</label> </label>
<div className="mt-1 flex"> <div className="mt-1 flex">
<button <button
className="border border-gray-300 px-2 mr-1" className="border border-gray-400 px-2 mr-1 text-gray-900"
onClick={() => setSign(-sign)} onClick={() => setSign(-sign)}
> >
{sign > 0 ? '+' : '-'} {sign > 0 ? '+' : '-'}
@ -119,7 +119,7 @@ export const GetInfoModal = ({
name="val" name="val"
id="val" id="val"
ref={inputRef} ref={inputRef}
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm text-gray-900 border-gray-300 rounded-md font-mono"
value={value} value={value}
onChange={(e) => { onChange={(e) => {
setValue(e.target.value) setValue(e.target.value)
@ -139,7 +139,7 @@ export const GetInfoModal = ({
name="segName" name="segName"
id="segName" id="segName"
disabled={!isSegNameEditable} disabled={!isSegNameEditable}
className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md font-mono" className="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm text-gray-900 border-gray-300 rounded-md font-mono"
value={segName} value={segName}
onChange={(e) => { onChange={(e) => {
setSegName(e.target.value) setSegName(e.target.value)

View File

@ -17,15 +17,7 @@ import { useStore } from 'useStore'
import { processCodeMirrorRanges } from 'lib/selections' import { processCodeMirrorRanges } from 'lib/selections'
import { LanguageServerClient } from 'editor/lsp' import { LanguageServerClient } from 'editor/lsp'
import kclLanguage from 'editor/lsp/language' import kclLanguage from 'editor/lsp/language'
import { isTauri } from 'lib/isTauri' import { EditorView, lineHighlightField } from 'editor/highlightextension'
import { useParams } from 'react-router-dom'
import { writeTextFile } from '@tauri-apps/api/fs'
import { toast } from 'react-hot-toast'
import {
EditorView,
addLineHighlight,
lineHighlightField,
} from 'editor/highlightextension'
import { roundOff } from 'lib/utils' import { roundOff } from 'lib/utils'
import { kclErrToDiagnostic } from 'lang/errors' import { kclErrToDiagnostic } from 'lang/errors'
import { CSSRuleObject } from 'tailwindcss/types/config' import { CSSRuleObject } from 'tailwindcss/types/config'
@ -50,7 +42,6 @@ export const TextEditor = ({
}: { }: {
theme: Themes.Light | Themes.Dark theme: Themes.Light | Themes.Dark
}) => { }) => {
const pathParams = useParams()
const { editorView, isLSPServerReady, setEditorView, setIsLSPServerReady } = const { editorView, isLSPServerReady, setEditorView, setIsLSPServerReady } =
useStore((s) => ({ useStore((s) => ({
editorView: s.editorView, editorView: s.editorView,
@ -113,18 +104,6 @@ export const TextEditor = ({
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => { // const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
const onChange = (newCode: string) => { const onChange = (newCode: string) => {
kclManager.setCodeAndExecute(newCode) kclManager.setCodeAndExecute(newCode)
if (isTauri() && pathParams.id) {
// Save the file to disk
// Note that PROJECT_ENTRYPOINT is hardcoded until we support multiple files
writeTextFile(pathParams.id, newCode).catch((err) => {
// TODO: add Sentry per GH issue #254 (https://github.com/KittyCAD/modeling-app/issues/254)
console.error('error saving file', err)
toast.error('Error saving file, please check file permissions')
})
}
if (editorView) {
editorView?.dispatch({ effects: addLineHighlight.of([0, 0]) })
}
} //, []); } //, []);
const onUpdate = (viewUpdate: ViewUpdate) => { const onUpdate = (viewUpdate: ViewUpdate) => {
if (!editorView) { if (!editorView) {

View File

@ -18,7 +18,11 @@ import { bracket } from 'lib/exampleKcl'
import { createContext, useContext, useEffect, useState } from 'react' import { createContext, useContext, useEffect, useState } from 'react'
import { getNodeFromPath } from './queryAst' import { getNodeFromPath } from './queryAst'
import { IndexLoaderData } from 'Router' import { IndexLoaderData } from 'Router'
import { useLoaderData } from 'react-router-dom' import { Params, useLoaderData } from 'react-router-dom'
import { isTauri } from 'lib/isTauri'
import { writeTextFile } from '@tauri-apps/api/fs'
import { toast } from 'react-hot-toast'
import { useParams } from 'react-router-dom'
const PERSIST_CODE_TOKEN = 'persistCode' const PERSIST_CODE_TOKEN = 'persistCode'
@ -41,6 +45,7 @@ class KclManager {
private _kclErrors: KCLError[] = [] private _kclErrors: KCLError[] = []
private _isExecuting = false private _isExecuting = false
private _wasmInitFailed = true private _wasmInitFailed = true
private _params: Params<string> = {}
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
private _defferer = deferExecution((code: string) => { private _defferer = deferExecution((code: string) => {
@ -71,6 +76,21 @@ class KclManager {
set code(code) { set code(code) {
this._code = code this._code = code
this._codeCallBack(code) this._codeCallBack(code)
if (isTauri()) {
setTimeout(() => {
// Wait one event loop to give a chance for params to be set
// Save the file to disk
// Note that PROJECT_ENTRYPOINT is hardcoded until we support multiple files
this._params.id &&
writeTextFile(this._params.id, code).catch((err) => {
// TODO: add Sentry per GH issue #254 (https://github.com/KittyCAD/modeling-app/issues/254)
console.error('error saving file', err)
toast.error('Error saving file, please check file permissions')
})
})
} else {
localStorage.setItem(PERSIST_CODE_TOKEN, code)
}
} }
get programMemory() { get programMemory() {
@ -117,8 +137,17 @@ class KclManager {
this._wasmInitFailedCallback(wasmInitFailed) this._wasmInitFailedCallback(wasmInitFailed)
} }
setParams(params: Params<string>) {
this._params = params
}
constructor(engineCommandManager: EngineCommandManager) { constructor(engineCommandManager: EngineCommandManager) {
this.engineCommandManager = engineCommandManager this.engineCommandManager = engineCommandManager
if (isTauri()) {
this.code = ''
return
}
const storedCode = localStorage.getItem(PERSIST_CODE_TOKEN) const storedCode = localStorage.getItem(PERSIST_CODE_TOKEN)
// TODO #819 remove zustand persistence logic in a few months // TODO #819 remove zustand persistence logic in a few months
// short term migration, shouldn't make a difference for tauri app users // short term migration, shouldn't make a difference for tauri app users
@ -130,6 +159,7 @@ class KclManager {
zustandStore.state.code = '' zustandStore.state.code = ''
localStorage.setItem('store', JSON.stringify(zustandStore)) localStorage.setItem('store', JSON.stringify(zustandStore))
} else if (storedCode === null) { } else if (storedCode === null) {
console.log('stored brack thing')
this.code = bracket this.code = bracket
} else { } else {
this.code = storedCode this.code = storedCode
@ -189,8 +219,7 @@ class KclManager {
this._programMemory = programMemory this._programMemory = programMemory
this._ast = { ...ast } this._ast = { ...ast }
if (updateCode) { if (updateCode) {
this._code = recast(ast) this.code = recast(ast)
this._codeCallBack(this._code)
} }
this._executeCallback() this._executeCallback()
} }
@ -233,13 +262,17 @@ class KclManager {
this.ast = ast this.ast = ast
if (code) this.code = code if (code) this.code = code
} }
setCode(code: string) { setCode(code: string, shouldWriteFile = true) {
if (shouldWriteFile) {
// use the normal code setter
this.code = code
return
}
this._code = code this._code = code
this._codeCallBack(code) this._codeCallBack(code)
localStorage.setItem(PERSIST_CODE_TOKEN, code)
} }
setCodeAndExecute(code: string) { setCodeAndExecute(code: string, shouldWriteFile = true) {
this.setCode(code) this.setCode(code, shouldWriteFile)
if (code.trim()) { if (code.trim()) {
this._defferer(code) this._defferer(code)
return return
@ -270,15 +303,12 @@ class KclManager {
execute: boolean, execute: boolean,
optionalParams?: { optionalParams?: {
focusPath?: PathToNode focusPath?: PathToNode
callBack?: (ast: Program) => void
} }
): Promise<Selections | null> { ): Promise<Selections | null> {
const newCode = recast(ast) const newCode = recast(ast)
const astWithUpdatedSource = parse(newCode) const astWithUpdatedSource = parse(newCode)
optionalParams?.callBack?.(astWithUpdatedSource)
let returnVal: Selections | null = null let returnVal: Selections | null = null
this.code = newCode
if (optionalParams?.focusPath) { if (optionalParams?.focusPath) {
const { node } = getNodeFromPath<any>( const { node } = getNodeFromPath<any>(
astWithUpdatedSource, astWithUpdatedSource,
@ -299,12 +329,12 @@ class KclManager {
if (execute) { if (execute) {
// Call execute on the set ast. // Call execute on the set ast.
await this.executeAst(astWithUpdatedSource) await this.executeAst(astWithUpdatedSource, true)
} else { } else {
// When we don't re-execute, we still want to update the program // When we don't re-execute, we still want to update the program
// memory with the new ast. So we will hit the mock executor // memory with the new ast. So we will hit the mock executor
// instead. // instead.
await this.executeAstMock(astWithUpdatedSource) await this.executeAstMock(astWithUpdatedSource, true)
} }
return returnVal return returnVal
} }
@ -369,6 +399,11 @@ export function KclContextProvider({
setWasmInitFailed, setWasmInitFailed,
}) })
}, []) }, [])
const params = useParams()
useEffect(() => {
kclManager.setParams(params)
}, [params])
return ( return (
<KclContext.Provider <KclContext.Provider
value={{ value={{

View File

@ -889,6 +889,7 @@ export class EngineCommandManager {
// TODO: instead of sending a single command with `object_ids: Object.keys(this.artifactMap)` // TODO: instead of sending a single command with `object_ids: Object.keys(this.artifactMap)`
// we need to loop over them each individually because if the engine doesn't recognise a single // we need to loop over them each individually because if the engine doesn't recognise a single
// id the whole command fails. // id the whole command fails.
const artifactsToDelete: any = {}
Object.entries(this.artifactMap).forEach(([id, artifact]) => { Object.entries(this.artifactMap).forEach(([id, artifact]) => {
const artifactTypesToDelete: ArtifactMap[string]['commandType'][] = [ const artifactTypesToDelete: ArtifactMap[string]['commandType'][] = [
// 'start_path' creates a new scene object for the path, which is why it needs to be deleted, // 'start_path' creates a new scene object for the path, which is why it needs to be deleted,
@ -898,7 +899,9 @@ export class EngineCommandManager {
'start_path', 'start_path',
] ]
if (!artifactTypesToDelete.includes(artifact.commandType)) return if (!artifactTypesToDelete.includes(artifact.commandType)) return
artifactsToDelete[id] = artifact
})
Object.keys(artifactsToDelete).forEach((id) => {
const deletCmd: EngineCommand = { const deletCmd: EngineCommand = {
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),

View File

@ -26,5 +26,4 @@ const bracket = startSketchOn('XY')
|> close(%) |> close(%)
|> extrude(width, %) |> extrude(width, %)
show(bracket)
` `

View File

@ -9,7 +9,6 @@ import { documentDir, homeDir, sep } from '@tauri-apps/api/path'
import { isTauri } from './isTauri' import { isTauri } from './isTauri'
import { ProjectWithEntryPointMetadata } from '../Router' import { ProjectWithEntryPointMetadata } from '../Router'
import { metadata } from 'tauri-plugin-fs-extra-api' import { metadata } from 'tauri-plugin-fs-extra-api'
import { bracket } from './exampleKcl'
const PROJECT_FOLDER = 'kittycad-modeling-projects' const PROJECT_FOLDER = 'kittycad-modeling-projects'
export const FILE_EXT = '.kcl' export const FILE_EXT = '.kcl'
@ -211,7 +210,8 @@ export function sortProject(project: FileEntry[]): FileEntry[] {
// Creates a new file in the default directory with the default project name // Creates a new file in the default directory with the default project name
// Returns the path to the new file // Returns the path to the new file
export async function createNewProject( export async function createNewProject(
path: string path: string,
initCode = ''
): Promise<ProjectWithEntryPointMetadata> { ): Promise<ProjectWithEntryPointMetadata> {
if (!isTauri) { if (!isTauri) {
throw new Error('createNewProject() can only be called from a Tauri app') throw new Error('createNewProject() can only be called from a Tauri app')
@ -225,10 +225,12 @@ export async function createNewProject(
}) })
} }
await writeTextFile(path + sep + PROJECT_ENTRYPOINT, bracket).catch((err) => { await writeTextFile(path + sep + PROJECT_ENTRYPOINT, initCode).catch(
console.error('Error creating new file:', err) (err) => {
throw err console.error('Error creating new file:', err)
}) throw err
}
)
const m = await metadata(path) const m = await metadata(path)

View File

@ -43,7 +43,10 @@ function OnboardingWithNewFile() {
ONBOARDING_PROJECT_NAME, ONBOARDING_PROJECT_NAME,
nextIndex nextIndex
) )
const newFile = await createNewProject(defaultDirectory + sep + name) const newFile = await createNewProject(
defaultDirectory + sep + name,
bracket
)
navigate( navigate(
`${paths.FILE}/${encodeURIComponent( `${paths.FILE}/${encodeURIComponent(
newFile.path + sep + PROJECT_ENTRYPOINT newFile.path + sep + PROJECT_ENTRYPOINT
@ -79,7 +82,7 @@ function OnboardingWithNewFile() {
<ActionButton <ActionButton
Element="button" Element="button"
onClick={() => { onClick={() => {
kclManager.setCode(bracket) kclManager.setCodeAndExecute(bracket)
next() next()
}} }}
icon={{ icon: faArrowRight }} icon={{ icon: faArrowRight }}

View File

@ -32,6 +32,7 @@ import {
} from 'lib/tauriFS' } from 'lib/tauriFS'
import { ONBOARDING_PROJECT_NAME } from './Onboarding' import { ONBOARDING_PROJECT_NAME } from './Onboarding'
import { sep } from '@tauri-apps/api/path' import { sep } from '@tauri-apps/api/path'
import { bracket } from 'lib/exampleKcl'
export const Settings = () => { export const Settings = () => {
const loaderData = const loaderData =
@ -96,7 +97,10 @@ export const Settings = () => {
ONBOARDING_PROJECT_NAME, ONBOARDING_PROJECT_NAME,
nextIndex nextIndex
) )
const newFile = await createNewProject(defaultDirectory + sep + name) const newFile = await createNewProject(
defaultDirectory + sep + name,
bracket
)
navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`) navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`)
} }

View File

@ -253,11 +253,13 @@ export async function executeAst({
engineCommandManager, engineCommandManager,
defaultPlanes, defaultPlanes,
useFakeExecutor = false, useFakeExecutor = false,
programMemoryOverride,
}: { }: {
ast: Program ast: Program
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
defaultPlanes: DefaultPlanes defaultPlanes: DefaultPlanes
useFakeExecutor?: boolean useFakeExecutor?: boolean
programMemoryOverride?: ProgramMemory
}): Promise<{ }): Promise<{
logs: string[] logs: string[]
errors: KCLError[] errors: KCLError[]
@ -269,10 +271,13 @@ export async function executeAst({
engineCommandManager.startNewSession() engineCommandManager.startNewSession()
} }
const programMemory = await (useFakeExecutor const programMemory = await (useFakeExecutor
? enginelessExecutor(ast, { ? enginelessExecutor(
root: defaultProgramMemory, ast,
return: null, programMemoryOverride || {
}) root: defaultProgramMemory,
return: null,
}
)
: _executor( : _executor(
ast, ast,
{ {