Compare commits

..

1 Commits

Author SHA1 Message Date
aa19bcbc09 tmp media stream fix 2024-07-12 08:39:49 +10:00
361 changed files with 2514 additions and 164730 deletions

View File

@ -1,37 +0,0 @@
name: Cryptic KCL Error
description: File a bug report for source code that produces a confusing error
title: "[CRYPTIC]: "
labels: ["cryptic-error"]
assignees: []
body:
- type: markdown
attributes:
value: "Thank you for taking the time to report a confusing error. Please provide as much information as possible to help us resolve it."
- type: textarea
id: kcl
attributes:
label: Paste minimal KCL source that produces a cryptic error
description: Minimal KCL reproducer that produces a cryptic error
placeholder: "const ..."
render: javascript
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: Description of what you expected to happen (if you know).
placeholder: "I expected that..."
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context about the problem here.
placeholder: "Anything else you want to add..."
validations:
required: false

View File

@ -124,40 +124,20 @@ Before you submit a contribution PR to this repo, please ensure that:
## Release a new version ## Release a new version
#### 1. Bump the versions by running `./make-release.sh` and create a Cut Release PR 1. Bump the versions by running `./make-realease.sh` while on a fresh pull of main
That will create the branch with the updated json files for you: That will create the branch with the updated json files for you.
- run `./make-release.sh` or `./make-release.sh patch` for a patch update; run `./make-release.sh` for a patch update
- run `./make-release.sh minor` for minor; or run `./make-release.sh "minor"` for minor
- run `./make-release.sh major` for major. run `./make-release.sh "major"` for major
After it runs you should just need the push the branch and open a PR. After it runs you should just need to push the push the branch and open a PR (it will suggest a changelog for you too, delete any that are not user facing)
**Important:** It needs to be prefixed with `Cut release v` to build in release mode and a few other things to test in the best context possible, the intent would be for instance to have `Cut release v1.2.3` for the `v1.2.3` release candidate. The PR may serve as a place to discuss the human-readable changelog and extra QA.
The PR may then serve as a place to discuss the human-readable changelog and extra QA. The `make-release.sh` tool suggests a changelog for you too to be used as PR description, just make sure to delete lines that are not user facing. 2. Merge the PR
#### 2. Smoke test artifacts from the Cut Release PR
The release builds can be find under the `artifact` zip, at the very bottom of the `ci` action page for each commit on this branch.
We don't have a strict process, but click around and check for anything obvious, posting results as comments in the Cut Release PR.
The other `ci` output in Cut Release PRs is `updater-test`, because we don't have a way to test this fully automated, we have a semi-automated process. Download updater-test zip file, install the app, run it, expect an updater prompt to a dummy v0.99.99, install it and check that the app comes back at that version (on both macOS and Windows).
#### 3. Merge the Cut Release PR
This will kick the `create-release` action, that creates a _Draft_ release out of this Cut Release PR merge after less than a minute, with the new version as title and Cut Release PR as description.
#### 4. Publish the release
Head over to https://github.com/KittyCAD/modeling-app/releases, the draft release corresponding to the merged Cut Release PR should show up at the top as _Draft_. Click on it, verify the content, and hit _Publish_.
#### 5. Profit
A new Action kicks in at https://github.com/KittyCAD/modeling-app/actions, which can be found under `release` event filter.
3. Profit (A new Action kicks in at https://github.com/KittyCAD/modeling-app/actions if the PR was correctly named)
## Fuzzing the parser ## Fuzzing the parser

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

View File

@ -3099,49 +3099,6 @@ const sketch002 = startSketchOn(extrude001, $seg01)
).not.toBeDisabled() ).not.toBeDisabled()
}) })
test('Fillet button states test', async ({ page }) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> startProfileAt([-5, -5], %)
|> line([0, 10], %)
|> line([10, 0], %)
|> line([0, -10], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)`
)
})
await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
const selectSegment = () => page.getByText(`line([10, 0], %)`).click()
const selectClose = () => page.getByText(`close(%)`).click()
const clickEmpty = () => page.mouse.click(950, 100)
// expect fillet button without any bodies in the scene
await selectSegment()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
await clickEmpty()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
// test fillet button with the body in the scene
const codeToAdd = `${await u.codeLocator.allInnerTexts()}
const extrude001 = extrude(10, sketch001)`
await u.codeLocator.fill(codeToAdd)
await selectSegment()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
await selectClose()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
await clickEmpty()
await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
})
const removeAfterFirstParenthesis = (inputString: string) => { const removeAfterFirstParenthesis = (inputString: string) => {
const index = inputString.indexOf('(') const index = inputString.indexOf('(')
if (index !== -1) { if (index !== -1) {
@ -3543,62 +3500,11 @@ test.describe('Command bar tests', () => {
`const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)` `const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
) )
}) })
test('Command bar works and can change a setting', async ({ page }) => {
test('Fillet from command bar', async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XY')
|> startProfileAt([-5, -5], %)
|> line([0, 10], %)
|> line([10, 0], %)
|> line([0, -10], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
const extrude001 = extrude(-10, sketch001)`
)
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
const selectSegment = () => page.getByText(`line([0, -10], %)`).click()
await selectSegment()
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'Fillet' }).click()
await page.waitForTimeout(100)
await page.keyboard.press('Enter')
await page.waitForTimeout(100)
await page.keyboard.press('Enter')
await page.waitForTimeout(100)
await expect(page.locator('.cm-activeLine')).toContainText(
`fillet({ radius: ${KCL_DEFAULT_LENGTH}, tags: [seg01] }, %)`
)
})
test('Command bar can change a setting, and switch back and forth between arguments', async ({
page,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await u.waitForAuthSkipAppStart()
const commandBarButton = page.getByRole('button', { name: 'Commands' })
const cmdSearchBar = page.getByPlaceholder('Search commands')
const themeOption = page.getByRole('option', {
name: 'theme',
exact: false,
})
const commandLevelArgButton = page.getByRole('button', { name: 'level' })
const commandThemeArgButton = page.getByRole('button', { name: 'value' })
// This selector changes after we set the setting
let commandOptionInput = page.getByPlaceholder('Select an option')
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled() ).not.toBeDisabled()
@ -3609,17 +3515,23 @@ const extrude001 = extrude(-10, sketch001)`
.or(page.getByRole('button', { name: '⌘K' })) .or(page.getByRole('button', { name: '⌘K' }))
.click() .click()
let cmdSearchBar = page.getByPlaceholder('Search commands')
await expect(cmdSearchBar).toBeVisible() await expect(cmdSearchBar).toBeVisible()
await page.keyboard.press('Escape') await page.keyboard.press('Escape')
cmdSearchBar = page.getByPlaceholder('Search commands')
await expect(cmdSearchBar).not.toBeVisible() await expect(cmdSearchBar).not.toBeVisible()
// Now try the same, but with the keyboard shortcut, check focus // Now try the same, but with the keyboard shortcut, check focus
await page.keyboard.press('Meta+K') await page.keyboard.press('Meta+K')
cmdSearchBar = page.getByPlaceholder('Search commands')
await expect(cmdSearchBar).toBeVisible() await expect(cmdSearchBar).toBeVisible()
await expect(cmdSearchBar).toBeFocused() await expect(cmdSearchBar).toBeFocused()
// Try typing in the command bar // Try typing in the command bar
await cmdSearchBar.fill('theme') await page.keyboard.type('theme')
const themeOption = page.getByRole('option', {
name: 'Settings · app · theme',
})
await expect(themeOption).toBeVisible() await expect(themeOption).toBeVisible()
await themeOption.click() await themeOption.click()
const themeInput = page.getByPlaceholder('Select an option') const themeInput = page.getByPlaceholder('Select an option')
@ -3641,24 +3553,6 @@ const extrude001 = extrude(-10, sketch001)`
).toBeVisible() ).toBeVisible()
// Check that the theme changed // Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`) await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
commandOptionInput = page.getByPlaceholder('system')
// Test case for https://github.com/KittyCAD/modeling-app/issues/2882
await commandBarButton.click()
await cmdSearchBar.focus()
await cmdSearchBar.fill('theme')
await themeOption.click()
await expect(commandThemeArgButton).toBeDisabled()
await commandOptionInput.focus()
await commandOptionInput.fill('lig')
await commandLevelArgButton.click()
await expect(commandLevelArgButton).toBeDisabled()
// Test case for https://github.com/KittyCAD/modeling-app/issues/2881
await commandThemeArgButton.click()
await expect(commandThemeArgButton).toBeDisabled()
await expect(commandLevelArgButton).toHaveText('level: project')
}) })
test('Command bar keybinding works from code editor and can change a setting', async ({ test('Command bar keybinding works from code editor and can change a setting', async ({
@ -3683,7 +3577,7 @@ const extrude001 = extrude(-10, sketch001)`
await expect(cmdSearchBar).toBeFocused() await expect(cmdSearchBar).toBeFocused()
// Try typing in the command bar // Try typing in the command bar
await cmdSearchBar.fill('theme') await page.keyboard.type('theme')
const themeOption = page.getByRole('option', { const themeOption = page.getByRole('option', {
name: 'Settings · app · theme', name: 'Settings · app · theme',
}) })
@ -3754,9 +3648,7 @@ const extrude001 = extrude(-10, sketch001)`
await page.mouse.click(700, 200) await page.mouse.click(700, 200)
// Assert that we're on the distance step // Assert that we're on the distance step
await expect( await expect(page.getByRole('button', { name: 'distance' })).toBeDisabled()
page.getByRole('button', { name: 'distance', exact: false })
).toBeDisabled()
// Assert that the an alternative variable name is chosen, // Assert that the an alternative variable name is chosen,
// since the default variable name is already in use (distance) // since the default variable name is already in use (distance)
@ -3771,12 +3663,11 @@ const extrude001 = extrude(-10, sketch001)`
// Review step and argument hotkeys // Review step and argument hotkeys
await expect(submitButton).toBeEnabled() await expect(submitButton).toBeEnabled()
await expect(submitButton).toBeFocused() await page.keyboard.press('Backspace')
await submitButton.press('Backspace')
// Assert we're back on the distance step // Assert we're back on the distance step
await expect( await expect(
page.getByRole('button', { name: 'distance', exact: false }) page.getByRole('button', { name: 'Distance 5', exact: false })
).toBeDisabled() ).toBeDisabled()
await continueButton.click() await continueButton.click()
@ -3800,47 +3691,6 @@ const extrude001 = extrude(distance001, sketch001)`.replace(
) // remove newlines ) // remove newlines
) )
}) })
test('Can switch between sketch tools via command bar', async ({ page }) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
const sketchButton = page.getByRole('button', { name: 'Start Sketch' })
const cmdBarButton = page.getByRole('button', { name: 'Commands' })
const rectangleToolCommand = page.getByRole('option', {
name: 'Rectangle',
})
const rectangleToolButton = page.getByRole('button', { name: 'Rectangle' })
const lineToolCommand = page.getByRole('option', { name: 'Line' })
const lineToolButton = page.getByRole('button', { name: 'Line' })
const arcToolCommand = page.getByRole('option', { name: 'Tangential Arc' })
const arcToolButton = page.getByRole('button', { name: 'Tangential Arc' })
// Start a sketch
await sketchButton.click()
await page.mouse.click(700, 200)
// Switch between sketch tools via the command bar
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
await cmdBarButton.click()
await rectangleToolCommand.click()
await expect(rectangleToolButton).toHaveAttribute('aria-pressed', 'true')
await cmdBarButton.click()
await lineToolCommand.click()
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
// Click in the scene a couple times to draw a line
// so tangential arc is valid
await page.mouse.click(700, 200)
await page.mouse.move(700, 300, { steps: 5 })
await page.mouse.click(700, 300)
// switch to tangential arc via command bar
await cmdBarButton.click()
await arcToolCommand.click()
await expect(arcToolButton).toHaveAttribute('aria-pressed', 'true')
})
}) })
test.describe('Regression tests', () => { test.describe('Regression tests', () => {
@ -4792,10 +4642,10 @@ test.describe('Sketch tests', () => {
// click extrude // click extrude
await page.getByRole('button', { name: 'Extrude' }).click() await page.getByRole('button', { name: 'Extrude' }).click()
// sketch selection should already have been made. "Selection: 1 face" only show up when the selection has been made already // sketch selection should already have been made. "Selection 1 face" only show up when the selection has been made already
// otherwise the cmdbar would be waiting for a selection. // otherwise the cmdbar would be waiting for a selection.
await expect( await expect(
page.getByRole('button', { name: 'selection : 1 face', exact: false }) page.getByRole('button', { name: 'Selection 1 face' })
).toBeVisible() ).toBeVisible()
}) })
test("Existing sketch with bad code delete user's code", async ({ page }) => { test("Existing sketch with bad code delete user's code", async ({ page }) => {
@ -7221,7 +7071,6 @@ test.describe('Test network and connection issues', () => {
// Expect the network to be up // Expect the network to be up
await expect(page.getByText('Network Health (Connected)')).toBeVisible() await expect(page.getByText('Network Health (Connected)')).toBeVisible()
await expect(page.getByTestId('loading-stream')).not.toBeAttached()
// Click off the code pane. // Click off the code pane.
await page.mouse.click(100, 100) await page.mouse.click(100, 100)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -16,14 +16,14 @@ export const TEST_COLORS = {
} as const } as const
async function waitForPageLoad(page: Page) { async function waitForPageLoad(page: Page) {
// wait for 'Loading stream...' spinner
await page.getByTestId('loading-stream').waitFor()
// wait for all spinners to be gone // wait for all spinners to be gone
await expect(page.getByTestId('loading')).not.toBeAttached({ await page
timeout: 20_000, .getByTestId('loading')
}) .waitFor({ state: 'detached', timeout: 20_000 })
await expect(page.getByTestId('start-sketch')).toBeEnabled({ await page.getByTestId('start-sketch').waitFor()
timeout: 20_000,
})
} }
async function removeCurrentCode(page: Page) { async function removeCurrentCode(page: Page) {
@ -471,10 +471,8 @@ export const doExport = async (
page: Page page: Page
): Promise<Paths> => { ): Promise<Paths> => {
await page.getByRole('button', { name: APP_NAME }).click() await page.getByRole('button', { name: APP_NAME }).click()
await expect( await expect(page.getByRole('button', { name: 'Export Part' })).toBeVisible()
page.getByRole('button', { name: 'Export', exact: false }) await page.getByRole('button', { name: 'Export Part' }).click()
).toBeVisible()
await page.getByRole('button', { name: 'Export', exact: false }).click()
await expect(page.getByTestId('command-bar')).toBeVisible() await expect(page.getByTestId('command-bar')).toBeVisible()
// Go through export via command bar // Go through export via command bar

View File

@ -77,7 +77,7 @@ describe('ZMA authorized user flows', () => {
const menuButton = await $('[data-testid="user-sidebar-toggle"]') const menuButton = await $('[data-testid="user-sidebar-toggle"]')
await click(menuButton) await click(menuButton)
const settingsButton = await $('[data-testid="user-settings"]') const settingsButton = await $('[data-testid="settings-button"]')
await click(settingsButton) await click(settingsButton)
const projectDirInput = await $('[data-testid="project-directory-input"]') const projectDirInput = await $('[data-testid="project-directory-input"]')

View File

@ -1,6 +1,6 @@
{ {
"name": "untitled-app", "name": "untitled-app",
"version": "0.24.3", "version": "0.24.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.17.0", "@codemirror/autocomplete": "^6.17.0",

View File

@ -30,7 +30,7 @@ import { URI } from 'vscode-uri'
import { LanguageServerClient } from '../client' import { LanguageServerClient } from '../client'
import { CompletionItemKindMap } from './autocomplete' import { CompletionItemKindMap } from './autocomplete'
import { addToken, SemanticToken } from './semantic-tokens' import { addToken, SemanticToken } from './semantic-tokens'
import { posToOffset, formatMarkdownContents } from './util' import { deferExecution, posToOffset, formatMarkdownContents } from './util'
import lspAutocompleteExt from './autocomplete' import lspAutocompleteExt from './autocomplete'
import lspHoverExt from './hover' import lspHoverExt from './hover'
import lspFormatExt from './format' import lspFormatExt from './format'
@ -93,10 +93,23 @@ export class LanguageServerPlugin implements PluginValue {
private doSemanticTokens: boolean = false private doSemanticTokens: boolean = false
private doFoldingRanges: boolean = false private doFoldingRanges: boolean = false
// When a doc update needs to be sent to the server, this holds the private _defferer = deferExecution((code: string) => {
// timeout handle for it. When null, the server has the up-to-date try {
// document. // Update the state (not the editor) with the new code.
private sendScheduled: number | null = null this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: code }],
})
this.requestSemanticTokens()
this.updateFoldingRanges()
} catch (e) {
console.error(e)
}
}, this.changesDelay)
constructor(options: LanguageServerOptions, private view: EditorView) { constructor(options: LanguageServerOptions, private view: EditorView) {
this.client = options.client this.client = options.client
@ -139,9 +152,14 @@ export class LanguageServerPlugin implements PluginValue {
} }
update(viewUpdate: ViewUpdate) { update(viewUpdate: ViewUpdate) {
if (viewUpdate.docChanged) { // If the doc didn't change we can return early.
this.scheduleSendDoc() if (!viewUpdate.docChanged) {
return
} }
this.sendChange({
documentText: viewUpdate.state.doc.toString(),
})
} }
destroy() { destroy() {
@ -166,6 +184,16 @@ export class LanguageServerPlugin implements PluginValue {
this.updateFoldingRanges() this.updateFoldingRanges()
} }
async sendChange({ documentText }: { documentText: string }) {
if (!this.client.ready) return
this._defferer(documentText)
}
requestDiagnostics() {
this.sendChange({ documentText: this.getDocText() })
}
async requestHoverTooltip( async requestHoverTooltip(
view: EditorView, view: EditorView,
{ line, character }: { line: number; character: number } { line, character }: { line: number; character: number }
@ -176,7 +204,7 @@ export class LanguageServerPlugin implements PluginValue {
) )
return null return null
this.ensureDocSent() this.sendChange({ documentText: this.getDocText() })
const result = await this.client.textDocumentHover({ const result = await this.client.textDocumentHover({
textDocument: { uri: this.getDocUri() }, textDocument: { uri: this.getDocUri() },
position: { line, character }, position: { line, character },
@ -199,42 +227,6 @@ export class LanguageServerPlugin implements PluginValue {
return { pos, end, create: (view) => ({ dom }), above: true } return { pos, end, create: (view) => ({ dom }), above: true }
} }
scheduleSendDoc() {
if (this.sendScheduled != null) window.clearTimeout(this.sendScheduled)
this.sendScheduled = window.setTimeout(
() => this.sendDoc(),
this.changesDelay
)
}
sendDoc() {
if (this.sendScheduled != null) {
window.clearTimeout(this.sendScheduled)
this.sendScheduled = null
}
if (!this.client.ready) return
try {
// Update the state (not the editor) with the new code.
this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: this.view.state.doc.toString() }],
})
this.requestSemanticTokens()
this.updateFoldingRanges()
} catch (e) {
console.error(e)
}
}
ensureDocSent() {
if (this.sendScheduled != null) this.sendDoc()
}
async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> { async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> {
if ( if (
!this.doFoldingRanges || !this.doFoldingRanges ||
@ -292,7 +284,13 @@ export class LanguageServerPlugin implements PluginValue {
) )
return null return null
this.ensureDocSent() this.client.textDocumentDidChange({
textDocument: {
uri: this.getDocUri(),
version: this.documentVersion++,
},
contentChanges: [{ text: this.getDocText() }],
})
const result = await this.client.textDocumentFormatting({ const result = await this.client.textDocumentFormatting({
textDocument: { uri: this.getDocUri() }, textDocument: { uri: this.getDocUri() },
@ -332,7 +330,9 @@ export class LanguageServerPlugin implements PluginValue {
) )
return null return null
this.ensureDocSent() this.sendChange({
documentText: context.state.doc.toString(),
})
const result = await this.client.textDocumentCompletion({ const result = await this.client.textDocumentCompletion({
textDocument: { uri: this.getDocUri() }, textDocument: { uri: this.getDocUri() },

108
src-tauri/Cargo.lock generated
View File

@ -332,7 +332,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -367,7 +367,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -407,7 +407,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -550,7 +550,7 @@ dependencies = [
"proc-macro-crate 3.1.0", "proc-macro-crate 3.1.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
"syn_derive", "syn_derive",
] ]
@ -823,7 +823,7 @@ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1073,7 +1073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1083,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1107,7 +1107,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim 0.10.0", "strsim 0.10.0",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1118,7 +1118,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1179,7 +1179,7 @@ checksum = "4078275de501a61ceb9e759d37bdd3d7210e654dbc167ac1a3678ef4435ed57b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
"synstructure", "synstructure",
] ]
@ -1216,7 +1216,7 @@ dependencies = [
"regex", "regex",
"serde", "serde",
"serde_tokenstream", "serde_tokenstream",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1227,7 +1227,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1288,7 +1288,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1320,7 +1320,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1427,7 +1427,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1588,7 +1588,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1704,7 +1704,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -1980,7 +1980,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -2008,7 +2008,7 @@ dependencies = [
"inflections", "inflections",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -2083,7 +2083,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -3377,7 +3377,7 @@ dependencies = [
"regex", "regex",
"regex-syntax 0.8.3", "regex-syntax 0.8.3",
"structmeta", "structmeta",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -3496,7 +3496,7 @@ dependencies = [
"phf_shared 0.11.2", "phf_shared 0.11.2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -3564,7 +3564,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4438,7 +4438,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde_derive_internals", "serde_derive_internals",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4558,7 +4558,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4569,7 +4569,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4602,7 +4602,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4623,7 +4623,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde", "serde",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4665,7 +4665,7 @@ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4933,7 +4933,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"structmeta-derive", "structmeta-derive",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4944,7 +4944,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4966,7 +4966,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -4999,9 +4999,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.71" version = "2.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -5017,7 +5017,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -5034,7 +5034,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -5251,7 +5251,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"syn 2.0.71", "syn 2.0.70",
"tauri-utils", "tauri-utils",
"thiserror", "thiserror",
"time", "time",
@ -5269,7 +5269,7 @@ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
"tauri-codegen", "tauri-codegen",
"tauri-utils", "tauri-utils",
] ]
@ -5627,22 +5627,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.62" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.62" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -5740,7 +5740,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -5940,7 +5940,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -5969,7 +5969,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -6099,7 +6099,7 @@ checksum = "c88cc88fd23b5a04528f3a8436024f20010a16ec18eb23c164b1242f65860130"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
"termcolor", "termcolor",
] ]
@ -6316,7 +6316,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -6415,7 +6415,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6449,7 +6449,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6590,7 +6590,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -6696,7 +6696,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -6707,7 +6707,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]
@ -7159,7 +7159,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.71", "syn 2.0.70",
] ]
[[package]] [[package]]

View File

@ -80,5 +80,5 @@
} }
}, },
"productName": "Zoo Modeling App", "productName": "Zoo Modeling App",
"version": "0.24.3" "version": "0.24.0"
} }

View File

@ -26,6 +26,7 @@ import useHotkeyWrapper from 'lib/hotkeyWrapper'
import Gizmo from 'components/Gizmo' import Gizmo from 'components/Gizmo'
import { CoreDumpManager } from 'lib/coredump' import { CoreDumpManager } from 'lib/coredump'
import { UnitsMenu } from 'components/UnitsMenu' import { UnitsMenu } from 'components/UnitsMenu'
import { useAppState } from 'AppState'
export function App() { export function App() {
useRefreshSettings(paths.FILE + 'SETTINGS') useRefreshSettings(paths.FILE + 'SETTINGS')
@ -44,7 +45,9 @@ export function App() {
}, [projectName, projectPath]) }, [projectName, projectPath])
useHotKeyListener() useHotKeyListener()
const { context, state } = useModelingContext() const { context } = useModelingContext()
const { streamDimensions, didDragInStream, buttonDownInStream } =
useAppState()
const { auth, settings } = useSettingsAuthContext() const { auth, settings } = useSettingsAuthContext()
const token = auth?.context?.token const token = auth?.context?.token
@ -57,6 +60,7 @@ export function App() {
const { const {
app: { onboardingStatus }, app: { onboardingStatus },
} = settings.context } = settings.context
const { state } = useModelingContext()
useHotkeys('backspace', (e) => { useHotkeys('backspace', (e) => {
e.preventDefault() e.preventDefault()
@ -73,7 +77,7 @@ export function App() {
(p) => p === onboardingStatus.current (p) => p === onboardingStatus.current
) )
? 'opacity-20' ? 'opacity-20'
: context.store?.didDragInStream : didDragInStream
? 'opacity-40' ? 'opacity-40'
: '' : ''
@ -91,11 +95,11 @@ export function App() {
clientX: e.clientX, clientX: e.clientX,
clientY: e.clientY, clientY: e.clientY,
el: e.currentTarget, el: e.currentTarget,
...context.store?.streamDimensions, ...streamDimensions,
}) })
const newCmdId = uuidv4() const newCmdId = uuidv4()
if (context.store?.buttonDownInStream === undefined) { if (buttonDownInStream === undefined) {
debounceSocketSend({ debounceSocketSend({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
@ -117,7 +121,7 @@ export function App() {
className={ className={
'transition-opacity transition-duration-75 ' + 'transition-opacity transition-duration-75 ' +
paneOpacity + paneOpacity +
(context.store?.buttonDownInStream ? ' pointer-events-none' : '') (buttonDownInStream ? ' pointer-events-none' : '')
} }
project={{ project, file }} project={{ project, file }}
enableMenu={true} enableMenu={true}

View File

@ -1,4 +1,10 @@
import { createContext, useContext, useState, ReactNode } from 'react' import {
createContext,
useContext,
useState,
ReactNode,
useEffect,
} from 'react'
/* /*
@ -11,11 +17,23 @@ Please do not fill this up with junk.
interface AppState { interface AppState {
isStreamReady: boolean isStreamReady: boolean
setAppState: (newAppState: Partial<AppState>) => void setAppState: (newAppState: Partial<AppState>) => void
mediaStream?: MediaStream
buttonDownInStream: number | undefined
didDragInStream: boolean
streamDimensions: { streamWidth: number; streamHeight: number }
// openPanes: SidebarType[]
} }
const AppStateContext = createContext<AppState>({ const AppStateContext = createContext<AppState>({
isStreamReady: false, isStreamReady: false,
setAppState: () => {}, setAppState: () => {},
buttonDownInStream: undefined,
didDragInStream: false,
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
mediaStream: undefined,
// openPanes: persistedContext.openPanes || ['code'],
}) })
export const useAppState = () => useContext(AppStateContext) export const useAppState = () => useContext(AppStateContext)
@ -24,47 +42,38 @@ export const AppStateProvider = ({ children }: { children: ReactNode }) => {
const [appState, _setAppState] = useState<AppState>({ const [appState, _setAppState] = useState<AppState>({
isStreamReady: false, isStreamReady: false,
setAppState: () => {}, setAppState: () => {},
buttonDownInStream: undefined,
didDragInStream: false,
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
mediaStream: undefined,
// openPanes: persistedContext.openPanes || ['code'],
}) })
const setAppState = (newAppState: Partial<AppState>) => useEffect(() => {
_setAppState({ ...appState, ...newAppState }) // console.log('appState change', appState)
}, [appState])
const setAppState = (newAppState: Partial<AppState>) => {
// console.log('appstate', newAppState)
_setAppState({
...appState,
...newAppState,
mediaStream: newAppState.mediaStream || appState.mediaStream,
})
}
return ( return (
<AppStateContext.Provider <AppStateContext.Provider
value={{ value={{
isStreamReady: appState.isStreamReady, isStreamReady: appState.isStreamReady,
setAppState, setAppState,
mediaStream: appState.mediaStream,
buttonDownInStream: appState.buttonDownInStream,
didDragInStream: appState.didDragInStream,
streamDimensions: appState.streamDimensions,
}} }}
> >
{children} {children}
</AppStateContext.Provider> </AppStateContext.Provider>
) )
} }
interface AppStream {
mediaStream: MediaStream
setMediaStream: (mediaStream: MediaStream) => void
}
const AppStreamContext = createContext<AppStream>({
mediaStream: undefined as unknown as MediaStream,
setMediaStream: () => {},
})
export const useAppStream = () => useContext(AppStreamContext)
export const AppStreamProvider = ({ children }: { children: ReactNode }) => {
const [mediaStream, setMediaStream] = useState<MediaStream>(
undefined as unknown as MediaStream
)
return (
<AppStreamContext.Provider
value={{
mediaStream,
setMediaStream,
}}
>
{children}
</AppStreamContext.Provider>
)
}

View File

@ -49,17 +49,17 @@ const router = createBrowserRouter([
/* Make sure auth is the outermost provider or else we will have /* Make sure auth is the outermost provider or else we will have
* inefficient re-renders, use the react profiler to see. */ * inefficient re-renders, use the react profiler to see. */
element: ( element: (
<AppStateProvider>
<CommandBarProvider> <CommandBarProvider>
<SettingsAuthProvider> <SettingsAuthProvider>
<LspProvider> <LspProvider>
<KclContextProvider> <KclContextProvider>
<AppStateProvider>
<Outlet /> <Outlet />
</AppStateProvider>
</KclContextProvider> </KclContextProvider>
</LspProvider> </LspProvider>
</SettingsAuthProvider> </SettingsAuthProvider>
</CommandBarProvider> </CommandBarProvider>
</AppStateProvider>
), ),
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
children: [ children: [

View File

@ -16,7 +16,6 @@ import {
canRectangleTool, canRectangleTool,
isEditingExistingSketch, isEditingExistingSketch,
} from 'machines/modelingMachine' } from 'machines/modelingMachine'
import { DEV } from 'env'
export function Toolbar({ export function Toolbar({
className = '', className = '',
@ -61,7 +60,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: { tool: 'line' }, data: 'line',
}), }),
{ enabled: !disableLineButton, scopes: ['sketch'] } { enabled: !disableLineButton, scopes: ['sketch'] }
) )
@ -76,7 +75,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: { tool: 'tangentialArc' }, data: 'tangentialArc',
}), }),
{ enabled: !disableTangentialArc, scopes: ['sketch'] } { enabled: !disableTangentialArc, scopes: ['sketch'] }
) )
@ -90,7 +89,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: { tool: 'rectangle' }, data: 'rectangle',
}), }),
{ enabled: !disableRectangle, scopes: ['sketch'] } { enabled: !disableRectangle, scopes: ['sketch'] }
) )
@ -119,16 +118,6 @@ export function Toolbar({
}), }),
{ enabled: !disableAllButtons, scopes: ['modeling'] } { enabled: !disableAllButtons, scopes: ['modeling'] }
) )
const disableFillet = !state.can('Fillet') || disableAllButtons
useHotkeys(
'f',
() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Fillet', groupId: 'modeling' },
}),
{ enabled: !disableFillet, scopes: ['modeling'] }
)
function handleToolbarButtonsWheelEvent(ev: WheelEvent<HTMLSpanElement>) { function handleToolbarButtonsWheelEvent(ev: WheelEvent<HTMLSpanElement>) {
const span = toolbarButtonsRef.current const span = toolbarButtonsRef.current
@ -274,7 +263,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: { tool: 'line' }, data: 'line',
}) })
} }
aria-pressed={state?.matches('Sketch.Line tool')} aria-pressed={state?.matches('Sketch.Line tool')}
@ -304,7 +293,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: { tool: 'tangentialArc' }, data: 'tangentialArc',
}) })
} }
aria-pressed={state.matches('Sketch.Tangential arc to')} aria-pressed={state.matches('Sketch.Tangential arc to')}
@ -334,7 +323,7 @@ export function Toolbar({
? send('CancelSketch') ? send('CancelSketch')
: send({ : send({
type: 'change tool', type: 'change tool',
data: { tool: 'rectangle' }, data: 'rectangle',
}) })
} }
aria-pressed={state.matches('Sketch.Rectangle tool')} aria-pressed={state.matches('Sketch.Rectangle tool')}
@ -415,36 +404,6 @@ export function Toolbar({
</ActionButton> </ActionButton>
</li> </li>
)} )}
{state.matches('idle') && (DEV || (window as any)._enableFillet) && (
<li className="contents">
<ActionButton
className={buttonClassName}
Element="button"
onClick={() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Fillet', groupId: 'modeling' },
})
}
disabled={disableFillet}
title={disableFillet ? 'fillet' : "edge can't be filleted"}
iconStart={{
icon: 'fillet', // todo: add fillet icon
iconClassName,
bgClassName,
}}
>
Fillet
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: F
</Tooltip>
</ActionButton>
</li>
)}
</ul> </ul>
</menu> </menu>
) )

View File

@ -47,6 +47,7 @@ import {
PipeExpression, PipeExpression,
Program, Program,
ProgramMemory, ProgramMemory,
programMemoryInit,
recast, recast,
SketchGroup, SketchGroup,
ExtrudeGroup, ExtrudeGroup,
@ -129,7 +130,7 @@ export const HIDE_HOVER_SEGMENT_LENGTH = 60 // in pixels
export class SceneEntities { export class SceneEntities {
engineCommandManager: EngineCommandManager engineCommandManager: EngineCommandManager
scene: Scene scene: Scene
sceneProgramMemory: ProgramMemory = ProgramMemory.empty() sceneProgramMemory: ProgramMemory = { root: {}, return: null }
activeSegments: { [key: string]: Group } = {} activeSegments: { [key: string]: Group } = {}
intersectionPlane: Mesh | null = null intersectionPlane: Mesh | null = null
axisGroup: Group | null = null axisGroup: Group | null = null
@ -549,9 +550,9 @@ export class SceneEntities {
const variableDeclarationName = const variableDeclarationName =
_node1.node?.declarations?.[0]?.id?.name || '' _node1.node?.declarations?.[0]?.id?.name || ''
const sg = kclManager.programMemory.get( const sg = kclManager.programMemory.root[
variableDeclarationName variableDeclarationName
) as SketchGroup ] as SketchGroup
const lastSeg = sg.value.slice(-1)[0] || sg.start const lastSeg = sg.value.slice(-1)[0] || sg.start
const index = sg.value.length // because we've added a new segment that's not in the memory yet, no need for `-1` const index = sg.value.length // because we've added a new segment that's not in the memory yet, no need for `-1`
@ -767,9 +768,9 @@ export class SceneEntities {
programMemoryOverride, programMemoryOverride,
}) })
this.sceneProgramMemory = programMemory this.sceneProgramMemory = programMemory
const sketchGroup = programMemory.get( const sketchGroup = programMemory.root[
variableDeclarationName variableDeclarationName
) as SketchGroup ] as SketchGroup
const sgPaths = sketchGroup.value const sgPaths = sketchGroup.value
const orthoFactor = orthoScale(sceneInfra.camControls.camera) const orthoFactor = orthoScale(sceneInfra.camControls.camera)
@ -819,9 +820,9 @@ export class SceneEntities {
// Prepare to update the THREEjs scene // Prepare to update the THREEjs scene
this.sceneProgramMemory = programMemory this.sceneProgramMemory = programMemory
const sketchGroup = programMemory.get( const sketchGroup = programMemory.root[
variableDeclarationName variableDeclarationName
) as SketchGroup ] as SketchGroup
const sgPaths = sketchGroup.value const sgPaths = sketchGroup.value
const orthoFactor = orthoScale(sceneInfra.camControls.camera) const orthoFactor = orthoScale(sceneInfra.camControls.camera)
@ -1080,9 +1081,9 @@ export class SceneEntities {
}) })
this.sceneProgramMemory = programMemory this.sceneProgramMemory = programMemory
const maybeSketchGroup = programMemory.get(variableDeclarationName) const maybeSketchGroup = programMemory.root[variableDeclarationName]
let sketchGroup = undefined let sketchGroup = undefined
if (maybeSketchGroup?.type === 'SketchGroup') { if (maybeSketchGroup.type === 'SketchGroup') {
sketchGroup = maybeSketchGroup sketchGroup = maybeSketchGroup
} else if ((maybeSketchGroup as ExtrudeGroup).sketchGroup) { } else if ((maybeSketchGroup as ExtrudeGroup).sketchGroup) {
sketchGroup = (maybeSketchGroup as ExtrudeGroup).sketchGroup sketchGroup = (maybeSketchGroup as ExtrudeGroup).sketchGroup
@ -1772,7 +1773,7 @@ function prepareTruncatedMemoryAndAst(
if (err(_node)) return _node if (err(_node)) return _node
const variableDeclarationName = _node.node?.declarations?.[0]?.id?.name || '' const variableDeclarationName = _node.node?.declarations?.[0]?.id?.name || ''
const lastSeg = ( const lastSeg = (
programMemory.get(variableDeclarationName) as SketchGroup programMemory.root[variableDeclarationName] as SketchGroup
).value.slice(-1)[0] ).value.slice(-1)[0]
if (draftSegment) { if (draftSegment) {
// truncatedAst needs to setup with another segment at the end // truncatedAst needs to setup with another segment at the end
@ -1823,27 +1824,33 @@ function prepareTruncatedMemoryAndAst(
..._ast, ..._ast,
body: [JSON.parse(JSON.stringify(_ast.body[bodyIndex]))], body: [JSON.parse(JSON.stringify(_ast.body[bodyIndex]))],
} }
const programMemoryOverride = programMemoryInit()
if (err(programMemoryOverride)) return programMemoryOverride
// Grab all the TagDeclarators and TagIdentifiers from memory. // Grab all the TagDeclarators and TagIdentifiers from memory.
let start = _node.node.start let start = _node.node.start
const programMemoryOverride = programMemory.filterVariables(true, (value) => { for (const key in programMemory.root) {
const value = programMemory.root[key]
if (!('__meta' in value)) {
continue
}
if ( if (
!('__meta' in value) ||
value.__meta === undefined || value.__meta === undefined ||
value.__meta.length === 0 || value.__meta.length === 0 ||
value.__meta[0].sourceRange === undefined value.__meta[0].sourceRange === undefined
) { ) {
return false continue
} }
if (value.__meta[0].sourceRange[0] >= start) { if (value.__meta[0].sourceRange[0] >= start) {
// We only want things before our start point. // We only want things before our start point.
return false continue
} }
return value.type === 'TagIdentifier' if (value.type === 'TagIdentifier') {
}) programMemoryOverride.root[key] = JSON.parse(JSON.stringify(value))
if (err(programMemoryOverride)) return programMemoryOverride }
}
for (let i = 0; i < bodyIndex; i++) { for (let i = 0; i < bodyIndex; i++) {
const node = _ast.body[i] const node = _ast.body[i]
@ -1851,15 +1858,12 @@ function prepareTruncatedMemoryAndAst(
continue continue
} }
const name = node.declarations[0].id.name const name = node.declarations[0].id.name
const memoryItem = programMemory.get(name) // const memoryItem = kclManager.programMemory.root[name]
const memoryItem = programMemory.root[name]
if (!memoryItem) { if (!memoryItem) {
continue continue
} }
const error = programMemoryOverride.set( programMemoryOverride.root[name] = JSON.parse(JSON.stringify(memoryItem))
name,
JSON.parse(JSON.stringify(memoryItem))
)
if (err(error)) return error
} }
return { return {
truncatedAst, truncatedAst,
@ -1896,7 +1900,7 @@ export function sketchGroupFromPathToNode({
) )
if (err(_varDec)) return _varDec if (err(_varDec)) return _varDec
const varDec = _varDec.node const varDec = _varDec.node
const result = programMemory.get(varDec?.id?.name || '') const result = programMemory.root[varDec?.id?.name || '']
if (result?.type === 'ExtrudeGroup') { if (result?.type === 'ExtrudeGroup') {
return result.sketchGroup return result.sketchGroup
} }

Some files were not shown because too many files have changed in this diff Show More