Do not write to file or update code editor a ridiculous amount of times and update them both at the most appropriate moments. (#4479)
* Reapply "Deflake project settings override on desktop (#4370)" (#4450)
This reverts commit b11040c23c
.
* Refactor writeToFile and updateCodeEditor to happen at appropriate times
* Turn error into warning about out of date AST.
* Rename setUp to setup
* ONLY reload current file on changes.
* If value is falsey then don't try to executeAst
* Fix up code based selections after constraints
* Correct any last missing code mods
* Update src/clientSideScene/ClientSideSceneComp.tsx
Remove eslint rule no-floating-promises
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
* Fixups
* Fix FileTree failing
---------
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
This commit is contained in:
@ -344,14 +344,13 @@ test.describe('Testing settings', () => {
|
||||
await test.step('Refresh the application and see project setting applied', async () => {
|
||||
// Make sure we're done navigating before we reload
|
||||
await expect(settingsCloseButton).not.toBeVisible()
|
||||
await page.reload({ waitUntil: 'domcontentloaded' })
|
||||
|
||||
await page.reload({ waitUntil: 'domcontentloaded' })
|
||||
await expect(logoLink).toHaveCSS('--primary-hue', projectThemeColor)
|
||||
})
|
||||
|
||||
await test.step(`Navigate back to the home view and see user setting applied`, async () => {
|
||||
await logoLink.click()
|
||||
await page.screenshot({ path: 'out.png' })
|
||||
await expect(logoLink).toHaveCSS('--primary-hue', userThemeColor)
|
||||
})
|
||||
|
||||
|
@ -202,12 +202,20 @@ const Overlay = ({
|
||||
let xAlignment = overlay.angle < 0 ? '0%' : '-100%'
|
||||
let yAlignment = overlay.angle < -90 || overlay.angle >= 90 ? '0%' : '-100%'
|
||||
|
||||
// It's possible for the pathToNode to request a newer AST node
|
||||
// than what's available in the AST at the moment of query.
|
||||
// It eventually settles on being updated.
|
||||
const _node1 = getNodeFromPath<Node<CallExpression>>(
|
||||
kclManager.ast,
|
||||
overlay.pathToNode,
|
||||
'CallExpression'
|
||||
)
|
||||
if (err(_node1)) return
|
||||
|
||||
// For that reason, to prevent console noise, we do not use err here.
|
||||
if (_node1 instanceof Error) {
|
||||
console.warn('ast older than pathToNode, not fatal, eventually settles', '')
|
||||
return
|
||||
}
|
||||
const callExpression = _node1.node
|
||||
|
||||
const constraints = getConstraintInfo(
|
||||
@ -637,10 +645,16 @@ const ConstraintSymbol = ({
|
||||
kclManager.ast,
|
||||
kclManager.programMemory
|
||||
)
|
||||
|
||||
if (!transform) return
|
||||
const { modifiedAst } = transform
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
kclManager.updateAst(modifiedAst, true)
|
||||
|
||||
await kclManager.updateAst(modifiedAst, true)
|
||||
|
||||
// Code editor will be updated in the modelingMachine.
|
||||
const newCode = recast(modifiedAst)
|
||||
if (err(newCode)) return
|
||||
await codeManager.updateCodeEditor(newCode)
|
||||
} catch (e) {
|
||||
console.log('error', e)
|
||||
}
|
||||
|
@ -453,6 +453,7 @@ export class SceneEntities {
|
||||
const { modifiedAst } = addStartProfileAtRes
|
||||
|
||||
await kclManager.updateAst(modifiedAst, false)
|
||||
|
||||
this.removeIntersectionPlane()
|
||||
this.scene.remove(draftPointGroup)
|
||||
|
||||
@ -685,7 +686,7 @@ export class SceneEntities {
|
||||
})
|
||||
return nextAst
|
||||
}
|
||||
setUpDraftSegment = async (
|
||||
setupDraftSegment = async (
|
||||
sketchPathToNode: PathToNode,
|
||||
forward: [number, number, number],
|
||||
up: [number, number, number],
|
||||
@ -856,10 +857,11 @@ export class SceneEntities {
|
||||
}
|
||||
|
||||
await kclManager.executeAstMock(modifiedAst)
|
||||
|
||||
if (intersectsProfileStart) {
|
||||
sceneInfra.modelingSend({ type: 'CancelSketch' })
|
||||
} else {
|
||||
await this.setUpDraftSegment(
|
||||
await this.setupDraftSegment(
|
||||
sketchPathToNode,
|
||||
forward,
|
||||
up,
|
||||
@ -867,6 +869,8 @@ export class SceneEntities {
|
||||
segmentName
|
||||
)
|
||||
}
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(modifiedAst)
|
||||
},
|
||||
onMove: (args) => {
|
||||
this.onDragSegment({
|
||||
@ -991,10 +995,14 @@ export class SceneEntities {
|
||||
if (trap(_node)) return
|
||||
const sketchInit = _node.node?.declarations?.[0]?.init
|
||||
|
||||
if (sketchInit.type === 'PipeExpression') {
|
||||
if (sketchInit.type !== 'PipeExpression') {
|
||||
return
|
||||
}
|
||||
|
||||
updateRectangleSketch(sketchInit, x, y, tags[0])
|
||||
|
||||
let _recastAst = parse(recast(_ast))
|
||||
const newCode = recast(_ast)
|
||||
let _recastAst = parse(newCode)
|
||||
if (trap(_recastAst)) return
|
||||
_ast = _recastAst
|
||||
|
||||
@ -1002,6 +1010,11 @@ export class SceneEntities {
|
||||
await kclManager.executeAstMock(_ast)
|
||||
sceneInfra.modelingSend({ type: 'Finish rectangle' })
|
||||
|
||||
// lee: I had this at the bottom of the function, but it's
|
||||
// possible sketchFromKclValue "fails" when sketching on a face,
|
||||
// and this couldn't wouldn't run.
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(_ast)
|
||||
|
||||
const { execState } = await executeAst({
|
||||
ast: _ast,
|
||||
useFakeExecutor: true,
|
||||
@ -1027,7 +1040,6 @@ export class SceneEntities {
|
||||
sgPaths.forEach((seg, index) =>
|
||||
this.updateSegment(seg, index, 0, _ast, orthoFactor, sketch)
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -1187,13 +1199,17 @@ export class SceneEntities {
|
||||
if (err(moddedResult)) return
|
||||
modded = moddedResult.modifiedAst
|
||||
|
||||
let _recastAst = parse(recast(modded))
|
||||
const newCode = recast(modded)
|
||||
if (err(newCode)) return
|
||||
let _recastAst = parse(newCode)
|
||||
if (trap(_recastAst)) return Promise.reject(_recastAst)
|
||||
_ast = _recastAst
|
||||
|
||||
// Update the primary AST and unequip the rectangle tool
|
||||
await kclManager.executeAstMock(_ast)
|
||||
sceneInfra.modelingSend({ type: 'Finish circle' })
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(_ast)
|
||||
}
|
||||
},
|
||||
})
|
||||
@ -1229,6 +1245,7 @@ export class SceneEntities {
|
||||
forward,
|
||||
position,
|
||||
})
|
||||
await codeManager.writeToFile()
|
||||
}
|
||||
},
|
||||
onDrag: async ({
|
||||
|
@ -22,6 +22,7 @@ import usePlatform from 'hooks/usePlatform'
|
||||
import { FileEntry } from 'lib/project'
|
||||
import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
|
||||
import { normalizeLineEndings } from 'lib/codeEditor'
|
||||
import { reportRejection } from 'lib/trap'
|
||||
|
||||
function getIndentationCSS(level: number) {
|
||||
return `calc(1rem * ${level + 1})`
|
||||
@ -189,8 +190,6 @@ const FileTreeItem = ({
|
||||
// the ReactNodes are destroyed, so is this listener :)
|
||||
useFileSystemWatcher(
|
||||
async (eventType, path) => {
|
||||
// Don't try to read a file that was removed.
|
||||
if (isCurrentFile && eventType !== 'unlink') {
|
||||
// Prevents a cyclic read / write causing editor problems such as
|
||||
// misplaced cursor positions.
|
||||
if (codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher) {
|
||||
@ -198,6 +197,7 @@ const FileTreeItem = ({
|
||||
return
|
||||
}
|
||||
|
||||
if (isCurrentFile && eventType === 'change') {
|
||||
let code = await window.electron.readFile(path, { encoding: 'utf-8' })
|
||||
code = normalizeLineEndings(code)
|
||||
codeManager.updateCodeStateEditor(code)
|
||||
@ -242,11 +242,11 @@ const FileTreeItem = ({
|
||||
// Show the renaming form
|
||||
addCurrentItemToRenaming()
|
||||
} else if (e.code === 'Space') {
|
||||
handleClick()
|
||||
void handleClick().catch(reportRejection)
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
async function handleClick() {
|
||||
setTreeSelection(fileOrDir)
|
||||
|
||||
if (fileOrDir.children !== null) return // Don't open directories
|
||||
@ -258,12 +258,10 @@ const FileTreeItem = ({
|
||||
`import("${fileOrDir.path.replace(project.path, '.')}")\n` +
|
||||
codeManager.code
|
||||
)
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
codeManager.writeToFile()
|
||||
await codeManager.writeToFile()
|
||||
|
||||
// Prevent seeing the model built one piece at a time when changing files
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
kclManager.executeCode(true)
|
||||
await kclManager.executeCode(true)
|
||||
} else {
|
||||
// Let the lsp servers know we closed a file.
|
||||
onFileClose(currentFile?.path || null, project?.path || null)
|
||||
@ -295,7 +293,7 @@ const FileTreeItem = ({
|
||||
style={{ paddingInlineStart: getIndentationCSS(level) }}
|
||||
onClick={(e) => {
|
||||
e.currentTarget.focus()
|
||||
handleClick()
|
||||
void handleClick().catch(reportRejection)
|
||||
}}
|
||||
onKeyUp={handleKeyUp}
|
||||
>
|
||||
@ -655,6 +653,13 @@ export const FileTreeInner = ({
|
||||
const isCurrentFile = loaderData.file?.path === path
|
||||
const hasChanged = eventType === 'change'
|
||||
if (isCurrentFile && hasChanged) return
|
||||
|
||||
// If it's a settings file we wrote to already from the app ignore it.
|
||||
if (codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher) {
|
||||
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
|
||||
return
|
||||
}
|
||||
|
||||
fileSend({ type: 'Refresh' })
|
||||
},
|
||||
[loaderData?.project?.path, fileContext.selectedDirectory.path].filter(
|
||||
|
@ -304,6 +304,7 @@ export const ModelingMachineProvider = ({
|
||||
const dispatchSelection = (selection?: EditorSelection) => {
|
||||
if (!selection) return // TODO less of hack for the below please
|
||||
if (!editorManager.editorView) return
|
||||
|
||||
setTimeout(() => {
|
||||
if (!editorManager.editorView) return
|
||||
editorManager.editorView.dispatch({
|
||||
@ -732,6 +733,11 @@ export const ModelingMachineProvider = ({
|
||||
sketchDetails.origin
|
||||
)
|
||||
if (err(updatedAst)) return Promise.reject(updatedAst)
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||
updatedAst.newAst
|
||||
)
|
||||
|
||||
const selection = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -768,6 +774,11 @@ export const ModelingMachineProvider = ({
|
||||
sketchDetails.origin
|
||||
)
|
||||
if (err(updatedAst)) return Promise.reject(updatedAst)
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||
updatedAst.newAst
|
||||
)
|
||||
|
||||
const selection = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -813,6 +824,11 @@ export const ModelingMachineProvider = ({
|
||||
sketchDetails.origin
|
||||
)
|
||||
if (err(updatedAst)) return Promise.reject(updatedAst)
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||
updatedAst.newAst
|
||||
)
|
||||
|
||||
const selection = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -846,6 +862,11 @@ export const ModelingMachineProvider = ({
|
||||
sketchDetails.origin
|
||||
)
|
||||
if (err(updatedAst)) return Promise.reject(updatedAst)
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||
updatedAst.newAst
|
||||
)
|
||||
|
||||
const selection = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -881,6 +902,11 @@ export const ModelingMachineProvider = ({
|
||||
sketchDetails.origin
|
||||
)
|
||||
if (err(updatedAst)) return Promise.reject(updatedAst)
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||
updatedAst.newAst
|
||||
)
|
||||
|
||||
const selection = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -917,6 +943,11 @@ export const ModelingMachineProvider = ({
|
||||
sketchDetails.origin
|
||||
)
|
||||
if (err(updatedAst)) return Promise.reject(updatedAst)
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||
updatedAst.newAst
|
||||
)
|
||||
|
||||
const selection = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -953,6 +984,11 @@ export const ModelingMachineProvider = ({
|
||||
sketchDetails.origin
|
||||
)
|
||||
if (err(updatedAst)) return Promise.reject(updatedAst)
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||
updatedAst.newAst
|
||||
)
|
||||
|
||||
const selection = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -999,6 +1035,11 @@ export const ModelingMachineProvider = ({
|
||||
sketchDetails.origin
|
||||
)
|
||||
if (err(updatedAst)) return Promise.reject(updatedAst)
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
||||
updatedAst.newAst
|
||||
)
|
||||
|
||||
const selection = updateSelections(
|
||||
{ 0: pathToReplacedNode },
|
||||
selectionRanges,
|
||||
|
@ -41,6 +41,7 @@ import { reportRejection } from 'lib/trap'
|
||||
import { getAppSettingsFilePath } from 'lib/desktop'
|
||||
import { isDesktop } from 'lib/isDesktop'
|
||||
import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
|
||||
import { codeManager } from 'lib/singletons'
|
||||
import { createRouteCommands } from 'lib/commandBarConfigs/routeCommandConfig'
|
||||
|
||||
type MachineContext<T extends AnyStateMachine> = {
|
||||
@ -201,13 +202,13 @@ export const SettingsAuthProviderBase = ({
|
||||
console.error('Error executing AST after settings change', e)
|
||||
}
|
||||
},
|
||||
persistSettings: ({ context, event }) => {
|
||||
async persistSettings({ context, event }) {
|
||||
// Without this, when a user changes the file, it'd
|
||||
// create a detection loop with the file-system watcher.
|
||||
if (event.doNotPersist) return
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
saveSettings(context, loadedProject?.project?.path)
|
||||
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
|
||||
return saveSettings(context, loadedProject?.project?.path)
|
||||
},
|
||||
},
|
||||
}),
|
||||
@ -221,7 +222,7 @@ export const SettingsAuthProviderBase = ({
|
||||
}, [])
|
||||
|
||||
useFileSystemWatcher(
|
||||
async () => {
|
||||
async (eventType: string) => {
|
||||
// If there is a projectPath but it no longer exists it means
|
||||
// it was exterally removed. If we let the code past this condition
|
||||
// execute it will recreate the directory due to code in
|
||||
@ -235,6 +236,9 @@ export const SettingsAuthProviderBase = ({
|
||||
}
|
||||
}
|
||||
|
||||
// Only reload if there are changes. Ignore everything else.
|
||||
if (eventType !== 'change') return
|
||||
|
||||
const data = await loadAndValidateSettings(loadedProject?.project?.path)
|
||||
settingsSend({
|
||||
type: 'Set all settings',
|
||||
|
@ -96,10 +96,10 @@ export class KclPlugin implements PluginValue {
|
||||
|
||||
const newCode = viewUpdate.state.doc.toString()
|
||||
codeManager.code = newCode
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
codeManager.writeToFile()
|
||||
|
||||
void codeManager.writeToFile().then(() => {
|
||||
this.scheduleUpdateDoc()
|
||||
})
|
||||
}
|
||||
|
||||
scheduleUpdateDoc() {
|
||||
|
@ -26,6 +26,7 @@ export function useRefreshSettings(routeId: string = PATHS.INDEX) {
|
||||
ctx.settings.send({
|
||||
type: 'Set all settings',
|
||||
settings: routeData,
|
||||
doNotPersist: true,
|
||||
})
|
||||
}, [])
|
||||
}
|
||||
|
@ -2,13 +2,13 @@ import {
|
||||
SetVarNameModal,
|
||||
createSetVarNameModal,
|
||||
} from 'components/SetVarNameModal'
|
||||
import { editorManager, kclManager } from 'lib/singletons'
|
||||
import { reportRejection, trap } from 'lib/trap'
|
||||
import { editorManager, kclManager, codeManager } from 'lib/singletons'
|
||||
import { reportRejection, trap, err } from 'lib/trap'
|
||||
import { moveValueIntoNewVariable } from 'lang/modifyAst'
|
||||
import { isNodeSafeToReplace } from 'lang/queryAst'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useModelingContext } from './useModelingContext'
|
||||
import { PathToNode, SourceRange } from 'lang/wasm'
|
||||
import { PathToNode, SourceRange, recast } from 'lang/wasm'
|
||||
import { useKclContext } from 'lang/KclProvider'
|
||||
import { toSync } from 'lib/utils'
|
||||
|
||||
@ -57,6 +57,11 @@ export function useConvertToVariable(range?: SourceRange) {
|
||||
)
|
||||
|
||||
await kclManager.updateAst(_modifiedAst, true)
|
||||
|
||||
const newCode = recast(_modifiedAst)
|
||||
if (err(newCode)) return
|
||||
codeManager.updateCodeEditor(newCode)
|
||||
|
||||
return pathToReplacedNode
|
||||
} catch (e) {
|
||||
console.log('error', e)
|
||||
|
@ -357,9 +357,6 @@ export class KclManager {
|
||||
this.clearAst()
|
||||
return
|
||||
}
|
||||
codeManager.updateCodeEditor(newCode)
|
||||
// Write the file to disk.
|
||||
await codeManager.writeToFile()
|
||||
this._ast = { ...newAst }
|
||||
|
||||
const { logs, errors, execState } = await executeAst({
|
||||
@ -434,13 +431,9 @@ export class KclManager {
|
||||
|
||||
// Update the code state and the editor.
|
||||
codeManager.updateCodeStateEditor(code)
|
||||
// Write back to the file system.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
codeManager.writeToFile()
|
||||
|
||||
// execute the code.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.executeCode()
|
||||
// Write back to the file system.
|
||||
void codeManager.writeToFile().then(() => this.executeCode())
|
||||
}
|
||||
// There's overlapping responsibility between updateAst and executeAst.
|
||||
// updateAst was added as it was used a lot before xState migration so makes the port easier.
|
||||
@ -501,11 +494,6 @@ export class KclManager {
|
||||
}
|
||||
|
||||
if (execute) {
|
||||
// Call execute on the set ast.
|
||||
// Update the code state and editor.
|
||||
codeManager.updateCodeEditor(newCode)
|
||||
// Write the file to disk.
|
||||
await codeManager.writeToFile()
|
||||
await this.executeAst({
|
||||
ast: astWithUpdatedSource,
|
||||
zoomToFit: optionalParams?.zoomToFit,
|
||||
|
@ -7,6 +7,8 @@ import toast from 'react-hot-toast'
|
||||
import { editorManager } from 'lib/singletons'
|
||||
import { Annotation, Transaction } from '@codemirror/state'
|
||||
import { KeyBinding } from '@codemirror/view'
|
||||
import { recast, Program } from 'lang/wasm'
|
||||
import { err } from 'lib/trap'
|
||||
|
||||
const PERSIST_CODE_KEY = 'persistCode'
|
||||
|
||||
@ -121,24 +123,39 @@ export default class CodeManager {
|
||||
// Only write our buffer contents to file once per second. Any faster
|
||||
// and file-system watchers which read, will receive empty data during
|
||||
// writes.
|
||||
|
||||
clearTimeout(this.timeoutWriter)
|
||||
this.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.timeoutWriter = setTimeout(() => {
|
||||
if (!this._currentFilePath)
|
||||
return reject(new Error('currentFilePath not set'))
|
||||
|
||||
// Wait one event loop to give a chance for params to be set
|
||||
// Save the file to disk
|
||||
this._currentFilePath &&
|
||||
window.electron
|
||||
.writeFile(this._currentFilePath, this.code ?? '')
|
||||
.then(resolve)
|
||||
.catch((err: Error) => {
|
||||
// TODO: add tracing 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')
|
||||
reject(err)
|
||||
})
|
||||
}, 1000)
|
||||
})
|
||||
} else {
|
||||
safeLSSetItem(PERSIST_CODE_KEY, this.code)
|
||||
}
|
||||
}
|
||||
|
||||
async updateEditorWithAstAndWriteToFile(ast: Program) {
|
||||
const newCode = recast(ast)
|
||||
if (err(newCode)) return
|
||||
this.updateCodeStateEditor(newCode)
|
||||
await this.writeToFile()
|
||||
}
|
||||
}
|
||||
|
||||
function safeLSGetItem(key: string) {
|
||||
|
@ -35,7 +35,12 @@ import {
|
||||
ArtifactGraph,
|
||||
getSweepFromSuspectedPath,
|
||||
} from 'lang/std/artifactGraph'
|
||||
import { kclManager, engineCommandManager, editorManager } from 'lib/singletons'
|
||||
import {
|
||||
kclManager,
|
||||
engineCommandManager,
|
||||
editorManager,
|
||||
codeManager,
|
||||
} from 'lib/singletons'
|
||||
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||
|
||||
// Apply Fillet To Selection
|
||||
@ -253,6 +258,9 @@ async function updateAstAndFocus(
|
||||
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
||||
focusPath: pathToFilletNode,
|
||||
})
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
|
||||
if (updatedAst?.selections) {
|
||||
editorManager.selectRange(updatedAst?.selections)
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ export async function loadAndValidateSettings(
|
||||
if (err(appSettingsPayload)) return Promise.reject(appSettingsPayload)
|
||||
|
||||
let settingsNext = createSettings()
|
||||
|
||||
// Because getting the default directory is async, we need to set it after
|
||||
if (onDesktop) {
|
||||
settings.app.projectDirectory.default = await getInitialDefaultDir()
|
||||
|
@ -115,6 +115,7 @@ export function useCalculateKclExpression({
|
||||
setCalcResult(typeof result === 'number' ? String(result) : 'NAN')
|
||||
init && setValueNode(init)
|
||||
}
|
||||
if (!value) return
|
||||
execAstAndSetResult().catch(() => {
|
||||
setCalcResult('NAN')
|
||||
setValueNode(null)
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
sceneEntitiesManager,
|
||||
engineCommandManager,
|
||||
editorManager,
|
||||
codeManager,
|
||||
} from 'lib/singletons'
|
||||
import {
|
||||
horzVertInfo,
|
||||
@ -531,8 +532,10 @@ export const modelingMachine = setup({
|
||||
}
|
||||
}
|
||||
),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
'hide default planes': () => kclManager.hidePlanes(),
|
||||
'hide default planes': () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
kclManager.hidePlanes()
|
||||
},
|
||||
'reset sketch metadata': assign({
|
||||
sketchDetails: null,
|
||||
sketchEnginePathId: '',
|
||||
@ -595,7 +598,6 @@ export const modelingMachine = setup({
|
||||
if (trap(extrudeSketchRes)) return
|
||||
const { modifiedAst, pathToExtrudeArg } = extrudeSketchRes
|
||||
|
||||
store.videoElement?.pause()
|
||||
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
||||
focusPath: [pathToExtrudeArg],
|
||||
zoomToFit: true,
|
||||
@ -604,11 +606,9 @@ export const modelingMachine = setup({
|
||||
type: 'path',
|
||||
},
|
||||
})
|
||||
if (!engineCommandManager.engineConnection?.idleMode) {
|
||||
store.videoElement?.play().catch((e) => {
|
||||
console.warn('Video playing was prevented', e)
|
||||
})
|
||||
}
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
|
||||
if (updatedAst?.selections) {
|
||||
editorManager.selectRange(updatedAst?.selections)
|
||||
}
|
||||
@ -642,7 +642,6 @@ export const modelingMachine = setup({
|
||||
if (trap(revolveSketchRes)) return
|
||||
const { modifiedAst, pathToRevolveArg } = revolveSketchRes
|
||||
|
||||
store.videoElement?.pause()
|
||||
const updatedAst = await kclManager.updateAst(modifiedAst, true, {
|
||||
focusPath: [pathToRevolveArg],
|
||||
zoomToFit: true,
|
||||
@ -651,11 +650,9 @@ export const modelingMachine = setup({
|
||||
type: 'path',
|
||||
},
|
||||
})
|
||||
if (!engineCommandManager.engineConnection?.idleMode) {
|
||||
store.videoElement?.play().catch((e) => {
|
||||
console.warn('Video playing was prevented', e)
|
||||
})
|
||||
}
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
|
||||
if (updatedAst?.selections) {
|
||||
editorManager.selectRange(updatedAst?.selections)
|
||||
}
|
||||
@ -685,6 +682,7 @@ export const modelingMachine = setup({
|
||||
}
|
||||
|
||||
await kclManager.updateAst(modifiedAst, true)
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(modifiedAst)
|
||||
})().catch(reportRejection)
|
||||
},
|
||||
'AST fillet': ({ event }) => {
|
||||
@ -702,6 +700,9 @@ export const modelingMachine = setup({
|
||||
radius
|
||||
)
|
||||
if (err(applyFilletToSelectionResult)) return applyFilletToSelectionResult
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||
},
|
||||
'set selection filter to curves only': () => {
|
||||
;(async () => {
|
||||
@ -758,25 +759,35 @@ export const modelingMachine = setup({
|
||||
'remove sketch grid': () => sceneEntitiesManager.removeSketchGrid(),
|
||||
'set up draft line': ({ context: { sketchDetails } }) => {
|
||||
if (!sketchDetails) return
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
sceneEntitiesManager.setUpDraftSegment(
|
||||
sceneEntitiesManager
|
||||
.setupDraftSegment(
|
||||
sketchDetails.sketchPathToNode,
|
||||
sketchDetails.zAxis,
|
||||
sketchDetails.yAxis,
|
||||
sketchDetails.origin,
|
||||
'line'
|
||||
)
|
||||
.then(() => {
|
||||
return codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||
})
|
||||
},
|
||||
'set up draft arc': ({ context: { sketchDetails } }) => {
|
||||
if (!sketchDetails) return
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
sceneEntitiesManager.setUpDraftSegment(
|
||||
sceneEntitiesManager
|
||||
.setupDraftSegment(
|
||||
sketchDetails.sketchPathToNode,
|
||||
sketchDetails.zAxis,
|
||||
sketchDetails.yAxis,
|
||||
sketchDetails.origin,
|
||||
'tangentialArcTo'
|
||||
)
|
||||
.then(() => {
|
||||
return codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||
})
|
||||
},
|
||||
'listen for rectangle origin': ({ context: { sketchDetails } }) => {
|
||||
if (!sketchDetails) return
|
||||
@ -834,31 +845,43 @@ export const modelingMachine = setup({
|
||||
'set up draft rectangle': ({ context: { sketchDetails }, event }) => {
|
||||
if (event.type !== 'Add rectangle origin') return
|
||||
if (!sketchDetails || !event.data) return
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
sceneEntitiesManager.setupDraftRectangle(
|
||||
sceneEntitiesManager
|
||||
.setupDraftRectangle(
|
||||
sketchDetails.sketchPathToNode,
|
||||
sketchDetails.zAxis,
|
||||
sketchDetails.yAxis,
|
||||
sketchDetails.origin,
|
||||
event.data
|
||||
)
|
||||
.then(() => {
|
||||
return codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||
})
|
||||
},
|
||||
'set up draft circle': ({ context: { sketchDetails }, event }) => {
|
||||
if (event.type !== 'Add circle origin') return
|
||||
if (!sketchDetails || !event.data) return
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
sceneEntitiesManager.setupDraftCircle(
|
||||
sceneEntitiesManager
|
||||
.setupDraftCircle(
|
||||
sketchDetails.sketchPathToNode,
|
||||
sketchDetails.zAxis,
|
||||
sketchDetails.yAxis,
|
||||
sketchDetails.origin,
|
||||
event.data
|
||||
)
|
||||
.then(() => {
|
||||
return codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||
})
|
||||
},
|
||||
'set up draft line without teardown': ({ context: { sketchDetails } }) => {
|
||||
if (!sketchDetails) return
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
sceneEntitiesManager.setUpDraftSegment(
|
||||
sceneEntitiesManager
|
||||
.setupDraftSegment(
|
||||
sketchDetails.sketchPathToNode,
|
||||
sketchDetails.zAxis,
|
||||
sketchDetails.yAxis,
|
||||
@ -866,6 +889,9 @@ export const modelingMachine = setup({
|
||||
'line',
|
||||
false
|
||||
)
|
||||
.then(() => {
|
||||
return codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||
})
|
||||
},
|
||||
'show default planes': () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
@ -882,12 +908,17 @@ export const modelingMachine = setup({
|
||||
'add axis n grid': ({ context: { sketchDetails } }) => {
|
||||
if (!sketchDetails) return
|
||||
if (localStorage.getItem('disableAxis')) return
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
sceneEntitiesManager.createSketchAxis(
|
||||
sketchDetails.sketchPathToNode || [],
|
||||
sketchDetails.zAxis,
|
||||
sketchDetails.yAxis,
|
||||
sketchDetails.origin
|
||||
)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||
},
|
||||
'reset client scene mouse handlers': () => {
|
||||
// when not in sketch mode we don't need any mouse listeners
|
||||
@ -916,10 +947,13 @@ export const modelingMachine = setup({
|
||||
'Delete segment': ({ context: { sketchDetails }, event }) => {
|
||||
if (event.type !== 'Delete segment') return
|
||||
if (!sketchDetails || !event.data) return
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
deleteSegment({
|
||||
pathToNode: event.data,
|
||||
sketchDetails,
|
||||
}).then(() => {
|
||||
return codeManager.updateEditorWithAstAndWriteToFile(kclManager.ast)
|
||||
})
|
||||
},
|
||||
'Reset Segment Overlays': () => sceneEntitiesManager.resetOverlays(),
|
||||
@ -984,6 +1018,9 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
|
||||
return {
|
||||
selectionType: 'completeSelection',
|
||||
selection: updateSelections(
|
||||
@ -1018,6 +1055,7 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
return {
|
||||
selectionType: 'completeSelection',
|
||||
selection: updateSelections(
|
||||
@ -1052,6 +1090,7 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
return {
|
||||
selectionType: 'completeSelection',
|
||||
selection: updateSelections(
|
||||
@ -1084,6 +1123,7 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
const updatedSelectionRanges = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -1117,6 +1157,7 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
const updatedSelectionRanges = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -1150,6 +1191,7 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
const updatedSelectionRanges = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -1183,6 +1225,7 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
const updatedSelectionRanges = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -1220,6 +1263,8 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
|
||||
const updatedSelectionRanges = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -1252,6 +1297,7 @@ export const modelingMachine = setup({
|
||||
)
|
||||
if (trap(updatedAst, { suppress: true })) return
|
||||
if (!updatedAst) return
|
||||
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||
const updatedSelectionRanges = updateSelections(
|
||||
pathToNodeMap,
|
||||
selectionRanges,
|
||||
@ -1556,7 +1602,7 @@ export const modelingMachine = setup({
|
||||
},
|
||||
},
|
||||
|
||||
entry: 'setup client side sketch segments',
|
||||
entry: ['setup client side sketch segments'],
|
||||
},
|
||||
|
||||
'Await horizontal distance info': {
|
||||
@ -1801,7 +1847,7 @@ export const modelingMachine = setup({
|
||||
onError: 'SketchIdle',
|
||||
onDone: {
|
||||
target: 'SketchIdle',
|
||||
actions: ['Set selection'],
|
||||
actions: 'Set selection',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
Reference in New Issue
Block a user