Compare commits

...

22 Commits

Author SHA1 Message Date
c0f04d5f86 Cut release v0.23.0 (#2904) 2024-07-04 12:22:06 +10:00
3dbc701f26 remove bad scaling on delete (#2902)
remove weird scaling
2024-07-04 11:05:27 +10:00
16e7ae38e3 fix auto complete for circle (#2903)
crcle

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-03 18:05:24 -07:00
24c7260327 ctrl-c is copy, we should not bind to copy or paste or any common shit (#2895)
* ctrl-c is copy, we should not bind to copy or paste or any common shit

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-03 15:26:04 -07:00
72cfc4a471 fix version in vercel as main (#2899)
* fix version in vercel as nightly

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* its actually the main branch

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* format

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-03 15:24:17 -07:00
2d128ed32e Bump wasm-pack from 0.12.1 to 0.13.0 (#2887)
Bumps [wasm-pack](https://github.com/rustwasm/wasm-pack) from 0.12.1 to 0.13.0.
- [Release notes](https://github.com/rustwasm/wasm-pack/releases)
- [Changelog](https://github.com/rustwasm/wasm-pack/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-pack/compare/v0.12.1...v0.13.0)

---
updated-dependencies:
- dependency-name: wasm-pack
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 11:34:01 -07:00
cd6749ba02 Bump three from 0.164.1 to 0.166.1 (#2886)
Bumps [three](https://github.com/mrdoob/three.js) from 0.164.1 to 0.166.1.
- [Release notes](https://github.com/mrdoob/three.js/releases)
- [Commits](https://github.com/mrdoob/three.js/commits)

---
updated-dependencies:
- dependency-name: three
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 11:33:39 -07:00
7243405e1b Bump @playwright/test from 1.44.1 to 1.45.1 (#2885)
Bumps [@playwright/test](https://github.com/microsoft/playwright) from 1.44.1 to 1.45.1.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.44.1...v1.45.1)

---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 11:33:23 -07:00
c8da057ec2 Bump html2canvas-pro from 1.5.0 to 1.5.1 (#2888)
Bumps [html2canvas-pro](https://github.com/yorickshan/html2canvas-pro) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/yorickshan/html2canvas-pro/releases)
- [Changelog](https://github.com/yorickshan/html2canvas-pro/blob/main/CHANGELOG.md)
- [Commits](https://github.com/yorickshan/html2canvas-pro/compare/v1.5.0...v1.5.1)

---
updated-dependencies:
- dependency-name: html2canvas-pro
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 11:14:32 -07:00
220fe5b2b8 bad code on exit-sketch should no delete code (#2890)
* bad code on exitsketch should no delete code

* clean up
2024-07-03 22:03:04 +10:00
4e6429de49 add fixme to failing test (#2891) 2024-07-03 20:54:58 +10:00
5391a65b18 Grouping tests (#2884)
test grouping
2024-07-03 14:34:45 +10:00
592628917a test grouping (#2883) 2024-07-03 12:41:24 +10:00
4c6e8633f7 zustand part 3 (#2878)
* zustand part 3

* clean up

* yarn lock
2024-07-02 16:22:46 -07:00
c5150468a2 more keybindings w copilot tests (#2875)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-02 10:08:02 -07:00
39126dbff1 fix copilot regression (#2876)
* fix copilot regression

* fix zoom part of test

* fix enable copilot
2024-07-02 08:50:40 -07:00
f86a69f12a initial migration from zustand (#2852)
* inital migration with a couple lingering concerns

* move is stream ready back

* put htmlRef back in useStore

* final tidy of useStore

* test tweaks

* tweak more

* more test tweaks

* fmt

* test tweaks

* attempts at fixing 'Basic default modeling and sketch hotkeys work'

* more tries

* 😭

* try again

* fmt
2024-07-02 17:16:27 +10:00
de354ee5d3 zustand updated for the lsp provider (#2874)
updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-01 21:43:15 -07:00
dfef7338ee disable copilot in sketch mode (#2865)
* disable copilot in sketch mode

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-01 21:05:31 -07:00
ee08948f54 add playwright tests for undo from click and point operations (#2866)
* add playwright tests for undo from click and point operations

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* more determinitic

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-01 20:55:28 -07:00
832f6b65e2 Bump serde_json from 1.0.119 to 1.0.120 in /src/wasm-lib (#2872)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.119 to 1.0.120.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.119...v1.0.120)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 20:34:46 -07:00
68efd77c5d fixes perms for releases (#2864)
* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add to specific job

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-07-01 15:58:08 -07:00
62 changed files with 3522 additions and 2911 deletions

View File

@ -377,6 +377,8 @@ jobs:
TS_NODE_COMPILER_OPTIONS: '{"module": "commonjs"}'
publish-apps-release:
permissions:
contents: write
runs-on: ubuntu-latest
if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }}
needs: [check-format, check-types, check-typos, build-test-web, prepare-json-files, build-test-apps]

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "untitled-app",
"version": "0.22.7",
"version": "0.23.0",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.16.3",
@ -35,7 +35,7 @@
"codemirror": "^6.0.1",
"decamelize": "^6.0.0",
"fuse.js": "^7.0.0",
"html2canvas-pro": "^1.5.0",
"html2canvas-pro": "^1.5.1",
"json-rpc-2.0": "^1.6.0",
"jszip": "^3.10.1",
"re-resizable": "^6.9.11",
@ -48,7 +48,7 @@
"react-modal-promise": "^1.0.2",
"react-router-dom": "^6.23.1",
"sketch-helpers": "^0.0.4",
"three": "^0.164.1",
"three": "^0.166.1",
"typescript": "^5.4.5",
"ua-parser-js": "^1.0.37",
"uuid": "^9.0.1",
@ -56,8 +56,7 @@
"vscode-languageserver-protocol": "^3.17.5",
"vscode-uri": "^3.0.8",
"web-vitals": "^3.5.2",
"xstate": "^4.38.2",
"zustand": "^4.5.2"
"xstate": "^4.38.2"
},
"scripts": {
"start": "vite",
@ -110,7 +109,7 @@
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.24.3",
"@iarna/toml": "^2.2.5",
"@playwright/test": "^1.44.1",
"@playwright/test": "^1.45.1",
"@tauri-apps/cli": "==2.0.0-beta.13",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^15.0.2",
@ -158,7 +157,7 @@
"vitest": "^1.6.0",
"vitest-webgl-canvas-mock": "^1.1.0",
"wait-on": "^7.2.0",
"wasm-pack": "^0.12.1",
"wasm-pack": "^0.13.0",
"ws": "^8.17.0",
"yarn": "^1.22.22"
}

View File

@ -74,5 +74,5 @@
}
},
"productName": "Zoo Modeling App",
"version": "0.22.7"
"version": "0.23.0"
}

View File

@ -1,6 +1,5 @@
import { MouseEventHandler, useEffect, useRef } from 'react'
import { MouseEventHandler, useEffect, useMemo, useRef } from 'react'
import { uuidv4 } from 'lib/utils'
import { useStore } from './useStore'
import { useHotKeyListener } from './hooks/useHotKeyListener'
import { Stream } from './components/Stream'
import { EngineCommand } from './lang/std/engineConnection'
@ -26,6 +25,7 @@ import ModalContainer from 'react-modal-promise'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
import Gizmo from 'components/Gizmo'
import { CoreDumpManager } from 'lib/coredump'
import { useAppState } from 'AppState'
export function App() {
useRefreshSettings(paths.FILE + 'SETTINGS')
@ -44,22 +44,20 @@ export function App() {
}, [projectName, projectPath])
useHotKeyListener()
const { buttonDownInStream, didDragInStream, streamDimensions, setHtmlRef } =
useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
didDragInStream: s.didDragInStream,
streamDimensions: s.streamDimensions,
setHtmlRef: s.setHtmlRef,
}))
const { context } = useModelingContext()
const { setAppState } = useAppState()
useEffect(() => {
setHtmlRef(ref)
setAppState({ htmlRef: ref })
}, [ref])
const { auth, settings } = useSettingsAuthContext()
const token = auth?.context?.token
const coreDumpManager = new CoreDumpManager(engineCommandManager, ref, token)
const coreDumpManager = useMemo(
() => new CoreDumpManager(engineCommandManager, ref, token),
[]
)
const {
app: { onboardingStatus },
@ -81,7 +79,7 @@ export function App() {
(p) => p === onboardingStatus.current
)
? 'opacity-20'
: didDragInStream
: context.store?.didDragInStream
? 'opacity-40'
: ''
@ -99,11 +97,11 @@ export function App() {
clientX: e.clientX,
clientY: e.clientY,
el: e.currentTarget,
...streamDimensions,
...context.store?.streamDimensions,
})
const newCmdId = uuidv4()
if (buttonDownInStream === undefined) {
if (context.store?.buttonDownInStream === undefined) {
debounceSocketSend({
type: 'modeling_cmd_req',
cmd: {
@ -125,7 +123,7 @@ export function App() {
className={
'transition-opacity transition-duration-75 ' +
paneOpacity +
(buttonDownInStream ? ' pointer-events-none' : '')
(context.store?.buttonDownInStream ? ' pointer-events-none' : '')
}
project={{ project, file }}
enableMenu={true}

45
src/AppState.tsx Normal file
View File

@ -0,0 +1,45 @@
import { createContext, useContext, useState, ReactNode } from 'react'
/*
This is for a very small handful of global state we need that doesn't fit into
any of the Xstate machines.
Please do not fill this up with junk.
*/
interface AppState {
isStreamReady: boolean
htmlRef: React.RefObject<HTMLDivElement> | null
setAppState: (newAppState: Partial<AppState>) => void
}
const AppStateContext = createContext<AppState>({
htmlRef: null,
isStreamReady: false,
setAppState: () => {},
})
export const useAppState = () => useContext(AppStateContext)
export const AppStateProvider = ({ children }: { children: ReactNode }) => {
const [appState, _setAppState] = useState<AppState>({
htmlRef: null,
isStreamReady: false,
setAppState: () => {},
})
const setAppState = (newAppState: Partial<AppState>) =>
_setAppState({ ...appState, ...newAppState })
return (
<AppStateContext.Provider
value={{
htmlRef: appState.htmlRef,
isStreamReady: appState.isStreamReady,
setAppState,
}}
>
{children}
</AppStateContext.Provider>
)
}

View File

@ -33,6 +33,14 @@ import LspProvider from 'components/LspProvider'
import { KclContextProvider } from 'lang/KclProvider'
import { BROWSER_PROJECT_NAME } from 'lib/constants'
import { getState, setState } from 'lib/tauri'
import { CoreDumpManager } from 'lib/coredump'
import { engineCommandManager } from 'lib/singletons'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
import toast from 'react-hot-toast'
import { coreDump } from 'lang/wasm'
import { useMemo } from 'react'
import { AppStateProvider, useAppState } from 'AppState'
const router = createBrowserRouter([
{
@ -45,7 +53,9 @@ const router = createBrowserRouter([
<SettingsAuthProvider>
<LspProvider>
<KclContextProvider>
<Outlet />
<AppStateProvider>
<Outlet />
</AppStateProvider>
</KclContextProvider>
</LspProvider>
</SettingsAuthProvider>
@ -87,6 +97,7 @@ const router = createBrowserRouter([
<Auth>
<FileMachineProvider>
<ModelingMachineProvider>
<CoreDump />
<Outlet />
<App />
<CommandBar />
@ -165,3 +176,31 @@ export const Router = () => {
</NetworkContext.Provider>
)
}
function CoreDump() {
const { auth } = useSettingsAuthContext()
const token = auth?.context?.token
const { htmlRef } = useAppState()
const coreDumpManager = useMemo(
() => new CoreDumpManager(engineCommandManager, htmlRef, token),
[]
)
useHotkeyWrapper(['meta + shift + .'], () => {
toast.promise(
coreDump(coreDumpManager, true),
{
loading: 'Starting core dump...',
success: 'Core dump completed successfully',
error: 'Error while exporting core dump',
},
{
success: {
// Note: this extended duration is especially important for Playwright e2e testing
// default duration is 2000 - https://react-hot-toast.com/docs/toast#default-durations
duration: 6000,
},
}
)
})
return null
}

View File

@ -8,10 +8,10 @@ import { NetworkHealthState } from 'hooks/useNetworkStatus'
import { ActionButton } from 'components/ActionButton'
import { isSingleCursorInPipe } from 'lang/queryAst'
import { useKclContext } from 'lang/KclProvider'
import { useStore } from 'useStore'
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
import { useHotkeys } from 'react-hotkeys-hook'
import Tooltip from 'components/Tooltip'
import { useAppState } from 'AppState'
export function Toolbar({
className = '',
@ -38,9 +38,8 @@ export function Toolbar({
const toolbarButtonsRef = useRef<HTMLUListElement>(null)
const { overallState } = useNetworkContext()
const { isExecuting } = useKclContext()
const { isStreamReady } = useStore((s) => ({
isStreamReady: s.isStreamReady,
}))
const { isStreamReady } = useAppState()
const disableAllButtons =
(overallState !== NetworkHealthState.Ok &&
overallState !== NetworkHealthState.Weak) ||

View File

@ -37,7 +37,7 @@ import { Dialog, Popover, Transition } from '@headlessui/react'
import { LineInputsType } from 'lang/std/sketchcombos'
import toast from 'react-hot-toast'
import { InstanceProps, create } from 'react-modal-promise'
import { executeAst } from 'useStore'
import { executeAst } from 'lang/langHelpers'
import {
deleteSegmentFromPipeExpression,
makeRemoveSingleConstraintInput,

View File

@ -58,7 +58,7 @@ import {
editorManager,
} from 'lib/singletons'
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
import { executeAst, useStore } from 'useStore'
import { executeAst } from 'lang/langHelpers'
import {
createArcGeometry,
dashedStraight,
@ -1444,11 +1444,10 @@ export class SceneEntities {
selected.material.color = defaultPlaneColor(type)
},
onClick: async (args) => {
const { streamDimensions } = useStore.getState()
const { entity_id } = await sendSelectEventToEngine(
args?.mouseEvent,
document.getElementById('video-stream') as HTMLVideoElement,
streamDimensions
sceneInfra._streamDimensions
)
let _entity_id = entity_id

View File

@ -103,6 +103,10 @@ export class SceneInfra {
_baseUnit: BaseUnit = 'mm'
_baseUnitMultiplier = 1
_theme: Themes = Themes.System
_streamDimensions: { streamWidth: number; streamHeight: number } = {
streamWidth: 1280,
streamHeight: 720,
}
extraSegmentTexture: Texture
lastMouseState: MouseState = { type: 'idle' }
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}

View File

@ -10,7 +10,7 @@ import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst'
import { engineCommandManager, kclManager } from 'lib/singletons'
import { useKclContext } from 'lang/KclProvider'
import { useModelingContext } from 'hooks/useModelingContext'
import { executeAst } from 'useStore'
import { executeAst } from 'lang/langHelpers'
import { trap } from 'lib/trap'
export const AvailableVars = ({

View File

@ -24,7 +24,7 @@ export const CommandBar = () => {
}, [pathname])
// Hook up keyboard shortcuts
useHotkeyWrapper(['mod+k', 'ctrl+c'], () => {
useHotkeyWrapper(['mod+k'], () => {
if (commandBarState.context.commands.length === 0) return
if (commandBarState.matches('Closed')) {
commandBarSend({ type: 'Open' })

View File

@ -1,11 +1,5 @@
import type * as LSP from 'vscode-languageserver-protocol'
import React, {
createContext,
useMemo,
useEffect,
useContext,
useState,
} from 'react'
import React, { createContext, useMemo, useContext, useState } from 'react'
import {
LanguageServerClient,
FromServer,
@ -16,7 +10,6 @@ import {
import { TEST, VITE_KC_API_BASE_URL } from 'env'
import KclLanguageSupport from 'editor/plugins/lsp/kcl/language'
import { copilotPlugin } from 'editor/plugins/lsp/copilot'
import { useStore } from 'useStore'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { Extension } from '@codemirror/state'
import { LanguageSupport } from '@codemirror/language'
@ -73,19 +66,8 @@ type LspContext = {
export const LspStateContext = createContext({} as LspContext)
export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const {
isKclLspServerReady,
isCopilotLspServerReady,
setIsKclLspServerReady,
setIsCopilotLspServerReady,
} = useStore((s) => ({
isKclLspServerReady: s.isKclLspServerReady,
isCopilotLspServerReady: s.isCopilotLspServerReady,
setIsKclLspServerReady: s.setIsKclLspServerReady,
setIsCopilotLspServerReady: s.setIsCopilotLspServerReady,
}))
const [isLspReady, setIsLspReady] = useState(false)
const [isCopilotReady, setIsCopilotReady] = useState(false)
const [isKclLspReady, setIsKclLspReady] = useState(false)
const [isCopilotLspReady, setIsCopilotLspReady] = useState(false)
const {
auth,
@ -132,7 +114,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
fromServer,
intoServer,
initializedCallback: () => {
setIsLspReady(true)
setIsKclLspReady(true)
},
})
@ -143,7 +125,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
])
useMemo(() => {
if (!isTauri() && isKclLspServerReady && kclLspClient && codeManager.code) {
if (!isTauri() && isKclLspReady && kclLspClient && codeManager.code) {
kclLspClient.textDocumentDidOpen({
textDocument: {
uri: `file:///${PROJECT_ENTRYPOINT}`,
@ -153,7 +135,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
},
})
}
}, [kclLspClient, isKclLspServerReady])
}, [kclLspClient, isKclLspReady])
// Here we initialize the plugin which will start the client.
// Now that we have multi-file support the name of the file is a dep of
@ -162,7 +144,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
// We do not want to restart the server, its just wasteful.
const kclLSP = useMemo(() => {
let plugin = null
if (isKclLspServerReady && !TEST && kclLspClient) {
if (isKclLspReady && !TEST && kclLspClient) {
// Set up the lsp plugin.
const lsp = new KclLanguageSupport({
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
@ -193,7 +175,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
plugin = lsp
}
return plugin
}, [kclLspClient, isKclLspServerReady])
}, [kclLspClient, isKclLspReady])
const { lspClient: copilotLspClient } = useMemo(() => {
if (!token || token === '' || TEST) {
@ -225,7 +207,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
fromServer,
intoServer,
initializedCallback: () => {
setIsCopilotReady(true)
setIsCopilotLspReady(true)
},
})
return { lspClient }
@ -238,7 +220,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
// We do not want to restart the server, its just wasteful.
const copilotLSP = useMemo(() => {
let plugin = null
if (isCopilotLspServerReady && !TEST && copilotLspClient) {
if (isCopilotLspReady && !TEST && copilotLspClient) {
// Set up the lsp plugin.
const lsp = copilotPlugin({
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
@ -250,7 +232,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
plugin = lsp
}
return plugin
}, [copilotLspClient, isCopilotLspServerReady])
}, [copilotLspClient, isCopilotLspReady])
let lspClients: LanguageServerClient[] = []
if (kclLspClient) {
@ -260,13 +242,6 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
lspClients.push(copilotLspClient)
}
useEffect(() => {
setIsKclLspServerReady(isLspReady)
}, [isLspReady])
useEffect(() => {
setIsCopilotLspServerReady(isCopilotReady)
}, [isCopilotReady])
const onProjectClose = (
file: FileEntry | null,
projectPath: string | null,

View File

@ -30,7 +30,6 @@ import {
applyConstraintAngleBetween,
} from './Toolbar/SetAngleBetween'
import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
import { useStore } from 'useStore'
import {
Selections,
canExtrudeSelection,
@ -54,13 +53,7 @@ import {
sketchOnExtrudedFace,
startSketchOnDefault,
} from 'lang/modifyAst'
import {
Program,
VariableDeclaration,
coreDump,
parse,
recast,
} from 'lang/wasm'
import { Program, VariableDeclaration, parse, recast } from 'lang/wasm'
import {
getNodeFromPath,
getNodePathFromSourceRange,
@ -72,11 +65,9 @@ import { exportFromEngine } from 'lib/exportFromEngine'
import { Models } from '@kittycad/lib/dist/types/src'
import toast from 'react-hot-toast'
import { EditorSelection, Transaction } from '@uiw/react-codemirror'
import { CoreDumpManager } from 'lib/coredump'
import { useSearchParams } from 'react-router-dom'
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
import { getVarNameModal } from 'hooks/useToolbarGuards'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
import { uuidv4 } from 'lib/utils'
import { err, trap } from 'lib/trap'
import { useCommandsContext } from 'hooks/useCommandsContext'
@ -112,38 +103,6 @@ export const ModelingMachineProvider = ({
let [searchParams] = useSearchParams()
const pool = searchParams.get('pool')
useSetupEngineManager(streamRef, token, {
pool: pool,
theme: theme.current,
highlightEdges: highlightEdges.current,
enableSSAO: enableSSAO.current,
showScaleGrid: showScaleGrid.current,
})
const { htmlRef } = useStore((s) => ({
htmlRef: s.htmlRef,
}))
const coreDumpManager = new CoreDumpManager(
engineCommandManager,
htmlRef,
token
)
useHotkeyWrapper(['meta + shift + .'], () => {
toast.promise(
coreDump(coreDumpManager, true),
{
loading: 'Starting core dump...',
success: 'Core dump completed successfully',
error: 'Error while exporting core dump',
},
{
success: {
// Note: this extended duration is especially important for Playwright e2e testing
// default duration is 2000 - https://react-hot-toast.com/docs/toast#default-durations
duration: 6000,
},
}
)
})
const { commandBarState } = useCommandsContext()
// Settings machine setup
@ -163,6 +122,12 @@ export const ModelingMachineProvider = ({
modelingMachine,
{
actions: {
'disable copilot': () => {
editorManager.setCopilotEnabled(false)
},
'enable copilot': () => {
editorManager.setCopilotEnabled(true)
},
'sketch exit execute': () => {
;(async () => {
await sceneInfra.camControls.snapToPerspectiveBeforeHandingBackControlToEngine()
@ -514,11 +479,15 @@ export const ModelingMachineProvider = ({
services: {
'AST-undo-startSketchOn': async ({ sketchDetails }) => {
if (!sketchDetails) return
const newAst: Program = JSON.parse(JSON.stringify(kclManager.ast))
const varDecIndex = sketchDetails.sketchPathToNode[1][0]
// remove body item at varDecIndex
newAst.body = newAst.body.filter((_, i) => i !== varDecIndex)
await kclManager.executeAstMock(newAst)
if (kclManager.ast.body.length) {
// this assumes no changes have been made to the sketch besides what we did when entering the sketch
// i.e. doesn't account for user's adding code themselves, maybe we need store a flag userEditedSinceSketchMode?
const newAst: Program = JSON.parse(JSON.stringify(kclManager.ast))
const varDecIndex = sketchDetails.sketchPathToNode[1][0]
// remove body item at varDecIndex
newAst.body = newAst.body.filter((_, i) => i !== varDecIndex)
await kclManager.executeAstMock(newAst)
}
sceneInfra.setCallbacks({
onClick: () => {},
onDrag: () => {},
@ -898,6 +867,16 @@ export const ModelingMachineProvider = ({
}
)
useSetupEngineManager(streamRef, token, {
pool: pool,
theme: theme.current,
highlightEdges: highlightEdges.current,
enableSSAO: enableSSAO.current,
modelingSend,
modelingContext: modelingState.context,
showScaleGrid: showScaleGrid.current,
})
useEffect(() => {
kclManager.registerExecuteCallback(() => {
modelingSend({ type: 'Re-execute' })

View File

@ -1,6 +1,6 @@
import { useStore } from 'useStore'
import styles from './ModelingPane.module.css'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useModelingContext } from 'hooks/useModelingContext'
export interface ModelingPaneProps
extends React.PropsWithChildren,
@ -33,11 +33,9 @@ export const ModelingPane = ({
}: ModelingPaneProps) => {
const { settings } = useSettingsAuthContext()
const onboardingStatus = settings.context.app.onboardingStatus
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const pointerEventsCssClass =
buttonDownInStream || onboardingStatus.current === 'camera'
context.store?.buttonDownInStream || onboardingStatus.current === 'camera'
? 'pointer-events-none '
: 'pointer-events-auto '
return (

View File

@ -2,7 +2,6 @@ import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { Resizable } from 're-resizable'
import { HTMLAttributes, useCallback, useEffect, useState } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { useStore } from 'useStore'
import { Tab } from '@headlessui/react'
import {
SidebarPane,
@ -15,6 +14,7 @@ import { ActionIcon } from 'components/ActionIcon'
import styles from './ModelingSidebar.module.css'
import { ModelingPane } from './ModelingPane'
import { isTauri } from 'lib/isTauri'
import { useModelingContext } from 'hooks/useModelingContext'
interface ModelingSidebarProps {
paneOpacity: '' | 'opacity-20' | 'opacity-40'
@ -23,14 +23,11 @@ interface ModelingSidebarProps {
export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
const { settings } = useSettingsAuthContext()
const onboardingStatus = settings.context.app.onboardingStatus
const { openPanes, buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
openPanes: s.openPanes,
}))
const { context } = useModelingContext()
const pointerEventsCssClass =
buttonDownInStream ||
context.store?.buttonDownInStream ||
onboardingStatus.current === 'camera' ||
openPanes.length === 0
context.store?.openPanes.length === 0
? 'pointer-events-none '
: 'pointer-events-auto '
@ -45,7 +42,7 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
maxWidth={800}
handleClasses={{
right:
(openPanes.length === 0 ? 'hidden ' : 'block ') +
(context.store?.openPanes.length === 0 ? 'hidden ' : 'block ') +
'translate-x-1/2 hover:bg-chalkboard-10 hover:dark:bg-chalkboard-110 bg-transparent transition-colors duration-75 transition-ease-out delay-100 ',
left: 'hidden',
top: 'hidden',
@ -82,11 +79,10 @@ function ModelingSidebarSection({
const { settings } = useSettingsAuthContext()
const showDebugPanel = settings.context.modeling.showDebugPanel
const paneIds = panes.map((pane) => pane.id)
const { openPanes, setOpenPanes } = useStore((s) => ({
openPanes: s.openPanes,
setOpenPanes: s.setOpenPanes,
}))
const foundOpenPane = openPanes.find((pane) => paneIds.includes(pane))
const { send, context } = useModelingContext()
const foundOpenPane = context.store?.openPanes.find((pane) =>
paneIds.includes(pane)
)
const [currentPane, setCurrentPane] = useState(
foundOpenPane || ('none' as SidebarType | 'none')
)
@ -94,17 +90,37 @@ function ModelingSidebarSection({
const togglePane = useCallback(
(newPane: SidebarType | 'none') => {
if (newPane === 'none') {
setOpenPanes(openPanes.filter((p) => p !== currentPane))
send({
type: 'Set context',
data: {
openPanes: context.store?.openPanes.filter(
(p) => p !== currentPane
),
},
})
setCurrentPane('none')
} else if (newPane === currentPane) {
setCurrentPane('none')
setOpenPanes(openPanes.filter((p) => p !== newPane))
send({
type: 'Set context',
data: {
openPanes: context.store?.openPanes.filter((p) => p !== newPane),
},
})
} else {
setOpenPanes([...openPanes.filter((p) => p !== currentPane), newPane])
send({
type: 'Set context',
data: {
openPanes: [
...context.store?.openPanes.filter((p) => p !== currentPane),
newPane,
],
},
})
setCurrentPane(newPane)
}
},
[openPanes, setOpenPanes, currentPane, setCurrentPane]
[context.store?.openPanes, send, currentPane, setCurrentPane]
)
// Filter out the debug panel if it's not supposed to be shown
@ -122,11 +138,11 @@ function ModelingSidebarSection({
if (
!showDebugPanel.current &&
currentPane === 'debug' &&
openPanes.includes('debug')
context.store?.openPanes.includes('debug')
) {
togglePane('debug')
}
}, [showDebugPanel.current, togglePane, openPanes])
}, [showDebugPanel.current, togglePane, context.store?.openPanes])
return (
<div className={'group contents ' + className} {...props}>
@ -152,7 +168,9 @@ function ModelingSidebarSection({
: ' border-r-0') +
' p-2 col-start-1 col-span-1 h-fit w-fit flex flex-col items-start gap-2 ' +
'bg-chalkboard-10 border border-solid border-chalkboard-20 dark:bg-chalkboard-90 dark:border-chalkboard-80 group-focus-within:border-primary dark:group-focus-within:border-chalkboard-50 ' +
(openPanes.length === 1 && currentPane === 'none' ? 'pr-0.5' : '')
(context.store?.openPanes.length === 1 && currentPane === 'none'
? 'pr-0.5'
: '')
}
>
<Tab key="none" className="sr-only">
@ -172,7 +190,7 @@ function ModelingSidebarSection({
as="article"
className={
'col-start-2 col-span-1 ' +
(openPanes.length === 1
(context.store?.openPanes.length === 1
? currentPane !== 'none'
? `row-start-1 row-end-3`
: `hidden`

View File

@ -2,22 +2,19 @@ import { coreDump } from 'lang/wasm'
import { CoreDumpManager } from 'lib/coredump'
import { CustomIcon } from './CustomIcon'
import { engineCommandManager } from 'lib/singletons'
import React from 'react'
import React, { useMemo } from 'react'
import toast from 'react-hot-toast'
import Tooltip from './Tooltip'
import { useStore } from 'useStore'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useAppState } from 'AppState'
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
const { auth } = useSettingsAuthContext()
const token = auth?.context?.token
const { htmlRef } = useStore((s) => ({
htmlRef: s.htmlRef,
}))
const coreDumpManager = new CoreDumpManager(
engineCommandManager,
htmlRef,
token
const { htmlRef } = useAppState()
const coreDumpManager = useMemo(
() => new CoreDumpManager(engineCommandManager, htmlRef, token),
[]
)
async function refresh() {

View File

@ -1,5 +1,4 @@
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
import { useStore } from '../useStore'
import { getNormalisedCoordinates } from '../lib/utils'
import Loading from './Loading'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
@ -10,25 +9,12 @@ import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
import { butName } from 'lib/cameraControls'
import { sendSelectEventToEngine } from 'lib/selections'
export const Stream = ({ className = '' }: { className?: string }) => {
export const Stream = () => {
const [isLoading, setIsLoading] = useState(true)
const [clickCoords, setClickCoords] = useState<{ x: number; y: number }>()
const videoRef = useRef<HTMLVideoElement>(null)
const {
mediaStream,
setButtonDownInStream,
didDragInStream,
setDidDragInStream,
streamDimensions,
} = useStore((s) => ({
mediaStream: s.mediaStream,
setButtonDownInStream: s.setButtonDownInStream,
didDragInStream: s.didDragInStream,
setDidDragInStream: s.setDidDragInStream,
streamDimensions: s.streamDimensions,
}))
const { settings } = useSettingsAuthContext()
const { state } = useModelingContext()
const { state, send, context } = useModelingContext()
const { overallState } = useNetworkContext()
const isNetworkOkay =
@ -74,9 +60,9 @@ export const Stream = ({ className = '' }: { className?: string }) => {
)
return
if (!videoRef.current) return
if (!mediaStream) return
videoRef.current.srcObject = mediaStream
}, [mediaStream])
if (!context.store?.mediaStream) return
videoRef.current.srcObject = context.store.mediaStream
}, [context.store?.mediaStream])
const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {
if (!isNetworkOkay) return
@ -88,25 +74,44 @@ export const Stream = ({ className = '' }: { className?: string }) => {
clientX: e.clientX,
clientY: e.clientY,
el: videoRef.current,
...streamDimensions,
...context.store?.streamDimensions,
})
setButtonDownInStream(e.button)
send({
type: 'Set context',
data: {
buttonDownInStream: e.button,
},
})
setClickCoords({ x, y })
}
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
if (!isNetworkOkay) return
if (!videoRef.current) return
setButtonDownInStream(undefined)
send({
type: 'Set context',
data: {
buttonDownInStream: undefined,
},
})
if (state.matches('Sketch')) return
if (state.matches('Sketch no face')) return
if (!didDragInStream && butName(e).left) {
sendSelectEventToEngine(e, videoRef.current, streamDimensions)
if (!context.store?.didDragInStream && butName(e).left) {
sendSelectEventToEngine(
e,
videoRef.current,
context.store?.streamDimensions
)
}
setDidDragInStream(false)
send({
type: 'Set context',
data: {
didDragInStream: false,
},
})
setClickCoords(undefined)
}
@ -120,8 +125,13 @@ export const Stream = ({ className = '' }: { className?: string }) => {
((clickCoords.x - e.clientX) ** 2 + (clickCoords.y - e.clientY) ** 2) **
0.5
if (delta > 5 && !didDragInStream) {
setDidDragInStream(true)
if (delta > 5 && !context.store?.didDragInStream) {
send({
type: 'Set context',
data: {
didDragInStream: true,
},
})
}
}

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
import {

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
import {

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { Program, ProgramMemory, Value } from '../../lang/wasm'
import {

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
import {

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { Selection, Selections } from 'lib/selections'
import { PathToNode, Program, Value } from '../../lang/wasm'
import {

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { BinaryPart, Program, Value } from '../../lang/wasm'
import {

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
import {

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
import {
getNodePathFromSourceRange,

View File

@ -1,4 +1,4 @@
import { toolTips } from '../../useStore'
import { toolTips } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { BinaryPart, Program, Value } from '../../lang/wasm'
import {

View File

@ -27,6 +27,7 @@ function diagnosticIsEqual(d1: Diagnostic, d2: Diagnostic): boolean {
export default class EditorManager {
private _editorView: EditorView | null = null
private _copilotEnabled: boolean = true
private _isShiftDown: boolean = false
private _selectionRanges: Selections = {
@ -47,6 +48,14 @@ export default class EditorManager {
private _highlightRange: [number, number] = [0, 0]
setCopilotEnabled(enabled: boolean) {
this._copilotEnabled = enabled
}
get copilotEnabled(): boolean {
return this._copilotEnabled
}
setEditorView(editorView: EditorView) {
this._editorView = editorView
}

View File

@ -40,6 +40,7 @@ import { CopilotLspCompletionParams } from 'wasm-lib/kcl/bindings/CopilotLspComp
import { CopilotCompletionResponse } from 'wasm-lib/kcl/bindings/CopilotCompletionResponse'
import { CopilotAcceptCompletionParams } from 'wasm-lib/kcl/bindings/CopilotAcceptCompletionParams'
import { CopilotRejectCompletionParams } from 'wasm-lib/kcl/bindings/CopilotRejectCompletionParams'
import { editorManager } from 'lib/singletons'
const copilotPluginAnnotation = Annotation.define<null>()
export const copilotPluginEvent = copilotPluginAnnotation.of(null)
@ -269,6 +270,11 @@ export class CompletionRequester implements PluginValue {
return
}
// Make sure we are in a state where we can request completions.
if (!editorManager.copilotEnabled) {
return
}
this.lastPos = this.viewUpdate.state.selection.main.head
this._deffererCodeUpdate(true)
}
@ -618,6 +624,16 @@ export const copilotPlugin = (options: LanguageServerOptions): Extension => {
},
})
const rejectSuggestionCommand = (view: EditorView): boolean => {
if (view.plugin === null) return false
// Get the current plugin from the map.
const p = view.plugin(completionPlugin)
if (p === null) return false
return p.rejectSuggestionCommand()
}
const copilotAutocompleteKeymap: readonly KeyBinding[] = [
{
key: 'Tab',
@ -633,27 +649,30 @@ export const copilotPlugin = (options: LanguageServerOptions): Extension => {
},
{
key: 'Backspace',
run: (view: EditorView): boolean => {
if (view.plugin === null) return false
// Get the current plugin from the map.
const p = view.plugin(completionPlugin)
if (p === null) return false
return p.rejectSuggestionCommand()
},
run: rejectSuggestionCommand,
},
{
key: 'Delete',
run: (view: EditorView): boolean => {
if (view.plugin === null) return false
// Get the current plugin from the map.
const p = view.plugin(completionPlugin)
if (p === null) return false
return p.rejectSuggestionCommand()
},
run: rejectSuggestionCommand,
},
{ key: 'Mod-z', run: rejectSuggestionCommand, preventDefault: true },
{
key: 'Mod-y',
mac: 'Mod-Shift-z',
run: rejectSuggestionCommand,
preventDefault: true,
},
{
linux: 'Ctrl-Shift-z',
run: rejectSuggestionCommand,
preventDefault: true,
},
{ key: 'Mod-u', run: rejectSuggestionCommand, preventDefault: true },
{
key: 'Alt-u',
mac: 'Mod-Shift-u',
run: rejectSuggestionCommand,
preventDefault: true,
},
]

View File

@ -1,9 +1,10 @@
import { useLayoutEffect, useEffect, useRef } from 'react'
import { useStore } from '../useStore'
import { engineCommandManager, kclManager } from 'lib/singletons'
import { deferExecution } from 'lib/utils'
import { Themes } from 'lib/theme'
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
import { useModelingContext } from './useModelingContext'
import { useAppState } from 'AppState'
export function useSetupEngineManager(
streamRef: React.RefObject<HTMLDivElement>,
@ -13,26 +14,20 @@ export function useSetupEngineManager(
theme: Themes.System,
highlightEdges: true,
enableSSAO: true,
modelingSend: (() => {}) as any,
modelingContext: {} as any,
showScaleGrid: false,
} as {
pool: string | null
theme: Themes
highlightEdges: boolean
enableSSAO: boolean
modelingSend: ReturnType<typeof useModelingContext>['send']
modelingContext: ReturnType<typeof useModelingContext>['context']
showScaleGrid: boolean
}
) {
const {
setMediaStream,
setIsStreamReady,
setStreamDimensions,
streamDimensions,
} = useStore((s) => ({
setMediaStream: s.setMediaStream,
setIsStreamReady: s.setIsStreamReady,
setStreamDimensions: s.setStreamDimensions,
streamDimensions: s.streamDimensions,
}))
const { setAppState } = useAppState()
const streamWidth = streamRef?.current?.offsetWidth
const streamHeight = streamRef?.current?.offsetHeight
@ -52,10 +47,19 @@ export function useSetupEngineManager(
streamWidth,
streamHeight
)
if (!hasSetNonZeroDimensions.current && quadHeight && quadWidth) {
if (
!hasSetNonZeroDimensions.current &&
quadHeight &&
quadWidth &&
settings.modelingSend
) {
engineCommandManager.start({
setMediaStream,
setIsStreamReady,
setMediaStream: (mediaStream) =>
settings.modelingSend({
type: 'Set context',
data: { mediaStream },
}),
setIsStreamReady: (isStreamReady) => setAppState({ isStreamReady }),
width: quadWidth,
height: quadHeight,
executeCode: () => {
@ -72,9 +76,14 @@ export function useSetupEngineManager(
return modifyGrid(kclManager.engineCommandManager, hidden)
},
})
setStreamDimensions({
streamWidth: quadWidth,
streamHeight: quadHeight,
settings.modelingSend({
type: 'Set context',
data: {
streamDimensions: {
streamWidth: quadWidth,
streamHeight: quadHeight,
},
},
})
hasSetNonZeroDimensions.current = true
}
@ -83,6 +92,7 @@ export function useSetupEngineManager(
useLayoutEffect(startEngineInstance, [
streamRef?.current?.offsetWidth,
streamRef?.current?.offsetHeight,
settings.modelingSend,
])
useEffect(() => {
@ -92,16 +102,21 @@ export function useSetupEngineManager(
streamRef?.current?.offsetHeight
)
if (
streamDimensions.streamWidth !== width ||
streamDimensions.streamHeight !== height
settings.modelingContext.store.streamDimensions.streamWidth !== width ||
settings.modelingContext.store.streamDimensions.streamHeight !== height
) {
engineCommandManager.handleResize({
streamWidth: width,
streamHeight: height,
})
setStreamDimensions({
streamWidth: width,
streamHeight: height,
settings.modelingSend({
type: 'Set context',
data: {
streamDimensions: {
streamWidth: width,
streamHeight: height,
},
},
})
}
}, 500)

View File

@ -8,9 +8,9 @@ import { settingsMachine } from 'machines/settingsMachine'
import { homeMachine } from 'machines/homeMachine'
import { Command, CommandSetConfig, CommandSetSchema } from 'lib/commandTypes'
import { useKclContext } from 'lang/KclProvider'
import { useStore } from 'useStore'
import { useNetworkContext } from 'hooks/useNetworkContext'
import { NetworkHealthState } from 'hooks/useNetworkStatus'
import { useAppState } from 'AppState'
// This might not be necessary, AnyStateMachine from xstate is working
export type AllMachines =
@ -47,9 +47,7 @@ export default function useStateMachineCommands<
const { commandBarSend } = useCommandsContext()
const { overallState } = useNetworkContext()
const { isExecuting } = useKclContext()
const { isStreamReady } = useStore((s) => ({
isStreamReady: s.isStreamReady,
}))
const { isStreamReady } = useAppState()
useEffect(() => {
const disableAllButtons =

View File

@ -1,4 +1,4 @@
import { executeAst, lintAst } from 'useStore'
import { executeAst, lintAst } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { KCLError, kclErrorsToDiagnostics } from './errors'
import { uuidv4 } from 'lib/utils'

View File

@ -8,7 +8,7 @@ import toast from 'react-hot-toast'
import { editorManager } from 'lib/singletons'
import { Annotation, KeyBinding, Transaction } from '@uiw/react-codemirror'
const PERSIST_CODE_TOKEN = 'persistCode'
const PERSIST_CODE_KEY = 'persistCode'
const codeManagerUpdateAnnotation = Annotation.define<null>()
export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(null)
@ -25,7 +25,7 @@ export default class CodeManager {
return
}
const storedCode = safeLSGetItem(PERSIST_CODE_TOKEN)
const storedCode = safeLSGetItem(PERSIST_CODE_KEY)
// TODO #819 remove zustand persistence logic in a few months
// short term migration, shouldn't make a difference for tauri app users
// anyway since that's filesystem based.
@ -125,7 +125,7 @@ export default class CodeManager {
})
})
} else {
safeLSSetItem(PERSIST_CODE_TOKEN, this.code)
safeLSSetItem(PERSIST_CODE_KEY, this.code)
}
}
}

120
src/lang/langHelpers.ts Normal file
View File

@ -0,0 +1,120 @@
import {
Program,
_executor,
ProgramMemory,
programMemoryInit,
kclLint,
} from 'lang/wasm'
import { enginelessExecutor } from 'lib/testHelpers'
import { EngineCommandManager } from 'lang/std/engineConnection'
import { KCLError } from 'lang/errors'
import { Diagnostic } from '@codemirror/lint'
export type ToolTip =
| 'lineTo'
| 'line'
| 'angledLine'
| 'angledLineOfXLength'
| 'angledLineOfYLength'
| 'angledLineToX'
| 'angledLineToY'
| 'xLine'
| 'yLine'
| 'xLineTo'
| 'yLineTo'
| 'angledLineThatIntersects'
| 'tangentialArcTo'
export const toolTips = [
'sketch_line',
'move',
// original tooltips
'line',
'lineTo',
'angledLine',
'angledLineOfXLength',
'angledLineOfYLength',
'angledLineToX',
'angledLineToY',
'xLine',
'yLine',
'xLineTo',
'yLineTo',
'angledLineThatIntersects',
'tangentialArcTo',
] as any as ToolTip[]
export async function executeAst({
ast,
engineCommandManager,
useFakeExecutor = false,
programMemoryOverride,
}: {
ast: Program
engineCommandManager: EngineCommandManager
useFakeExecutor?: boolean
programMemoryOverride?: ProgramMemory
}): Promise<{
logs: string[]
errors: KCLError[]
programMemory: ProgramMemory
}> {
try {
if (!useFakeExecutor) {
engineCommandManager.endSession()
engineCommandManager.startNewSession()
}
const programMemory = await (useFakeExecutor
? enginelessExecutor(ast, programMemoryOverride || programMemoryInit())
: _executor(ast, programMemoryInit(), engineCommandManager, false))
await engineCommandManager.waitForAllCommands()
return {
logs: [],
errors: [],
programMemory,
}
} catch (e: any) {
if (e instanceof KCLError) {
return {
errors: [e],
logs: [],
programMemory: {
root: {},
return: null,
},
}
} else {
console.log(e)
return {
logs: [e],
errors: [],
programMemory: {
root: {},
return: null,
},
}
}
}
}
export async function lintAst({
ast,
}: {
ast: Program
}): Promise<Array<Diagnostic>> {
try {
const discovered_findings = await kclLint(ast)
return discovered_findings.map((lint) => {
return {
message: lint.finding.title,
severity: 'info',
from: lint.pos[0],
to: lint.pos[1],
}
})
} catch (e: any) {
console.log(e)
return []
}
}

View File

@ -1,4 +1,4 @@
import { ToolTip } from '../useStore'
import { ToolTip } from 'lang/langHelpers'
import { Selection, Selections } from 'lib/selections'
import {
ArrayExpression,

View File

@ -23,7 +23,7 @@ import {
isLiteralArrayOrStatic,
isNotLiteralArrayOrStatic,
} from 'lang/std/sketchcombos'
import { toolTips, ToolTip } from '../../useStore'
import { toolTips, ToolTip } from 'lang/langHelpers'
import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
import {

View File

@ -1,5 +1,5 @@
import { getNodeFromPath } from 'lang/queryAst'
import { ToolTip, toolTips } from '../../useStore'
import { ToolTip, toolTips } from 'lang/langHelpers'
import {
Program,
VariableDeclarator,

View File

@ -8,7 +8,7 @@ import {
ConstraintLevel,
getConstraintLevelFromSourceRange,
} from './sketchcombos'
import { ToolTip } from '../../useStore'
import { ToolTip } from 'lang/langHelpers'
import { Selections } from 'lib/selections'
import { err } from 'lib/trap'
import { enginelessExecutor } from '../../lib/testHelpers'

View File

@ -1,5 +1,5 @@
import { TransformCallback, VarValues } from './stdTypes'
import { toolTips, ToolTip } from '../../useStore'
import { ToolTip, toolTips } from 'lang/langHelpers'
import { Selections, Selection } from 'lib/selections'
import { cleanErrs, err } from 'lib/trap'
import {

View File

@ -1,4 +1,4 @@
import { ToolTip } from 'useStore'
import { ToolTip } from 'lang/langHelpers'
import {
ProgramMemory,
Path,

View File

@ -5,7 +5,7 @@ import { findUniqueName } from 'lang/modifyAst'
import { PrevVariable, findAllPreviousVariables } from 'lang/queryAst'
import { Value, parse } from 'lang/wasm'
import { useEffect, useRef, useState } from 'react'
import { executeAst } from 'useStore'
import { executeAst } from 'lang/langHelpers'
import { trap } from 'lib/trap'
const isValidVariableName = (name: string) =>

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
import { FormEvent, useEffect } from 'react'
import { FormEvent, useEffect, useRef } from 'react'
import { remove } from '@tauri-apps/plugin-fs'
import {
getNextProjectIndex,
@ -39,6 +39,7 @@ import {
listProjects,
renameProjectDirectory,
} from 'lib/tauri'
import { useAppState } from 'AppState'
// This route only opens in the Tauri desktop context for now,
// as defined in Router.tsx, so we can use the Tauri APIs and types.
@ -64,6 +65,12 @@ const Home = () => {
splitKey: '|',
}
)
const ref = useRef<HTMLDivElement>(null)
const { setAppState } = useAppState()
useEffect(() => {
setAppState({ htmlRef: ref })
}, [ref])
const [state, send, actor] = useMachine(homeMachine, {
context: {
@ -198,7 +205,7 @@ const Home = () => {
}
return (
<div className="relative flex flex-col h-screen overflow-hidden">
<div className="relative flex flex-col h-screen overflow-hidden" ref={ref}>
<AppHeader showToolbar={false} />
<div className="w-full flex flex-col overflow-hidden max-w-5xl px-4 mx-auto mt-24 lg:px-2">
<section>

View File

@ -1,6 +1,5 @@
import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import {
CameraSystem,
@ -8,11 +7,10 @@ import {
cameraSystems,
} from 'lib/cameraControls'
import { SettingsSection } from 'components/Settings/SettingsSection'
import { useModelingContext } from 'hooks/useModelingContext'
export default function Units() {
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.STREAMING)
const {
@ -31,7 +29,7 @@ export default function Units() {
<div
className={
'max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<SettingsSection

View File

@ -1,12 +1,10 @@
import usePlatform from 'hooks/usePlatform'
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
import { useModelingContext } from 'hooks/useModelingContext'
export default function CmdK() {
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.USER_MENU)
const platformName = usePlatform()
@ -16,7 +14,7 @@ export default function CmdK() {
<div
className={
'max-w-full xl:max-w-4xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<h2 className="text-2xl font-bold">Command Bar</h2>

View File

@ -1,12 +1,10 @@
import { useModelingContext } from 'hooks/useModelingContext'
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
export default function OnboardingCodeEditor() {
useDemoCode()
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
@ -15,7 +13,7 @@ export default function OnboardingCodeEditor() {
<div
className={
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<section className="flex-1 overflow-y-auto">

View File

@ -1,12 +1,10 @@
import { APP_NAME } from 'lib/constants'
import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
import { useModelingContext } from 'hooks/useModelingContext'
export default function Export() {
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.SKETCHING)
@ -15,7 +13,7 @@ export default function Export() {
<div
className={
'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<section className="flex-1">

View File

@ -6,14 +6,12 @@ import {
useNextClick,
} from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
import { bracketWidthConstantLine } from 'lib/exampleKcl'
import { useModelingContext } from 'hooks/useModelingContext'
export default function OnboardingInteractiveNumbers() {
useDemoCode()
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.COMMAND_K)
@ -22,7 +20,7 @@ export default function OnboardingInteractiveNumbers() {
<div
className={
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<section className="flex-1 overflow-y-auto mb-6">

View File

@ -1,15 +1,13 @@
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
import { Themes, getSystemTheme } from 'lib/theme'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { bracketThicknessCalculationLine } from 'lib/exampleKcl'
import { useModelingContext } from 'hooks/useModelingContext'
export default function OnboardingParametricModeling() {
useDemoCode()
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const {
settings: {
context: {
@ -32,7 +30,7 @@ export default function OnboardingParametricModeling() {
<div
className={
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<section className="flex-1 overflow-y-auto mb-6">

View File

@ -1,12 +1,10 @@
import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
import { isTauri } from 'lib/isTauri'
import { useModelingContext } from 'hooks/useModelingContext'
export default function ProjectMenu() {
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.EXPORT)
const tauri = isTauri()
@ -16,7 +14,7 @@ export default function ProjectMenu() {
<div
className={
'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<section className="flex-1">

View File

@ -1,11 +1,11 @@
import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from 'useStore'
import { useEffect } from 'react'
import { codeManager, kclManager } from 'lib/singletons'
import { useModelingContext } from 'hooks/useModelingContext'
export default function Sketching() {
const buttonDownInStream = useStore((s) => s.buttonDownInStream)
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.FUTURE_WORK)
@ -23,7 +23,7 @@ export default function Sketching() {
<div
className={
'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<h1 className="text-2xl font-bold">Sketching</h1>

View File

@ -1,11 +1,9 @@
import { useModelingContext } from 'hooks/useModelingContext'
import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
export default function Streaming() {
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.EDITOR)
@ -14,7 +12,7 @@ export default function Streaming() {
<div
className={
'max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<section className="flex-1 overflow-y-auto">

View File

@ -1,12 +1,10 @@
import { OnboardingButtons, useDismiss, useNextClick } from '.'
import { onboardingPaths } from 'routes/Onboarding/paths'
import { useStore } from '../../useStore'
import { useEffect, useState } from 'react'
import { useModelingContext } from 'hooks/useModelingContext'
export default function UserMenu() {
const { buttonDownInStream } = useStore((s) => ({
buttonDownInStream: s.buttonDownInStream,
}))
const { context } = useModelingContext()
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.PROJECT_MENU)
const [avatarErrored, setAvatarErrored] = useState(false)
@ -33,7 +31,7 @@ export default function UserMenu() {
<div
className={
'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
(buttonDownInStream ? '' : ' pointer-events-auto')
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
}
>
<section className="flex-1">

View File

@ -12,8 +12,11 @@ import { SettingsSectionsList } from 'components/Settings/SettingsSectionsList'
import { AllSettingsFields } from 'components/Settings/AllSettingsFields'
import { AllKeybindingsFields } from 'components/Settings/AllKeybindingsFields'
import { KeybindingsSectionsList } from 'components/Settings/KeybindingsSectionsList'
import { isTauri } from 'lib/isTauri'
export const APP_VERSION = import.meta.env.PACKAGE_VERSION || 'unknown'
export const APP_VERSION = isTauri()
? import.meta.env.PACKAGE_VERSION || 'unknown'
: 'main'
export const Settings = () => {
const navigate = useNavigate()

View File

@ -1,212 +0,0 @@
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import {
Program,
_executor,
ProgramMemory,
programMemoryInit,
kclLint,
} from './lang/wasm'
import { enginelessExecutor } from './lib/testHelpers'
import { EngineCommandManager } from './lang/std/engineConnection'
import { KCLError } from './lang/errors'
import { SidebarType } from 'components/ModelingSidebar/ModelingPanes'
import { Diagnostic } from '@codemirror/lint'
export type ToolTip =
| 'lineTo'
| 'line'
| 'angledLine'
| 'angledLineOfXLength'
| 'angledLineOfYLength'
| 'angledLineToX'
| 'angledLineToY'
| 'xLine'
| 'yLine'
| 'xLineTo'
| 'yLineTo'
| 'angledLineThatIntersects'
| 'tangentialArcTo'
export const toolTips = [
'sketch_line',
'move',
// original tooltips
'line',
'lineTo',
'angledLine',
'angledLineOfXLength',
'angledLineOfYLength',
'angledLineToX',
'angledLineToY',
'xLine',
'yLine',
'xLineTo',
'yLineTo',
'angledLineThatIntersects',
'tangentialArcTo',
] as any as ToolTip[]
export interface StoreState {
mediaStream?: MediaStream
setMediaStream: (mediaStream: MediaStream) => void
isStreamReady: boolean
setIsStreamReady: (isStreamReady: boolean) => void
isKclLspServerReady: boolean
isCopilotLspServerReady: boolean
setIsKclLspServerReady: (isKclLspServerReady: boolean) => void
setIsCopilotLspServerReady: (isCopilotLspServerReady: boolean) => void
buttonDownInStream: number | undefined
setButtonDownInStream: (buttonDownInStream: number | undefined) => void
didDragInStream: boolean
setDidDragInStream: (didDragInStream: boolean) => void
fileId: string
setFileId: (fileId: string) => void
streamDimensions: { streamWidth: number; streamHeight: number }
setStreamDimensions: (dimensions: {
streamWidth: number
streamHeight: number
}) => void
setHtmlRef: (ref: React.RefObject<HTMLDivElement>) => void
htmlRef: React.RefObject<HTMLDivElement> | null
showHomeMenu: boolean
setHomeShowMenu: (showMenu: boolean) => void
openPanes: SidebarType[]
setOpenPanes: (panes: SidebarType[]) => void
homeMenuItems: {
name: string
path: string
}[]
setHomeMenuItems: (items: { name: string; path: string }[]) => void
}
export const useStore = create<StoreState>()(
persist(
(set, get) => {
return {
setMediaStream: (mediaStream) => set({ mediaStream }),
isStreamReady: false,
setIsStreamReady: (isStreamReady) => set({ isStreamReady }),
isKclLspServerReady: false,
isCopilotLspServerReady: false,
setIsKclLspServerReady: (isKclLspServerReady) =>
set({ isKclLspServerReady }),
setIsCopilotLspServerReady: (isCopilotLspServerReady) =>
set({ isCopilotLspServerReady }),
buttonDownInStream: undefined,
setButtonDownInStream: (buttonDownInStream) => {
set({ buttonDownInStream })
},
setHtmlRef: (htmlRef) => {
set({ htmlRef })
},
htmlRef: null,
didDragInStream: false,
setDidDragInStream: (didDragInStream) => {
set({ didDragInStream })
},
// For stream event handling
fileId: '',
setFileId: (fileId) => set({ fileId }),
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
setStreamDimensions: (streamDimensions) => {
set({ streamDimensions })
},
// tauri specific app settings
defaultDir: {
dir: '',
},
openPanes: ['code'],
setOpenPanes: (openPanes) => set({ openPanes }),
showHomeMenu: true,
setHomeShowMenu: (showHomeMenu) => set({ showHomeMenu }),
homeMenuItems: [],
setHomeMenuItems: (homeMenuItems) => set({ homeMenuItems }),
}
},
{
name: 'store',
partialize: (state) =>
Object.fromEntries(
Object.entries(state).filter(([key]) => ['openPanes'].includes(key))
),
}
)
)
export async function executeAst({
ast,
engineCommandManager,
useFakeExecutor = false,
programMemoryOverride,
}: {
ast: Program
engineCommandManager: EngineCommandManager
useFakeExecutor?: boolean
programMemoryOverride?: ProgramMemory
}): Promise<{
logs: string[]
errors: KCLError[]
programMemory: ProgramMemory
}> {
try {
if (!useFakeExecutor) {
engineCommandManager.endSession()
engineCommandManager.startNewSession()
}
const programMemory = await (useFakeExecutor
? enginelessExecutor(ast, programMemoryOverride || programMemoryInit())
: _executor(ast, programMemoryInit(), engineCommandManager, false))
await engineCommandManager.waitForAllCommands()
return {
logs: [],
errors: [],
programMemory,
}
} catch (e: any) {
if (e instanceof KCLError) {
return {
errors: [e],
logs: [],
programMemory: {
root: {},
return: null,
},
}
} else {
console.log(e)
return {
logs: [e],
errors: [],
programMemory: {
root: {},
return: null,
},
}
}
}
}
export async function lintAst({
ast,
}: {
ast: Program
}): Promise<Array<Diagnostic>> {
try {
const discovered_findings = await kclLint(ast)
return discovered_findings.map((lint) => {
return {
message: lint.finding.title,
severity: 'info',
from: lint.pos[0],
to: lint.pos[1],
}
})
} catch (e: any) {
console.log(e)
return []
}
}

View File

@ -2606,9 +2606,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.119"
version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8eddb61f0697cc3989c5d64b452f5488e2b8a60fd7d5076a3045076ffef8cb0"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"indexmap 2.2.5",
"itoa",

View File

@ -15,7 +15,7 @@ clap = "4.5.7"
gloo-utils = "0.2.0"
kcl-lib = { path = "kcl" }
kittycad.workspace = true
serde_json = "1.0.119"
serde_json = "1.0.120"
tokio = { version = "1.38.0", features = ["sync"] }
toml = "0.8.14"
uuid = { version = "1.9.1", features = ["v4", "js", "serde"] }

View File

@ -11,5 +11,5 @@ hyper = { version = "0.14.29", features = ["server"] }
kcl-lib = { version = "0.1.62", path = "../kcl" }
pico-args = "0.5.0"
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.119"
serde_json = "1.0.120"
tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }

View File

@ -33,7 +33,7 @@ reqwest = { version = "0.11.26", default-features = false, features = ["stream",
ropey = "1.6.1"
schemars = { version = "0.8.17", features = ["impl_json_schema", "url", "uuid1"] }
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.119"
serde_json = "1.0.120"
sha2 = "0.10.8"
thiserror = "1.0.61"
toml = "0.8.14"

View File

@ -69,6 +69,7 @@ impl StdLibFnArg {
|| self.type_ == "ExtrudeGroup"
|| self.type_ == "ExtrudeGroupSet"
|| self.type_ == "SketchSurface"
|| self.type_ == "SketchSurfaceOrGroup"
{
return Ok(Some((index, format!("${{{}:{}}}", index, "%"))));
} else if self.type_ == "TagDeclarator" && self.required {
@ -894,4 +895,11 @@ mod tests {
}, ${2:%})${}"#
);
}
#[test]
fn get_autocomplete_snippet_circle() {
let circle_fn: Box<dyn StdLibFn> = Box::new(crate::std::shapes::Circle);
let snippet = circle_fn.to_autocomplete_snippet().unwrap();
assert_eq!(snippet, r#"circle([${0:3.14}, ${1:3.14}], ${2:3.14}, ${3:%})${}"#);
}
}

View File

@ -1697,12 +1697,12 @@
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@playwright/test@^1.44.1":
version "1.44.1"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.44.1.tgz#cc874ec31342479ad99838040e99b5f604299bcb"
integrity sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==
"@playwright/test@^1.45.1":
version "1.45.1"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.45.1.tgz#819b90fa43d17000fce5ebd127043fd661938b7a"
integrity sha512-Wo1bWTzQvGA7LyKGIZc8nFSTFf2TkthGIFBR+QVNilvwouGzFd4PYukZe3rvf5PSqjHi1+1NyKSDZKcQWETzaA==
dependencies:
playwright "1.44.1"
playwright "1.45.1"
"@promptbook/utils@0.50.0-10":
version "0.50.0-10"
@ -5145,10 +5145,10 @@ html-encoding-sniffer@^3.0.0:
dependencies:
whatwg-encoding "^2.0.0"
html2canvas-pro@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/html2canvas-pro/-/html2canvas-pro-1.5.0.tgz#18925def43505bad352a394b95fffb45d6d46a8f"
integrity sha512-izxSphcINRwfEVV6eamsPVdhsxSYqX8n/hxzK+niVWdB+onM+aYRoVO+xgS9iMmZoUleZTWg1tJwryikib2hXg==
html2canvas-pro@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/html2canvas-pro/-/html2canvas-pro-1.5.1.tgz#e62aea27c598152308be35754b8b0f188908e171"
integrity sha512-6LmbLb3qNg8f3jSSRdzDwG7c9VIFDC9jOP3iZ6mK1cjc9W6F2Mkh/n2WmBECxAzF2yHEznJFmgbQAut1g+NbEQ==
dependencies:
css-line-break "^2.1.0"
text-segmentation "^1.0.3"
@ -6632,17 +6632,17 @@ pkg-types@^1.0.3, pkg-types@^1.1.1:
mlly "^1.7.0"
pathe "^1.1.2"
playwright-core@1.44.1:
version "1.44.1"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.44.1.tgz#53ec975503b763af6fc1a7aa995f34bc09ff447c"
integrity sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==
playwright-core@1.45.1:
version "1.45.1"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.45.1.tgz#549a2701556b58245cc75263f9fc2795c1158dc1"
integrity sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==
playwright@1.44.1:
version "1.44.1"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.44.1.tgz#5634369d777111c1eea9180430b7a184028e7892"
integrity sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==
playwright@1.45.1:
version "1.45.1"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.45.1.tgz#aaa6b0d6db14796b599d80c6679e63444e942534"
integrity sha512-Hjrgae4kpSQBr98nhCj3IScxVeVUixqj+5oyif8TdIn2opTCPEzqAqNMeK42i3cWDCVu9MI+ZsGWw+gVR4ISBg==
dependencies:
playwright-core "1.44.1"
playwright-core "1.45.1"
optionalDependencies:
fsevents "2.3.2"
@ -7848,10 +7848,10 @@ thenify-all@^1.0.0:
dependencies:
any-promise "^1.0.0"
three@^0.164.1:
version "0.164.1"
resolved "https://registry.yarnpkg.com/three/-/three-0.164.1.tgz#b742f76bd8dfd3736ba0d86a12dfddb73c5cdcc0"
integrity sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==
three@^0.166.1:
version "0.166.1"
resolved "https://registry.yarnpkg.com/three/-/three-0.166.1.tgz#322cfc48fff4e751cd47d61fd1558c387d098d7c"
integrity sha512-LtuafkKHHzm61AQA1be2MAYIw1IjmhOUxhBa0prrLpEMWbV7ijvxCRHjSgHPGp2493wLBzwKV46tA9nivLEgKg==
through@^2.3.8:
version "2.3.8"
@ -8159,11 +8159,6 @@ use-latest@^1.2.1:
dependencies:
use-isomorphic-layout-effect "^1.1.1"
use-sync-external-store@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
use-sync-external-store@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
@ -8343,10 +8338,10 @@ warning@^4.0.3:
dependencies:
loose-envify "^1.0.0"
wasm-pack@^0.12.1:
version "0.12.1"
resolved "https://registry.yarnpkg.com/wasm-pack/-/wasm-pack-0.12.1.tgz#974c1fbbf5b65c9e135e0d1fba3a97de1a21a489"
integrity sha512-dIyKWUumPFsGohdndZjDXRFaokUT/kQS+SavbbiXVAvA/eN4riX5QNdB6AhXQx37zNxluxQkuixZUgJ8adKjOg==
wasm-pack@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/wasm-pack/-/wasm-pack-0.13.0.tgz#c2637e0129e1854735f3daead45d92165d54709d"
integrity sha512-AmboGZEnZoIcVCzSlkLEmNFEqJN+IwgshJ5S7pi30uNUTce4LvWkifQzsQRxnWj47G8gkqZxlyGlyQplsnIS7w==
dependencies:
binary-install "^1.0.1"
@ -8718,10 +8713,3 @@ zip-stream@^6.0.1:
archiver-utils "^5.0.0"
compress-commons "^6.0.2"
readable-stream "^4.0.0"
zustand@^4.5.2:
version "4.5.2"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.2.tgz#fddbe7cac1e71d45413b3682cdb47b48034c3848"
integrity sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==
dependencies:
use-sync-external-store "1.2.0"