Compare commits
8 Commits
jtran/fix-
...
v0.26.5
Author | SHA1 | Date | |
---|---|---|---|
0b24216dc5 | |||
2d3841bf61 | |||
51a71a180e | |||
1ec25dfe96 | |||
8de29dd461 | |||
b11040c23c | |||
2bc4f076cb | |||
9e1cf90c81 |
4
.github/workflows/cargo-test.yml
vendored
4
.github/workflows/cargo-test.yml
vendored
@ -5,6 +5,8 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'src/wasm-lib/**.rs'
|
- 'src/wasm-lib/**.rs'
|
||||||
- 'src/wasm-lib/**.hbs'
|
- 'src/wasm-lib/**.hbs'
|
||||||
|
- 'src/wasm-lib/**.gen'
|
||||||
|
- 'src/wasm-lib/**.snap'
|
||||||
- '**/Cargo.toml'
|
- '**/Cargo.toml'
|
||||||
- '**/Cargo.lock'
|
- '**/Cargo.lock'
|
||||||
- '**/rust-toolchain.toml'
|
- '**/rust-toolchain.toml'
|
||||||
@ -15,6 +17,8 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'src/wasm-lib/**.rs'
|
- 'src/wasm-lib/**.rs'
|
||||||
- 'src/wasm-lib/**.hbs'
|
- 'src/wasm-lib/**.hbs'
|
||||||
|
- 'src/wasm-lib/**.gen'
|
||||||
|
- 'src/wasm-lib/**.snap'
|
||||||
- '**/Cargo.toml'
|
- '**/Cargo.toml'
|
||||||
- '**/Cargo.lock'
|
- '**/Cargo.lock'
|
||||||
- '**/rust-toolchain.toml'
|
- '**/rust-toolchain.toml'
|
||||||
|
2
Makefile
2
Makefile
@ -19,7 +19,7 @@ $(XSTATE_TYPEGENS): $(TS_SRC)
|
|||||||
yarn xstate typegen 'src/**/*.ts?(x)'
|
yarn xstate typegen 'src/**/*.ts?(x)'
|
||||||
|
|
||||||
public/wasm_lib_bg.wasm: $(WASM_LIB_FILES)
|
public/wasm_lib_bg.wasm: $(WASM_LIB_FILES)
|
||||||
yarn build:wasm-dev
|
yarn build:wasm
|
||||||
|
|
||||||
node_modules: package.json yarn.lock
|
node_modules: package.json yarn.lock
|
||||||
yarn install
|
yarn install
|
||||||
|
@ -110,7 +110,7 @@ Which commands from setup are one off vs need to be run every time?
|
|||||||
The following will need to be run when checking out a new commit and guarantees the build is not stale:
|
The following will need to be run when checking out a new commit and guarantees the build is not stale:
|
||||||
```bash
|
```bash
|
||||||
yarn install
|
yarn install
|
||||||
yarn build:wasm-dev # or yarn build:wasm for slower but more production-like build
|
yarn build:wasm
|
||||||
yarn start # or yarn build:local && yarn serve for slower but more production-like build
|
yarn start # or yarn build:local && yarn serve for slower but more production-like build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -694,6 +694,9 @@ test.describe('Editor tests', () => {
|
|||||||
.toHaveText(`sketch001 = startSketchOn('XZ')
|
.toHaveText(`sketch001 = startSketchOn('XZ')
|
||||||
|> startProfileAt([3.14, 12], %)
|
|> startProfileAt([3.14, 12], %)
|
||||||
|> xLine(5, %) // lin`)
|
|> xLine(5, %) // lin`)
|
||||||
|
|
||||||
|
// expect there to be no KCL errors
|
||||||
|
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('with tab to accept the completion', async ({ page }) => {
|
test('with tab to accept the completion', async ({ page }) => {
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
@ -258,7 +258,7 @@ test.describe('Testing settings', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test(
|
test.fixme(
|
||||||
`Project settings override user settings on desktop`,
|
`Project settings override user settings on desktop`,
|
||||||
{ tag: ['@electron', '@skipWin'] },
|
{ tag: ['@electron', '@skipWin'] },
|
||||||
async ({ browser: _ }, testInfo) => {
|
async ({ browser: _ }, testInfo) => {
|
||||||
@ -318,7 +318,6 @@ test.describe('Testing settings', () => {
|
|||||||
timeout: 5_000,
|
timeout: 5_000,
|
||||||
})
|
})
|
||||||
.toContain(`themeColor = "${userThemeColor}"`)
|
.toContain(`themeColor = "${userThemeColor}"`)
|
||||||
// Only close the button after we've confirmed
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await test.step('Set project theme color', async () => {
|
await test.step('Set project theme color', async () => {
|
||||||
@ -345,13 +344,14 @@ test.describe('Testing settings', () => {
|
|||||||
await test.step('Refresh the application and see project setting applied', async () => {
|
await test.step('Refresh the application and see project setting applied', async () => {
|
||||||
// Make sure we're done navigating before we reload
|
// Make sure we're done navigating before we reload
|
||||||
await expect(settingsCloseButton).not.toBeVisible()
|
await expect(settingsCloseButton).not.toBeVisible()
|
||||||
|
|
||||||
await page.reload({ waitUntil: 'domcontentloaded' })
|
await page.reload({ waitUntil: 'domcontentloaded' })
|
||||||
|
|
||||||
await expect(logoLink).toHaveCSS('--primary-hue', projectThemeColor)
|
await expect(logoLink).toHaveCSS('--primary-hue', projectThemeColor)
|
||||||
})
|
})
|
||||||
|
|
||||||
await test.step(`Navigate back to the home view and see user setting applied`, async () => {
|
await test.step(`Navigate back to the home view and see user setting applied`, async () => {
|
||||||
await logoLink.click()
|
await logoLink.click()
|
||||||
|
await page.screenshot({ path: 'out.png' })
|
||||||
await expect(logoLink).toHaveCSS('--primary-hue', userThemeColor)
|
await expect(logoLink).toHaveCSS('--primary-hue', userThemeColor)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "zoo-modeling-app",
|
"name": "zoo-modeling-app",
|
||||||
"version": "0.26.3",
|
"version": "0.26.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"productName": "Zoo Modeling App",
|
"productName": "Zoo Modeling App",
|
||||||
"author": {
|
"author": {
|
||||||
|
@ -189,15 +189,15 @@ const FileTreeItem = ({
|
|||||||
// the ReactNodes are destroyed, so is this listener :)
|
// the ReactNodes are destroyed, so is this listener :)
|
||||||
useFileSystemWatcher(
|
useFileSystemWatcher(
|
||||||
async (eventType, path) => {
|
async (eventType, path) => {
|
||||||
// Prevents a cyclic read / write causing editor problems such as
|
|
||||||
// misplaced cursor positions.
|
|
||||||
if (codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher) {
|
|
||||||
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't try to read a file that was removed.
|
// Don't try to read a file that was removed.
|
||||||
if (isCurrentFile && eventType !== 'unlink') {
|
if (isCurrentFile && eventType !== 'unlink') {
|
||||||
|
// Prevents a cyclic read / write causing editor problems such as
|
||||||
|
// misplaced cursor positions.
|
||||||
|
if (codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher) {
|
||||||
|
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let code = await window.electron.readFile(path, { encoding: 'utf-8' })
|
let code = await window.electron.readFile(path, { encoding: 'utf-8' })
|
||||||
code = normalizeLineEndings(code)
|
code = normalizeLineEndings(code)
|
||||||
codeManager.updateCodeStateEditor(code)
|
codeManager.updateCodeStateEditor(code)
|
||||||
@ -242,11 +242,11 @@ const FileTreeItem = ({
|
|||||||
// Show the renaming form
|
// Show the renaming form
|
||||||
addCurrentItemToRenaming()
|
addCurrentItemToRenaming()
|
||||||
} else if (e.code === 'Space') {
|
} else if (e.code === 'Space') {
|
||||||
void handleClick()
|
handleClick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleClick() {
|
function handleClick() {
|
||||||
setTreeSelection(fileOrDir)
|
setTreeSelection(fileOrDir)
|
||||||
|
|
||||||
if (fileOrDir.children !== null) return // Don't open directories
|
if (fileOrDir.children !== null) return // Don't open directories
|
||||||
@ -258,10 +258,12 @@ const FileTreeItem = ({
|
|||||||
`import("${fileOrDir.path.replace(project.path, '.')}")\n` +
|
`import("${fileOrDir.path.replace(project.path, '.')}")\n` +
|
||||||
codeManager.code
|
codeManager.code
|
||||||
)
|
)
|
||||||
await codeManager.writeToFile()
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
codeManager.writeToFile()
|
||||||
|
|
||||||
// Prevent seeing the model built one piece at a time when changing files
|
// Prevent seeing the model built one piece at a time when changing files
|
||||||
await kclManager.executeCode(true)
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
kclManager.executeCode(true)
|
||||||
} else {
|
} else {
|
||||||
// Let the lsp servers know we closed a file.
|
// Let the lsp servers know we closed a file.
|
||||||
onFileClose(currentFile?.path || null, project?.path || null)
|
onFileClose(currentFile?.path || null, project?.path || null)
|
||||||
@ -293,7 +295,7 @@ const FileTreeItem = ({
|
|||||||
style={{ paddingInlineStart: getIndentationCSS(level) }}
|
style={{ paddingInlineStart: getIndentationCSS(level) }}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.currentTarget.focus()
|
e.currentTarget.focus()
|
||||||
void handleClick()
|
handleClick()
|
||||||
}}
|
}}
|
||||||
onKeyUp={handleKeyUp}
|
onKeyUp={handleKeyUp}
|
||||||
>
|
>
|
||||||
@ -653,13 +655,6 @@ export const FileTreeInner = ({
|
|||||||
const isCurrentFile = loaderData.file?.path === path
|
const isCurrentFile = loaderData.file?.path === path
|
||||||
const hasChanged = eventType === 'change'
|
const hasChanged = eventType === 'change'
|
||||||
if (isCurrentFile && hasChanged) return
|
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' })
|
fileSend({ type: 'Refresh' })
|
||||||
},
|
},
|
||||||
[loaderData?.project?.path, fileContext.selectedDirectory.path].filter(
|
[loaderData?.project?.path, fileContext.selectedDirectory.path].filter(
|
||||||
|
@ -41,7 +41,6 @@ import { reportRejection } from 'lib/trap'
|
|||||||
import { getAppSettingsFilePath } from 'lib/desktop'
|
import { getAppSettingsFilePath } from 'lib/desktop'
|
||||||
import { isDesktop } from 'lib/isDesktop'
|
import { isDesktop } from 'lib/isDesktop'
|
||||||
import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
|
import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
|
||||||
import { codeManager } from 'lib/singletons'
|
|
||||||
import { createRouteCommands } from 'lib/commandBarConfigs/routeCommandConfig'
|
import { createRouteCommands } from 'lib/commandBarConfigs/routeCommandConfig'
|
||||||
|
|
||||||
type MachineContext<T extends AnyStateMachine> = {
|
type MachineContext<T extends AnyStateMachine> = {
|
||||||
@ -202,13 +201,13 @@ export const SettingsAuthProviderBase = ({
|
|||||||
console.error('Error executing AST after settings change', e)
|
console.error('Error executing AST after settings change', e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async persistSettings({ context, event }) {
|
persistSettings: ({ context, event }) => {
|
||||||
// Without this, when a user changes the file, it'd
|
// Without this, when a user changes the file, it'd
|
||||||
// create a detection loop with the file-system watcher.
|
// create a detection loop with the file-system watcher.
|
||||||
if (event.doNotPersist) return
|
if (event.doNotPersist) return
|
||||||
|
|
||||||
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
return saveSettings(context, loadedProject?.project?.path)
|
saveSettings(context, loadedProject?.project?.path)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -222,7 +221,7 @@ export const SettingsAuthProviderBase = ({
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useFileSystemWatcher(
|
useFileSystemWatcher(
|
||||||
async (eventType: string) => {
|
async () => {
|
||||||
// If there is a projectPath but it no longer exists it means
|
// If there is a projectPath but it no longer exists it means
|
||||||
// it was exterally removed. If we let the code past this condition
|
// it was exterally removed. If we let the code past this condition
|
||||||
// execute it will recreate the directory due to code in
|
// execute it will recreate the directory due to code in
|
||||||
@ -236,9 +235,6 @@ export const SettingsAuthProviderBase = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only reload if there are changes. Ignore everything else.
|
|
||||||
if (eventType !== 'change') return
|
|
||||||
|
|
||||||
const data = await loadAndValidateSettings(loadedProject?.project?.path)
|
const data = await loadAndValidateSettings(loadedProject?.project?.path)
|
||||||
settingsSend({
|
settingsSend({
|
||||||
type: 'Set all settings',
|
type: 'Set all settings',
|
||||||
|
@ -72,9 +72,10 @@ export default class EditorManager {
|
|||||||
// we cannot use <>.constructor.name since it will get destroyed
|
// we cannot use <>.constructor.name since it will get destroyed
|
||||||
// when packaging the application.
|
// when packaging the application.
|
||||||
const isTreeHighlightPlugin =
|
const isTreeHighlightPlugin =
|
||||||
e.value.hasOwnProperty('tree') &&
|
e?.value &&
|
||||||
e.value.hasOwnProperty('decoratedTo') &&
|
e.value?.hasOwnProperty('tree') &&
|
||||||
e.value.hasOwnProperty('decorations')
|
e.value?.hasOwnProperty('decoratedTo') &&
|
||||||
|
e.value?.hasOwnProperty('decorations')
|
||||||
|
|
||||||
if (isTreeHighlightPlugin) {
|
if (isTreeHighlightPlugin) {
|
||||||
let originalUpdate = e.value.update
|
let originalUpdate = e.value.update
|
||||||
|
@ -96,10 +96,10 @@ export class KclPlugin implements PluginValue {
|
|||||||
|
|
||||||
const newCode = viewUpdate.state.doc.toString()
|
const newCode = viewUpdate.state.doc.toString()
|
||||||
codeManager.code = newCode
|
codeManager.code = newCode
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
codeManager.writeToFile()
|
||||||
|
|
||||||
void codeManager.writeToFile().then(() => {
|
this.scheduleUpdateDoc()
|
||||||
this.scheduleUpdateDoc()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleUpdateDoc() {
|
scheduleUpdateDoc() {
|
||||||
|
@ -26,7 +26,6 @@ export function useRefreshSettings(routeId: string = PATHS.INDEX) {
|
|||||||
ctx.settings.send({
|
ctx.settings.send({
|
||||||
type: 'Set all settings',
|
type: 'Set all settings',
|
||||||
settings: routeData,
|
settings: routeData,
|
||||||
doNotPersist: true,
|
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
}
|
}
|
||||||
|
@ -434,9 +434,13 @@ export class KclManager {
|
|||||||
|
|
||||||
// Update the code state and the editor.
|
// Update the code state and the editor.
|
||||||
codeManager.updateCodeStateEditor(code)
|
codeManager.updateCodeStateEditor(code)
|
||||||
|
|
||||||
// Write back to the file system.
|
// Write back to the file system.
|
||||||
void codeManager.writeToFile().then(() => this.executeCode())
|
// 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()
|
||||||
}
|
}
|
||||||
// There's overlapping responsibility between updateAst and executeAst.
|
// 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.
|
// updateAst was added as it was used a lot before xState migration so makes the port easier.
|
||||||
|
@ -121,28 +121,20 @@ export default class CodeManager {
|
|||||||
// Only write our buffer contents to file once per second. Any faster
|
// Only write our buffer contents to file once per second. Any faster
|
||||||
// and file-system watchers which read, will receive empty data during
|
// and file-system watchers which read, will receive empty data during
|
||||||
// writes.
|
// writes.
|
||||||
|
|
||||||
clearTimeout(this.timeoutWriter)
|
clearTimeout(this.timeoutWriter)
|
||||||
this.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
|
this.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
|
||||||
|
this.timeoutWriter = setTimeout(() => {
|
||||||
return new Promise((resolve, reject) => {
|
// Wait one event loop to give a chance for params to be set
|
||||||
this.timeoutWriter = setTimeout(() => {
|
// Save the file to disk
|
||||||
if (!this._currentFilePath)
|
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
|
|
||||||
window.electron
|
window.electron
|
||||||
.writeFile(this._currentFilePath, this.code ?? '')
|
.writeFile(this._currentFilePath, this.code ?? '')
|
||||||
.then(resolve)
|
|
||||||
.catch((err: Error) => {
|
.catch((err: Error) => {
|
||||||
// TODO: add tracing per GH issue #254 (https://github.com/KittyCAD/modeling-app/issues/254)
|
// TODO: add tracing per GH issue #254 (https://github.com/KittyCAD/modeling-app/issues/254)
|
||||||
console.error('error saving file', err)
|
console.error('error saving file', err)
|
||||||
toast.error('Error saving file, please check file permissions')
|
toast.error('Error saving file, please check file permissions')
|
||||||
reject(err)
|
|
||||||
})
|
})
|
||||||
}, 1000)
|
}, 1000)
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
safeLSSetItem(PERSIST_CODE_KEY, this.code)
|
safeLSSetItem(PERSIST_CODE_KEY, this.code)
|
||||||
}
|
}
|
||||||
|
@ -633,7 +633,7 @@ export function expandSweep(
|
|||||||
if (err(path)) return path
|
if (err(path)) return path
|
||||||
return {
|
return {
|
||||||
type: 'sweep',
|
type: 'sweep',
|
||||||
subType: 'extrusion',
|
subType: sweep.subType,
|
||||||
surfaces: Array.from(surfs.values()),
|
surfaces: Array.from(surfs.values()),
|
||||||
edges: Array.from(edges.values()),
|
edges: Array.from(edges.values()),
|
||||||
path,
|
path,
|
||||||
|
@ -178,7 +178,6 @@ export async function loadAndValidateSettings(
|
|||||||
if (err(appSettingsPayload)) return Promise.reject(appSettingsPayload)
|
if (err(appSettingsPayload)) return Promise.reject(appSettingsPayload)
|
||||||
|
|
||||||
let settingsNext = createSettings()
|
let settingsNext = createSettings()
|
||||||
|
|
||||||
// Because getting the default directory is async, we need to set it after
|
// Because getting the default directory is async, we need to set it after
|
||||||
if (onDesktop) {
|
if (onDesktop) {
|
||||||
settings.app.projectDirectory.default = await getInitialDefaultDir()
|
settings.app.projectDirectory.default = await getInitialDefaultDir()
|
||||||
|
2
src/wasm-lib/Cargo.lock
generated
2
src/wasm-lib/Cargo.lock
generated
@ -737,7 +737,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive-docs"
|
name = "derive-docs"
|
||||||
version = "0.1.29"
|
version = "0.1.30"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "derive-docs"
|
name = "derive-docs"
|
||||||
description = "A tool for generating documentation from Rust derive macros"
|
description = "A tool for generating documentation from Rust derive macros"
|
||||||
version = "0.1.29"
|
version = "0.1.30"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/KittyCAD/modeling-app"
|
repository = "https://github.com/KittyCAD/modeling-app"
|
||||||
|
Reference in New Issue
Block a user