Compare commits
	
		
			6 Commits
		
	
	
		
			jtran/anim
			...
			franknoiro
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c64c4705ef | |||
| a122128e0b | |||
| 0fe79ea7cb | |||
| 021e4b9565 | |||
| e57783483a | |||
| e952148cd2 | 
| @ -274,7 +274,6 @@ test.describe('Feature Tree pane', () => { | ||||
|         currentArgKey: 'distance', | ||||
|         currentArgValue: initialInput, | ||||
|         headerArguments: { | ||||
|           Selection: '1 face', | ||||
|           Distance: initialInput, | ||||
|         }, | ||||
|         highlightedHeaderArg: 'distance', | ||||
| @ -291,7 +290,6 @@ test.describe('Feature Tree pane', () => { | ||||
|       await cmdBar.expectState({ | ||||
|         stage: 'review', | ||||
|         headerArguments: { | ||||
|           Selection: '1 face', | ||||
|           // The calculated value is shown in the argument summary | ||||
|           Distance: initialInput, | ||||
|         }, | ||||
|  | ||||
| @ -17,7 +17,12 @@ function CommandBarHeader({ children }: React.PropsWithChildren<{}>) { | ||||
|     if (!selectedCommand?.args) return undefined | ||||
|     const s = { ...selectedCommand.args } | ||||
|     for (const [name, arg] of Object.entries(s)) { | ||||
|       if (arg.hidden) delete s[name] | ||||
|       if ( | ||||
|         typeof arg.hidden === 'function' | ||||
|           ? arg.hidden(commandBarState.context) | ||||
|           : arg.hidden | ||||
|       ) | ||||
|         delete s[name] | ||||
|     } | ||||
|     return s | ||||
|   }, [selectedCommand]) | ||||
|  | ||||
| @ -7,7 +7,7 @@ import toast from 'react-hot-toast' | ||||
| import { editorManager } from 'lib/singletons' | ||||
| import { Annotation, Transaction } from '@codemirror/state' | ||||
| import { EditorView, KeyBinding } from '@codemirror/view' | ||||
| import { recast, Program, parse } from 'lang/wasm' | ||||
| import { recast, Program, parse, SourceRange } from 'lang/wasm' | ||||
| import { err, reportRejection } from 'lib/trap' | ||||
| import { Compartment } from '@codemirror/state' | ||||
| import { history } from '@codemirror/commands' | ||||
| @ -57,6 +57,10 @@ export default class CodeManager { | ||||
|     return this._code | ||||
|   } | ||||
|  | ||||
|   getCodeAtRange(range: SourceRange) { | ||||
|     return this._code.slice(range[0], range[1]) | ||||
|   } | ||||
|  | ||||
|   localStoragePersistCode(): string { | ||||
|     return safeLSGetItem(PERSIST_CODE_KEY) || '' | ||||
|   } | ||||
|  | ||||
| @ -69,6 +69,8 @@ export type ModelingCommandSchema = { | ||||
|     edge: Selections | ||||
|   } | ||||
|   Fillet: { | ||||
|     // Enables editing workflow | ||||
|     nodeToEdit?: PathToNode | ||||
|     selection: Selections | ||||
|     radius: KclCommandValue | ||||
|   } | ||||
| @ -319,6 +321,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig< | ||||
|         multiple: false, // TODO: multiple selection | ||||
|         required: true, | ||||
|         skip: true, | ||||
|         hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit), | ||||
|       }, | ||||
|       // result: { | ||||
|       //   inputType: 'options', | ||||
| @ -407,6 +410,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig< | ||||
|         multiple: false, // TODO: multiple selection | ||||
|         required: true, | ||||
|         skip: true, | ||||
|         hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit), | ||||
|       }, | ||||
|       axisOrEdge: { | ||||
|         inputType: 'options', | ||||
| @ -416,6 +420,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig< | ||||
|           { name: 'Axis', isCurrent: true, value: 'Axis' }, | ||||
|           { name: 'Edge', isCurrent: false, value: 'Edge' }, | ||||
|         ], | ||||
|         hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit), | ||||
|       }, | ||||
|       axis: { | ||||
|         required: (commandContext) => | ||||
| @ -437,6 +442,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig< | ||||
|         selectionTypes: ['segment', 'sweepEdge', 'edgeCutEdge'], | ||||
|         multiple: false, | ||||
|         validation: revolveAxisValidator, | ||||
|         hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit), | ||||
|       }, | ||||
|       angle: { | ||||
|         inputType: 'kcl', | ||||
| @ -534,12 +540,21 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig< | ||||
|     status: 'development', | ||||
|     needsReview: true, | ||||
|     args: { | ||||
|       nodeToEdit: { | ||||
|         description: | ||||
|           'Path to the node in the AST to edit. Never shown to the user.', | ||||
|         skip: true, | ||||
|         inputType: 'text', | ||||
|         required: false, | ||||
|         hidden: true, | ||||
|       }, | ||||
|       selection: { | ||||
|         inputType: 'selection', | ||||
|         selectionTypes: ['segment', 'sweepEdge', 'edgeCutEdge'], | ||||
|         multiple: true, | ||||
|         required: true, | ||||
|         skip: false, | ||||
|         hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit), | ||||
|         warningMessage: | ||||
|           'Fillets cannot touch other fillets yet. This is under development.', | ||||
|       }, | ||||
|  | ||||
| @ -120,7 +120,12 @@ export type CommandArgumentConfig< | ||||
|       ) => boolean) | ||||
|   warningMessage?: string | ||||
|   /** If `true`, arg is used as passed-through data, never for user input */ | ||||
|   hidden?: boolean | ||||
|   hidden?: | ||||
|     | boolean | ||||
|     | (( | ||||
|         commandBarContext: { argumentsToSubmit: Record<string, unknown> }, // Should be the commandbarMachine's context, but it creates a circular dependency | ||||
|         machineContext?: C | ||||
|       ) => boolean) | ||||
|   skip?: boolean | ||||
|   /** For showing a summary display of the current value, such as in | ||||
|    *  the command bar's header | ||||
| @ -236,7 +241,12 @@ export type CommandArgument< | ||||
|         machineContext?: ContextFrom<T> | ||||
|       ) => boolean) | ||||
|   /** If `true`, arg is used as passed-through data, never for user input */ | ||||
|   hidden?: boolean | ||||
|   hidden?: | ||||
|     | boolean | ||||
|     | (( | ||||
|         commandBarContext: { argumentsToSubmit: Record<string, unknown> }, // Should be the commandbarMachine's context, but it creates a circular dependency | ||||
|         machineContext?: ContextFrom<T> | ||||
|       ) => boolean) | ||||
|   skip?: boolean | ||||
|   machineActor?: Actor<T> | ||||
|   warningMessage?: string | ||||
|  | ||||
| @ -1,5 +1,10 @@ | ||||
| import { CustomIconName } from 'components/CustomIcon' | ||||
| import { Artifact, getArtifactOfTypes } from 'lang/std/artifactGraph' | ||||
| import { | ||||
|   Artifact, | ||||
|   getArtifactByPredicate, | ||||
|   getArtifactOfTypes, | ||||
|   getArtifactsOfTypes, | ||||
| } from 'lang/std/artifactGraph' | ||||
| import { Operation } from '@rust/kcl-lib/bindings/Operation' | ||||
| import { codeManager, engineCommandManager, kclManager } from './singletons' | ||||
| import { err } from './trap' | ||||
| @ -293,6 +298,84 @@ const prepareToEditHelix: PrepareToEditCallback = async ({ operation }) => { | ||||
|   } | ||||
| } | ||||
|  | ||||
| const prepareToEditFillet: PrepareToEditCallback = async ({ | ||||
|   artifact, | ||||
|   operation, | ||||
| }) => { | ||||
|   const baseCommand = { | ||||
|     name: 'Fillet', | ||||
|     groupId: 'modeling', | ||||
|   } | ||||
|   if ( | ||||
|     operation.type !== 'StdLibCall' || | ||||
|     !operation.labeledArgs || | ||||
|     operation.name !== 'fillet' || | ||||
|     !('tags' in operation.labeledArgs) || | ||||
|     !('radius' in operation.labeledArgs) || | ||||
|     !operation.labeledArgs.radius || | ||||
|     !artifact || | ||||
|     artifact.type !== 'edgeCut' || | ||||
|     artifact.subType !== 'fillet' | ||||
|   ) { | ||||
|     return baseCommand | ||||
|   } | ||||
|  | ||||
|   if ( | ||||
|     !operation.labeledArgs.tags || | ||||
|     operation.labeledArgs.tags.value.type !== 'Array' | ||||
|   ) { | ||||
|     return baseCommand | ||||
|   } | ||||
|   const edgeIds = operation.labeledArgs.tags.value.value.map((tag) => | ||||
|     tag.type === 'Uuid' ? tag.value : '' | ||||
|   ) | ||||
|   if (!edgeIds.every((id) => id)) { | ||||
|     return baseCommand | ||||
|   } | ||||
|  | ||||
|   const edges = getArtifactsOfTypes( | ||||
|     { | ||||
|       keys: edgeIds, | ||||
|       types: ['sweepEdge', 'segment'], | ||||
|     }, | ||||
|     engineCommandManager.artifactGraph | ||||
|   ) | ||||
|   const selection: ModelingCommandSchema['Fillet']['selection'] = { | ||||
|     graphSelections: edges | ||||
|       .values() | ||||
|       .map((edge, index) => ({ | ||||
|         artifact: edge, | ||||
|         codeRef: { | ||||
|           range: operation.labeledArgs.tags?.sourceRange ?? [0, 0, 0], | ||||
|           pathToNode: getNodePathFromSourceRange( | ||||
|             kclManager.ast, | ||||
|             operation.labeledArgs.tags?.sourceRange ?? [0, 0, 0] | ||||
|           ), | ||||
|         }, | ||||
|       })) | ||||
|       .toArray(), | ||||
|     otherSelections: [], | ||||
|   } | ||||
|   const maybeRadius = await stringToKclExpression( | ||||
|     codeManager.getCodeAtRange(operation.labeledArgs.radius.sourceRange) | ||||
|   ) | ||||
|   if (err(maybeRadius) || 'errors' in maybeRadius) return baseCommand | ||||
|  | ||||
|   const argDefaultValues: ModelingCommandSchema['Fillet'] = { | ||||
|     nodeToEdit: getNodePathFromSourceRange( | ||||
|       kclManager.ast, | ||||
|       sourceRangeFromRust(operation.sourceRange) | ||||
|     ), | ||||
|     radius: maybeRadius, | ||||
|     selection, | ||||
|   } | ||||
|  | ||||
|   return { | ||||
|     ...baseCommand, | ||||
|     argDefaultValues, | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * A map of standard library calls to their corresponding information | ||||
|  * for use in the feature tree UI. | ||||
| @ -312,6 +395,7 @@ export const stdLibMap: Record<string, StdLibCallInfo> = { | ||||
|   fillet: { | ||||
|     label: 'Fillet', | ||||
|     icon: 'fillet3d', | ||||
|     prepareToEdit: prepareToEditFillet, | ||||
|   }, | ||||
|   helix: { | ||||
|     label: 'Helix', | ||||
|  | ||||
| @ -134,8 +134,10 @@ export const commandBarMachine = setup({ | ||||
|         // that is, the first argument that is not already in the argumentsToSubmit | ||||
|         // or hidden, or that is not undefined, or that is not marked as "skippable". | ||||
|         // TODO validate the type of the existing arguments | ||||
|         const nonHiddenArgs = Object.entries(selectedCommand.args).filter( | ||||
|           (a) => !a[1].hidden | ||||
|         const nonHiddenArgs = Object.entries(selectedCommand.args).filter((a) => | ||||
|           a[1].hidden && typeof a[1].hidden === 'function' | ||||
|             ? !a[1].hidden(context) | ||||
|             : !a[1].hidden | ||||
|         ) | ||||
|         let argIndex = 0 | ||||
|  | ||||
| @ -260,7 +262,11 @@ export const commandBarMachine = setup({ | ||||
|     }, | ||||
|     'All arguments are skippable': ({ context }) => { | ||||
|       return Object.values(context.selectedCommand!.args!).every( | ||||
|         (argConfig) => argConfig.skip || argConfig.hidden | ||||
|         (argConfig) => | ||||
|           argConfig.skip || | ||||
|           (typeof argConfig.hidden === 'function' | ||||
|             ? argConfig.hidden(context) | ||||
|             : argConfig.hidden) | ||||
|       ) | ||||
|     }, | ||||
|     'Has selected command': ({ context }) => !!context.selectedCommand, | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	