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:
@ -13,9 +13,11 @@ import {
|
||||
giveSketchFnCallTag,
|
||||
moveValueIntoNewVariable,
|
||||
sketchOnExtrudedFace,
|
||||
deleteSegmentFromPipeExpression,
|
||||
removeSingleConstraintInfo,
|
||||
} from './modifyAst'
|
||||
import { enginelessExecutor } from '../lib/testHelpers'
|
||||
import { getNodePathFromSourceRange } from './queryAst'
|
||||
import { findUsesOfTagInPipe, getNodePathFromSourceRange } from './queryAst'
|
||||
|
||||
beforeAll(async () => {
|
||||
await initPromise
|
||||
@ -364,3 +366,231 @@ const part002 = startSketchOn(part001, 'seg01')`)
|
||||
const part002 = startSketchOn(part001, 'END')`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing deleteSegmentFromPipeExpression', () => {
|
||||
it('Should delete a segment withOUT any dependent segments', async () => {
|
||||
const code = `const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([54.78, -95.91], %)
|
||||
|> line([306.21, 198.82], %)
|
||||
|> line([306.21, 198.85], %, 'a')
|
||||
|> line([306.21, 198.87], %)`
|
||||
const ast = parse(code)
|
||||
const programMemory = await enginelessExecutor(ast)
|
||||
const lineOfInterest = "line([306.21, 198.85], %, 'a')"
|
||||
const range: [number, number] = [
|
||||
code.indexOf(lineOfInterest),
|
||||
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||
]
|
||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||
const modifiedAst = deleteSegmentFromPipeExpression(
|
||||
[],
|
||||
ast,
|
||||
programMemory,
|
||||
code,
|
||||
pathToNode
|
||||
)
|
||||
const newCode = recast(modifiedAst)
|
||||
expect(newCode).toBe(`const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([54.78, -95.91], %)
|
||||
|> line([306.21, 198.82], %)
|
||||
|> line([306.21, 198.87], %)
|
||||
`)
|
||||
})
|
||||
describe('Should delete a segment WITH any dependent segments, unconstraining the dependent parts', () => {
|
||||
const makeCode = (
|
||||
line: string,
|
||||
replace1 = '',
|
||||
replace2 = ''
|
||||
) => `const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([54.78, -95.91], %)
|
||||
|> line([306.21, 198.82], %, 'b')
|
||||
${!replace1 ? ` |> ${line}\n` : ''} |> angledLine([-65, ${
|
||||
!replace1 ? "segLen('a', %)" : replace1
|
||||
}], %)
|
||||
|> line([306.21, 198.87], %)
|
||||
|> angledLine([65, ${!replace2 ? "segAng('a', %)" : replace2}], %)
|
||||
|> line([-963.39, -154.67], %)
|
||||
`
|
||||
test.each([
|
||||
['line', "line([306.21, 198.85], %, 'a')", ['365.11', '33']],
|
||||
['lineTo', "lineTo([306.21, 198.85], %, 'a')", ['110.48', '119.73']],
|
||||
['yLine', "yLine(198.85, %, 'a')", ['198.85', '90']],
|
||||
['xLine', "xLine(198.85, %, 'a')", ['198.85', '0']],
|
||||
['yLineTo', "yLineTo(198.85, %, 'a')", ['95.94', '90']],
|
||||
['xLineTo', "xLineTo(198.85, %, 'a')", ['162.14', '180']],
|
||||
[
|
||||
'angledLine',
|
||||
"angledLine({ angle: 45.5, length: 198.85 }, %, 'a')",
|
||||
['198.85', '45.5'],
|
||||
],
|
||||
[
|
||||
'angledLineOfXLength',
|
||||
"angledLineOfXLength({ angle: 45.5, length: 198.85 }, %, 'a')",
|
||||
['283.7', '45.5'],
|
||||
],
|
||||
[
|
||||
'angledLineOfYLength',
|
||||
"angledLineOfYLength({ angle: 45.5, length: 198.85 }, %, 'a')",
|
||||
['278.79', '45.5'],
|
||||
],
|
||||
[
|
||||
'angledLineToX',
|
||||
"angledLineToX({ angle: 45.5, to: 198.85 }, %, 'a')",
|
||||
['231.33', '134.5'],
|
||||
],
|
||||
[
|
||||
'angledLineToY',
|
||||
"angledLineToY({ angle: 45.5, to: 198.85 }, %, 'a')",
|
||||
['134.51', '45.5'],
|
||||
],
|
||||
[
|
||||
'angledLineThatIntersects',
|
||||
`angledLineThatIntersects({ angle: 45.5, intersectTag: 'b', offset: 198.85 }, %, 'a')`,
|
||||
['918.4', '45.5'],
|
||||
],
|
||||
])(`%s`, async (_, line, [replace1, replace2]) => {
|
||||
const code = makeCode(line)
|
||||
const ast = parse(code)
|
||||
const programMemory = await enginelessExecutor(ast)
|
||||
const lineOfInterest = line
|
||||
const range: [number, number] = [
|
||||
code.indexOf(lineOfInterest),
|
||||
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||
]
|
||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||
const dependentSegments = findUsesOfTagInPipe(ast, pathToNode)
|
||||
const modifiedAst = deleteSegmentFromPipeExpression(
|
||||
dependentSegments,
|
||||
ast,
|
||||
programMemory,
|
||||
code,
|
||||
pathToNode
|
||||
)
|
||||
const newCode = recast(modifiedAst)
|
||||
expect(newCode).toBe(makeCode(line, replace1, replace2))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Testing removeSingleConstraintInfo', () => {
|
||||
describe('with mostly object notation', () => {
|
||||
const code = `const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([3 + 0, 4 + 0], %)
|
||||
|> angledLine({ angle: 3 + 0, length: 3.14 + 0 }, %)
|
||||
|> lineTo([6.14 + 0, 3.14 + 0], %)
|
||||
|> xLineTo(8 + 0, %)
|
||||
|> yLineTo(5 + 0, %)
|
||||
|> yLine(3.14 + 0, %, 'a')
|
||||
|> xLine(3.14 + 0, %)
|
||||
|> angledLineOfXLength({ angle: 3 + 0, length: 3.14 + 0 }, %)
|
||||
|> angledLineOfYLength({ angle: 30 + 0, length: 3 + 0 }, %)
|
||||
|> angledLineToX({ angle: 12.14 + 0, to: 12 + 0 }, %)
|
||||
|> angledLineToY({ angle: 30 + 0, to: 10.14 + 0 }, %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: 3.14 + 0,
|
||||
intersectTag: 'a',
|
||||
offset: 0 + 0
|
||||
}, %)
|
||||
|> tangentialArcTo([3.14 + 0, 13.14 + 0], %)`
|
||||
test.each([
|
||||
[' line([3 + 0, 4], %)', 'arrayIndex', 1],
|
||||
[
|
||||
'angledLine({ angle: 3, length: 3.14 + 0 }, %)',
|
||||
'objectProperty',
|
||||
'angle',
|
||||
],
|
||||
['lineTo([6.14, 3.14 + 0], %)', 'arrayIndex', 0],
|
||||
['xLineTo(8, %)', '', ''],
|
||||
['yLineTo(5, %)', '', ''],
|
||||
["yLine(3.14, %, 'a')", '', ''],
|
||||
['xLine(3.14, %)', '', ''],
|
||||
[
|
||||
'angledLineOfXLength({ angle: 3, length: 3.14 + 0 }, %)',
|
||||
'objectProperty',
|
||||
'angle',
|
||||
],
|
||||
[
|
||||
'angledLineOfYLength({ angle: 30 + 0, length: 3 }, %)',
|
||||
'objectProperty',
|
||||
'length',
|
||||
],
|
||||
[
|
||||
'angledLineToX({ angle: 12.14 + 0, to: 12 }, %)',
|
||||
'objectProperty',
|
||||
'to',
|
||||
],
|
||||
[
|
||||
'angledLineToY({ angle: 30, to: 10.14 + 0 }, %)',
|
||||
'objectProperty',
|
||||
'angle',
|
||||
],
|
||||
[
|
||||
`angledLineThatIntersects({
|
||||
angle: 3.14 + 0,
|
||||
offset: 0,
|
||||
intersectTag: 'a'
|
||||
}, %)`,
|
||||
'objectProperty',
|
||||
'offset',
|
||||
],
|
||||
['tangentialArcTo([3.14 + 0, 13.14], %)', 'arrayIndex', 1],
|
||||
])('stdlib fn: %s', async (expectedFinish, key, value) => {
|
||||
const ast = parse(code)
|
||||
const programMemory = await enginelessExecutor(ast)
|
||||
const lineOfInterest = expectedFinish.split('(')[0] + '('
|
||||
const range: [number, number] = [
|
||||
code.indexOf(lineOfInterest) + 1,
|
||||
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||
]
|
||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||
const mod = removeSingleConstraintInfo(
|
||||
{
|
||||
pathToCallExp: pathToNode,
|
||||
[key]: value,
|
||||
},
|
||||
ast,
|
||||
programMemory
|
||||
)
|
||||
if (!mod) throw new Error('yo is undefined')
|
||||
const recastCode = recast(mod.modifiedAst)
|
||||
expect(recastCode).toContain(expectedFinish)
|
||||
})
|
||||
})
|
||||
describe('with array notation', () => {
|
||||
const code = `const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLine([3.14 + 0, 3.14 + 0], %)
|
||||
|> angledLineOfXLength([3 + 0, 3.14 + 0], %)
|
||||
|> angledLineOfYLength([30 + 0, 3 + 0], %)
|
||||
|> angledLineToX([12.14 + 0, 12 + 0], %)
|
||||
|> angledLineToY([30 + 0, 10.14 + 0], %)`
|
||||
test.each([
|
||||
['angledLine([3, 3.14 + 0], %)', 'arrayIndex', 0],
|
||||
['angledLineOfXLength([3, 3.14 + 0], %)', 'arrayIndex', 0],
|
||||
['angledLineOfYLength([30 + 0, 3], %)', 'arrayIndex', 1],
|
||||
['angledLineToX([12.14 + 0, 12], %)', 'arrayIndex', 1],
|
||||
['angledLineToY([30, 10.14 + 0], %)', 'arrayIndex', 0],
|
||||
])('stdlib fn: %s', async (expectedFinish, key, value) => {
|
||||
const ast = parse(code)
|
||||
const programMemory = await enginelessExecutor(ast)
|
||||
const lineOfInterest = expectedFinish.split('(')[0] + '('
|
||||
const range: [number, number] = [
|
||||
code.indexOf(lineOfInterest) + 1,
|
||||
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||
]
|
||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||
const mod = removeSingleConstraintInfo(
|
||||
{
|
||||
pathToCallExp: pathToNode,
|
||||
[key]: value,
|
||||
},
|
||||
ast,
|
||||
programMemory
|
||||
)
|
||||
if (!mod) throw new Error('yo is undefined')
|
||||
const recastCode = recast(mod.modifiedAst)
|
||||
expect(recastCode).toContain(expectedFinish)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user