Symbols overlay (#2033)

* start of overlay work

* add new icons

* add constraint symbols

* add three dots

* add primary colours

* refactor how we get constraint info for overlays

* refactor how we get constraint info for overlays

* get symbols working for tangential arc too

* extra data on constraint info

* add initial delete

* fix types and circular dep issue after rebase

* fix quirk with horz vert line overlays

* fix setup and tear down of overlays

* remove overlays that are too small

* throttle overlay updates and prove tests selecting html instead of hardcoded px coords

* initial show overaly on segment hover

* remove overlays when tool is equipped

* dounce overlay updates

* tsc

* make higlighting robust to small changes in source ranges

* replace with variable for unconstrained values, and improve styles for popover

* background tweak

* make overlays unconstrain inputs

* fix small regression

* write query for finding related tag references

* make delete segment safe

* typo

* un used imports

* test deleteSegmentFromPipeExpression

* add getConstraintInfo test

* test removeSingleConstraintInfo

* more tests

* tsc

* add tests for overlay buttons

* rename tests

* fmt

* better naming structure

* more reliablity

* more test tweaks

* fix selection test

* add delete segments with overlays tests

* dependant tag tests for segment delet

* typo

* test clean up

* fix some perf issus

* clean up

* clean up

* make things a little more dry

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* trigger ci

* Make constraint hover popovers readable on light mode

* Touch up the new variable dialog

* Little touch-up to three-dot menu style

* fix highlight issue

* fmt

* use optional chain

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)"

This reverts commit be3d61e4a3.

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* disable var panel in sketch mode

* fix overlay tests after mergi in main

* test tweak

* try fix ubuntu

* fmt

* more test tweaks

* tweak

* tweaks

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
This commit is contained in:
Kurt Hutten
2024-05-24 20:54:42 +10:00
committed by GitHub
parent 87c551b869
commit cf52e151fb
28 changed files with 4359 additions and 216 deletions

View File

@ -15,17 +15,26 @@ import {
BinaryExpression,
PathToNode,
ProgramMemory,
SourceRange,
} from './wasm'
import {
isNodeSafeToReplacePath,
findAllPreviousVariables,
findAllPreviousVariablesPath,
getNodeFromPath,
getNodePathFromSourceRange,
isNodeSafeToReplace,
} from './queryAst'
import { addTagForSketchOnFace } from './std/sketch'
import { isLiteralArrayOrStatic } from './std/sketchcombos'
import { addTagForSketchOnFace, getConstraintInfo } from './std/sketch'
import {
PathToNodeMap,
isLiteralArrayOrStatic,
removeSingleConstraint,
transformAstSketchLines,
} from './std/sketchcombos'
import { DefaultPlaneStr } from 'clientSideScene/sceneEntities'
import { roundOff } from 'lib/utils'
import { isOverlap, roundOff } from 'lib/utils'
import { ConstrainInfo } from './std/stdTypes'
export function startSketchOnDefault(
node: Program,
@ -241,11 +250,7 @@ export function extrudeSketch(
pathToExtrudeArg: PathToNode
} {
const _node = { ...node }
const { node: sketchExpression } = getNodeFromPath(
_node,
pathToNode,
'SketchExpression' // TODO fix this #25
)
const { node: sketchExpression } = getNodeFromPath(_node, pathToNode)
// determine if sketchExpression is in a pipeExpression or not
const { node: pipeExpression } = getNodeFromPath<PipeExpression>(
@ -619,6 +624,34 @@ export function giveSketchFnCallTag(
}
}
export function moveValueIntoNewVariablePath(
ast: Program,
programMemory: ProgramMemory,
pathToNode: PathToNode,
variableName: string
): {
modifiedAst: Program
pathToReplacedNode?: PathToNode
} {
const { isSafe, value, replacer } = isNodeSafeToReplacePath(ast, pathToNode)
if (!isSafe || value.type === 'Identifier') return { modifiedAst: ast }
const { insertIndex } = findAllPreviousVariablesPath(
ast,
programMemory,
pathToNode
)
let _node = JSON.parse(JSON.stringify(ast))
const boop = replacer(_node, variableName)
_node = boop.modifiedAst
_node.body.splice(
insertIndex,
0,
createVariableDeclaration(variableName, value)
)
return { modifiedAst: _node, pathToReplacedNode: boop.pathToReplaced }
}
export function moveValueIntoNewVariable(
ast: Program,
programMemory: ProgramMemory,
@ -626,6 +659,7 @@ export function moveValueIntoNewVariable(
variableName: string
): {
modifiedAst: Program
pathToReplacedNode?: PathToNode
} {
const { isSafe, value, replacer } = isNodeSafeToReplace(ast, sourceRange)
if (!isSafe || value.type === 'Identifier') return { modifiedAst: ast }
@ -636,11 +670,124 @@ export function moveValueIntoNewVariable(
sourceRange
)
let _node = JSON.parse(JSON.stringify(ast))
_node = replacer(_node, variableName).modifiedAst
const { modifiedAst, pathToReplaced } = replacer(_node, variableName)
_node = modifiedAst
_node.body.splice(
insertIndex,
0,
createVariableDeclaration(variableName, value)
)
return { modifiedAst: _node }
return { modifiedAst: _node, pathToReplacedNode: pathToReplaced }
}
/**
* Deletes a segment from a pipe expression, if the segment has a tag that other segments use, it will remove that value and replace it with the equivalent literal
* @param dependentRanges - The ranges of the segments that are dependent on the segment being deleted, this is usually the output of `findUsesOfTagInPipe`
*/
export function deleteSegmentFromPipeExpression(
dependentRanges: SourceRange[],
modifiedAst: Program,
programMemory: ProgramMemory,
code: string,
pathToNode: PathToNode
): Program {
let _modifiedAst: Program = JSON.parse(JSON.stringify(modifiedAst))
dependentRanges.forEach((range) => {
const path = getNodePathFromSourceRange(_modifiedAst, range)
const callExp = getNodeFromPath<CallExpression>(
_modifiedAst,
path,
'CallExpression',
true
)
const constraintInfo = getConstraintInfo(callExp.node, code, path).find(
({ sourceRange }) => isOverlap(sourceRange, range)
)
if (!constraintInfo) return
const input = makeRemoveSingleConstraintInput(
constraintInfo.argPosition,
callExp.shallowPath
)
if (!input) return
const transform = removeSingleConstraintInfo(
{
...input,
},
_modifiedAst,
programMemory
)
if (!transform) return
_modifiedAst = transform.modifiedAst
})
const pipeExpression = getNodeFromPath<PipeExpression>(
_modifiedAst,
pathToNode,
'PipeExpression'
).node
const pipeInPathIndex = pathToNode.findIndex(
([_, desc]) => desc === 'PipeExpression'
)
const segmentIndexInPipe = pathToNode[pipeInPathIndex + 1][0] as number
pipeExpression.body.splice(segmentIndexInPipe, 1)
return _modifiedAst
}
export function makeRemoveSingleConstraintInput(
argPosition: ConstrainInfo['argPosition'],
pathToNode: PathToNode
): Parameters<typeof removeSingleConstraintInfo>[0] | false {
return argPosition?.type === 'singleValue'
? {
pathToCallExp: pathToNode,
}
: argPosition?.type === 'arrayItem'
? {
pathToCallExp: pathToNode,
arrayIndex: argPosition.index,
}
: argPosition?.type === 'objectProperty'
? {
pathToCallExp: pathToNode,
objectProperty: argPosition.key,
}
: false
}
export function removeSingleConstraintInfo(
{
pathToCallExp,
arrayIndex,
objectProperty,
}: {
pathToCallExp: PathToNode
arrayIndex?: number
objectProperty?: string
},
ast: Program,
programMemory: ProgramMemory
):
| {
modifiedAst: Program
pathToNodeMap: PathToNodeMap
}
| false {
const transform = removeSingleConstraint({
pathToCallExp,
arrayIndex,
objectProperty,
ast,
})
if (!transform) return false
return transformAstSketchLines({
ast,
selectionRanges: [pathToCallExp],
transformInfos: [transform],
programMemory,
referenceSegName: '',
})
}