Add grouping of module instances in Feature Tree (#6125)

* Rename operations to be more generic grouping

* Add group enum

* Add module instance groups

* Change to export all operation ts-rs types to the same file

* Fix Feature Tree display of modules to use name

* Ignore clippy warning

* Update output after operation changes

* Change module instances in Feature Tree use to import icon

* Fix error message when attempting to delete module instance
This commit is contained in:
Jonathan Tran
2025-04-03 22:10:39 -04:00
committed by GitHub
parent c7b348390e
commit d38dcb9ba2
65 changed files with 12299 additions and 9315 deletions

View File

@ -1,5 +1,4 @@
import type { Operation } from '@rust/kcl-lib/bindings/Operation'
import type { OpKclValue } from '@rust/kcl-lib/bindings/OpKclValue'
import type { Operation, OpKclValue } from '@rust/kcl-lib/bindings/Operation'
import type { CustomIconName } from '@src/components/CustomIcon'
import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
@ -1118,10 +1117,20 @@ export function getOperationLabel(op: Operation): string {
return stdLibMap[op.name]?.label ?? op.name
case 'KclStdLibCall':
return stdLibMap[op.name]?.label ?? op.name
case 'UserDefinedFunctionCall':
return op.name ?? 'Anonymous custom function'
case 'UserDefinedFunctionReturn':
return 'User function return'
case 'GroupBegin':
if (op.group.type === 'FunctionCall') {
return op.group.name ?? 'anonymous'
} else if (op.group.type === 'ModuleInstance') {
return op.group.name
} else {
const _exhaustiveCheck: never = op.group
return '' // unreachable
}
case 'GroupEnd':
return 'Group end'
default:
const _exhaustiveCheck: never = op
return '' // unreachable
}
}
@ -1134,8 +1143,16 @@ export function getOperationIcon(op: Operation): CustomIconName {
return stdLibMap[op.name]?.icon ?? 'questionMark'
case 'KclStdLibCall':
return stdLibMap[op.name]?.icon ?? 'questionMark'
default:
case 'GroupBegin':
if (op.group.type === 'ModuleInstance') {
return 'import' // TODO: Use insert icon.
}
return 'make-variable'
case 'GroupEnd':
return 'questionMark'
default:
const _exhaustiveCheck: never = op
return 'questionMark' // unreachable
}
}
@ -1151,31 +1168,31 @@ export function filterOperations(operations: Operation[]): Operation[] {
* for use in the feature tree UI
*/
const operationFilters = [
isNotUserFunctionWithNoOperations,
isNotInsideUserFunction,
isNotUserFunctionReturn,
isNotGroupWithNoOperations,
isNotInsideGroup,
isNotGroupEnd,
]
/**
* A filter to exclude everything that occurs inside a UserDefinedFunctionCall
* and its corresponding UserDefinedFunctionReturn from a list of operations.
* This works even when there are nested function calls.
* A filter to exclude everything that occurs inside a GroupBegin and its
* corresponding GroupEnd from a list of operations. This works even when there
* are nested function calls and module instances.
*/
function isNotInsideUserFunction(operations: Operation[]): Operation[] {
function isNotInsideGroup(operations: Operation[]): Operation[] {
const ops: Operation[] = []
let depth = 0
for (const op of operations) {
if (depth === 0) {
ops.push(op)
}
if (op.type === 'UserDefinedFunctionCall') {
if (op.type === 'GroupBegin') {
depth++
}
if (op.type === 'UserDefinedFunctionReturn') {
if (op.type === 'GroupEnd') {
depth--
console.assert(
depth >= 0,
'Unbalanced UserDefinedFunctionCall and UserDefinedFunctionReturn; too many returns'
'Unbalanced GroupBegin and GroupEnd; too many ends'
)
}
}
@ -1184,26 +1201,23 @@ function isNotInsideUserFunction(operations: Operation[]): Operation[] {
}
/**
* A filter to exclude UserDefinedFunctionCall operations and their
* corresponding UserDefinedFunctionReturn that don't have any operations inside
* them from a list of operations.
* A filter to exclude GroupBegin operations and their corresponding GroupEnd
* that don't have any operations inside them from a list of operations.
*/
function isNotUserFunctionWithNoOperations(
operations: Operation[]
): Operation[] {
function isNotGroupWithNoOperations(operations: Operation[]): Operation[] {
return operations.filter((op, index) => {
if (
op.type === 'UserDefinedFunctionCall' &&
// If this is a call at the end of the array, it's preserved.
op.type === 'GroupBegin' &&
// If this is a begin at the end of the array, it's preserved.
index < operations.length - 1 &&
operations[index + 1].type === 'UserDefinedFunctionReturn'
operations[index + 1].type === 'GroupEnd'
)
return false
if (
op.type === 'UserDefinedFunctionReturn' &&
// If this return is at the beginning of the array, it's preserved.
op.type === 'GroupEnd' &&
// If this is an end at the beginning of the array, it's preserved.
index > 0 &&
operations[index - 1].type === 'UserDefinedFunctionCall'
operations[index - 1].type === 'GroupBegin'
)
return false
@ -1212,11 +1226,10 @@ function isNotUserFunctionWithNoOperations(
}
/**
* A filter to exclude UserDefinedFunctionReturn operations from a list of
* operations.
* A filter to exclude GroupEnd operations from a list of operations.
*/
function isNotUserFunctionReturn(ops: Operation[]): Operation[] {
return ops.filter((op) => op.type !== 'UserDefinedFunctionReturn')
function isNotGroupEnd(ops: Operation[]): Operation[] {
return ops.filter((op) => op.type !== 'GroupEnd')
}
export interface EnterEditFlowProps {
@ -1230,7 +1243,7 @@ export async function enterEditFlow({
}: EnterEditFlowProps): Promise<Error | CommandBarMachineEvent> {
if (operation.type !== 'StdLibCall' && operation.type !== 'KclStdLibCall') {
return new Error(
'Feature tree editing not yet supported for user-defined functions. Please edit in the code editor.'
'Feature tree editing not yet supported for user-defined functions or modules. Please edit in the code editor.'
)
}
const stdLibInfo = stdLibMap[operation.name]
@ -1269,7 +1282,7 @@ export async function enterAppearanceFlow({
}: EnterEditFlowProps): Promise<Error | CommandBarMachineEvent> {
if (operation.type !== 'StdLibCall' && operation.type !== 'KclStdLibCall') {
return new Error(
'Appearance setting not yet supported for user-defined functions. Please edit in the code editor.'
'Appearance setting not yet supported for user-defined functions or modules. Please edit in the code editor.'
)
}
const stdLibInfo = stdLibMap[operation.name]