Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not write to file or update code editor a ridiculous amount of times and update them both at the most appropriate moments. #4479

Merged
merged 13 commits into from
Nov 16, 2024
Merged
3 changes: 1 addition & 2 deletions e2e/playwright/testing-settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})

Expand Down
20 changes: 17 additions & 3 deletions src/clientSideScene/ClientSideSceneComp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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)
}
Expand Down
87 changes: 52 additions & 35 deletions src/clientSideScene/sceneEntities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ export class SceneEntities {
const { modifiedAst } = addStartProfileAtRes

await kclManager.updateAst(modifiedAst, false)

this.removeIntersectionPlane()
this.scene.remove(draftPointGroup)

Expand Down Expand Up @@ -685,7 +686,7 @@ export class SceneEntities {
})
return nextAst
}
setUpDraftSegment = async (
setupDraftSegment = async (
sketchPathToNode: PathToNode,
forward: [number, number, number],
up: [number, number, number],
Expand Down Expand Up @@ -856,17 +857,20 @@ export class SceneEntities {
}

await kclManager.executeAstMock(modifiedAst)

if (intersectsProfileStart) {
sceneInfra.modelingSend({ type: 'CancelSketch' })
} else {
await this.setUpDraftSegment(
await this.setupDraftSegment(
sketchPathToNode,
forward,
up,
origin,
segmentName
)
}

await codeManager.updateEditorWithAstAndWriteToFile(modifiedAst)
},
onMove: (args) => {
this.onDragSegment({
Expand Down Expand Up @@ -991,43 +995,51 @@ export class SceneEntities {
if (trap(_node)) return
const sketchInit = _node.node?.declarations?.[0]?.init

if (sketchInit.type === 'PipeExpression') {
updateRectangleSketch(sketchInit, x, y, tags[0])
if (sketchInit.type !== 'PipeExpression') {
return
}

let _recastAst = parse(recast(_ast))
if (trap(_recastAst)) return
_ast = _recastAst
updateRectangleSketch(sketchInit, x, y, tags[0])

// Update the primary AST and unequip the rectangle tool
await kclManager.executeAstMock(_ast)
sceneInfra.modelingSend({ type: 'Finish rectangle' })
const newCode = recast(_ast)
let _recastAst = parse(newCode)
if (trap(_recastAst)) return
_ast = _recastAst

const { execState } = await executeAst({
ast: _ast,
useFakeExecutor: true,
engineCommandManager: this.engineCommandManager,
programMemoryOverride,
idGenerator: kclManager.execState.idGenerator,
})
const programMemory = execState.memory
// Update the primary AST and unequip the rectangle tool
await kclManager.executeAstMock(_ast)
sceneInfra.modelingSend({ type: 'Finish rectangle' })

// Prepare to update the THREEjs scene
this.sceneProgramMemory = programMemory
const sketch = sketchFromKclValue(
programMemory.get(variableDeclarationName),
variableDeclarationName
)
if (err(sketch)) return
const sgPaths = sketch.paths
const orthoFactor = orthoScale(sceneInfra.camControls.camera)
// 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)

// Update the starting segment of the THREEjs scene
this.updateSegment(sketch.start, 0, 0, _ast, orthoFactor, sketch)
// Update the rest of the segments of the THREEjs scene
sgPaths.forEach((seg, index) =>
this.updateSegment(seg, index, 0, _ast, orthoFactor, sketch)
)
}
const { execState } = await executeAst({
ast: _ast,
useFakeExecutor: true,
engineCommandManager: this.engineCommandManager,
programMemoryOverride,
idGenerator: kclManager.execState.idGenerator,
})
const programMemory = execState.memory

// Prepare to update the THREEjs scene
this.sceneProgramMemory = programMemory
const sketch = sketchFromKclValue(
programMemory.get(variableDeclarationName),
variableDeclarationName
)
if (err(sketch)) return
const sgPaths = sketch.paths
const orthoFactor = orthoScale(sceneInfra.camControls.camera)

// Update the starting segment of the THREEjs scene
this.updateSegment(sketch.start, 0, 0, _ast, orthoFactor, sketch)
// Update the rest of the segments of the THREEjs scene
sgPaths.forEach((seg, index) =>
this.updateSegment(seg, index, 0, _ast, orthoFactor, sketch)
)
},
})
}
Expand Down Expand Up @@ -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)
}
},
})
Expand Down Expand Up @@ -1229,6 +1245,7 @@ export class SceneEntities {
forward,
position,
})
await codeManager.writeToFile()
}
},
onDrag: async ({
Expand Down
35 changes: 20 additions & 15 deletions src/components/FileTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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})`
Expand Down Expand Up @@ -189,15 +190,14 @@ 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) {
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
return
}
// Prevents a cyclic read / write causing editor problems such as
// misplaced cursor positions.
if (codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher) {
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
return
}

if (isCurrentFile && eventType === 'change') {
let code = await window.electron.readFile(path, { encoding: 'utf-8' })
code = normalizeLineEndings(code)
codeManager.updateCodeStateEditor(code)
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -295,7 +293,7 @@ const FileTreeItem = ({
style={{ paddingInlineStart: getIndentationCSS(level) }}
onClick={(e) => {
e.currentTarget.focus()
handleClick()
void handleClick().catch(reportRejection)
}}
onKeyUp={handleKeyUp}
>
Expand Down Expand Up @@ -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(
Expand Down
41 changes: 41 additions & 0 deletions src/components/ModelingMachineProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading
Loading