Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
c0f04d5f86 | |||
3dbc701f26 | |||
16e7ae38e3 | |||
24c7260327 | |||
72cfc4a471 | |||
2d128ed32e | |||
cd6749ba02 | |||
7243405e1b | |||
c8da057ec2 | |||
220fe5b2b8 | |||
4e6429de49 | |||
5391a65b18 | |||
592628917a | |||
4c6e8633f7 | |||
c5150468a2 | |||
39126dbff1 | |||
f86a69f12a | |||
de354ee5d3 | |||
dfef7338ee | |||
ee08948f54 | |||
832f6b65e2 | |||
68efd77c5d |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -377,6 +377,8 @@ jobs:
|
|||||||
TS_NODE_COMPILER_OPTIONS: '{"module": "commonjs"}'
|
TS_NODE_COMPILER_OPTIONS: '{"module": "commonjs"}'
|
||||||
|
|
||||||
publish-apps-release:
|
publish-apps-release:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }}
|
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]
|
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
13
package.json
13
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.22.7",
|
"version": "0.23.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.16.3",
|
"@codemirror/autocomplete": "^6.16.3",
|
||||||
@ -35,7 +35,7 @@
|
|||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"decamelize": "^6.0.0",
|
"decamelize": "^6.0.0",
|
||||||
"fuse.js": "^7.0.0",
|
"fuse.js": "^7.0.0",
|
||||||
"html2canvas-pro": "^1.5.0",
|
"html2canvas-pro": "^1.5.1",
|
||||||
"json-rpc-2.0": "^1.6.0",
|
"json-rpc-2.0": "^1.6.0",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"re-resizable": "^6.9.11",
|
"re-resizable": "^6.9.11",
|
||||||
@ -48,7 +48,7 @@
|
|||||||
"react-modal-promise": "^1.0.2",
|
"react-modal-promise": "^1.0.2",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"sketch-helpers": "^0.0.4",
|
"sketch-helpers": "^0.0.4",
|
||||||
"three": "^0.164.1",
|
"three": "^0.166.1",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"ua-parser-js": "^1.0.37",
|
"ua-parser-js": "^1.0.37",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
@ -56,8 +56,7 @@
|
|||||||
"vscode-languageserver-protocol": "^3.17.5",
|
"vscode-languageserver-protocol": "^3.17.5",
|
||||||
"vscode-uri": "^3.0.8",
|
"vscode-uri": "^3.0.8",
|
||||||
"web-vitals": "^3.5.2",
|
"web-vitals": "^3.5.2",
|
||||||
"xstate": "^4.38.2",
|
"xstate": "^4.38.2"
|
||||||
"zustand": "^4.5.2"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
@ -110,7 +109,7 @@
|
|||||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
"@babel/preset-env": "^7.24.3",
|
"@babel/preset-env": "^7.24.3",
|
||||||
"@iarna/toml": "^2.2.5",
|
"@iarna/toml": "^2.2.5",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.45.1",
|
||||||
"@tauri-apps/cli": "==2.0.0-beta.13",
|
"@tauri-apps/cli": "==2.0.0-beta.13",
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@testing-library/react": "^15.0.2",
|
"@testing-library/react": "^15.0.2",
|
||||||
@ -158,7 +157,7 @@
|
|||||||
"vitest": "^1.6.0",
|
"vitest": "^1.6.0",
|
||||||
"vitest-webgl-canvas-mock": "^1.1.0",
|
"vitest-webgl-canvas-mock": "^1.1.0",
|
||||||
"wait-on": "^7.2.0",
|
"wait-on": "^7.2.0",
|
||||||
"wasm-pack": "^0.12.1",
|
"wasm-pack": "^0.13.0",
|
||||||
"ws": "^8.17.0",
|
"ws": "^8.17.0",
|
||||||
"yarn": "^1.22.22"
|
"yarn": "^1.22.22"
|
||||||
}
|
}
|
||||||
|
@ -74,5 +74,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"productName": "Zoo Modeling App",
|
"productName": "Zoo Modeling App",
|
||||||
"version": "0.22.7"
|
"version": "0.23.0"
|
||||||
}
|
}
|
||||||
|
28
src/App.tsx
28
src/App.tsx
@ -1,6 +1,5 @@
|
|||||||
import { MouseEventHandler, useEffect, useRef } from 'react'
|
import { MouseEventHandler, useEffect, useMemo, useRef } from 'react'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
import { useStore } from './useStore'
|
|
||||||
import { useHotKeyListener } from './hooks/useHotKeyListener'
|
import { useHotKeyListener } from './hooks/useHotKeyListener'
|
||||||
import { Stream } from './components/Stream'
|
import { Stream } from './components/Stream'
|
||||||
import { EngineCommand } from './lang/std/engineConnection'
|
import { EngineCommand } from './lang/std/engineConnection'
|
||||||
@ -26,6 +25,7 @@ import ModalContainer from 'react-modal-promise'
|
|||||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
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 { useAppState } from 'AppState'
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
useRefreshSettings(paths.FILE + 'SETTINGS')
|
useRefreshSettings(paths.FILE + 'SETTINGS')
|
||||||
@ -44,22 +44,20 @@ export function App() {
|
|||||||
}, [projectName, projectPath])
|
}, [projectName, projectPath])
|
||||||
|
|
||||||
useHotKeyListener()
|
useHotKeyListener()
|
||||||
const { buttonDownInStream, didDragInStream, streamDimensions, setHtmlRef } =
|
const { context } = useModelingContext()
|
||||||
useStore((s) => ({
|
const { setAppState } = useAppState()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
didDragInStream: s.didDragInStream,
|
|
||||||
streamDimensions: s.streamDimensions,
|
|
||||||
setHtmlRef: s.setHtmlRef,
|
|
||||||
}))
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHtmlRef(ref)
|
setAppState({ htmlRef: ref })
|
||||||
}, [ref])
|
}, [ref])
|
||||||
|
|
||||||
const { auth, settings } = useSettingsAuthContext()
|
const { auth, settings } = useSettingsAuthContext()
|
||||||
const token = auth?.context?.token
|
const token = auth?.context?.token
|
||||||
|
|
||||||
const coreDumpManager = new CoreDumpManager(engineCommandManager, ref, token)
|
const coreDumpManager = useMemo(
|
||||||
|
() => new CoreDumpManager(engineCommandManager, ref, token),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
app: { onboardingStatus },
|
app: { onboardingStatus },
|
||||||
@ -81,7 +79,7 @@ export function App() {
|
|||||||
(p) => p === onboardingStatus.current
|
(p) => p === onboardingStatus.current
|
||||||
)
|
)
|
||||||
? 'opacity-20'
|
? 'opacity-20'
|
||||||
: didDragInStream
|
: context.store?.didDragInStream
|
||||||
? 'opacity-40'
|
? 'opacity-40'
|
||||||
: ''
|
: ''
|
||||||
|
|
||||||
@ -99,11 +97,11 @@ export function App() {
|
|||||||
clientX: e.clientX,
|
clientX: e.clientX,
|
||||||
clientY: e.clientY,
|
clientY: e.clientY,
|
||||||
el: e.currentTarget,
|
el: e.currentTarget,
|
||||||
...streamDimensions,
|
...context.store?.streamDimensions,
|
||||||
})
|
})
|
||||||
|
|
||||||
const newCmdId = uuidv4()
|
const newCmdId = uuidv4()
|
||||||
if (buttonDownInStream === undefined) {
|
if (context.store?.buttonDownInStream === undefined) {
|
||||||
debounceSocketSend({
|
debounceSocketSend({
|
||||||
type: 'modeling_cmd_req',
|
type: 'modeling_cmd_req',
|
||||||
cmd: {
|
cmd: {
|
||||||
@ -125,7 +123,7 @@ export function App() {
|
|||||||
className={
|
className={
|
||||||
'transition-opacity transition-duration-75 ' +
|
'transition-opacity transition-duration-75 ' +
|
||||||
paneOpacity +
|
paneOpacity +
|
||||||
(buttonDownInStream ? ' pointer-events-none' : '')
|
(context.store?.buttonDownInStream ? ' pointer-events-none' : '')
|
||||||
}
|
}
|
||||||
project={{ project, file }}
|
project={{ project, file }}
|
||||||
enableMenu={true}
|
enableMenu={true}
|
||||||
|
45
src/AppState.tsx
Normal file
45
src/AppState.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
@ -33,6 +33,14 @@ import LspProvider from 'components/LspProvider'
|
|||||||
import { KclContextProvider } from 'lang/KclProvider'
|
import { KclContextProvider } from 'lang/KclProvider'
|
||||||
import { BROWSER_PROJECT_NAME } from 'lib/constants'
|
import { BROWSER_PROJECT_NAME } from 'lib/constants'
|
||||||
import { getState, setState } from 'lib/tauri'
|
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([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@ -45,7 +53,9 @@ const router = createBrowserRouter([
|
|||||||
<SettingsAuthProvider>
|
<SettingsAuthProvider>
|
||||||
<LspProvider>
|
<LspProvider>
|
||||||
<KclContextProvider>
|
<KclContextProvider>
|
||||||
<Outlet />
|
<AppStateProvider>
|
||||||
|
<Outlet />
|
||||||
|
</AppStateProvider>
|
||||||
</KclContextProvider>
|
</KclContextProvider>
|
||||||
</LspProvider>
|
</LspProvider>
|
||||||
</SettingsAuthProvider>
|
</SettingsAuthProvider>
|
||||||
@ -87,6 +97,7 @@ const router = createBrowserRouter([
|
|||||||
<Auth>
|
<Auth>
|
||||||
<FileMachineProvider>
|
<FileMachineProvider>
|
||||||
<ModelingMachineProvider>
|
<ModelingMachineProvider>
|
||||||
|
<CoreDump />
|
||||||
<Outlet />
|
<Outlet />
|
||||||
<App />
|
<App />
|
||||||
<CommandBar />
|
<CommandBar />
|
||||||
@ -165,3 +176,31 @@ export const Router = () => {
|
|||||||
</NetworkContext.Provider>
|
</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
|
||||||
|
}
|
||||||
|
@ -8,10 +8,10 @@ import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
|||||||
import { ActionButton } from 'components/ActionButton'
|
import { ActionButton } from 'components/ActionButton'
|
||||||
import { isSingleCursorInPipe } from 'lang/queryAst'
|
import { isSingleCursorInPipe } from 'lang/queryAst'
|
||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
|
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import Tooltip from 'components/Tooltip'
|
import Tooltip from 'components/Tooltip'
|
||||||
|
import { useAppState } from 'AppState'
|
||||||
|
|
||||||
export function Toolbar({
|
export function Toolbar({
|
||||||
className = '',
|
className = '',
|
||||||
@ -38,9 +38,8 @@ export function Toolbar({
|
|||||||
const toolbarButtonsRef = useRef<HTMLUListElement>(null)
|
const toolbarButtonsRef = useRef<HTMLUListElement>(null)
|
||||||
const { overallState } = useNetworkContext()
|
const { overallState } = useNetworkContext()
|
||||||
const { isExecuting } = useKclContext()
|
const { isExecuting } = useKclContext()
|
||||||
const { isStreamReady } = useStore((s) => ({
|
const { isStreamReady } = useAppState()
|
||||||
isStreamReady: s.isStreamReady,
|
|
||||||
}))
|
|
||||||
const disableAllButtons =
|
const disableAllButtons =
|
||||||
(overallState !== NetworkHealthState.Ok &&
|
(overallState !== NetworkHealthState.Ok &&
|
||||||
overallState !== NetworkHealthState.Weak) ||
|
overallState !== NetworkHealthState.Weak) ||
|
||||||
|
@ -37,7 +37,7 @@ import { Dialog, Popover, Transition } from '@headlessui/react'
|
|||||||
import { LineInputsType } from 'lang/std/sketchcombos'
|
import { LineInputsType } from 'lang/std/sketchcombos'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { InstanceProps, create } from 'react-modal-promise'
|
import { InstanceProps, create } from 'react-modal-promise'
|
||||||
import { executeAst } from 'useStore'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import {
|
import {
|
||||||
deleteSegmentFromPipeExpression,
|
deleteSegmentFromPipeExpression,
|
||||||
makeRemoveSingleConstraintInput,
|
makeRemoveSingleConstraintInput,
|
||||||
|
@ -58,7 +58,7 @@ import {
|
|||||||
editorManager,
|
editorManager,
|
||||||
} from 'lib/singletons'
|
} from 'lib/singletons'
|
||||||
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
|
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
|
||||||
import { executeAst, useStore } from 'useStore'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import {
|
import {
|
||||||
createArcGeometry,
|
createArcGeometry,
|
||||||
dashedStraight,
|
dashedStraight,
|
||||||
@ -1444,11 +1444,10 @@ export class SceneEntities {
|
|||||||
selected.material.color = defaultPlaneColor(type)
|
selected.material.color = defaultPlaneColor(type)
|
||||||
},
|
},
|
||||||
onClick: async (args) => {
|
onClick: async (args) => {
|
||||||
const { streamDimensions } = useStore.getState()
|
|
||||||
const { entity_id } = await sendSelectEventToEngine(
|
const { entity_id } = await sendSelectEventToEngine(
|
||||||
args?.mouseEvent,
|
args?.mouseEvent,
|
||||||
document.getElementById('video-stream') as HTMLVideoElement,
|
document.getElementById('video-stream') as HTMLVideoElement,
|
||||||
streamDimensions
|
sceneInfra._streamDimensions
|
||||||
)
|
)
|
||||||
|
|
||||||
let _entity_id = entity_id
|
let _entity_id = entity_id
|
||||||
|
@ -103,6 +103,10 @@ export class SceneInfra {
|
|||||||
_baseUnit: BaseUnit = 'mm'
|
_baseUnit: BaseUnit = 'mm'
|
||||||
_baseUnitMultiplier = 1
|
_baseUnitMultiplier = 1
|
||||||
_theme: Themes = Themes.System
|
_theme: Themes = Themes.System
|
||||||
|
_streamDimensions: { streamWidth: number; streamHeight: number } = {
|
||||||
|
streamWidth: 1280,
|
||||||
|
streamHeight: 720,
|
||||||
|
}
|
||||||
extraSegmentTexture: Texture
|
extraSegmentTexture: Texture
|
||||||
lastMouseState: MouseState = { type: 'idle' }
|
lastMouseState: MouseState = { type: 'idle' }
|
||||||
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||||
|
@ -10,7 +10,7 @@ import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst'
|
|||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
import { useModelingContext } from 'hooks/useModelingContext'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
import { executeAst } from 'useStore'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import { trap } from 'lib/trap'
|
import { trap } from 'lib/trap'
|
||||||
|
|
||||||
export const AvailableVars = ({
|
export const AvailableVars = ({
|
||||||
|
@ -24,7 +24,7 @@ export const CommandBar = () => {
|
|||||||
}, [pathname])
|
}, [pathname])
|
||||||
|
|
||||||
// Hook up keyboard shortcuts
|
// Hook up keyboard shortcuts
|
||||||
useHotkeyWrapper(['mod+k', 'ctrl+c'], () => {
|
useHotkeyWrapper(['mod+k'], () => {
|
||||||
if (commandBarState.context.commands.length === 0) return
|
if (commandBarState.context.commands.length === 0) return
|
||||||
if (commandBarState.matches('Closed')) {
|
if (commandBarState.matches('Closed')) {
|
||||||
commandBarSend({ type: 'Open' })
|
commandBarSend({ type: 'Open' })
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
import type * as LSP from 'vscode-languageserver-protocol'
|
import type * as LSP from 'vscode-languageserver-protocol'
|
||||||
import React, {
|
import React, { createContext, useMemo, useContext, useState } from 'react'
|
||||||
createContext,
|
|
||||||
useMemo,
|
|
||||||
useEffect,
|
|
||||||
useContext,
|
|
||||||
useState,
|
|
||||||
} from 'react'
|
|
||||||
import {
|
import {
|
||||||
LanguageServerClient,
|
LanguageServerClient,
|
||||||
FromServer,
|
FromServer,
|
||||||
@ -16,7 +10,6 @@ import {
|
|||||||
import { TEST, VITE_KC_API_BASE_URL } from 'env'
|
import { TEST, VITE_KC_API_BASE_URL } from 'env'
|
||||||
import KclLanguageSupport from 'editor/plugins/lsp/kcl/language'
|
import KclLanguageSupport from 'editor/plugins/lsp/kcl/language'
|
||||||
import { copilotPlugin } from 'editor/plugins/lsp/copilot'
|
import { copilotPlugin } from 'editor/plugins/lsp/copilot'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
import { Extension } from '@codemirror/state'
|
import { Extension } from '@codemirror/state'
|
||||||
import { LanguageSupport } from '@codemirror/language'
|
import { LanguageSupport } from '@codemirror/language'
|
||||||
@ -73,19 +66,8 @@ type LspContext = {
|
|||||||
|
|
||||||
export const LspStateContext = createContext({} as LspContext)
|
export const LspStateContext = createContext({} as LspContext)
|
||||||
export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
const {
|
const [isKclLspReady, setIsKclLspReady] = useState(false)
|
||||||
isKclLspServerReady,
|
const [isCopilotLspReady, setIsCopilotLspReady] = useState(false)
|
||||||
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 {
|
const {
|
||||||
auth,
|
auth,
|
||||||
@ -132,7 +114,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
fromServer,
|
fromServer,
|
||||||
intoServer,
|
intoServer,
|
||||||
initializedCallback: () => {
|
initializedCallback: () => {
|
||||||
setIsLspReady(true)
|
setIsKclLspReady(true)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -143,7 +125,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
])
|
])
|
||||||
|
|
||||||
useMemo(() => {
|
useMemo(() => {
|
||||||
if (!isTauri() && isKclLspServerReady && kclLspClient && codeManager.code) {
|
if (!isTauri() && isKclLspReady && kclLspClient && codeManager.code) {
|
||||||
kclLspClient.textDocumentDidOpen({
|
kclLspClient.textDocumentDidOpen({
|
||||||
textDocument: {
|
textDocument: {
|
||||||
uri: `file:///${PROJECT_ENTRYPOINT}`,
|
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.
|
// 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
|
// 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.
|
// We do not want to restart the server, its just wasteful.
|
||||||
const kclLSP = useMemo(() => {
|
const kclLSP = useMemo(() => {
|
||||||
let plugin = null
|
let plugin = null
|
||||||
if (isKclLspServerReady && !TEST && kclLspClient) {
|
if (isKclLspReady && !TEST && kclLspClient) {
|
||||||
// Set up the lsp plugin.
|
// Set up the lsp plugin.
|
||||||
const lsp = new KclLanguageSupport({
|
const lsp = new KclLanguageSupport({
|
||||||
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
||||||
@ -193,7 +175,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
plugin = lsp
|
plugin = lsp
|
||||||
}
|
}
|
||||||
return plugin
|
return plugin
|
||||||
}, [kclLspClient, isKclLspServerReady])
|
}, [kclLspClient, isKclLspReady])
|
||||||
|
|
||||||
const { lspClient: copilotLspClient } = useMemo(() => {
|
const { lspClient: copilotLspClient } = useMemo(() => {
|
||||||
if (!token || token === '' || TEST) {
|
if (!token || token === '' || TEST) {
|
||||||
@ -225,7 +207,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
fromServer,
|
fromServer,
|
||||||
intoServer,
|
intoServer,
|
||||||
initializedCallback: () => {
|
initializedCallback: () => {
|
||||||
setIsCopilotReady(true)
|
setIsCopilotLspReady(true)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return { lspClient }
|
return { lspClient }
|
||||||
@ -238,7 +220,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
// We do not want to restart the server, its just wasteful.
|
// We do not want to restart the server, its just wasteful.
|
||||||
const copilotLSP = useMemo(() => {
|
const copilotLSP = useMemo(() => {
|
||||||
let plugin = null
|
let plugin = null
|
||||||
if (isCopilotLspServerReady && !TEST && copilotLspClient) {
|
if (isCopilotLspReady && !TEST && copilotLspClient) {
|
||||||
// Set up the lsp plugin.
|
// Set up the lsp plugin.
|
||||||
const lsp = copilotPlugin({
|
const lsp = copilotPlugin({
|
||||||
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
||||||
@ -250,7 +232,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
plugin = lsp
|
plugin = lsp
|
||||||
}
|
}
|
||||||
return plugin
|
return plugin
|
||||||
}, [copilotLspClient, isCopilotLspServerReady])
|
}, [copilotLspClient, isCopilotLspReady])
|
||||||
|
|
||||||
let lspClients: LanguageServerClient[] = []
|
let lspClients: LanguageServerClient[] = []
|
||||||
if (kclLspClient) {
|
if (kclLspClient) {
|
||||||
@ -260,13 +242,6 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
lspClients.push(copilotLspClient)
|
lspClients.push(copilotLspClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsKclLspServerReady(isLspReady)
|
|
||||||
}, [isLspReady])
|
|
||||||
useEffect(() => {
|
|
||||||
setIsCopilotLspServerReady(isCopilotReady)
|
|
||||||
}, [isCopilotReady])
|
|
||||||
|
|
||||||
const onProjectClose = (
|
const onProjectClose = (
|
||||||
file: FileEntry | null,
|
file: FileEntry | null,
|
||||||
projectPath: string | null,
|
projectPath: string | null,
|
||||||
|
@ -30,7 +30,6 @@ import {
|
|||||||
applyConstraintAngleBetween,
|
applyConstraintAngleBetween,
|
||||||
} from './Toolbar/SetAngleBetween'
|
} from './Toolbar/SetAngleBetween'
|
||||||
import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
|
import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import {
|
import {
|
||||||
Selections,
|
Selections,
|
||||||
canExtrudeSelection,
|
canExtrudeSelection,
|
||||||
@ -54,13 +53,7 @@ import {
|
|||||||
sketchOnExtrudedFace,
|
sketchOnExtrudedFace,
|
||||||
startSketchOnDefault,
|
startSketchOnDefault,
|
||||||
} from 'lang/modifyAst'
|
} from 'lang/modifyAst'
|
||||||
import {
|
import { Program, VariableDeclaration, parse, recast } from 'lang/wasm'
|
||||||
Program,
|
|
||||||
VariableDeclaration,
|
|
||||||
coreDump,
|
|
||||||
parse,
|
|
||||||
recast,
|
|
||||||
} from 'lang/wasm'
|
|
||||||
import {
|
import {
|
||||||
getNodeFromPath,
|
getNodeFromPath,
|
||||||
getNodePathFromSourceRange,
|
getNodePathFromSourceRange,
|
||||||
@ -72,11 +65,9 @@ import { exportFromEngine } from 'lib/exportFromEngine'
|
|||||||
import { Models } from '@kittycad/lib/dist/types/src'
|
import { Models } from '@kittycad/lib/dist/types/src'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { EditorSelection, Transaction } from '@uiw/react-codemirror'
|
import { EditorSelection, Transaction } from '@uiw/react-codemirror'
|
||||||
import { CoreDumpManager } from 'lib/coredump'
|
|
||||||
import { useSearchParams } from 'react-router-dom'
|
import { useSearchParams } from 'react-router-dom'
|
||||||
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
|
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
|
||||||
import { getVarNameModal } from 'hooks/useToolbarGuards'
|
import { getVarNameModal } from 'hooks/useToolbarGuards'
|
||||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
import { err, trap } from 'lib/trap'
|
import { err, trap } from 'lib/trap'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
@ -112,38 +103,6 @@ export const ModelingMachineProvider = ({
|
|||||||
let [searchParams] = useSearchParams()
|
let [searchParams] = useSearchParams()
|
||||||
const pool = searchParams.get('pool')
|
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()
|
const { commandBarState } = useCommandsContext()
|
||||||
|
|
||||||
// Settings machine setup
|
// Settings machine setup
|
||||||
@ -163,6 +122,12 @@ export const ModelingMachineProvider = ({
|
|||||||
modelingMachine,
|
modelingMachine,
|
||||||
{
|
{
|
||||||
actions: {
|
actions: {
|
||||||
|
'disable copilot': () => {
|
||||||
|
editorManager.setCopilotEnabled(false)
|
||||||
|
},
|
||||||
|
'enable copilot': () => {
|
||||||
|
editorManager.setCopilotEnabled(true)
|
||||||
|
},
|
||||||
'sketch exit execute': () => {
|
'sketch exit execute': () => {
|
||||||
;(async () => {
|
;(async () => {
|
||||||
await sceneInfra.camControls.snapToPerspectiveBeforeHandingBackControlToEngine()
|
await sceneInfra.camControls.snapToPerspectiveBeforeHandingBackControlToEngine()
|
||||||
@ -514,11 +479,15 @@ export const ModelingMachineProvider = ({
|
|||||||
services: {
|
services: {
|
||||||
'AST-undo-startSketchOn': async ({ sketchDetails }) => {
|
'AST-undo-startSketchOn': async ({ sketchDetails }) => {
|
||||||
if (!sketchDetails) return
|
if (!sketchDetails) return
|
||||||
const newAst: Program = JSON.parse(JSON.stringify(kclManager.ast))
|
if (kclManager.ast.body.length) {
|
||||||
const varDecIndex = sketchDetails.sketchPathToNode[1][0]
|
// this assumes no changes have been made to the sketch besides what we did when entering the sketch
|
||||||
// remove body item at varDecIndex
|
// i.e. doesn't account for user's adding code themselves, maybe we need store a flag userEditedSinceSketchMode?
|
||||||
newAst.body = newAst.body.filter((_, i) => i !== varDecIndex)
|
const newAst: Program = JSON.parse(JSON.stringify(kclManager.ast))
|
||||||
await kclManager.executeAstMock(newAst)
|
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({
|
sceneInfra.setCallbacks({
|
||||||
onClick: () => {},
|
onClick: () => {},
|
||||||
onDrag: () => {},
|
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(() => {
|
useEffect(() => {
|
||||||
kclManager.registerExecuteCallback(() => {
|
kclManager.registerExecuteCallback(() => {
|
||||||
modelingSend({ type: 'Re-execute' })
|
modelingSend({ type: 'Re-execute' })
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useStore } from 'useStore'
|
|
||||||
import styles from './ModelingPane.module.css'
|
import styles from './ModelingPane.module.css'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export interface ModelingPaneProps
|
export interface ModelingPaneProps
|
||||||
extends React.PropsWithChildren,
|
extends React.PropsWithChildren,
|
||||||
@ -33,11 +33,9 @@ export const ModelingPane = ({
|
|||||||
}: ModelingPaneProps) => {
|
}: ModelingPaneProps) => {
|
||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const onboardingStatus = settings.context.app.onboardingStatus
|
const onboardingStatus = settings.context.app.onboardingStatus
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const pointerEventsCssClass =
|
const pointerEventsCssClass =
|
||||||
buttonDownInStream || onboardingStatus.current === 'camera'
|
context.store?.buttonDownInStream || onboardingStatus.current === 'camera'
|
||||||
? 'pointer-events-none '
|
? 'pointer-events-none '
|
||||||
: 'pointer-events-auto '
|
: 'pointer-events-auto '
|
||||||
return (
|
return (
|
||||||
|
@ -2,7 +2,6 @@ import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
|||||||
import { Resizable } from 're-resizable'
|
import { Resizable } from 're-resizable'
|
||||||
import { HTMLAttributes, useCallback, useEffect, useState } from 'react'
|
import { HTMLAttributes, useCallback, useEffect, useState } from 'react'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { Tab } from '@headlessui/react'
|
import { Tab } from '@headlessui/react'
|
||||||
import {
|
import {
|
||||||
SidebarPane,
|
SidebarPane,
|
||||||
@ -15,6 +14,7 @@ import { ActionIcon } from 'components/ActionIcon'
|
|||||||
import styles from './ModelingSidebar.module.css'
|
import styles from './ModelingSidebar.module.css'
|
||||||
import { ModelingPane } from './ModelingPane'
|
import { ModelingPane } from './ModelingPane'
|
||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
interface ModelingSidebarProps {
|
interface ModelingSidebarProps {
|
||||||
paneOpacity: '' | 'opacity-20' | 'opacity-40'
|
paneOpacity: '' | 'opacity-20' | 'opacity-40'
|
||||||
@ -23,14 +23,11 @@ interface ModelingSidebarProps {
|
|||||||
export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const onboardingStatus = settings.context.app.onboardingStatus
|
const onboardingStatus = settings.context.app.onboardingStatus
|
||||||
const { openPanes, buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
openPanes: s.openPanes,
|
|
||||||
}))
|
|
||||||
const pointerEventsCssClass =
|
const pointerEventsCssClass =
|
||||||
buttonDownInStream ||
|
context.store?.buttonDownInStream ||
|
||||||
onboardingStatus.current === 'camera' ||
|
onboardingStatus.current === 'camera' ||
|
||||||
openPanes.length === 0
|
context.store?.openPanes.length === 0
|
||||||
? 'pointer-events-none '
|
? 'pointer-events-none '
|
||||||
: 'pointer-events-auto '
|
: 'pointer-events-auto '
|
||||||
|
|
||||||
@ -45,7 +42,7 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
|||||||
maxWidth={800}
|
maxWidth={800}
|
||||||
handleClasses={{
|
handleClasses={{
|
||||||
right:
|
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 ',
|
'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',
|
left: 'hidden',
|
||||||
top: 'hidden',
|
top: 'hidden',
|
||||||
@ -82,11 +79,10 @@ function ModelingSidebarSection({
|
|||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const showDebugPanel = settings.context.modeling.showDebugPanel
|
const showDebugPanel = settings.context.modeling.showDebugPanel
|
||||||
const paneIds = panes.map((pane) => pane.id)
|
const paneIds = panes.map((pane) => pane.id)
|
||||||
const { openPanes, setOpenPanes } = useStore((s) => ({
|
const { send, context } = useModelingContext()
|
||||||
openPanes: s.openPanes,
|
const foundOpenPane = context.store?.openPanes.find((pane) =>
|
||||||
setOpenPanes: s.setOpenPanes,
|
paneIds.includes(pane)
|
||||||
}))
|
)
|
||||||
const foundOpenPane = openPanes.find((pane) => paneIds.includes(pane))
|
|
||||||
const [currentPane, setCurrentPane] = useState(
|
const [currentPane, setCurrentPane] = useState(
|
||||||
foundOpenPane || ('none' as SidebarType | 'none')
|
foundOpenPane || ('none' as SidebarType | 'none')
|
||||||
)
|
)
|
||||||
@ -94,17 +90,37 @@ function ModelingSidebarSection({
|
|||||||
const togglePane = useCallback(
|
const togglePane = useCallback(
|
||||||
(newPane: SidebarType | 'none') => {
|
(newPane: SidebarType | 'none') => {
|
||||||
if (newPane === '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')
|
setCurrentPane('none')
|
||||||
} else if (newPane === currentPane) {
|
} else if (newPane === currentPane) {
|
||||||
setCurrentPane('none')
|
setCurrentPane('none')
|
||||||
setOpenPanes(openPanes.filter((p) => p !== newPane))
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
openPanes: context.store?.openPanes.filter((p) => p !== newPane),
|
||||||
|
},
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
setOpenPanes([...openPanes.filter((p) => p !== currentPane), newPane])
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
openPanes: [
|
||||||
|
...context.store?.openPanes.filter((p) => p !== currentPane),
|
||||||
|
newPane,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
setCurrentPane(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
|
// Filter out the debug panel if it's not supposed to be shown
|
||||||
@ -122,11 +138,11 @@ function ModelingSidebarSection({
|
|||||||
if (
|
if (
|
||||||
!showDebugPanel.current &&
|
!showDebugPanel.current &&
|
||||||
currentPane === 'debug' &&
|
currentPane === 'debug' &&
|
||||||
openPanes.includes('debug')
|
context.store?.openPanes.includes('debug')
|
||||||
) {
|
) {
|
||||||
togglePane('debug')
|
togglePane('debug')
|
||||||
}
|
}
|
||||||
}, [showDebugPanel.current, togglePane, openPanes])
|
}, [showDebugPanel.current, togglePane, context.store?.openPanes])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'group contents ' + className} {...props}>
|
<div className={'group contents ' + className} {...props}>
|
||||||
@ -152,7 +168,9 @@ function ModelingSidebarSection({
|
|||||||
: ' border-r-0') +
|
: ' border-r-0') +
|
||||||
' p-2 col-start-1 col-span-1 h-fit w-fit flex flex-col items-start gap-2 ' +
|
' 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 ' +
|
'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">
|
<Tab key="none" className="sr-only">
|
||||||
@ -172,7 +190,7 @@ function ModelingSidebarSection({
|
|||||||
as="article"
|
as="article"
|
||||||
className={
|
className={
|
||||||
'col-start-2 col-span-1 ' +
|
'col-start-2 col-span-1 ' +
|
||||||
(openPanes.length === 1
|
(context.store?.openPanes.length === 1
|
||||||
? currentPane !== 'none'
|
? currentPane !== 'none'
|
||||||
? `row-start-1 row-end-3`
|
? `row-start-1 row-end-3`
|
||||||
: `hidden`
|
: `hidden`
|
||||||
|
@ -2,22 +2,19 @@ import { coreDump } from 'lang/wasm'
|
|||||||
import { CoreDumpManager } from 'lib/coredump'
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
import { CustomIcon } from './CustomIcon'
|
import { CustomIcon } from './CustomIcon'
|
||||||
import { engineCommandManager } from 'lib/singletons'
|
import { engineCommandManager } from 'lib/singletons'
|
||||||
import React from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import Tooltip from './Tooltip'
|
import Tooltip from './Tooltip'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
|
import { useAppState } from 'AppState'
|
||||||
|
|
||||||
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
|
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
|
||||||
const { auth } = useSettingsAuthContext()
|
const { auth } = useSettingsAuthContext()
|
||||||
const token = auth?.context?.token
|
const token = auth?.context?.token
|
||||||
const { htmlRef } = useStore((s) => ({
|
const { htmlRef } = useAppState()
|
||||||
htmlRef: s.htmlRef,
|
const coreDumpManager = useMemo(
|
||||||
}))
|
() => new CoreDumpManager(engineCommandManager, htmlRef, token),
|
||||||
const coreDumpManager = new CoreDumpManager(
|
[]
|
||||||
engineCommandManager,
|
|
||||||
htmlRef,
|
|
||||||
token
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
|
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
|
||||||
import { useStore } from '../useStore'
|
|
||||||
import { getNormalisedCoordinates } from '../lib/utils'
|
import { getNormalisedCoordinates } from '../lib/utils'
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
@ -10,25 +9,12 @@ import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
|
|||||||
import { butName } from 'lib/cameraControls'
|
import { butName } from 'lib/cameraControls'
|
||||||
import { sendSelectEventToEngine } from 'lib/selections'
|
import { sendSelectEventToEngine } from 'lib/selections'
|
||||||
|
|
||||||
export const Stream = ({ className = '' }: { className?: string }) => {
|
export const Stream = () => {
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
const [clickCoords, setClickCoords] = useState<{ x: number; y: number }>()
|
const [clickCoords, setClickCoords] = useState<{ x: number; y: number }>()
|
||||||
const videoRef = useRef<HTMLVideoElement>(null)
|
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 { settings } = useSettingsAuthContext()
|
||||||
const { state } = useModelingContext()
|
const { state, send, context } = useModelingContext()
|
||||||
const { overallState } = useNetworkContext()
|
const { overallState } = useNetworkContext()
|
||||||
|
|
||||||
const isNetworkOkay =
|
const isNetworkOkay =
|
||||||
@ -74,9 +60,9 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return
|
||||||
if (!mediaStream) return
|
if (!context.store?.mediaStream) return
|
||||||
videoRef.current.srcObject = mediaStream
|
videoRef.current.srcObject = context.store.mediaStream
|
||||||
}, [mediaStream])
|
}, [context.store?.mediaStream])
|
||||||
|
|
||||||
const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {
|
const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||||
if (!isNetworkOkay) return
|
if (!isNetworkOkay) return
|
||||||
@ -88,25 +74,44 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
|||||||
clientX: e.clientX,
|
clientX: e.clientX,
|
||||||
clientY: e.clientY,
|
clientY: e.clientY,
|
||||||
el: videoRef.current,
|
el: videoRef.current,
|
||||||
...streamDimensions,
|
...context.store?.streamDimensions,
|
||||||
})
|
})
|
||||||
|
|
||||||
setButtonDownInStream(e.button)
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
buttonDownInStream: e.button,
|
||||||
|
},
|
||||||
|
})
|
||||||
setClickCoords({ x, y })
|
setClickCoords({ x, y })
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
|
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||||
if (!isNetworkOkay) return
|
if (!isNetworkOkay) return
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return
|
||||||
setButtonDownInStream(undefined)
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
buttonDownInStream: undefined,
|
||||||
|
},
|
||||||
|
})
|
||||||
if (state.matches('Sketch')) return
|
if (state.matches('Sketch')) return
|
||||||
if (state.matches('Sketch no face')) return
|
if (state.matches('Sketch no face')) return
|
||||||
|
|
||||||
if (!didDragInStream && butName(e).left) {
|
if (!context.store?.didDragInStream && butName(e).left) {
|
||||||
sendSelectEventToEngine(e, videoRef.current, streamDimensions)
|
sendSelectEventToEngine(
|
||||||
|
e,
|
||||||
|
videoRef.current,
|
||||||
|
context.store?.streamDimensions
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setDidDragInStream(false)
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
didDragInStream: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
setClickCoords(undefined)
|
setClickCoords(undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,8 +125,13 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
|||||||
((clickCoords.x - e.clientX) ** 2 + (clickCoords.y - e.clientY) ** 2) **
|
((clickCoords.x - e.clientX) ** 2 + (clickCoords.y - e.clientY) ** 2) **
|
||||||
0.5
|
0.5
|
||||||
|
|
||||||
if (delta > 5 && !didDragInStream) {
|
if (delta > 5 && !context.store?.didDragInStream) {
|
||||||
setDidDragInStream(true)
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
didDragInStream: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { Program, ProgramMemory, Value } from '../../lang/wasm'
|
import { Program, ProgramMemory, Value } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selection, Selections } from 'lib/selections'
|
import { Selection, Selections } from 'lib/selections'
|
||||||
import { PathToNode, Program, Value } from '../../lang/wasm'
|
import { PathToNode, Program, Value } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { BinaryPart, Program, Value } from '../../lang/wasm'
|
import { BinaryPart, Program, Value } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
getNodePathFromSourceRange,
|
getNodePathFromSourceRange,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { BinaryPart, Program, Value } from '../../lang/wasm'
|
import { BinaryPart, Program, Value } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -27,6 +27,7 @@ function diagnosticIsEqual(d1: Diagnostic, d2: Diagnostic): boolean {
|
|||||||
|
|
||||||
export default class EditorManager {
|
export default class EditorManager {
|
||||||
private _editorView: EditorView | null = null
|
private _editorView: EditorView | null = null
|
||||||
|
private _copilotEnabled: boolean = true
|
||||||
|
|
||||||
private _isShiftDown: boolean = false
|
private _isShiftDown: boolean = false
|
||||||
private _selectionRanges: Selections = {
|
private _selectionRanges: Selections = {
|
||||||
@ -47,6 +48,14 @@ export default class EditorManager {
|
|||||||
|
|
||||||
private _highlightRange: [number, number] = [0, 0]
|
private _highlightRange: [number, number] = [0, 0]
|
||||||
|
|
||||||
|
setCopilotEnabled(enabled: boolean) {
|
||||||
|
this._copilotEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
get copilotEnabled(): boolean {
|
||||||
|
return this._copilotEnabled
|
||||||
|
}
|
||||||
|
|
||||||
setEditorView(editorView: EditorView) {
|
setEditorView(editorView: EditorView) {
|
||||||
this._editorView = editorView
|
this._editorView = editorView
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ import { CopilotLspCompletionParams } from 'wasm-lib/kcl/bindings/CopilotLspComp
|
|||||||
import { CopilotCompletionResponse } from 'wasm-lib/kcl/bindings/CopilotCompletionResponse'
|
import { CopilotCompletionResponse } from 'wasm-lib/kcl/bindings/CopilotCompletionResponse'
|
||||||
import { CopilotAcceptCompletionParams } from 'wasm-lib/kcl/bindings/CopilotAcceptCompletionParams'
|
import { CopilotAcceptCompletionParams } from 'wasm-lib/kcl/bindings/CopilotAcceptCompletionParams'
|
||||||
import { CopilotRejectCompletionParams } from 'wasm-lib/kcl/bindings/CopilotRejectCompletionParams'
|
import { CopilotRejectCompletionParams } from 'wasm-lib/kcl/bindings/CopilotRejectCompletionParams'
|
||||||
|
import { editorManager } from 'lib/singletons'
|
||||||
|
|
||||||
const copilotPluginAnnotation = Annotation.define<null>()
|
const copilotPluginAnnotation = Annotation.define<null>()
|
||||||
export const copilotPluginEvent = copilotPluginAnnotation.of(null)
|
export const copilotPluginEvent = copilotPluginAnnotation.of(null)
|
||||||
@ -269,6 +270,11 @@ export class CompletionRequester implements PluginValue {
|
|||||||
return
|
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.lastPos = this.viewUpdate.state.selection.main.head
|
||||||
this._deffererCodeUpdate(true)
|
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[] = [
|
const copilotAutocompleteKeymap: readonly KeyBinding[] = [
|
||||||
{
|
{
|
||||||
key: 'Tab',
|
key: 'Tab',
|
||||||
@ -633,27 +649,30 @@ export const copilotPlugin = (options: LanguageServerOptions): Extension => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'Backspace',
|
key: 'Backspace',
|
||||||
run: (view: EditorView): boolean => {
|
run: rejectSuggestionCommand,
|
||||||
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()
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'Delete',
|
key: 'Delete',
|
||||||
run: (view: EditorView): boolean => {
|
run: rejectSuggestionCommand,
|
||||||
if (view.plugin === null) return false
|
},
|
||||||
|
{ key: 'Mod-z', run: rejectSuggestionCommand, preventDefault: true },
|
||||||
// Get the current plugin from the map.
|
{
|
||||||
const p = view.plugin(completionPlugin)
|
key: 'Mod-y',
|
||||||
if (p === null) return false
|
mac: 'Mod-Shift-z',
|
||||||
|
run: rejectSuggestionCommand,
|
||||||
return p.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,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { useLayoutEffect, useEffect, useRef } from 'react'
|
import { useLayoutEffect, useEffect, useRef } from 'react'
|
||||||
import { useStore } from '../useStore'
|
|
||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
import { deferExecution } from 'lib/utils'
|
import { deferExecution } from 'lib/utils'
|
||||||
import { Themes } from 'lib/theme'
|
import { Themes } from 'lib/theme'
|
||||||
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
|
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
|
||||||
|
import { useModelingContext } from './useModelingContext'
|
||||||
|
import { useAppState } from 'AppState'
|
||||||
|
|
||||||
export function useSetupEngineManager(
|
export function useSetupEngineManager(
|
||||||
streamRef: React.RefObject<HTMLDivElement>,
|
streamRef: React.RefObject<HTMLDivElement>,
|
||||||
@ -13,26 +14,20 @@ export function useSetupEngineManager(
|
|||||||
theme: Themes.System,
|
theme: Themes.System,
|
||||||
highlightEdges: true,
|
highlightEdges: true,
|
||||||
enableSSAO: true,
|
enableSSAO: true,
|
||||||
|
modelingSend: (() => {}) as any,
|
||||||
|
modelingContext: {} as any,
|
||||||
showScaleGrid: false,
|
showScaleGrid: false,
|
||||||
} as {
|
} as {
|
||||||
pool: string | null
|
pool: string | null
|
||||||
theme: Themes
|
theme: Themes
|
||||||
highlightEdges: boolean
|
highlightEdges: boolean
|
||||||
enableSSAO: boolean
|
enableSSAO: boolean
|
||||||
|
modelingSend: ReturnType<typeof useModelingContext>['send']
|
||||||
|
modelingContext: ReturnType<typeof useModelingContext>['context']
|
||||||
showScaleGrid: boolean
|
showScaleGrid: boolean
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const {
|
const { setAppState } = useAppState()
|
||||||
setMediaStream,
|
|
||||||
setIsStreamReady,
|
|
||||||
setStreamDimensions,
|
|
||||||
streamDimensions,
|
|
||||||
} = useStore((s) => ({
|
|
||||||
setMediaStream: s.setMediaStream,
|
|
||||||
setIsStreamReady: s.setIsStreamReady,
|
|
||||||
setStreamDimensions: s.setStreamDimensions,
|
|
||||||
streamDimensions: s.streamDimensions,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const streamWidth = streamRef?.current?.offsetWidth
|
const streamWidth = streamRef?.current?.offsetWidth
|
||||||
const streamHeight = streamRef?.current?.offsetHeight
|
const streamHeight = streamRef?.current?.offsetHeight
|
||||||
@ -52,10 +47,19 @@ export function useSetupEngineManager(
|
|||||||
streamWidth,
|
streamWidth,
|
||||||
streamHeight
|
streamHeight
|
||||||
)
|
)
|
||||||
if (!hasSetNonZeroDimensions.current && quadHeight && quadWidth) {
|
if (
|
||||||
|
!hasSetNonZeroDimensions.current &&
|
||||||
|
quadHeight &&
|
||||||
|
quadWidth &&
|
||||||
|
settings.modelingSend
|
||||||
|
) {
|
||||||
engineCommandManager.start({
|
engineCommandManager.start({
|
||||||
setMediaStream,
|
setMediaStream: (mediaStream) =>
|
||||||
setIsStreamReady,
|
settings.modelingSend({
|
||||||
|
type: 'Set context',
|
||||||
|
data: { mediaStream },
|
||||||
|
}),
|
||||||
|
setIsStreamReady: (isStreamReady) => setAppState({ isStreamReady }),
|
||||||
width: quadWidth,
|
width: quadWidth,
|
||||||
height: quadHeight,
|
height: quadHeight,
|
||||||
executeCode: () => {
|
executeCode: () => {
|
||||||
@ -72,9 +76,14 @@ export function useSetupEngineManager(
|
|||||||
return modifyGrid(kclManager.engineCommandManager, hidden)
|
return modifyGrid(kclManager.engineCommandManager, hidden)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
setStreamDimensions({
|
settings.modelingSend({
|
||||||
streamWidth: quadWidth,
|
type: 'Set context',
|
||||||
streamHeight: quadHeight,
|
data: {
|
||||||
|
streamDimensions: {
|
||||||
|
streamWidth: quadWidth,
|
||||||
|
streamHeight: quadHeight,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
hasSetNonZeroDimensions.current = true
|
hasSetNonZeroDimensions.current = true
|
||||||
}
|
}
|
||||||
@ -83,6 +92,7 @@ export function useSetupEngineManager(
|
|||||||
useLayoutEffect(startEngineInstance, [
|
useLayoutEffect(startEngineInstance, [
|
||||||
streamRef?.current?.offsetWidth,
|
streamRef?.current?.offsetWidth,
|
||||||
streamRef?.current?.offsetHeight,
|
streamRef?.current?.offsetHeight,
|
||||||
|
settings.modelingSend,
|
||||||
])
|
])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -92,16 +102,21 @@ export function useSetupEngineManager(
|
|||||||
streamRef?.current?.offsetHeight
|
streamRef?.current?.offsetHeight
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
streamDimensions.streamWidth !== width ||
|
settings.modelingContext.store.streamDimensions.streamWidth !== width ||
|
||||||
streamDimensions.streamHeight !== height
|
settings.modelingContext.store.streamDimensions.streamHeight !== height
|
||||||
) {
|
) {
|
||||||
engineCommandManager.handleResize({
|
engineCommandManager.handleResize({
|
||||||
streamWidth: width,
|
streamWidth: width,
|
||||||
streamHeight: height,
|
streamHeight: height,
|
||||||
})
|
})
|
||||||
setStreamDimensions({
|
settings.modelingSend({
|
||||||
streamWidth: width,
|
type: 'Set context',
|
||||||
streamHeight: height,
|
data: {
|
||||||
|
streamDimensions: {
|
||||||
|
streamWidth: width,
|
||||||
|
streamHeight: height,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
|
@ -8,9 +8,9 @@ import { settingsMachine } from 'machines/settingsMachine'
|
|||||||
import { homeMachine } from 'machines/homeMachine'
|
import { homeMachine } from 'machines/homeMachine'
|
||||||
import { Command, CommandSetConfig, CommandSetSchema } from 'lib/commandTypes'
|
import { Command, CommandSetConfig, CommandSetSchema } from 'lib/commandTypes'
|
||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { useNetworkContext } from 'hooks/useNetworkContext'
|
import { useNetworkContext } from 'hooks/useNetworkContext'
|
||||||
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
||||||
|
import { useAppState } from 'AppState'
|
||||||
|
|
||||||
// This might not be necessary, AnyStateMachine from xstate is working
|
// This might not be necessary, AnyStateMachine from xstate is working
|
||||||
export type AllMachines =
|
export type AllMachines =
|
||||||
@ -47,9 +47,7 @@ export default function useStateMachineCommands<
|
|||||||
const { commandBarSend } = useCommandsContext()
|
const { commandBarSend } = useCommandsContext()
|
||||||
const { overallState } = useNetworkContext()
|
const { overallState } = useNetworkContext()
|
||||||
const { isExecuting } = useKclContext()
|
const { isExecuting } = useKclContext()
|
||||||
const { isStreamReady } = useStore((s) => ({
|
const { isStreamReady } = useAppState()
|
||||||
isStreamReady: s.isStreamReady,
|
|
||||||
}))
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const disableAllButtons =
|
const disableAllButtons =
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { executeAst, lintAst } from 'useStore'
|
import { executeAst, lintAst } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { KCLError, kclErrorsToDiagnostics } from './errors'
|
import { KCLError, kclErrorsToDiagnostics } from './errors'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
|
@ -8,7 +8,7 @@ import toast from 'react-hot-toast'
|
|||||||
import { editorManager } from 'lib/singletons'
|
import { editorManager } from 'lib/singletons'
|
||||||
import { Annotation, KeyBinding, Transaction } from '@uiw/react-codemirror'
|
import { Annotation, KeyBinding, Transaction } from '@uiw/react-codemirror'
|
||||||
|
|
||||||
const PERSIST_CODE_TOKEN = 'persistCode'
|
const PERSIST_CODE_KEY = 'persistCode'
|
||||||
|
|
||||||
const codeManagerUpdateAnnotation = Annotation.define<null>()
|
const codeManagerUpdateAnnotation = Annotation.define<null>()
|
||||||
export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(null)
|
export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(null)
|
||||||
@ -25,7 +25,7 @@ export default class CodeManager {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const storedCode = safeLSGetItem(PERSIST_CODE_TOKEN)
|
const storedCode = safeLSGetItem(PERSIST_CODE_KEY)
|
||||||
// TODO #819 remove zustand persistence logic in a few months
|
// TODO #819 remove zustand persistence logic in a few months
|
||||||
// short term migration, shouldn't make a difference for tauri app users
|
// short term migration, shouldn't make a difference for tauri app users
|
||||||
// anyway since that's filesystem based.
|
// anyway since that's filesystem based.
|
||||||
@ -125,7 +125,7 @@ export default class CodeManager {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
safeLSSetItem(PERSIST_CODE_TOKEN, this.code)
|
safeLSSetItem(PERSIST_CODE_KEY, this.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
120
src/lang/langHelpers.ts
Normal file
120
src/lang/langHelpers.ts
Normal 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 []
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { ToolTip } from '../useStore'
|
import { ToolTip } from 'lang/langHelpers'
|
||||||
import { Selection, Selections } from 'lib/selections'
|
import { Selection, Selections } from 'lib/selections'
|
||||||
import {
|
import {
|
||||||
ArrayExpression,
|
ArrayExpression,
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
isLiteralArrayOrStatic,
|
isLiteralArrayOrStatic,
|
||||||
isNotLiteralArrayOrStatic,
|
isNotLiteralArrayOrStatic,
|
||||||
} from 'lang/std/sketchcombos'
|
} from 'lang/std/sketchcombos'
|
||||||
import { toolTips, ToolTip } from '../../useStore'
|
import { toolTips, ToolTip } from 'lang/langHelpers'
|
||||||
import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
|
import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { getNodeFromPath } from 'lang/queryAst'
|
import { getNodeFromPath } from 'lang/queryAst'
|
||||||
import { ToolTip, toolTips } from '../../useStore'
|
import { ToolTip, toolTips } from 'lang/langHelpers'
|
||||||
import {
|
import {
|
||||||
Program,
|
Program,
|
||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
ConstraintLevel,
|
ConstraintLevel,
|
||||||
getConstraintLevelFromSourceRange,
|
getConstraintLevelFromSourceRange,
|
||||||
} from './sketchcombos'
|
} from './sketchcombos'
|
||||||
import { ToolTip } from '../../useStore'
|
import { ToolTip } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { err } from 'lib/trap'
|
import { err } from 'lib/trap'
|
||||||
import { enginelessExecutor } from '../../lib/testHelpers'
|
import { enginelessExecutor } from '../../lib/testHelpers'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { TransformCallback, VarValues } from './stdTypes'
|
import { TransformCallback, VarValues } from './stdTypes'
|
||||||
import { toolTips, ToolTip } from '../../useStore'
|
import { ToolTip, toolTips } from 'lang/langHelpers'
|
||||||
import { Selections, Selection } from 'lib/selections'
|
import { Selections, Selection } from 'lib/selections'
|
||||||
import { cleanErrs, err } from 'lib/trap'
|
import { cleanErrs, err } from 'lib/trap'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ToolTip } from 'useStore'
|
import { ToolTip } from 'lang/langHelpers'
|
||||||
import {
|
import {
|
||||||
ProgramMemory,
|
ProgramMemory,
|
||||||
Path,
|
Path,
|
||||||
|
@ -5,7 +5,7 @@ import { findUniqueName } from 'lang/modifyAst'
|
|||||||
import { PrevVariable, findAllPreviousVariables } from 'lang/queryAst'
|
import { PrevVariable, findAllPreviousVariables } from 'lang/queryAst'
|
||||||
import { Value, parse } from 'lang/wasm'
|
import { Value, parse } from 'lang/wasm'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { executeAst } from 'useStore'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import { trap } from 'lib/trap'
|
import { trap } from 'lib/trap'
|
||||||
|
|
||||||
const isValidVariableName = (name: string) =>
|
const isValidVariableName = (name: string) =>
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
|||||||
import { FormEvent, useEffect } from 'react'
|
import { FormEvent, useEffect, useRef } from 'react'
|
||||||
import { remove } from '@tauri-apps/plugin-fs'
|
import { remove } from '@tauri-apps/plugin-fs'
|
||||||
import {
|
import {
|
||||||
getNextProjectIndex,
|
getNextProjectIndex,
|
||||||
@ -39,6 +39,7 @@ import {
|
|||||||
listProjects,
|
listProjects,
|
||||||
renameProjectDirectory,
|
renameProjectDirectory,
|
||||||
} from 'lib/tauri'
|
} from 'lib/tauri'
|
||||||
|
import { useAppState } from 'AppState'
|
||||||
|
|
||||||
// This route only opens in the Tauri desktop context for now,
|
// 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.
|
// as defined in Router.tsx, so we can use the Tauri APIs and types.
|
||||||
@ -64,6 +65,12 @@ const Home = () => {
|
|||||||
splitKey: '|',
|
splitKey: '|',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
|
const { setAppState } = useAppState()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setAppState({ htmlRef: ref })
|
||||||
|
}, [ref])
|
||||||
|
|
||||||
const [state, send, actor] = useMachine(homeMachine, {
|
const [state, send, actor] = useMachine(homeMachine, {
|
||||||
context: {
|
context: {
|
||||||
@ -198,7 +205,7 @@ const Home = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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} />
|
<AppHeader showToolbar={false} />
|
||||||
<div className="w-full flex flex-col overflow-hidden max-w-5xl px-4 mx-auto mt-24 lg:px-2">
|
<div className="w-full flex flex-col overflow-hidden max-w-5xl px-4 mx-auto mt-24 lg:px-2">
|
||||||
<section>
|
<section>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
import {
|
import {
|
||||||
CameraSystem,
|
CameraSystem,
|
||||||
@ -8,11 +7,10 @@ import {
|
|||||||
cameraSystems,
|
cameraSystems,
|
||||||
} from 'lib/cameraControls'
|
} from 'lib/cameraControls'
|
||||||
import { SettingsSection } from 'components/Settings/SettingsSection'
|
import { SettingsSection } from 'components/Settings/SettingsSection'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function Units() {
|
export default function Units() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.STREAMING)
|
const next = useNextClick(onboardingPaths.STREAMING)
|
||||||
const {
|
const {
|
||||||
@ -31,7 +29,7 @@ export default function Units() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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
|
<SettingsSection
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import usePlatform from 'hooks/usePlatform'
|
import usePlatform from 'hooks/usePlatform'
|
||||||
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function CmdK() {
|
export default function CmdK() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.USER_MENU)
|
const next = useNextClick(onboardingPaths.USER_MENU)
|
||||||
const platformName = usePlatform()
|
const platformName = usePlatform()
|
||||||
@ -16,7 +14,7 @@ export default function CmdK() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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>
|
<h2 className="text-2xl font-bold">Command Bar</h2>
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
|
|
||||||
export default function OnboardingCodeEditor() {
|
export default function OnboardingCodeEditor() {
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
|
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
|
||||||
|
|
||||||
@ -15,7 +13,7 @@ export default function OnboardingCodeEditor() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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">
|
<section className="flex-1 overflow-y-auto">
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { APP_NAME } from 'lib/constants'
|
import { APP_NAME } from 'lib/constants'
|
||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function Export() {
|
export default function Export() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.SKETCHING)
|
const next = useNextClick(onboardingPaths.SKETCHING)
|
||||||
|
|
||||||
@ -15,7 +13,7 @@ export default function Export() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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">
|
<section className="flex-1">
|
||||||
|
@ -6,14 +6,12 @@ import {
|
|||||||
useNextClick,
|
useNextClick,
|
||||||
} from '.'
|
} from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { bracketWidthConstantLine } from 'lib/exampleKcl'
|
import { bracketWidthConstantLine } from 'lib/exampleKcl'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function OnboardingInteractiveNumbers() {
|
export default function OnboardingInteractiveNumbers() {
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.COMMAND_K)
|
const next = useNextClick(onboardingPaths.COMMAND_K)
|
||||||
|
|
||||||
@ -22,7 +20,7 @@ export default function OnboardingInteractiveNumbers() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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">
|
<section className="flex-1 overflow-y-auto mb-6">
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { Themes, getSystemTheme } from 'lib/theme'
|
import { Themes, getSystemTheme } from 'lib/theme'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
import { bracketThicknessCalculationLine } from 'lib/exampleKcl'
|
import { bracketThicknessCalculationLine } from 'lib/exampleKcl'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function OnboardingParametricModeling() {
|
export default function OnboardingParametricModeling() {
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const {
|
const {
|
||||||
settings: {
|
settings: {
|
||||||
context: {
|
context: {
|
||||||
@ -32,7 +30,7 @@ export default function OnboardingParametricModeling() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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">
|
<section className="flex-1 overflow-y-auto mb-6">
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function ProjectMenu() {
|
export default function ProjectMenu() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.EXPORT)
|
const next = useNextClick(onboardingPaths.EXPORT)
|
||||||
const tauri = isTauri()
|
const tauri = isTauri()
|
||||||
@ -16,7 +14,7 @@ export default function ProjectMenu() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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">
|
<section className="flex-1">
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { codeManager, kclManager } from 'lib/singletons'
|
import { codeManager, kclManager } from 'lib/singletons'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function Sketching() {
|
export default function Sketching() {
|
||||||
const buttonDownInStream = useStore((s) => s.buttonDownInStream)
|
const { context } = useModelingContext()
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.FUTURE_WORK)
|
const next = useNextClick(onboardingPaths.FUTURE_WORK)
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ export default function Sketching() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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>
|
<h1 className="text-2xl font-bold">Sketching</h1>
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
|
|
||||||
export default function Streaming() {
|
export default function Streaming() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.EDITOR)
|
const next = useNextClick(onboardingPaths.EDITOR)
|
||||||
|
|
||||||
@ -14,7 +12,7 @@ export default function Streaming() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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">
|
<section className="flex-1 overflow-y-auto">
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function UserMenu() {
|
export default function UserMenu() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
||||||
const [avatarErrored, setAvatarErrored] = useState(false)
|
const [avatarErrored, setAvatarErrored] = useState(false)
|
||||||
@ -33,7 +31,7 @@ export default function UserMenu() {
|
|||||||
<div
|
<div
|
||||||
className={
|
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' +
|
'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">
|
<section className="flex-1">
|
||||||
|
@ -12,8 +12,11 @@ import { SettingsSectionsList } from 'components/Settings/SettingsSectionsList'
|
|||||||
import { AllSettingsFields } from 'components/Settings/AllSettingsFields'
|
import { AllSettingsFields } from 'components/Settings/AllSettingsFields'
|
||||||
import { AllKeybindingsFields } from 'components/Settings/AllKeybindingsFields'
|
import { AllKeybindingsFields } from 'components/Settings/AllKeybindingsFields'
|
||||||
import { KeybindingsSectionsList } from 'components/Settings/KeybindingsSectionsList'
|
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 = () => {
|
export const Settings = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
212
src/useStore.ts
212
src/useStore.ts
@ -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 []
|
|
||||||
}
|
|
||||||
}
|
|
4
src/wasm-lib/Cargo.lock
generated
4
src/wasm-lib/Cargo.lock
generated
@ -2606,9 +2606,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.119"
|
version = "1.0.120"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8eddb61f0697cc3989c5d64b452f5488e2b8a60fd7d5076a3045076ffef8cb0"
|
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.5",
|
"indexmap 2.2.5",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
@ -15,7 +15,7 @@ clap = "4.5.7"
|
|||||||
gloo-utils = "0.2.0"
|
gloo-utils = "0.2.0"
|
||||||
kcl-lib = { path = "kcl" }
|
kcl-lib = { path = "kcl" }
|
||||||
kittycad.workspace = true
|
kittycad.workspace = true
|
||||||
serde_json = "1.0.119"
|
serde_json = "1.0.120"
|
||||||
tokio = { version = "1.38.0", features = ["sync"] }
|
tokio = { version = "1.38.0", features = ["sync"] }
|
||||||
toml = "0.8.14"
|
toml = "0.8.14"
|
||||||
uuid = { version = "1.9.1", features = ["v4", "js", "serde"] }
|
uuid = { version = "1.9.1", features = ["v4", "js", "serde"] }
|
||||||
|
@ -11,5 +11,5 @@ hyper = { version = "0.14.29", features = ["server"] }
|
|||||||
kcl-lib = { version = "0.1.62", path = "../kcl" }
|
kcl-lib = { version = "0.1.62", path = "../kcl" }
|
||||||
pico-args = "0.5.0"
|
pico-args = "0.5.0"
|
||||||
serde = { version = "1.0.203", features = ["derive"] }
|
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"] }
|
tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }
|
||||||
|
@ -33,7 +33,7 @@ reqwest = { version = "0.11.26", default-features = false, features = ["stream",
|
|||||||
ropey = "1.6.1"
|
ropey = "1.6.1"
|
||||||
schemars = { version = "0.8.17", features = ["impl_json_schema", "url", "uuid1"] }
|
schemars = { version = "0.8.17", features = ["impl_json_schema", "url", "uuid1"] }
|
||||||
serde = { version = "1.0.203", features = ["derive"] }
|
serde = { version = "1.0.203", features = ["derive"] }
|
||||||
serde_json = "1.0.119"
|
serde_json = "1.0.120"
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
thiserror = "1.0.61"
|
thiserror = "1.0.61"
|
||||||
toml = "0.8.14"
|
toml = "0.8.14"
|
||||||
|
@ -69,6 +69,7 @@ impl StdLibFnArg {
|
|||||||
|| self.type_ == "ExtrudeGroup"
|
|| self.type_ == "ExtrudeGroup"
|
||||||
|| self.type_ == "ExtrudeGroupSet"
|
|| self.type_ == "ExtrudeGroupSet"
|
||||||
|| self.type_ == "SketchSurface"
|
|| self.type_ == "SketchSurface"
|
||||||
|
|| self.type_ == "SketchSurfaceOrGroup"
|
||||||
{
|
{
|
||||||
return Ok(Some((index, format!("${{{}:{}}}", index, "%"))));
|
return Ok(Some((index, format!("${{{}:{}}}", index, "%"))));
|
||||||
} else if self.type_ == "TagDeclarator" && self.required {
|
} else if self.type_ == "TagDeclarator" && self.required {
|
||||||
@ -894,4 +895,11 @@ mod tests {
|
|||||||
}, ${2:%})${}"#
|
}, ${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:%})${}"#);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
64
yarn.lock
64
yarn.lock
@ -1697,12 +1697,12 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
||||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||||
|
|
||||||
"@playwright/test@^1.44.1":
|
"@playwright/test@^1.45.1":
|
||||||
version "1.44.1"
|
version "1.45.1"
|
||||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.44.1.tgz#cc874ec31342479ad99838040e99b5f604299bcb"
|
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.45.1.tgz#819b90fa43d17000fce5ebd127043fd661938b7a"
|
||||||
integrity sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==
|
integrity sha512-Wo1bWTzQvGA7LyKGIZc8nFSTFf2TkthGIFBR+QVNilvwouGzFd4PYukZe3rvf5PSqjHi1+1NyKSDZKcQWETzaA==
|
||||||
dependencies:
|
dependencies:
|
||||||
playwright "1.44.1"
|
playwright "1.45.1"
|
||||||
|
|
||||||
"@promptbook/utils@0.50.0-10":
|
"@promptbook/utils@0.50.0-10":
|
||||||
version "0.50.0-10"
|
version "0.50.0-10"
|
||||||
@ -5145,10 +5145,10 @@ html-encoding-sniffer@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
whatwg-encoding "^2.0.0"
|
whatwg-encoding "^2.0.0"
|
||||||
|
|
||||||
html2canvas-pro@^1.5.0:
|
html2canvas-pro@^1.5.1:
|
||||||
version "1.5.0"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/html2canvas-pro/-/html2canvas-pro-1.5.0.tgz#18925def43505bad352a394b95fffb45d6d46a8f"
|
resolved "https://registry.yarnpkg.com/html2canvas-pro/-/html2canvas-pro-1.5.1.tgz#e62aea27c598152308be35754b8b0f188908e171"
|
||||||
integrity sha512-izxSphcINRwfEVV6eamsPVdhsxSYqX8n/hxzK+niVWdB+onM+aYRoVO+xgS9iMmZoUleZTWg1tJwryikib2hXg==
|
integrity sha512-6LmbLb3qNg8f3jSSRdzDwG7c9VIFDC9jOP3iZ6mK1cjc9W6F2Mkh/n2WmBECxAzF2yHEznJFmgbQAut1g+NbEQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
css-line-break "^2.1.0"
|
css-line-break "^2.1.0"
|
||||||
text-segmentation "^1.0.3"
|
text-segmentation "^1.0.3"
|
||||||
@ -6632,17 +6632,17 @@ pkg-types@^1.0.3, pkg-types@^1.1.1:
|
|||||||
mlly "^1.7.0"
|
mlly "^1.7.0"
|
||||||
pathe "^1.1.2"
|
pathe "^1.1.2"
|
||||||
|
|
||||||
playwright-core@1.44.1:
|
playwright-core@1.45.1:
|
||||||
version "1.44.1"
|
version "1.45.1"
|
||||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.44.1.tgz#53ec975503b763af6fc1a7aa995f34bc09ff447c"
|
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.45.1.tgz#549a2701556b58245cc75263f9fc2795c1158dc1"
|
||||||
integrity sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==
|
integrity sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==
|
||||||
|
|
||||||
playwright@1.44.1:
|
playwright@1.45.1:
|
||||||
version "1.44.1"
|
version "1.45.1"
|
||||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.44.1.tgz#5634369d777111c1eea9180430b7a184028e7892"
|
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.45.1.tgz#aaa6b0d6db14796b599d80c6679e63444e942534"
|
||||||
integrity sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==
|
integrity sha512-Hjrgae4kpSQBr98nhCj3IScxVeVUixqj+5oyif8TdIn2opTCPEzqAqNMeK42i3cWDCVu9MI+ZsGWw+gVR4ISBg==
|
||||||
dependencies:
|
dependencies:
|
||||||
playwright-core "1.44.1"
|
playwright-core "1.45.1"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "2.3.2"
|
fsevents "2.3.2"
|
||||||
|
|
||||||
@ -7848,10 +7848,10 @@ thenify-all@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
any-promise "^1.0.0"
|
any-promise "^1.0.0"
|
||||||
|
|
||||||
three@^0.164.1:
|
three@^0.166.1:
|
||||||
version "0.164.1"
|
version "0.166.1"
|
||||||
resolved "https://registry.yarnpkg.com/three/-/three-0.164.1.tgz#b742f76bd8dfd3736ba0d86a12dfddb73c5cdcc0"
|
resolved "https://registry.yarnpkg.com/three/-/three-0.166.1.tgz#322cfc48fff4e751cd47d61fd1558c387d098d7c"
|
||||||
integrity sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==
|
integrity sha512-LtuafkKHHzm61AQA1be2MAYIw1IjmhOUxhBa0prrLpEMWbV7ijvxCRHjSgHPGp2493wLBzwKV46tA9nivLEgKg==
|
||||||
|
|
||||||
through@^2.3.8:
|
through@^2.3.8:
|
||||||
version "2.3.8"
|
version "2.3.8"
|
||||||
@ -8159,11 +8159,6 @@ use-latest@^1.2.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
use-isomorphic-layout-effect "^1.1.1"
|
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:
|
use-sync-external-store@^1.0.0:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
|
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:
|
dependencies:
|
||||||
loose-envify "^1.0.0"
|
loose-envify "^1.0.0"
|
||||||
|
|
||||||
wasm-pack@^0.12.1:
|
wasm-pack@^0.13.0:
|
||||||
version "0.12.1"
|
version "0.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/wasm-pack/-/wasm-pack-0.12.1.tgz#974c1fbbf5b65c9e135e0d1fba3a97de1a21a489"
|
resolved "https://registry.yarnpkg.com/wasm-pack/-/wasm-pack-0.13.0.tgz#c2637e0129e1854735f3daead45d92165d54709d"
|
||||||
integrity sha512-dIyKWUumPFsGohdndZjDXRFaokUT/kQS+SavbbiXVAvA/eN4riX5QNdB6AhXQx37zNxluxQkuixZUgJ8adKjOg==
|
integrity sha512-AmboGZEnZoIcVCzSlkLEmNFEqJN+IwgshJ5S7pi30uNUTce4LvWkifQzsQRxnWj47G8gkqZxlyGlyQplsnIS7w==
|
||||||
dependencies:
|
dependencies:
|
||||||
binary-install "^1.0.1"
|
binary-install "^1.0.1"
|
||||||
|
|
||||||
@ -8718,10 +8713,3 @@ zip-stream@^6.0.1:
|
|||||||
archiver-utils "^5.0.0"
|
archiver-utils "^5.0.0"
|
||||||
compress-commons "^6.0.2"
|
compress-commons "^6.0.2"
|
||||||
readable-stream "^4.0.0"
|
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"
|
|
||||||
|
Reference in New Issue
Block a user