Cursors should stay after a code-mod (#113)

* setup to get path to nodes back from ast-mods

* fix cursor setting for constraint buttons that use transformSecondarySketchLinesTagFirst

* fix cursors for constraints that use transformAstSketchLines
This commit is contained in:
Kurt Hutten
2023-04-14 07:49:36 +10:00
committed by GitHub
parent 2fc68e7c82
commit 15699361a0
17 changed files with 410 additions and 312 deletions

View File

@ -93,7 +93,7 @@ export const Toolbar = () => {
ast, ast,
pathToNode pathToNode
) )
updateAst(modifiedAst, pathToExtrudeArg) updateAst(modifiedAst, { focusPath: pathToExtrudeArg })
}} }}
className="border m-1 px-1 rounded text-xs" className="border m-1 px-1 rounded text-xs"
> >
@ -111,7 +111,7 @@ export const Toolbar = () => {
pathToNode, pathToNode,
false false
) )
updateAst(modifiedAst, pathToExtrudeArg) updateAst(modifiedAst, { focusPath: pathToExtrudeArg })
}} }}
className="border m-1 px-1 rounded text-xs" className="border m-1 px-1 rounded text-xs"
> >

View File

@ -11,17 +11,18 @@ import {
transformSecondarySketchLinesTagFirst, transformSecondarySketchLinesTagFirst,
getTransformInfos, getTransformInfos,
} from '../../lang/std/sketchcombos' } from '../../lang/std/sketchcombos'
import { updateCursors } from '../../lang/util'
export const EqualAngle = () => { export const EqualAngle = () => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
(s) => ({ useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
programMemory: s.programMemory, programMemory: s.programMemory,
}) setCursor: s.setCursor,
) }))
const [enableEqual, setEnableEqual] = useState(false) const [enableEqual, setEnableEqual] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>() const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
useEffect(() => { useEffect(() => {
@ -72,18 +73,19 @@ export const EqualAngle = () => {
return ( return (
<button <button
onClick={() => onClick={async () => {
transformInfos && if (!(transformInfos && ast)) return
ast && const { modifiedAst, pathToNodeMap } =
updateAst(
transformSecondarySketchLinesTagFirst({ transformSecondarySketchLinesTagFirst({
ast, ast,
selectionRanges, selectionRanges,
transformInfos, transformInfos,
programMemory, programMemory,
})?.modifiedAst })
) updateAst(modifiedAst, {
} callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
}}
className={`border m-1 px-1 rounded text-xs ${ className={`border m-1 px-1 rounded text-xs ${
enableEqual ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400' enableEqual ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
}`} }`}

View File

@ -11,17 +11,18 @@ import {
transformSecondarySketchLinesTagFirst, transformSecondarySketchLinesTagFirst,
getTransformInfos, getTransformInfos,
} from '../../lang/std/sketchcombos' } from '../../lang/std/sketchcombos'
import { updateCursors } from '../../lang/util'
export const EqualLength = () => { export const EqualLength = () => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
(s) => ({ useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
programMemory: s.programMemory, programMemory: s.programMemory,
}) setCursor: s.setCursor,
) }))
const [enableEqual, setEnableEqual] = useState(false) const [enableEqual, setEnableEqual] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>() const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
useEffect(() => { useEffect(() => {
@ -72,18 +73,19 @@ export const EqualLength = () => {
return ( return (
<button <button
onClick={() => onClick={() => {
transformInfos && if (!(transformInfos && ast)) return
ast && const { modifiedAst, pathToNodeMap } =
updateAst(
transformSecondarySketchLinesTagFirst({ transformSecondarySketchLinesTagFirst({
ast, ast,
selectionRanges, selectionRanges,
transformInfos, transformInfos,
programMemory, programMemory,
})?.modifiedAst })
) updateAst(modifiedAst, {
} callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
}}
className={`border m-1 px-1 rounded text-xs ${ className={`border m-1 px-1 rounded text-xs ${
enableEqual ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400' enableEqual ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
}`} }`}

View File

@ -10,21 +10,22 @@ import {
getTransformInfos, getTransformInfos,
transformAstSketchLines, transformAstSketchLines,
} from '../../lang/std/sketchcombos' } from '../../lang/std/sketchcombos'
import { updateCursors } from '../../lang/util'
export const HorzVert = ({ export const HorzVert = ({
horOrVert, horOrVert,
}: { }: {
horOrVert: 'vertical' | 'horizontal' horOrVert: 'vertical' | 'horizontal'
}) => { }) => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
(s) => ({ useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
programMemory: s.programMemory, programMemory: s.programMemory,
}) setCursor: s.setCursor,
) }))
const [enableHorz, setEnableHorz] = useState(false) const [enableHorz, setEnableHorz] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>() const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
useEffect(() => { useEffect(() => {
@ -51,19 +52,19 @@ export const HorzVert = ({
return ( return (
<button <button
onClick={() => onClick={() => {
transformInfos && if (!transformInfos || !ast) return
ast && const { modifiedAst, pathToNodeMap } = transformAstSketchLines({
updateAst( ast,
transformAstSketchLines({ selectionRanges,
ast, transformInfos,
selectionRanges, programMemory,
transformInfos, referenceSegName: '',
programMemory, })
referenceSegName: '', updateAst(modifiedAst, {
})?.modifiedAst callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
) })
} }}
className={`border m-1 px-1 rounded text-xs ${ className={`border m-1 px-1 rounded text-xs ${
enableHorz ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400' enableHorz ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
}`} }`}

View File

@ -20,19 +20,20 @@ import {
import { GetInfoModal } from '../SetHorVertDistanceModal' import { GetInfoModal } from '../SetHorVertDistanceModal'
import { createVariableDeclaration } from '../../lang/modifyAst' import { createVariableDeclaration } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers' import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { updateCursors } from '../../lang/util'
const getModalInfo = create(GetInfoModal as any) const getModalInfo = create(GetInfoModal as any)
export const Intersect = () => { export const Intersect = () => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
(s) => ({ useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
programMemory: s.programMemory, programMemory: s.programMemory,
}) setCursor: s.setCursor,
) }))
const [enable, setEnable] = useState(false) const [enable, setEnable] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>() const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
const [forecdSelectionRanges, setForcedSelectionRanges] = const [forecdSelectionRanges, setForcedSelectionRanges] =
@ -125,63 +126,66 @@ export const Intersect = () => {
return ( return (
<button <button
onClick={async () => { onClick={async () => {
if (transformInfos && ast && forecdSelectionRanges) { if (!(transformInfos && ast && forecdSelectionRanges)) return
const { modifiedAst, tagInfo, valueUsedInTransform } = const { modifiedAst, tagInfo, valueUsedInTransform, pathToNodeMap } =
transformSecondarySketchLinesTagFirst({
ast: JSON.parse(JSON.stringify(ast)),
selectionRanges: forecdSelectionRanges,
transformInfos,
programMemory,
})
const {
segName,
value,
valueNode,
variableName,
newVariableInsertIndex,
sign,
}: {
segName: string
value: number
valueNode: Value
variableName?: string
newVariableInsertIndex: number
sign: number
} = await getModalInfo({
segName: tagInfo?.tag,
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: 'offset',
} as any)
if (segName === tagInfo?.tag && value === valueUsedInTransform) {
updateAst(modifiedAst, {
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
} else {
// transform again but forcing certain values
const finalValue = removeDoubleNegatives(
valueNode as BinaryPart,
sign,
variableName
)
const { modifiedAst: _modifiedAst, pathToNodeMap } =
transformSecondarySketchLinesTagFirst({ transformSecondarySketchLinesTagFirst({
ast: JSON.parse(JSON.stringify(ast)), ast,
selectionRanges: forecdSelectionRanges, selectionRanges: forecdSelectionRanges,
transformInfos, transformInfos,
programMemory, programMemory,
forceSegName: segName,
forceValueUsedInTransform: finalValue,
}) })
const { if (variableName) {
segName, const newBody = [..._modifiedAst.body]
value, newBody.splice(
valueNode, newVariableInsertIndex,
variableName, 0,
newVariableInsertIndex, createVariableDeclaration(variableName, valueNode)
sign,
}: {
segName: string
value: number
valueNode: Value
variableName?: string
newVariableInsertIndex: number
sign: number
} = await getModalInfo({
segName: tagInfo?.tag,
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: 'offset',
} as any)
if (segName === tagInfo?.tag && value === valueUsedInTransform) {
updateAst(modifiedAst)
} else {
// transform again but forcing certain values
const finalValue = removeDoubleNegatives(
valueNode as BinaryPart,
sign,
variableName
) )
const { modifiedAst: _modifiedAst } = _modifiedAst.body = newBody
transformSecondarySketchLinesTagFirst({
ast,
selectionRanges: forecdSelectionRanges,
transformInfos,
programMemory,
forceSegName: segName,
forceValueUsedInTransform: finalValue,
})
if (variableName) {
const newBody = [..._modifiedAst.body]
newBody.splice(
newVariableInsertIndex,
0,
createVariableDeclaration(variableName, valueNode)
)
_modifiedAst.body = newBody
}
updateAst(_modifiedAst)
} }
updateAst(_modifiedAst, {
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
} }
}} }}
className={`border m-1 px-1 rounded text-xs ${ className={`border m-1 px-1 rounded text-xs ${

View File

@ -10,17 +10,18 @@ import {
getRemoveConstraintsTransforms, getRemoveConstraintsTransforms,
transformAstSketchLines, transformAstSketchLines,
} from '../../lang/std/sketchcombos' } from '../../lang/std/sketchcombos'
import { updateCursors } from '../../lang/util'
export const RemoveConstrainingValues = () => { export const RemoveConstrainingValues = () => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
(s) => ({ useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
programMemory: s.programMemory, programMemory: s.programMemory,
}) setCursor: s.setCursor,
) }))
const [enableHorz, setEnableHorz] = useState(false) const [enableHorz, setEnableHorz] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>() const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
useEffect(() => { useEffect(() => {
@ -55,19 +56,19 @@ export const RemoveConstrainingValues = () => {
return ( return (
<button <button
onClick={() => onClick={() => {
transformInfos && if (!transformInfos || !ast) return
ast && const { modifiedAst, pathToNodeMap } = transformAstSketchLines({
updateAst( ast,
transformAstSketchLines({ selectionRanges,
ast, transformInfos,
selectionRanges, programMemory,
transformInfos, referenceSegName: '',
programMemory, })
referenceSegName: '', updateAst(modifiedAst, {
})?.modifiedAst callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
) })
} }}
className={`border m-1 px-1 rounded text-xs ${ className={`border m-1 px-1 rounded text-xs ${
enableHorz ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400' enableHorz ? 'bg-gray-50 text-gray-800' : 'bg-gray-200 text-gray-400'
}`} }`}

View File

@ -18,6 +18,7 @@ import {
createVariableDeclaration, createVariableDeclaration,
} from '../../lang/modifyAst' } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers' import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { updateCursors } from '../../lang/util'
const getModalInfo = create(SetAngleLengthModal as any) const getModalInfo = create(SetAngleLengthModal as any)
@ -26,19 +27,15 @@ export const SetAbsDistance = ({
}: { }: {
buttonType: 'xAbs' | 'yAbs' | 'snapToYAxis' | 'snapToXAxis' buttonType: 'xAbs' | 'yAbs' | 'snapToYAxis' | 'snapToXAxis'
}) => { }) => {
const { const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
guiMode, useStore((s) => ({
selectionRanges: selections, guiMode: s.guiMode,
ast, ast: s.ast,
programMemory, updateAst: s.updateAst,
updateAst, selectionRanges: s.selectionRanges,
} = useStore((s) => ({ programMemory: s.programMemory,
guiMode: s.guiMode, setCursor: s.setCursor,
ast: s.ast, }))
updateAst: s.updateAst,
selectionRanges: s.selectionRanges,
programMemory: s.programMemory,
}))
const disType: ConstraintType = const disType: ConstraintType =
buttonType === 'xAbs' || buttonType === 'yAbs' buttonType === 'xAbs' || buttonType === 'yAbs'
? buttonType ? buttonType
@ -49,7 +46,7 @@ export const SetAbsDistance = ({
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>() const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
useEffect(() => { useEffect(() => {
if (!ast) return if (!ast) return
const paths = selections.codeBasedSelections.map(({ range }) => const paths = selectionRanges.codeBasedSelections.map(({ range }) =>
getNodePathFromSourceRange(ast, range) getNodePathFromSourceRange(ast, range)
) )
const nodes = paths.map( const nodes = paths.map(
@ -62,25 +59,25 @@ export const SetAbsDistance = ({
toolTips.includes(node.callee.name as any) toolTips.includes(node.callee.name as any)
) )
const theTransforms = getTransformInfos(selections, ast, disType) const theTransforms = getTransformInfos(selectionRanges, ast, disType)
setTransformInfos(theTransforms) setTransformInfos(theTransforms)
const enableY = const enableY =
disType === 'yAbs' && disType === 'yAbs' &&
selections.otherSelections.length === 1 && selectionRanges.otherSelections.length === 1 &&
selections.otherSelections[0] === 'x-axis' // select the x axis to set the distance from it i.e. y selectionRanges.otherSelections[0] === 'x-axis' // select the x axis to set the distance from it i.e. y
const enableX = const enableX =
disType === 'xAbs' && disType === 'xAbs' &&
selections.otherSelections.length === 1 && selectionRanges.otherSelections.length === 1 &&
selections.otherSelections[0] === 'y-axis' // select the y axis to set the distance from it i.e. x selectionRanges.otherSelections[0] === 'y-axis' // select the y axis to set the distance from it i.e. x
const _enableHorz = const _enableHorz =
isAllTooltips && isAllTooltips &&
theTransforms.every(Boolean) && theTransforms.every(Boolean) &&
selections.codeBasedSelections.length === 1 && selectionRanges.codeBasedSelections.length === 1 &&
(enableX || enableY) (enableX || enableY)
setEnableAngLen(_enableHorz) setEnableAngLen(_enableHorz)
}, [guiMode, selections]) }, [guiMode, selectionRanges])
if (guiMode.mode !== 'sketch') return null if (guiMode.mode !== 'sketch') return null
const isAlign = buttonType === 'snapToYAxis' || buttonType === 'snapToXAxis' const isAlign = buttonType === 'snapToYAxis' || buttonType === 'snapToXAxis'
@ -91,7 +88,7 @@ export const SetAbsDistance = ({
if (!(transformInfos && ast)) return if (!(transformInfos && ast)) return
const { valueUsedInTransform } = transformAstSketchLines({ const { valueUsedInTransform } = transformAstSketchLines({
ast: JSON.parse(JSON.stringify(ast)), ast: JSON.parse(JSON.stringify(ast)),
selectionRanges: selections, selectionRanges: selectionRanges,
transformInfos, transformInfos,
programMemory, programMemory,
referenceSegName: '', referenceSegName: '',
@ -108,14 +105,15 @@ export const SetAbsDistance = ({
? createIdentifier('_0') ? createIdentifier('_0')
: removeDoubleNegatives(valueNode, sign, variableName) : removeDoubleNegatives(valueNode, sign, variableName)
const { modifiedAst: _modifiedAst } = transformAstSketchLines({ const { modifiedAst: _modifiedAst, pathToNodeMap } =
ast: JSON.parse(JSON.stringify(ast)), transformAstSketchLines({
selectionRanges: selections, ast: JSON.parse(JSON.stringify(ast)),
transformInfos, selectionRanges: selectionRanges,
programMemory, transformInfos,
referenceSegName: '', programMemory,
forceValueUsedInTransform: finalValue, referenceSegName: '',
}) forceValueUsedInTransform: finalValue,
})
if (variableName) { if (variableName) {
const newBody = [..._modifiedAst.body] const newBody = [..._modifiedAst.body]
newBody.splice( newBody.splice(
@ -126,7 +124,9 @@ export const SetAbsDistance = ({
_modifiedAst.body = newBody _modifiedAst.body = newBody
} }
updateAst(_modifiedAst) updateAst(_modifiedAst, {
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
} catch (e) { } catch (e) {
console.log('e', e) console.log('e', e)
} }

View File

@ -19,19 +19,20 @@ import {
import { GetInfoModal } from '../SetHorVertDistanceModal' import { GetInfoModal } from '../SetHorVertDistanceModal'
import { createVariableDeclaration } from '../../lang/modifyAst' import { createVariableDeclaration } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers' import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { updateCursors } from '../../lang/util'
const getModalInfo = create(GetInfoModal as any) const getModalInfo = create(GetInfoModal as any)
export const SetAngleBetween = () => { export const SetAngleBetween = () => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
(s) => ({ useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
programMemory: s.programMemory, programMemory: s.programMemory,
}) setCursor: s.setCursor,
) }))
const [enable, setEnable] = useState(false) const [enable, setEnable] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>() const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
useEffect(() => { useEffect(() => {
@ -83,63 +84,66 @@ export const SetAngleBetween = () => {
return ( return (
<button <button
onClick={async () => { onClick={async () => {
if (transformInfos && ast) { if (!(transformInfos && ast)) return
const { modifiedAst, tagInfo, valueUsedInTransform } = const { modifiedAst, tagInfo, valueUsedInTransform, pathToNodeMap } =
transformSecondarySketchLinesTagFirst({
ast: JSON.parse(JSON.stringify(ast)),
selectionRanges,
transformInfos,
programMemory,
})
const {
segName,
value,
valueNode,
variableName,
newVariableInsertIndex,
sign,
}: {
segName: string
value: number
valueNode: Value
variableName?: string
newVariableInsertIndex: number
sign: number
} = await getModalInfo({
segName: tagInfo?.tag,
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: 'angle',
} as any)
if (segName === tagInfo?.tag && value === valueUsedInTransform) {
updateAst(modifiedAst, {
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
} else {
const finalValue = removeDoubleNegatives(
valueNode as BinaryPart,
sign,
variableName
)
// transform again but forcing certain values
const { modifiedAst: _modifiedAst, pathToNodeMap } =
transformSecondarySketchLinesTagFirst({ transformSecondarySketchLinesTagFirst({
ast: JSON.parse(JSON.stringify(ast)), ast,
selectionRanges, selectionRanges,
transformInfos, transformInfos,
programMemory, programMemory,
forceSegName: segName,
forceValueUsedInTransform: finalValue,
}) })
const { if (variableName) {
segName, const newBody = [..._modifiedAst.body]
value, newBody.splice(
valueNode, newVariableInsertIndex,
variableName, 0,
newVariableInsertIndex, createVariableDeclaration(variableName, valueNode)
sign,
}: {
segName: string
value: number
valueNode: Value
variableName?: string
newVariableInsertIndex: number
sign: number
} = await getModalInfo({
segName: tagInfo?.tag,
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: 'angle',
} as any)
if (segName === tagInfo?.tag && value === valueUsedInTransform) {
updateAst(modifiedAst)
} else {
const finalValue = removeDoubleNegatives(
valueNode as BinaryPart,
sign,
variableName
) )
// transform again but forcing certain values _modifiedAst.body = newBody
const { modifiedAst: _modifiedAst } =
transformSecondarySketchLinesTagFirst({
ast,
selectionRanges,
transformInfos,
programMemory,
forceSegName: segName,
forceValueUsedInTransform: finalValue,
})
if (variableName) {
const newBody = [..._modifiedAst.body]
newBody.splice(
newVariableInsertIndex,
0,
createVariableDeclaration(variableName, valueNode)
)
_modifiedAst.body = newBody
}
updateAst(_modifiedAst)
} }
updateAst(_modifiedAst, {
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
} }
}} }}
className={`border m-1 px-1 rounded text-xs ${ className={`border m-1 px-1 rounded text-xs ${

View File

@ -20,6 +20,7 @@ import {
import { GetInfoModal } from '../SetHorVertDistanceModal' import { GetInfoModal } from '../SetHorVertDistanceModal'
import { createLiteral, createVariableDeclaration } from '../../lang/modifyAst' import { createLiteral, createVariableDeclaration } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers' import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { updateCursors } from '../../lang/util'
const getModalInfo = create(GetInfoModal as any) const getModalInfo = create(GetInfoModal as any)
@ -32,15 +33,15 @@ export const SetHorzVertDistance = ({
| 'alignEndsHorizontally' | 'alignEndsHorizontally'
| 'alignEndsVertically' | 'alignEndsVertically'
}) => { }) => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
(s) => ({ useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
programMemory: s.programMemory, programMemory: s.programMemory,
}) setCursor: s.setCursor,
) }))
const constraint: ConstraintType = const constraint: ConstraintType =
buttonType === 'setHorzDistance' || buttonType === 'setVertDistance' buttonType === 'setHorzDistance' || buttonType === 'setVertDistance'
? buttonType ? buttonType
@ -105,67 +106,66 @@ export const SetHorzVertDistance = ({
return ( return (
<button <button
onClick={async () => { onClick={async () => {
if (transformInfos && ast) { if (!(transformInfos && ast)) return
const { modifiedAst, tagInfo, valueUsedInTransform } = const { modifiedAst, tagInfo, valueUsedInTransform, pathToNodeMap } =
transformSecondarySketchLinesTagFirst({
ast: JSON.parse(JSON.stringify(ast)),
selectionRanges,
transformInfos,
programMemory,
})
const {
segName,
value,
valueNode,
variableName,
newVariableInsertIndex,
sign,
}: {
segName: string
value: number
valueNode: Value
variableName?: string
newVariableInsertIndex: number
sign: number
} = await (!isAlign &&
getModalInfo({
segName: tagInfo?.tag,
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName:
constraint === 'setHorzDistance' ? 'xDis' : 'yDis',
} as any))
if (segName === tagInfo?.tag && value === valueUsedInTransform) {
updateAst(modifiedAst, {
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
} else {
let finalValue = isAlign
? createLiteral(0)
: removeDoubleNegatives(valueNode as BinaryPart, sign, variableName)
// transform again but forcing certain values
const { modifiedAst: _modifiedAst, pathToNodeMap } =
transformSecondarySketchLinesTagFirst({ transformSecondarySketchLinesTagFirst({
ast: JSON.parse(JSON.stringify(ast)), ast,
selectionRanges, selectionRanges,
transformInfos, transformInfos,
programMemory, programMemory,
forceSegName: segName,
forceValueUsedInTransform: finalValue,
}) })
const { if (variableName) {
segName, const newBody = [..._modifiedAst.body]
value, newBody.splice(
valueNode, newVariableInsertIndex,
variableName, 0,
newVariableInsertIndex, createVariableDeclaration(variableName, valueNode)
sign, )
}: { _modifiedAst.body = newBody
segName: string
value: number
valueNode: Value
variableName?: string
newVariableInsertIndex: number
sign: number
} = await (!isAlign &&
getModalInfo({
segName: tagInfo?.tag,
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName:
constraint === 'setHorzDistance' ? 'xDis' : 'yDis',
} as any))
if (segName === tagInfo?.tag && value === valueUsedInTransform) {
updateAst(modifiedAst)
} else {
let finalValue = isAlign
? createLiteral(0)
: removeDoubleNegatives(
valueNode as BinaryPart,
sign,
variableName
)
// transform again but forcing certain values
const { modifiedAst: _modifiedAst } =
transformSecondarySketchLinesTagFirst({
ast,
selectionRanges,
transformInfos,
programMemory,
forceSegName: segName,
forceValueUsedInTransform: finalValue,
})
if (variableName) {
const newBody = [..._modifiedAst.body]
newBody.splice(
newVariableInsertIndex,
0,
createVariableDeclaration(variableName, valueNode)
)
_modifiedAst.body = newBody
}
updateAst(_modifiedAst)
} }
updateAst(_modifiedAst, {
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
} }
}} }}
className={`border m-1 px-1 rounded text-xs ${ className={`border m-1 px-1 rounded text-xs ${

View File

@ -19,6 +19,7 @@ import {
} from '../../lang/modifyAst' } from '../../lang/modifyAst'
import { removeDoubleNegatives } from '../AvailableVarsHelpers' import { removeDoubleNegatives } from '../AvailableVarsHelpers'
import { normaliseAngle } from '../../lib/utils' import { normaliseAngle } from '../../lib/utils'
import { updateCursors } from '../../lang/util'
const getModalInfo = create(SetAngleLengthModal as any) const getModalInfo = create(SetAngleLengthModal as any)
@ -27,15 +28,15 @@ export const SetAngleLength = ({
}: { }: {
angleOrLength: 'setAngle' | 'setLength' angleOrLength: 'setAngle' | 'setLength'
}) => { }) => {
const { guiMode, selectionRanges, ast, programMemory, updateAst } = useStore( const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
(s) => ({ useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
programMemory: s.programMemory, programMemory: s.programMemory,
}) setCursor: s.setCursor,
) }))
const [enableAngLen, setEnableAngLen] = useState(false) const [enableAngLen, setEnableAngLen] = useState(false)
const [transformInfos, setTransformInfos] = useState<TransformInfo[]>() const [transformInfos, setTransformInfos] = useState<TransformInfo[]>()
useEffect(() => { useEffect(() => {
@ -116,14 +117,15 @@ export const SetAngleLength = ({
]) ])
} }
const { modifiedAst: _modifiedAst } = transformAstSketchLines({ const { modifiedAst: _modifiedAst, pathToNodeMap } =
ast: JSON.parse(JSON.stringify(ast)), transformAstSketchLines({
selectionRanges, ast: JSON.parse(JSON.stringify(ast)),
transformInfos, selectionRanges,
programMemory, transformInfos,
referenceSegName: '', programMemory,
forceValueUsedInTransform: finalValue, referenceSegName: '',
}) forceValueUsedInTransform: finalValue,
})
if (variableName) { if (variableName) {
const newBody = [..._modifiedAst.body] const newBody = [..._modifiedAst.body]
newBody.splice( newBody.splice(
@ -134,7 +136,9 @@ export const SetAngleLength = ({
_modifiedAst.body = newBody _modifiedAst.body = newBody
} }
updateAst(_modifiedAst) updateAst(_modifiedAst, {
callBack: updateCursors(setCursor, selectionRanges, pathToNodeMap),
})
} catch (e) { } catch (e) {
console.log('e', e) console.log('e', e)
} }

View File

@ -668,7 +668,7 @@ function makeArrayExpression(
expression: ArrayExpression expression: ArrayExpression
lastIndex: number lastIndex: number
} { } {
// should be called array opening brace '[' index // should be called with index to an array opening brace '['
const openingBraceToken = tokens[index] const openingBraceToken = tokens[index]
const firstElementToken = nextMeaningfulToken(tokens, index) const firstElementToken = nextMeaningfulToken(tokens, index)
const { elements, lastIndex } = makeArrayElements( const { elements, lastIndex } = makeArrayElements(

View File

@ -536,10 +536,16 @@ export function giveSketchFnCallTag(
ast: Program, ast: Program,
range: Selection['range'], range: Selection['range'],
tag?: string tag?: string
): { modifiedAst: Program; tag: string; isTagExisting: boolean } { ): {
modifiedAst: Program
tag: string
isTagExisting: boolean
pathToNode: PathToNode
} {
const path = getNodePathFromSourceRange(ast, range)
const { node: primaryCallExp } = getNodeFromPath<CallExpression>( const { node: primaryCallExp } = getNodeFromPath<CallExpression>(
ast, ast,
getNodePathFromSourceRange(ast, range), path,
'CallExpression' 'CallExpression'
) )
const firstArg = getFirstArg(primaryCallExp) const firstArg = getFirstArg(primaryCallExp)
@ -557,6 +563,7 @@ export function giveSketchFnCallTag(
modifiedAst: ast, modifiedAst: ast,
tag: tagStr, tag: tagStr,
isTagExisting, isTagExisting,
pathToNode: path,
} }
} }

View File

@ -10,7 +10,6 @@ import {
VariableDeclaration, VariableDeclaration,
ReturnStatement, ReturnStatement,
ArrayExpression, ArrayExpression,
Identifier,
} from './abstractSyntaxTree' } from './abstractSyntaxTree'
import { createIdentifier, splitPathAtLastIndex } from './modifyAst' import { createIdentifier, splitPathAtLastIndex } from './modifyAst'
import { getSketchSegmentFromSourceRange } from './std/sketchConstraints' import { getSketchSegmentFromSourceRange } from './std/sketchConstraints'

View File

@ -1392,14 +1392,18 @@ export function replaceSketchLine({
from: [number, number] from: [number, number]
createCallback: TransformCallback createCallback: TransformCallback
referencedSegment?: Path referencedSegment?: Path
}): { modifiedAst: Program; valueUsedInTransform?: number } { }): {
modifiedAst: Program
valueUsedInTransform?: number
pathToNode: PathToNode
} {
if (![...toolTips, 'intersect'].includes(fnName)) if (![...toolTips, 'intersect'].includes(fnName))
throw new Error('not a tooltip') throw new Error('not a tooltip')
const _node = { ...node } const _node = { ...node }
const thePath = getNodePathFromSourceRange(_node, sourceRange) const thePath = getNodePathFromSourceRange(_node, sourceRange)
const { add } = sketchLineHelperMap[fnName] const { add } = sketchLineHelperMap[fnName]
const { modifiedAst, valueUsedInTransform } = add({ const { modifiedAst, valueUsedInTransform, pathToNode } = add({
node: _node, node: _node,
previousProgramMemory: programMemory, previousProgramMemory: programMemory,
pathToNode: thePath, pathToNode: thePath,
@ -1409,7 +1413,7 @@ export function replaceSketchLine({
replaceExisting: true, replaceExisting: true,
createCallback, createCallback,
}) })
return { modifiedAst, valueUsedInTransform } return { modifiedAst, valueUsedInTransform, pathToNode }
} }
export function addTagForSketchOnFace( export function addTagForSketchOnFace(

View File

@ -25,7 +25,7 @@ import {
giveSketchFnCallTag, giveSketchFnCallTag,
} from '../modifyAst' } from '../modifyAst'
import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch' import { createFirstArg, getFirstArg, replaceSketchLine } from './sketch'
import { ProgramMemory } from '../executor' import { PathToNode, ProgramMemory } from '../executor'
import { getSketchSegmentFromSourceRange } from './sketchConstraints' import { getSketchSegmentFromSourceRange } from './sketchConstraints'
import { getAngle, roundOff, normaliseAngle } from '../../lib/utils' import { getAngle, roundOff, normaliseAngle } from '../../lib/utils'
@ -785,6 +785,10 @@ const transformMap: TransformMap = {
tooltip: 'angledLine', tooltip: 'angledLine',
createNode: basicAngledLineCreateNode('len', 'ang', 'len'), createNode: basicAngledLineCreateNode('len', 'ang', 'len'),
}, },
equalAngle: {
tooltip: 'angledLine',
createNode: basicAngledLineCreateNode('ang', 'len', 'len'),
},
}, },
}, },
angledLineOfXLength: { angledLineOfXLength: {
@ -1319,6 +1323,8 @@ export function getRemoveConstraintsTransforms(
return theTransforms return theTransforms
} }
type PathToNodeMap = { [key: number]: PathToNode }
export function transformSecondarySketchLinesTagFirst({ export function transformSecondarySketchLinesTagFirst({
ast, ast,
selectionRanges, selectionRanges,
@ -1336,6 +1342,7 @@ export function transformSecondarySketchLinesTagFirst({
}): { }): {
modifiedAst: Program modifiedAst: Program
valueUsedInTransform?: number valueUsedInTransform?: number
pathToNodeMap: PathToNodeMap
tagInfo: { tagInfo: {
tag: string tag: string
isTagExisting: boolean isTagExisting: boolean
@ -1344,25 +1351,30 @@ export function transformSecondarySketchLinesTagFirst({
// let node = JSON.parse(JSON.stringify(ast)) // let node = JSON.parse(JSON.stringify(ast))
const primarySelection = selectionRanges.codeBasedSelections[0].range const primarySelection = selectionRanges.codeBasedSelections[0].range
const { modifiedAst, tag, isTagExisting } = giveSketchFnCallTag( const { modifiedAst, tag, isTagExisting, pathToNode } = giveSketchFnCallTag(
ast, ast,
primarySelection, primarySelection,
forceSegName forceSegName
) )
const result = transformAstSketchLines({
ast: modifiedAst,
selectionRanges: {
...selectionRanges,
codeBasedSelections: selectionRanges.codeBasedSelections.slice(1),
},
referencedSegmentRange: primarySelection,
transformInfos,
programMemory,
referenceSegName: tag,
forceValueUsedInTransform,
})
const updatedPathToNodeMap = incrementPathToNodeMap(result.pathToNodeMap)
updatedPathToNodeMap[0] = pathToNode
return { return {
...transformAstSketchLines({ ...result,
ast: modifiedAst, pathToNodeMap: updatedPathToNodeMap,
selectionRanges: {
...selectionRanges,
codeBasedSelections: selectionRanges.codeBasedSelections.slice(1),
},
referencedSegmentRange: primarySelection,
transformInfos,
programMemory,
referenceSegName: tag,
forceValueUsedInTransform,
}),
tagInfo: { tagInfo: {
tag, tag,
isTagExisting, isTagExisting,
@ -1370,6 +1382,17 @@ export function transformSecondarySketchLinesTagFirst({
} }
} }
function incrementPathToNodeMap(
pathToNodeMap: PathToNodeMap,
increment = 1
): PathToNodeMap {
const newMap: PathToNodeMap = {}
Object.entries(pathToNodeMap).forEach(([key, path]) => {
newMap[Number(key) + increment] = path
})
return newMap
}
export function transformAstSketchLines({ export function transformAstSketchLines({
ast, ast,
selectionRanges, selectionRanges,
@ -1386,10 +1409,15 @@ export function transformAstSketchLines({
referenceSegName: string referenceSegName: string
forceValueUsedInTransform?: Value forceValueUsedInTransform?: Value
referencedSegmentRange?: Selection['range'] referencedSegmentRange?: Selection['range']
}): { modifiedAst: Program; valueUsedInTransform?: number } { }): {
modifiedAst: Program
valueUsedInTransform?: number
pathToNodeMap: PathToNodeMap
} {
// deep clone since we are mutating in a loop, of which any could fail // deep clone since we are mutating in a loop, of which any could fail
let node = JSON.parse(JSON.stringify(ast)) let node = JSON.parse(JSON.stringify(ast))
let _valueUsedInTransform // TODO should this be an array? let _valueUsedInTransform // TODO should this be an array?
const pathToNodeMap: PathToNodeMap = {}
selectionRanges.codeBasedSelections.forEach(({ range }, index) => { selectionRanges.codeBasedSelections.forEach(({ range }, index) => {
const callBack = transformInfos?.[index].createNode const callBack = transformInfos?.[index].createNode
@ -1428,29 +1456,36 @@ export function transformAstSketchLines({
.segment .segment
: sketchGroup.value.find((path) => path.name === _referencedSegmentName) : sketchGroup.value.find((path) => path.name === _referencedSegmentName)
const { to, from } = seg const { to, from } = seg
const { modifiedAst, valueUsedInTransform } = replaceSketchLine({ const { modifiedAst, valueUsedInTransform, pathToNode } = replaceSketchLine(
node: node, {
programMemory, node: node,
sourceRange: range, programMemory,
referencedSegment, sourceRange: range,
fnName: transformTo || (callExp.callee.name as TooTip), referencedSegment,
to, fnName: transformTo || (callExp.callee.name as TooTip),
from, to,
createCallback: callBack({ from,
referenceSegName: _referencedSegmentName, createCallback: callBack({
varValA, referenceSegName: _referencedSegmentName,
varValB, varValA,
tag: callBackTag, varValB,
forceValueUsedInTransform, tag: callBackTag,
}), forceValueUsedInTransform,
}) }),
}
)
node = modifiedAst node = modifiedAst
pathToNodeMap[index] = pathToNode
if (typeof valueUsedInTransform === 'number') { if (typeof valueUsedInTransform === 'number') {
_valueUsedInTransform = valueUsedInTransform _valueUsedInTransform = valueUsedInTransform
} }
}) })
return { modifiedAst: node, valueUsedInTransform: _valueUsedInTransform } return {
modifiedAst: node,
valueUsedInTransform: _valueUsedInTransform,
pathToNodeMap,
}
} }
function createSegLen(referenceSegName: string): Value { function createSegLen(referenceSegName: string): Value {

28
src/lang/util.ts Normal file
View File

@ -0,0 +1,28 @@
import { Selections, StoreState } from '../useStore'
import { Program } from './abstractSyntaxTree'
import { PathToNode } from './executor'
import { getNodeFromPath } from './queryAst'
export function updateCursors(
setCursor: StoreState['setCursor'],
selectionRanges: Selections,
pathToNodeMap: { [key: number]: PathToNode }
): (newAst: Program) => void {
return (newAst: Program) => {
const newSelections: Selections = {
...selectionRanges,
codeBasedSelections: [],
}
Object.entries(pathToNodeMap).forEach(([index, path]) => {
const node = getNodeFromPath(newAst, path).node as any
const type = selectionRanges.codeBasedSelections[Number(index)].type
if (node) {
newSelections.codeBasedSelections.push({
range: [node.start, node.end],
type: type || 'default',
})
}
})
setCursor(newSelections)
}
}

View File

@ -88,7 +88,7 @@ export type GuiModes =
position: Position position: Position
} }
interface StoreState { export interface StoreState {
editorView: EditorView | null editorView: EditorView | null
setEditorView: (editorView: EditorView) => void setEditorView: (editorView: EditorView) => void
highlightRange: [number, number] highlightRange: [number, number]
@ -105,7 +105,13 @@ interface StoreState {
resetLogs: () => void resetLogs: () => void
ast: Program | null ast: Program | null
setAst: (ast: Program | null) => void setAst: (ast: Program | null) => void
updateAst: (ast: Program, focusPath?: PathToNode) => void updateAst: (
ast: Program,
optionalParams?: {
focusPath?: PathToNode
callBack?: (ast: Program) => void
}
) => void
updateAstAsync: (ast: Program, focusPath?: PathToNode) => void updateAstAsync: (ast: Program, focusPath?: PathToNode) => void
code: string code: string
setCode: (code: string) => void setCode: (code: string) => void
@ -185,11 +191,12 @@ export const useStore = create<StoreState>()(
setAst: (ast) => { setAst: (ast) => {
set({ ast }) set({ ast })
}, },
updateAst: async (ast, focusPath) => { updateAst: async (ast, { focusPath, callBack = () => {} } = {}) => {
const newCode = recast(ast) const newCode = recast(ast)
const astWithUpdatedSource = abstractSyntaxTree( const astWithUpdatedSource = abstractSyntaxTree(
await asyncLexer(newCode) await asyncLexer(newCode)
) )
callBack(astWithUpdatedSource)
set({ ast: astWithUpdatedSource, code: newCode }) set({ ast: astWithUpdatedSource, code: newCode })
if (focusPath) { if (focusPath) {
@ -216,7 +223,7 @@ export const useStore = create<StoreState>()(
// setup a new update // setup a new update
pendingAstUpdates.push( pendingAstUpdates.push(
setTimeout(() => { setTimeout(() => {
get().updateAst(ast, focusPath) get().updateAst(ast, { focusPath })
}, 100) as unknown as number }, 100) as unknown as number
) )
}, },