* Extend KCL argument input * Migrate length constraint to be a command * Add ability for `kcl` arguments to provide an initial variable name * Move named variable flow into command palette * Fix one e2e test * Remove unwanted `ZERO` behavior when length constraint has no `variableName` * Fix issue with `getSelectionCountByType` with sketches not yet in artifactGraph * Update broken constraint tests * Look at this (photo)Graph *in the voice of Nickelback* * Fix segment overlays tests, which had out-of-date selectors * Return early from `useConvertToVariable` if no selectionRanges * Fixup for review comment from #4677 (#4696) Signed-off-by: Nick Cameron <nrc@ncameron.org> * Invalidate nightly bucket files after publish (#4627) * Invalidate nightly bucket files after publish * Fix conflict resolution * Add some more warnings (#4697) * Add installation instructions for all platforms (#4592) * Add installation instructions for all platforms Fixes #4511 * Typo * Typo2 * Improve linux instructions, thanks @TomPridham Co-authored-by: Tom Pridham <pridham.tom@gmail.com> --------- Co-authored-by: Tom Pridham <pridham.tom@gmail.com> * Bump node to v22.12.0 (LTS) (#4706) * Point-and-click Shell (#4666) * WIP: experimenting with Loft UI Relates to #4470 * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Add selection guard * Working loft for two sketches in the right hardcoded order * First pass at handling more than 2 sketches * WIP selections * WIP selections * More checks * Appends the loft line after the 'last' sketch in the code * Clean up * Enable multiple selections after the button click * First point-click loft test (not working locally, loft gets inserted at the wrong place) * Lint * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * Clean up and working pw test * Add test for doesSceneHaveSweepableSketch with count = 2 * Clean up loftSketches function * Add pw test for preselected sketches * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Trigger CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Move to fromPromise-based Actor * Move error logic out of loftSketches, fix pw tests * Remove comments * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Trigger CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Trigger CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Fix typo * Revert snapshots * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Trigger CI * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * Trigger CI * WIP: initial shell code addition * Rollback pw values to pre cam change * WIP: more additions * WIP: closer * WIP: first time working shell mod * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * Add extrude lookup for more generic shell * Handle walls * Add pw tests for cap shell * Add shell wall test * Fix lint * Add selection guard and clean up * Lint fix * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * WIP mutliple faces * WIP circular dep * Lint * Look at this (photo)Graph *in the voice of Nickelback* * Trigger CI * Working multi-face shell across types * Cap and wall pw test * Apply suggestions from Frank's review Co-authored-by: Frank Noirot <frank@zoo.dev> * Fix test annotations * Add unit tests for doesSceneHaveExtrudedSketch * Manual resolution of snapshot conflicts * Fix assertParse * Updated pathToNode construct --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Frank Noirot <frank@zoo.dev> * More aggressive using of cache on engine settings changes (#4691) * move around the files for cache to better localtions Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * udpates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * ensure we can change the grid setting via the command bar Signed-off-by: Jess Frazelle <github@jessfraz.com> * pass thru all setttings Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix playwright test Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores) * emoty --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix use of `as` --------- Signed-off-by: Nick Cameron <nrc@ncameron.org> Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Nick Cameron <nrc@ncameron.org> Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com> Co-authored-by: Tom Pridham <pridham.tom@gmail.com> Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
261 lines
8.1 KiB
TypeScript
261 lines
8.1 KiB
TypeScript
import { Completion } from '@codemirror/autocomplete'
|
|
import { EditorView, ViewUpdate } from '@codemirror/view'
|
|
import { CustomIcon } from 'components/CustomIcon'
|
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
|
import { CommandArgument, KclCommandValue } from 'lib/commandTypes'
|
|
import { getSystemTheme } from 'lib/theme'
|
|
import { useCalculateKclExpression } from 'lib/useCalculateKclExpression'
|
|
import { roundOff } from 'lib/utils'
|
|
import { varMentions } from 'lib/varCompletionExtension'
|
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
import { useHotkeys } from 'react-hotkeys-hook'
|
|
import styles from './CommandBarKclInput.module.css'
|
|
import { createIdentifier, createVariableDeclaration } from 'lang/modifyAst'
|
|
import { useCodeMirror } from 'components/ModelingSidebar/ModelingPanes/CodeEditor'
|
|
import { useSelector } from '@xstate/react'
|
|
|
|
const machineContextSelector = (snapshot?: {
|
|
context: Record<string, unknown>
|
|
}) => snapshot?.context
|
|
|
|
function CommandBarKclInput({
|
|
arg,
|
|
stepBack,
|
|
onSubmit,
|
|
}: {
|
|
arg: CommandArgument<unknown> & {
|
|
inputType: 'kcl'
|
|
name: string
|
|
}
|
|
stepBack: () => void
|
|
onSubmit: (event: unknown) => void
|
|
}) {
|
|
const { commandBarSend, commandBarState } = useCommandsContext()
|
|
const previouslySetValue = commandBarState.context.argumentsToSubmit[
|
|
arg.name
|
|
] as KclCommandValue | undefined
|
|
const { settings } = useSettingsAuthContext()
|
|
const argMachineContext = useSelector(
|
|
arg.machineActor,
|
|
machineContextSelector
|
|
)
|
|
const defaultValue = useMemo(
|
|
() =>
|
|
arg.defaultValue
|
|
? arg.defaultValue instanceof Function
|
|
? arg.defaultValue(commandBarState.context, argMachineContext)
|
|
: arg.defaultValue
|
|
: '',
|
|
[arg.defaultValue, commandBarState.context, argMachineContext]
|
|
)
|
|
const initialVariableName = useMemo(() => {
|
|
// Use the configured variable name if it exists
|
|
if (arg.variableName !== undefined) {
|
|
return arg.variableName instanceof Function
|
|
? arg.variableName(commandBarState.context, argMachineContext)
|
|
: arg.variableName
|
|
}
|
|
// or derive it from the previously set value or the argument name
|
|
return previouslySetValue && 'variableName' in previouslySetValue
|
|
? previouslySetValue.variableName
|
|
: arg.name
|
|
}, [
|
|
arg.variableName,
|
|
commandBarState.context,
|
|
argMachineContext,
|
|
arg.name,
|
|
previouslySetValue,
|
|
])
|
|
const [value, setValue] = useState(
|
|
previouslySetValue?.valueText || defaultValue || ''
|
|
)
|
|
const [createNewVariable, setCreateNewVariable] = useState(
|
|
(previouslySetValue && 'variableName' in previouslySetValue) ||
|
|
arg.createVariableByDefault ||
|
|
false
|
|
)
|
|
const [canSubmit, setCanSubmit] = useState(true)
|
|
useHotkeys('mod + k, mod + /', () => commandBarSend({ type: 'Close' }))
|
|
const editorRef = useRef<HTMLDivElement>(null)
|
|
|
|
const {
|
|
prevVariables,
|
|
calcResult,
|
|
newVariableInsertIndex,
|
|
valueNode,
|
|
newVariableName,
|
|
setNewVariableName,
|
|
isNewVariableNameUnique,
|
|
} = useCalculateKclExpression({
|
|
value,
|
|
initialVariableName,
|
|
})
|
|
const varMentionData: Completion[] = prevVariables.map((v) => ({
|
|
label: v.key,
|
|
detail: String(roundOff(v.value as number)),
|
|
}))
|
|
|
|
const { setContainer } = useCodeMirror({
|
|
container: editorRef.current,
|
|
initialDocValue: value,
|
|
autoFocus: true,
|
|
selection: {
|
|
anchor: 0,
|
|
head:
|
|
previouslySetValue && 'valueText' in previouslySetValue
|
|
? previouslySetValue.valueText.length
|
|
: defaultValue.length,
|
|
},
|
|
theme:
|
|
settings.context.app.theme.current === 'system'
|
|
? getSystemTheme()
|
|
: settings.context.app.theme.current,
|
|
extensions: [
|
|
EditorView.domEventHandlers({
|
|
keydown: (event) => {
|
|
if (event.key === 'Backspace' && value === '') {
|
|
event.preventDefault()
|
|
stepBack()
|
|
} else if (event.key === 'Enter') {
|
|
event.preventDefault()
|
|
handleSubmit()
|
|
}
|
|
},
|
|
}),
|
|
varMentions(varMentionData),
|
|
EditorView.updateListener.of((vu: ViewUpdate) => {
|
|
if (vu.docChanged) {
|
|
setValue(vu.state.doc.toString())
|
|
}
|
|
}),
|
|
],
|
|
})
|
|
|
|
useEffect(() => {
|
|
if (editorRef.current) {
|
|
setContainer(editorRef.current)
|
|
}
|
|
}, [arg, editorRef])
|
|
|
|
useEffect(() => {
|
|
setCanSubmit(
|
|
calcResult !== 'NAN' && (!createNewVariable || isNewVariableNameUnique)
|
|
)
|
|
}, [calcResult, createNewVariable, isNewVariableNameUnique])
|
|
|
|
function handleSubmit(e?: React.FormEvent<HTMLFormElement>) {
|
|
e?.preventDefault()
|
|
if (!canSubmit || valueNode === null) return
|
|
|
|
onSubmit(
|
|
createNewVariable
|
|
? ({
|
|
valueAst: valueNode,
|
|
valueText: value,
|
|
valueCalculated: calcResult,
|
|
variableName: newVariableName,
|
|
insertIndex: newVariableInsertIndex,
|
|
variableIdentifierAst: createIdentifier(newVariableName),
|
|
variableDeclarationAst: createVariableDeclaration(
|
|
newVariableName,
|
|
valueNode
|
|
),
|
|
} satisfies KclCommandValue)
|
|
: ({
|
|
valueAst: valueNode,
|
|
valueText: value,
|
|
valueCalculated: calcResult,
|
|
} satisfies KclCommandValue)
|
|
)
|
|
}
|
|
|
|
return (
|
|
<form id="arg-form" onSubmit={handleSubmit} data-can-submit={canSubmit}>
|
|
<label className="flex gap-4 items-center mx-4 my-4 border-solid border-b border-chalkboard-50">
|
|
<span
|
|
data-testid="cmd-bar-arg-name"
|
|
className="capitalize text-chalkboard-80 dark:text-chalkboard-20"
|
|
>
|
|
{arg.name}
|
|
</span>
|
|
<div
|
|
data-testid="cmd-bar-arg-value"
|
|
ref={editorRef}
|
|
className={styles.editor}
|
|
/>
|
|
<CustomIcon
|
|
name="equal"
|
|
className="w-5 h-5 text-chalkboard-70 dark:text-chalkboard-40"
|
|
/>
|
|
<span
|
|
className={
|
|
calcResult === 'NAN'
|
|
? 'text-destroy-80 dark:text-destroy-40'
|
|
: 'text-succeed-80 dark:text-succeed-40'
|
|
}
|
|
>
|
|
{calcResult === 'NAN'
|
|
? "Can't calculate"
|
|
: roundOff(Number(calcResult), 4)}
|
|
</span>
|
|
</label>
|
|
{createNewVariable ? (
|
|
<div className="flex items-baseline gap-4 mx-4 border-solid border-0 border-b border-chalkboard-50">
|
|
<label
|
|
htmlFor="variable-name"
|
|
className="text-base text-chalkboard-80 dark:text-chalkboard-20"
|
|
>
|
|
Variable name
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="variable-name"
|
|
name="variable-name"
|
|
className="flex-1 border-none bg-transparent focus:outline-none"
|
|
placeholder="Variable name"
|
|
value={newVariableName}
|
|
autoCapitalize="off"
|
|
autoCorrect="off"
|
|
autoComplete="off"
|
|
spellCheck="false"
|
|
autoFocus
|
|
onChange={(e) => setNewVariableName(e.target.value)}
|
|
onKeyDown={(e) => {
|
|
if (e.currentTarget.value === '' && e.key === 'Backspace') {
|
|
setCreateNewVariable(false)
|
|
}
|
|
}}
|
|
onKeyUp={(e) => {
|
|
if (e.key === 'Enter') {
|
|
handleSubmit()
|
|
}
|
|
}}
|
|
/>
|
|
<span
|
|
className={
|
|
isNewVariableNameUnique
|
|
? 'text-succeed-60 dark:text-succeed-40'
|
|
: 'text-destroy-60 dark:text-destroy-40'
|
|
}
|
|
>
|
|
{isNewVariableNameUnique ? 'Available' : 'Unavailable'}
|
|
</span>
|
|
</div>
|
|
) : (
|
|
<div className="flex justify-between gap-2 px-4">
|
|
<button
|
|
onClick={() => setCreateNewVariable(true)}
|
|
className="text-blue border-none bg-transparent font-sm flex gap-1 items-center pl-0 pr-1"
|
|
>
|
|
<CustomIcon name="plus" className="w-5 h-5" />
|
|
Create new variable
|
|
</button>
|
|
</div>
|
|
)}
|
|
</form>
|
|
)
|
|
}
|
|
|
|
export default CommandBarKclInput
|