generate kcl examples in docs from macro (#1710)

* rearrange

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* examples

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* recast

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add more tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add more samples

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* more docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* more

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* more samples

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* more

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* make serial

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix hang

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix import

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* atan

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* atan

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* make all tests pass

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* must have code balock

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* new docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* new docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2024-03-13 12:56:46 -07:00
committed by GitHub
parent 6bab45a56a
commit a60bdd4cc3
36 changed files with 3584 additions and 538 deletions

View File

@ -25,7 +25,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = abs(-4)"
]
}, },
{ {
"name": "acos", "name": "acos",
@ -53,7 +56,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = acos(0.5)"
]
}, },
{ {
"name": "angleToMatchLengthX", "name": "angleToMatchLengthX",
@ -1050,7 +1056,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part001 = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line({ to: [1, 3.82], tag: 'seg01' }, %)\n |> angledLineToX([\n -angleToMatchLengthX('seg01', 10, %),\n 5\n ], %)\n |> close(%)"
]
}, },
{ {
"name": "angleToMatchLengthY", "name": "angleToMatchLengthY",
@ -2047,7 +2056,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part001 = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line({ to: [1, 3.82], tag: 'seg01' }, %)\n |> angledLineToX([\n -angleToMatchLengthY('seg01', 10, %),\n 5\n ], %)\n |> close(%)"
]
}, },
{ {
"name": "angledLine", "name": "angledLine",
@ -4024,7 +4036,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> angledLine({ angle: 45, length: 10, tag: \"edge1\" }, %)\n |> line([10, 10], %)\n |> line([0, 10], %)\n |> close(%, \"edge2\")\n |> extrude(10, %)"
]
}, },
{ {
"name": "angledLineOfXLength", "name": "angledLineOfXLength",
@ -6001,7 +6016,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XZ')\n |> startProfileAt([0, 0], %)\n |> angledLineOfXLength({ angle: 45, length: 10, tag: \"edge1\" }, %)\n |> line([10, 10], %)\n |> line([0, 10], %)\n |> close(%, \"edge2\")\n |> extrude(10, %)"
]
}, },
{ {
"name": "angledLineOfYLength", "name": "angledLineOfYLength",
@ -7978,7 +7996,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('YZ')\n |> startProfileAt([0, 0], %)\n |> angledLineOfYLength({ angle: 45, length: 10, tag: \"edge1\" }, %)\n |> line([10, 10], %)\n |> line([0, 10], %)\n |> close(%, \"edge2\")\n |> extrude(10, %)\n |> fillet({ radius: 2, tags: [\"edge1\"] }, %)"
]
}, },
{ {
"name": "angledLineThatIntersects", "name": "angledLineThatIntersects",
@ -9945,7 +9966,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part001 = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> lineTo({ to: [2, 2], tag: \"yo\" }, %)\n |> lineTo([3, 1], %)\n |> angledLineThatIntersects({\n angle: 180,\n intersectTag: 'yo',\n offset: 12,\n tag: \"yo2\"\n }, %)\n |> line([4, 0], %)\n |> close(%, \"yo3\")\n |> extrude(10, %)"
]
}, },
{ {
"name": "angledLineToX", "name": "angledLineToX",
@ -11922,7 +11946,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> angledLineToX({ angle: 45, to: 10, tag: \"edge1\" }, %)\n |> line([10, 10], %)\n |> line([0, 10], %)\n |> close(%, \"edge2\")\n |> extrude(10, %)\n |> fillet({ radius: 2, tags: [\"edge1\"] }, %)"
]
}, },
{ {
"name": "angledLineToY", "name": "angledLineToY",
@ -13899,7 +13926,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> angledLineToY({ angle: 45, to: 10, tag: \"edge1\" }, %)\n |> line([10, 10], %)\n |> line([0, 10], %)\n |> close(%, \"edge2\")\n |> extrude(10, %)"
]
}, },
{ {
"name": "arc", "name": "arc",
@ -15915,7 +15945,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('-YZ')\n |> startProfileAt([0, 0], %)\n |> arc({\n angle_start: 0,\n angle_end: 360,\n radius: 10,\n tag: \"edge1\"\n }, %)\n |> extrude(10, %)"
]
}, },
{ {
"name": "asin", "name": "asin",
@ -15943,7 +15976,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = asin(0.5)"
]
}, },
{ {
"name": "atan", "name": "atan",
@ -15971,7 +16007,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = atan(1.0)"
]
}, },
{ {
"name": "bezierCurve", "name": "bezierCurve",
@ -17954,7 +17993,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> bezierCurve({\n to: [10, 10],\n control1: [5, 0],\n control2: [5, 10],\n tag: \"edge1\"\n }, %)\n |> close(%)\n |> extrude(10, %)"
]
}, },
{ {
"name": "ceil", "name": "ceil",
@ -17982,7 +18024,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = ceil(4.5)"
]
}, },
{ {
"name": "circle", "name": "circle",
@ -19284,7 +19329,8 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": []
}, },
{ {
"name": "close", "name": "close",
@ -21225,7 +21271,11 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XZ')\n |> startProfileAt([0, 0], %)\n |> line([10, 10], %)\n |> line([10, 0], %)\n |> close(%)",
"startSketchOn('YZ')\n |> startProfileAt([0, 0], %)\n |> line([10, 10], %)\n |> line([10, 0], %)\n |> close(%, \"edge1\")"
]
}, },
{ {
"name": "cos", "name": "cos",
@ -21253,7 +21303,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const anotherVar = cos(2 * pi())"
]
}, },
{ {
"name": "e", "name": "e",
@ -21271,7 +21324,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = e()"
]
}, },
{ {
"name": "extrude", "name": "extrude",
@ -23007,7 +23063,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line([0, 10], %)\n |> line([10, 0], %)\n |> line([0, -10], %)\n |> close(%)\n |> extrude(5, %)"
]
}, },
{ {
"name": "fillet", "name": "fillet",
@ -24567,7 +24626,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part001 = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line({ to: [0, 10], tag: \"thing\" }, %)\n |> line([10, 0], %)\n |> line({ to: [0, -10], tag: \"thing2\" }, %)\n |> close(%)\n |> extrude(10, %)\n |> fillet({ radius: 2, tags: [\"thing\", \"thing2\"] }, %)"
]
}, },
{ {
"name": "floor", "name": "floor",
@ -24595,7 +24657,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = floor(4.5)"
]
}, },
{ {
"name": "getExtrudeWallTransform", "name": "getExtrudeWallTransform",
@ -25425,7 +25490,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const box = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line([0, 10], %)\n |> line([10, 0], %)\n |> line({ to: [0, -10], tag: \"surface\" }, %)\n |> close(%)\n |> extrude(5, %)\n\nconst transform = getExtrudeWallTransform('surface', box)"
]
}, },
{ {
"name": "getNextAdjacentEdge", "name": "getNextAdjacentEdge",
@ -26208,7 +26276,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part001 = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line({ to: [0, 10], tag: \"thing\" }, %)\n |> line({ to: [10, 0], tag: \"thing1\" }, %)\n |> line({ to: [0, -10], tag: \"thing2\" }, %)\n |> close(%)\n |> extrude(10, %)\n |> fillet({\n radius: 2,\n tags: [getNextAdjacentEdge(\"thing\", %)]\n }, %)"
]
}, },
{ {
"name": "getOppositeEdge", "name": "getOppositeEdge",
@ -26991,7 +27062,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part001 = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line({ to: [0, 10], tag: \"thing\" }, %)\n |> line([10, 0], %)\n |> line({ to: [0, -10], tag: \"thing2\" }, %)\n |> close(%)\n |> extrude(10, %)\n |> fillet({\n radius: 2,\n tags: [\"thing\", getOppositeEdge(\"thing\", %)]\n }, %)"
]
}, },
{ {
"name": "getPreviousAdjacentEdge", "name": "getPreviousAdjacentEdge",
@ -27774,7 +27848,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part001 = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line({ to: [0, 10], tag: \"thing\" }, %)\n |> line({ to: [10, 0], tag: \"thing1\" }, %)\n |> line({ to: [0, -10], tag: \"thing2\" }, %)\n |> close(%)\n |> extrude(10, %)\n |> fillet({\n radius: 2,\n tags: [getPreviousAdjacentEdge(\"thing2\", %)]\n }, %)"
]
}, },
{ {
"name": "hole", "name": "hole",
@ -31652,7 +31729,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const square = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line([0, 10], %)\n |> line([10, 0], %)\n |> line([0, -10], %)\n |> close(%)\n |> hole(circle([2, 2], .5, startSketchOn('XY')), %)\n |> hole(circle([2, 8], .5, startSketchOn('XY')), %)\n |> extrude(2, %)"
]
}, },
{ {
"name": "import", "name": "import",
@ -32302,7 +32382,14 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const model = import(\"thing.obj\")",
"const model = import(\"cube.obj\", { type: \"obj\", units: \"m\" })",
"const model = import(\"my_model.gltf\")",
"const model = import(\"my_model.sldprt\")",
"const model = import(\"my_model.step\")"
]
}, },
{ {
"name": "lastSegX", "name": "lastSegX",
@ -33282,7 +33369,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn(\"YZ\")\n |> startProfileAt([0, 0], %)\n |> line({ to: [5, 0], tag: \"thing\" }, %)\n |> line([5, 5], %)\n |> line([0, lastSegX(%)], %)\n |> close(%)\n |> extrude(5, %)"
]
}, },
{ {
"name": "lastSegY", "name": "lastSegY",
@ -34262,7 +34352,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn(\"YZ\")\n |> startProfileAt([0, 0], %)\n |> line({ to: [5, 0], tag: \"thing\" }, %)\n |> line([5, 5], %)\n |> line([0, lastSegY(%)], %)\n |> close(%)\n |> extrude(5, %)"
]
}, },
{ {
"name": "legAngX", "name": "legAngX",
@ -34299,7 +34392,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"legAngX(5, 3)"
]
}, },
{ {
"name": "legAngY", "name": "legAngY",
@ -34336,7 +34432,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"legAngY(5, 3)"
]
}, },
{ {
"name": "legLen", "name": "legLen",
@ -34373,7 +34472,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"legLen(5, 3)"
]
}, },
{ {
"name": "line", "name": "line",
@ -36349,7 +36451,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('-XY')\n |> startProfileAt([0, 0], %)\n |> line([10, 10], %)\n |> line({ to: [20, 10], tag: \"edge1\" }, %)\n |> close(%, \"edge2\")\n |> extrude(10, %)"
]
}, },
{ {
"name": "lineTo", "name": "lineTo",
@ -38325,7 +38430,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"fn rectShape = (pos, w, l) => {\n const rr = startSketchOn('YZ')\n |> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)\n |> lineTo({\n to: [pos[0] + w / 2, pos[1] - (l / 2)],\n tag: \"edge1\"\n }, %)\n |> lineTo({\n to: [pos[0] + w / 2, pos[1] + l / 2],\n tag: \"edge2\"\n }, %)\n |> lineTo({\n to: [pos[0] - (w / 2), pos[1] + l / 2],\n tag: \"edge3\"\n }, %)\n |> close(%, \"edge4\")\n return rr\n}\n\n// Create the mounting plate extrusion, holes, and fillets\nconst part = rectShape([0, 0], 20, 20)"
]
}, },
{ {
"name": "ln", "name": "ln",
@ -38353,7 +38461,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = ln(4)"
]
}, },
{ {
"name": "log", "name": "log",
@ -38390,7 +38501,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = log(4, 2)"
]
}, },
{ {
"name": "log10", "name": "log10",
@ -38418,7 +38532,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = log10(4)"
]
}, },
{ {
"name": "log2", "name": "log2",
@ -38446,7 +38563,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = log2(4)"
]
}, },
{ {
"name": "max", "name": "max",
@ -38477,7 +38597,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = max(4, 5, 6)"
]
}, },
{ {
"name": "min", "name": "min",
@ -38508,7 +38631,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = min(4, 5, 6)"
]
}, },
{ {
"name": "patternCircular2d", "name": "patternCircular2d",
@ -40485,7 +40611,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part = startSketchOn('XY')\n |> circle([0, 0], 2, %)\n |> patternCircular2d({\n center: [20, 20],\n repetitions: 12,\n arcDegrees: 210,\n rotateDuplicates: true\n }, %)"
]
}, },
{ {
"name": "patternCircular3d", "name": "patternCircular3d",
@ -42063,7 +42192,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line([0, 1], %)\n |> line([1, 0], %)\n |> line([0, -1], %)\n |> close(%)\n |> extrude(1, %)\n |> patternCircular3d({\n axis: [1, 1, 0],\n center: [10, 0, 10],\n repetitions: 10,\n arcDegrees: 360,\n rotateDuplicates: true\n }, %)"
]
}, },
{ {
"name": "patternLinear2d", "name": "patternLinear2d",
@ -44035,7 +44167,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part = startSketchOn('XY')\n |> circle([0, 0], 2, %)\n |> patternLinear2d({\n axis: [0, 1],\n repetitions: 12,\n distance: 2\n }, %)"
]
}, },
{ {
"name": "patternLinear3d", "name": "patternLinear3d",
@ -45597,7 +45732,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part = startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line([0, 1], %)\n |> line([1, 0], %)\n |> line([0, -1], %)\n |> close(%)\n |> extrude(1, %)\n |> patternLinear3d({\n axis: [1, 0, 1],\n repetitions: 3,\n distance: 6\n }, %)"
]
}, },
{ {
"name": "pi", "name": "pi",
@ -45615,7 +45753,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = pi() * 3.0"
]
}, },
{ {
"name": "pow", "name": "pow",
@ -45652,7 +45793,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = pow(4, 2)"
]
}, },
{ {
"name": "segAng", "name": "segAng",
@ -46640,7 +46784,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const part001 = startSketchOn('XY')\n |> startProfileAt([4.83, 12.56], %)\n |> line([15.1, 2.48], %)\n |> line({ to: [3.15, -9.85], tag: 'seg01' }, %)\n |> line([-15.17, -4.1], %)\n |> angledLine([segAng('seg01', %), 12.35], %)\n |> line([-13.02, 10.03], %)\n |> close(%)\n |> extrude(4, %)"
]
}, },
{ {
"name": "segEndX", "name": "segEndX",
@ -47628,7 +47775,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn(\"YZ\")\n |> startProfileAt([0, 0], %)\n |> line({ to: [5, 0], tag: \"thing\" }, %)\n |> line([5, 5], %)\n |> line([segEndX(\"thing\", %), 5], %)\n |> close(%)\n |> extrude(5, %)"
]
}, },
{ {
"name": "segEndY", "name": "segEndY",
@ -48616,7 +48766,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn(\"YZ\")\n |> startProfileAt([0, 0], %)\n |> line({ to: [5, 0], tag: \"thing\" }, %)\n |> line([5, 5], %)\n |> line([segEndY(\"thing\", %), 5], %)\n |> close(%)\n |> extrude(5, %)"
]
}, },
{ {
"name": "segLen", "name": "segLen",
@ -49604,7 +49757,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn(\"YZ\")\n |> startProfileAt([0, 0], %)\n |> line({ to: [5, 0], tag: \"thing\" }, %)\n |> line([5, 5], %)\n |> line([0, segLen(\"thing\", %)], %)\n |> close(%)\n |> extrude(5, %)"
]
}, },
{ {
"name": "sin", "name": "sin",
@ -49632,7 +49788,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = sin(2 * pi())"
]
}, },
{ {
"name": "sqrt", "name": "sqrt",
@ -49660,7 +49819,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = sqrt(4)"
]
}, },
{ {
"name": "startProfileAt", "name": "startProfileAt",
@ -50975,7 +51137,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line([10, 10], %)"
]
}, },
{ {
"name": "startSketchAt", "name": "startSketchAt",
@ -51990,7 +52155,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchAt([0, 0])\n |> line([10, 10], %)"
]
}, },
{ {
"name": "startSketchOn", "name": "startSketchOn",
@ -53254,7 +53422,11 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> line([10, 10], %)\n |> line({ to: [20, 10], tag: \"edge1\" }, %)\n |> close(%, \"edge2\")",
"fn cube = (pos, scale) => {\n const sg = startSketchOn('XY')\n |> startProfileAt(pos, %)\n |> line([0, scale], %)\n |> line([scale, 0], %)\n |> line([0, -scale], %)\n |> close(%)\n |> extrude(scale, %)\n\n return sg\n}\n\nconst box = cube([0, 0], 20)\n\nconst part001 = startSketchOn(box, \"start\")\n |> startProfileAt([0, 0], %)\n |> line([10, 10], %)\n |> line({ to: [20, 10], tag: \"edge1\" }, %)\n |> close(%)\n |> extrude(20, %)"
]
}, },
{ {
"name": "tan", "name": "tan",
@ -53282,7 +53454,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = tan(2 * pi())"
]
}, },
{ {
"name": "tangentialArc", "name": "tangentialArc",
@ -55277,7 +55452,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('-YZ')\n |> startProfileAt([0, 0], %)\n |> line({ to: [10, 10], tag: \"edge0\" }, %)\n |> tangentialArc({ radius: 10, offset: 90, tag: \"edge1\" }, %)\n |> close(%)\n |> extrude(10, %)"
]
}, },
{ {
"name": "tangentialArcTo", "name": "tangentialArcTo",
@ -57232,7 +57410,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('-YZ')\n |> startProfileAt([0, 0], %)\n |> line({ to: [10, 10], tag: \"edge0\" }, %)\n |> tangentialArcTo([10, 0], %)\n |> close(%)"
]
}, },
{ {
"name": "tau", "name": "tau",
@ -57250,10 +57431,13 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = tau()"
]
}, },
{ {
"name": "to_degrees", "name": "toDegrees",
"summary": "Converts a number from radians to degrees.", "summary": "Converts a number from radians to degrees.",
"description": "", "description": "",
"tags": [], "tags": [],
@ -57278,10 +57462,13 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = toDegrees(2 * pi())"
]
}, },
{ {
"name": "to_radians", "name": "toRadians",
"summary": "Converts a number from degrees to radians.", "summary": "Converts a number from degrees to radians.",
"description": "", "description": "",
"tags": [], "tags": [],
@ -57306,7 +57493,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"const myVar = toRadians(180)"
]
}, },
{ {
"name": "xLine", "name": "xLine",
@ -59272,7 +59462,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('YZ')\n |> startProfileAt([0, 0], %)\n |> xLine(10, %)\n |> line([10, 10], %)\n |> close(%, \"edge1\")\n |> extrude(10, %)"
]
}, },
{ {
"name": "xLineTo", "name": "xLineTo",
@ -61238,7 +61431,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> xLineTo({ to: 10, tag: \"edge1\" }, %)\n |> line([10, 10], %)\n |> close(%, \"edge2\")\n |> extrude(10, %)"
]
}, },
{ {
"name": "yLine", "name": "yLine",
@ -63204,7 +63400,10 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XY')\n |> startProfileAt([0, 0], %)\n |> yLine(10, %)\n |> line([10, 10], %)\n |> close(%, \"edge1\")\n |> extrude(10, %)"
]
}, },
{ {
"name": "yLineTo", "name": "yLineTo",
@ -65170,6 +65369,9 @@
"required": true "required": true
}, },
"unpublished": false, "unpublished": false,
"deprecated": false "deprecated": false,
"examples": [
"startSketchOn('XZ')\n |> startProfileAt([0, 0], %)\n |> yLineTo({ to: 10, tag: \"edge1\" }, %)\n |> line([10, 10], %)\n |> close(%, \"edge2\")\n |> extrude(10, %)\n |> fillet({ radius: 2, tags: [\"edge2\"] }, %)"
]
} }
] ]

File diff suppressed because it is too large Load Diff

View File

@ -947,8 +947,9 @@ dependencies = [
[[package]] [[package]]
name = "derive-docs" name = "derive-docs"
version = "0.1.10" version = "0.1.11"
dependencies = [ dependencies = [
"Inflector",
"convert_case", "convert_case",
"expectorate", "expectorate",
"once_cell", "once_cell",
@ -962,22 +963,6 @@ dependencies = [
"syn 2.0.52", "syn 2.0.52",
] ]
[[package]]
name = "derive-docs"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc85a0d10f808387cd56147b520be7efd94b8b198b1453f987b133cd2a90b7e"
dependencies = [
"convert_case",
"once_cell",
"proc-macro2",
"quote",
"regex",
"serde",
"serde_tokenstream",
"syn 2.0.52",
]
[[package]] [[package]]
name = "diesel_derives" name = "diesel_derives"
version = "2.1.2" version = "2.1.2"
@ -1919,7 +1904,7 @@ dependencies = [
"criterion", "criterion",
"dashmap", "dashmap",
"databake", "databake",
"derive-docs 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "derive-docs",
"expectorate", "expectorate",
"futures", "futures",
"gltf-json", "gltf-json",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "derive-docs" name = "derive-docs"
description = "A tool for generating documentation from Rust derive macros" description = "A tool for generating documentation from Rust derive macros"
version = "0.1.10" version = "0.1.11"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app" repository = "https://github.com/KittyCAD/modeling-app"
@ -12,6 +12,7 @@ rust-version = "1.73"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
Inflector = "0.11.4"
convert_case = "0.6.0" convert_case = "0.6.0"
once_cell = "1.19.0" once_cell = "1.19.0"
proc-macro2 = "1" proc-macro2 = "1"

View File

@ -2,7 +2,12 @@
// automated enforcement. // automated enforcement.
#![allow(clippy::style)] #![allow(clippy::style)]
#[cfg(test)]
mod tests;
mod unbox;
use convert_case::Casing; use convert_case::Casing;
use inflector::Inflector;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use quote::{format_ident, quote, quote_spanned, ToTokens}; use quote::{format_ident, quote, quote_spanned, ToTokens};
use regex::Regex; use regex::Regex;
@ -12,6 +17,7 @@ use syn::{
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
Attribute, Signature, Visibility, Attribute, Signature, Visibility,
}; };
use unbox::unbox;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct StdlibMetadata { struct StdlibMetadata {
@ -101,6 +107,21 @@ fn do_stdlib_inner(
} }
let name = metadata.name; let name = metadata.name;
// Fail if the name is not camel case.
let whitelist = [
"patternLinear3d",
"patternLinear2d",
"patternCircular3d",
"patternCircular2d",
];
if !name.is_camel_case() && !whitelist.contains(&name.as_str()) {
errors.push(Error::new_spanned(
&ast.sig.ident,
format!("stdlib function names must be in camel case: `{}`", name),
));
}
let name_ident = format_ident!("{}", name.to_case(convert_case::Case::UpperCamel)); let name_ident = format_ident!("{}", name.to_case(convert_case::Case::UpperCamel));
let name_str = name.to_string(); let name_str = name.to_string();
@ -110,16 +131,16 @@ fn do_stdlib_inner(
let boxed_fn_name_ident = format_ident!("boxed_{}", fn_name_str); let boxed_fn_name_ident = format_ident!("boxed_{}", fn_name_str);
let _visibility = &ast.vis; let _visibility = &ast.vis;
let (summary_text, description_text) = extract_doc_from_attrs(&ast.attrs); let doc_info = extract_doc_from_attrs(&ast.attrs);
let comment_text = { let comment_text = {
let mut buf = String::new(); let mut buf = String::new();
buf.push_str("Std lib function: "); buf.push_str("Std lib function: ");
buf.push_str(&name_str); buf.push_str(&name_str);
if let Some(s) = &summary_text { if let Some(s) = &doc_info.summary {
buf.push_str("\n"); buf.push_str("\n");
buf.push_str(&s); buf.push_str(&s);
} }
if let Some(s) = &description_text { if let Some(s) = &doc_info.description {
buf.push_str("\n"); buf.push_str("\n");
buf.push_str(&s); buf.push_str(&s);
} }
@ -129,17 +150,60 @@ fn do_stdlib_inner(
#[doc = #comment_text] #[doc = #comment_text]
}; };
let summary = if let Some(summary) = summary_text { let summary = if let Some(summary) = doc_info.summary {
quote! { #summary } quote! { #summary }
} else { } else {
quote! { "" } quote! { "" }
}; };
let description = if let Some(description) = description_text { let description = if let Some(description) = doc_info.description {
quote! { #description } quote! { #description }
} else { } else {
quote! { "" } quote! { "" }
}; };
let cb = doc_info.code_blocks.clone();
let code_blocks = if !cb.is_empty() {
quote! {
let code_blocks = vec![#(#cb),*];
code_blocks.iter().map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
}).collect::<Vec<String>>()
}
} else {
errors.push(Error::new_spanned(
&ast.sig,
"stdlib functions must have at least one code block",
));
quote! { vec![] }
};
// Make sure the function name is in all the code blocks.
for code_block in doc_info.code_blocks.iter() {
if !code_block.contains(&name) {
errors.push(Error::new_spanned(
&ast.sig,
format!(
"stdlib functions must have the function name `{}` in the code block",
name
),
));
}
}
let test_code_blocks = doc_info
.code_blocks
.iter()
.enumerate()
.map(|(index, code_block)| generate_code_block_test(&fn_name_str, code_block, index))
.collect::<Vec<_>>();
let tags = metadata let tags = metadata
.tags .tags
.iter() .iter()
@ -242,7 +306,7 @@ fn do_stdlib_inner(
let mut args = args.iter(); let mut args = args.iter();
let ok = args.next().unwrap(); let ok = args.next().unwrap();
if let syn::GenericArgument::Type(ty) = ok { if let syn::GenericArgument::Type(ty) = ok {
let ty = unbox(unbox_vec(ty.clone())); let ty = unbox(ty.clone());
quote! { #ty } quote! { #ty }
} else { } else {
quote! { () } quote! { () }
@ -254,7 +318,7 @@ fn do_stdlib_inner(
quote! { () } quote! { () }
} }
} else { } else {
let ty = unbox(unbox_vec(*ty.clone())); let ty = unbox(*ty.clone());
quote! { #ty } quote! { #ty }
} }
} else { } else {
@ -295,9 +359,16 @@ fn do_stdlib_inner(
pub(crate) const #name_ident: #name_ident = #name_ident {}; pub(crate) const #name_ident: #name_ident = #name_ident {};
}; };
let test_mod_name = format_ident!("test_examples_{}", fn_name_str);
// The final TokenStream returned will have a few components that reference // The final TokenStream returned will have a few components that reference
// `#name_ident`, the name of the function to which this macro was applied... // `#name_ident`, the name of the function to which this macro was applied...
let stream = quote! { let stream = quote! {
#[cfg(test)]
mod #test_mod_name {
#(#test_code_blocks)*
}
// ... a struct type called `#name_ident` that has no members // ... a struct type called `#name_ident` that has no members
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#description_doc_comment #description_doc_comment
@ -359,6 +430,10 @@ fn do_stdlib_inner(
#deprecated #deprecated
} }
fn examples(&self) -> Vec<String> {
#code_blocks
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
#boxed_fn_name_ident #boxed_fn_name_ident
} }
@ -394,10 +469,18 @@ fn get_crate(var: Option<String>) -> proc_macro2::TokenStream {
quote!(crate::docs) quote!(crate::docs)
} }
fn extract_doc_from_attrs(attrs: &[syn::Attribute]) -> (Option<String>, Option<String>) { #[derive(Debug)]
let doc = syn::Ident::new("doc", proc_macro2::Span::call_site()); struct DocInfo {
pub summary: Option<String>,
pub description: Option<String>,
pub code_blocks: Vec<String>,
}
let mut lines = attrs.iter().flat_map(|attr| { fn extract_doc_from_attrs(attrs: &[syn::Attribute]) -> DocInfo {
let doc = syn::Ident::new("doc", proc_macro2::Span::call_site());
let mut code_blocks: Vec<String> = Vec::new();
let raw_lines = attrs.iter().flat_map(|attr| {
if let syn::Meta::NameValue(nv) = &attr.meta { if let syn::Meta::NameValue(nv) = &attr.meta {
if nv.path.is_ident(&doc) { if nv.path.is_ident(&doc) {
if let syn::Expr::Lit(syn::ExprLit { if let syn::Expr::Lit(syn::ExprLit {
@ -411,6 +494,53 @@ fn extract_doc_from_attrs(attrs: &[syn::Attribute]) -> (Option<String>, Option<S
Vec::new() Vec::new()
}); });
// Parse any code blocks from the doc string.
let mut code_block: Option<String> = None;
let mut parsed_lines = Vec::new();
for line in raw_lines {
if line.starts_with("```") {
if let Some(ref inner_code_block) = code_block {
code_blocks.push(inner_code_block.trim().to_string());
code_block = None;
} else {
code_block = Some(String::new());
}
continue;
}
if let Some(ref mut code_block) = code_block {
code_block.push_str(&line);
code_block.push('\n');
} else {
parsed_lines.push(line);
}
}
// Parse code blocks that start with a tab or a space.
let mut lines = Vec::new();
for line in parsed_lines {
if line.starts_with(" ") || line.starts_with('\t') {
if let Some(ref mut code_block) = code_block {
code_block.push_str(&line.trim_start_matches(" ").trim_start_matches('\t'));
code_block.push('\n');
} else {
code_block = Some(format!("{}\n", line));
}
} else {
if let Some(ref inner_code_block) = code_block {
code_blocks.push(inner_code_block.trim().to_string());
code_block = None;
}
lines.push(line);
}
}
let mut lines = lines.into_iter();
if let Some(code_block) = code_block {
code_blocks.push(code_block.trim().to_string());
}
// Skip initial blank lines; they make for excessively terse summaries. // Skip initial blank lines; they make for excessively terse summaries.
let summary = loop { let summary = loop {
match lines.next() { match lines.next() {
@ -426,7 +556,7 @@ fn extract_doc_from_attrs(attrs: &[syn::Attribute]) -> (Option<String>, Option<S
} }
}; };
match (summary, first) { let (summary, description) = match (summary, first) {
(None, _) => (None, None), (None, _) => (None, None),
(summary, None) => (summary, None), (summary, None) => (summary, None),
(Some(summary), Some(first)) => ( (Some(summary), Some(first)) => (
@ -449,6 +579,12 @@ fn extract_doc_from_attrs(attrs: &[syn::Attribute]) -> (Option<String>, Option<S
.to_string(), .to_string(),
), ),
), ),
};
DocInfo {
summary,
description,
code_blocks,
} }
} }
@ -458,16 +594,34 @@ fn normalize_comment_string(s: String) -> Vec<String> {
.map(|(idx, s)| { .map(|(idx, s)| {
// Rust-style comments are intrinsically single-line. We don't want // Rust-style comments are intrinsically single-line. We don't want
// to trim away formatting such as an initial '*'. // to trim away formatting such as an initial '*'.
// We also don't want to trim away a tab character, which is
// used to denote a code block. Code blocks can also be denoted
// by four spaces, but we don't want to trim those away either.
// We only want to trim a single space character from the start of
// a line, and only if it's the first character.
let new = s
.chars()
.enumerate()
.flat_map(|(idx, c)| {
if idx == 0 {
if c == ' ' {
return None;
}
}
Some(c)
})
.collect::<String>()
.trim_end()
.to_string();
let s = new.as_str();
if idx == 0 { if idx == 0 {
s.trim_start().trim_end() s
} else { } else {
let trimmed = s.trim_start().trim_end(); s.strip_prefix("* ").unwrap_or_else(|| s.strip_prefix('*').unwrap_or(s))
trimmed
.strip_prefix("* ")
.unwrap_or_else(|| trimmed.strip_prefix('*').unwrap_or(trimmed))
} }
.to_string()
}) })
.map(ToString::to_string)
.collect() .collect()
} }
@ -575,319 +729,59 @@ fn parse_array_type(type_name: &str) -> Option<(&str, usize)> {
Some((inner_type.as_str(), length)) Some((inner_type.as_str(), length))
} }
// Unbox a syn::Type that is boxed to the inner object. // For each kcl code block, we want to generate a test that checks that the
fn unbox(t: syn::Type) -> syn::Type { // code block is valid kcl code and compiles and executes.
match t { fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> proc_macro2::TokenStream {
syn::Type::Path(syn::TypePath { ref path, .. }) => { let test_name = format_ident!("serial_test_example_{}{}", fn_name, index);
let path = &path.segments;
if path.len() == 1 { // TODO: We ignore import for now, because the files don't exist and we just want
let seg = &path[0]; // to show easy imports.
if seg.ident == "Box" { let ignored = if fn_name == "import" {
if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }) = quote! { #[ignore] }
&seg.arguments } else {
{ quote! {}
if args.len() == 1 { };
let mut args = args.iter();
let ok = args.next().unwrap(); quote! {
if let syn::GenericArgument::Type(ty) = ok { #[tokio::test(flavor = "multi_thread", worker_threads = 5)]
return ty.clone(); #ignored
} async fn #test_name() {
} let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
} let http_client = reqwest::Client::builder()
} .user_agent(user_agent)
} // For file conversions we need this to be long.
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
// For file conversions we need this to be long.
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
// Create the client.
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await.unwrap();
let tokens = crate::token::lexer(#code_block);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(crate::engine::conn::EngineConnection::new(ws).await.unwrap())),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx).await.unwrap();
} }
_ => {
return t;
}
}
t
}
// For a Vec<Box<T>> return Vec<T>.
// For a Vec<T> return Vec<T>.
// For a Box<T> return T.
fn unbox_vec(t: syn::Type) -> syn::Type {
match t {
syn::Type::Path(syn::TypePath { ref path, .. }) => {
let path = &path.segments;
if path.len() == 1 {
let seg = &path[0];
if seg.ident == "Vec" {
if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }) =
&seg.arguments
{
if args.len() == 1 {
let mut args = args.iter();
let ok = args.next().unwrap();
if let syn::GenericArgument::Type(ty) = ok {
let unboxed = unbox(ty.clone());
// Wrap it back in a vec.
let wrapped = syn::Type::Path(syn::TypePath {
qself: None,
path: syn::Path {
leading_colon: None,
segments: {
let mut segments = syn::punctuated::Punctuated::new();
segments.push_value(syn::PathSegment {
ident: syn::Ident::new("Vec", proc_macro2::Span::call_site()),
arguments: syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments {
colon2_token: None,
lt_token: syn::token::Lt::default(),
args: {
let mut args = syn::punctuated::Punctuated::new();
args.push_value(syn::GenericArgument::Type(unboxed));
args
},
gt_token: syn::token::Gt::default(),
},
),
});
segments
},
},
});
return wrapped;
}
}
}
}
}
}
_ => {
return t;
}
}
t
}
#[cfg(test)]
mod tests {
use quote::quote;
use super::*;
#[test]
fn test_get_inner_array_type() {
for (expected, input) in [
(Some(("f64", 2)), "[f64;2]"),
(Some(("String", 2)), "[String; 2]"),
(Some(("Option<String>", 12)), "[Option<String>;12]"),
(Some(("Option<String>", 12)), "[Option<String>; 12]"),
] {
let actual = parse_array_type(input);
assert_eq!(actual, expected);
}
}
#[test]
fn test_stdlib_line_to() {
let (item, errors) = do_stdlib(
quote! {
name = "lineTo",
},
quote! {
fn inner_line_to(
data: LineToData,
sketch_group: SketchGroup,
args: &Args,
) -> Result<SketchGroup, KclError> {
Ok(())
}
},
)
.unwrap();
let _expected = quote! {};
assert!(errors.is_empty());
expectorate::assert_contents("tests/lineTo.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_min() {
let (item, errors) = do_stdlib(
quote! {
name = "min",
},
quote! {
fn inner_min(
/// The args to do shit to.
args: Vec<f64>
) -> f64 {
let mut min = std::f64::MAX;
for arg in args.iter() {
if *arg < min {
min = *arg;
}
}
min
}
},
)
.unwrap();
let _expected = quote! {};
assert!(errors.is_empty());
expectorate::assert_contents("tests/min.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_show() {
let (item, errors) = do_stdlib(
quote! {
name = "show",
},
quote! {
fn inner_show(
/// The args to do shit to.
_args: Vec<f64>
) {
}
},
)
.unwrap();
let _expected = quote! {};
assert!(errors.is_empty());
expectorate::assert_contents("tests/show.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_box() {
let (item, errors) = do_stdlib(
quote! {
name = "show",
},
quote! {
fn inner_show(
/// The args to do shit to.
args: Box<f64>
) -> Box<f64> {
args
}
},
)
.unwrap();
let _expected = quote! {};
assert!(errors.is_empty());
expectorate::assert_contents("tests/box.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_option() {
let (item, errors) = do_stdlib(
quote! {
name = "show",
},
quote! {
fn inner_show(
/// The args to do shit to.
args: Option<f64>
) -> Result<Box<f64>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents("tests/option.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_array() {
let (item, errors) = do_stdlib(
quote! {
name = "show",
},
quote! {
fn inner_show(
/// The args to do shit to.
args: [f64; 2]
) -> Result<Box<f64>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents("tests/array.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_option_input_format() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Box<f64>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/option_input_format.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
#[test]
fn test_stdlib_return_vec_sketch_group() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<SketchGroup>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/return_vec_sketch_group.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
#[test]
fn test_stdlib_return_vec_box_sketch_group() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/return_vec_box_sketch_group.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
} }
} }

View File

@ -0,0 +1,461 @@
use quote::quote;
use crate::{do_stdlib, parse_array_type};
#[test]
fn test_get_inner_array_type() {
for (expected, input) in [
(Some(("f64", 2)), "[f64;2]"),
(Some(("String", 2)), "[String; 2]"),
(Some(("Option<String>", 12)), "[Option<String>;12]"),
(Some(("Option<String>", 12)), "[Option<String>; 12]"),
] {
let actual = parse_array_type(input);
assert_eq!(actual, expected);
}
}
#[test]
fn test_stdlib_line_to() {
let (item, errors) = do_stdlib(
quote! {
name = "lineTo",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// lineTo
///
/// ```
/// This is another code block.
/// yes sirrr.
/// lineTo
/// ```
fn inner_line_to(
data: LineToData,
sketch_group: SketchGroup,
args: &Args,
) -> Result<SketchGroup, KclError> {
Ok(())
}
},
)
.unwrap();
let _expected = quote! {};
assert!(errors.is_empty());
expectorate::assert_contents("tests/lineTo.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_min() {
let (item, errors) = do_stdlib(
quote! {
name = "min",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// min
///
/// ```
/// This is another code block.
/// yes sirrr.
/// min
/// ```
fn inner_min(
/// The args to do shit to.
args: Vec<f64>
) -> f64 {
let mut min = std::f64::MAX;
for arg in args.iter() {
if *arg < min {
min = *arg;
}
}
min
}
},
)
.unwrap();
let _expected = quote! {};
assert!(errors.is_empty());
expectorate::assert_contents("tests/min.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_show() {
let (item, errors) = do_stdlib(
quote! {
name = "show",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// show
fn inner_show(
/// The args to do shit to.
_args: Vec<f64>
) {
}
},
)
.unwrap();
let _expected = quote! {};
assert!(errors.is_empty());
expectorate::assert_contents("tests/show.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_box() {
let (item, errors) = do_stdlib(
quote! {
name = "show",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// show
fn inner_show(
/// The args to do shit to.
args: Box<f64>
) -> Box<f64> {
args
}
},
)
.unwrap();
let _expected = quote! {};
assert!(errors.is_empty());
expectorate::assert_contents("tests/box.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_option() {
let (item, errors) = do_stdlib(
quote! {
name = "show",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// show
fn inner_show(
/// The args to do shit to.
args: Option<f64>
) -> Result<Box<f64>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents("tests/option.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_array() {
let (item, errors) = do_stdlib(
quote! {
name = "show",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// show
///
/// ```
/// This is another code block.
/// yes sirrr.
/// show
/// ```
fn inner_show(
/// The args to do shit to.
args: [f64; 2]
) -> Result<Box<f64>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents("tests/array.gen", &openapitor::types::get_text_fmt(&item).unwrap());
}
#[test]
fn test_stdlib_option_input_format() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// import
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Box<f64>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/option_input_format.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
#[test]
fn test_stdlib_return_vec_sketch_group() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// import
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<SketchGroup>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/return_vec_sketch_group.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
#[test]
fn test_stdlib_return_vec_box_sketch_group() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// import
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/return_vec_box_sketch_group.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
#[test]
fn test_stdlib_doc_comment_with_code() {
let (item, errors) = do_stdlib(
quote! {
name = "myFunc",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// myFunc
///
/// ```
/// This is another code block.
/// yes sirrr.
/// myFunc
/// ```
fn inner_my_func(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/doc_comment_with_code.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
#[test]
fn test_stdlib_doc_comment_with_code_on_ignored_function() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
/// import
///
/// ```
/// This is another code block.
/// yes sirrr.
/// import
/// ```
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/doc_comment_with_code_on_ignored_function.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
#[test]
fn test_stdlib_fail_non_camel_case() {
let (_, errors) = do_stdlib(
quote! {
name = "import_thing",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
///
/// ```
/// This is another code block.
/// yes sirrr.
/// ```
fn inner_import_thing(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(!errors.is_empty());
assert_eq!(
errors[1].to_string(),
"stdlib function names must be in camel case: `import_thing`"
);
}
#[test]
fn test_stdlib_fail_no_code_block() {
let (_, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(!errors.is_empty());
assert_eq!(
errors[1].to_string(),
"stdlib functions must have at least one code block"
);
}
#[test]
fn test_stdlib_fail_name_not_in_code_block() {
let (_, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
/// This is some function.
/// It does shit.
///
/// This is code.
/// It does other shit.
///
/// ```
/// This is another code block.
/// yes sirrr.
/// ```
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(!errors.is_empty());
assert_eq!(
errors[1].to_string(),
"stdlib functions must have the function name `import` in the code block"
);
}

View File

@ -0,0 +1,91 @@
// Unbox a Vec<Box<T>> to Vec<T>.
// Unbox a Box<T> to T.
pub(crate) fn unbox(t: syn::Type) -> syn::Type {
unbox_inner(unbox_vec(t))
}
// Unbox a syn::Type that is boxed to the inner object.
fn unbox_inner(t: syn::Type) -> syn::Type {
match t {
syn::Type::Path(syn::TypePath { ref path, .. }) => {
let path = &path.segments;
if path.len() == 1 {
let seg = &path[0];
if seg.ident == "Box" {
if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }) =
&seg.arguments
{
if args.len() == 1 {
let mut args = args.iter();
let ok = args.next().unwrap();
if let syn::GenericArgument::Type(ty) = ok {
return ty.clone();
}
}
}
}
}
}
_ => {
return t;
}
}
t
}
// For a Vec<Box<T>> return Vec<T>.
// For a Vec<T> return Vec<T>.
fn unbox_vec(t: syn::Type) -> syn::Type {
match t {
syn::Type::Path(syn::TypePath { ref path, .. }) => {
let path = &path.segments;
if path.len() == 1 {
let seg = &path[0];
if seg.ident == "Vec" {
if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }) =
&seg.arguments
{
if args.len() == 1 {
let mut args = args.iter();
let ok = args.next().unwrap();
if let syn::GenericArgument::Type(ty) = ok {
let unboxed = unbox(ty.clone());
// Wrap it back in a vec.
let wrapped = syn::Type::Path(syn::TypePath {
qself: None,
path: syn::Path {
leading_colon: None,
segments: {
let mut segments = syn::punctuated::Punctuated::new();
segments.push_value(syn::PathSegment {
ident: syn::Ident::new("Vec", proc_macro2::Span::call_site()),
arguments: syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments {
colon2_token: None,
lt_token: syn::token::Lt::default(),
args: {
let mut args = syn::punctuated::Punctuated::new();
args.push_value(syn::GenericArgument::Type(unboxed));
args
},
gt_token: syn::token::Gt::default(),
},
),
});
segments
},
},
});
return wrapped;
}
}
}
}
}
}
_ => {
return t;
}
}
t
}

View File

@ -1,11 +1,94 @@
#[cfg(test)]
mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is another code block.\nyes sirrr.\nshow");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show1() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nshow");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: show"] #[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct Show {} pub(crate) struct Show {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: show"] #[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
pub(crate) const Show: Show = Show {}; pub(crate) const Show: Show = Show {};
fn boxed_show( fn boxed_show(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +108,11 @@ impl crate::docs::StdLibFn for Show {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -68,6 +151,24 @@ impl crate::docs::StdLibFn for Show {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec![
"This is another code block.\nyes sirrr.\nshow",
"This is code.\nIt does other shit.\nshow",
];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_show boxed_show
} }
@ -77,6 +178,18 @@ impl crate::docs::StdLibFn for Show {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" show"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" This is another code block."]
#[doc = r" yes sirrr."]
#[doc = r" show"]
#[doc = r" ```"]
fn inner_show(#[doc = r" The args to do shit to."] args: [f64; 2]) -> Result<Box<f64>> { fn inner_show(#[doc = r" The args to do shit to."] args: [f64; 2]) -> Result<Box<f64>> {
args args
} }

View File

@ -1,11 +1,54 @@
#[cfg(test)]
mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nshow");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: show"] #[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct Show {} pub(crate) struct Show {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: show"] #[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
pub(crate) const Show: Show = Show {}; pub(crate) const Show: Show = Show {};
fn boxed_show( fn boxed_show(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +68,11 @@ impl crate::docs::StdLibFn for Show {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -68,6 +111,21 @@ impl crate::docs::StdLibFn for Show {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec!["This is code.\nIt does other shit.\nshow"];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_show boxed_show
} }
@ -77,6 +135,12 @@ impl crate::docs::StdLibFn for Show {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" show"]
fn inner_show(#[doc = r" The args to do shit to."] args: Box<f64>) -> Box<f64> { fn inner_show(#[doc = r" The args to do shit to."] args: Box<f64>) -> Box<f64> {
args args
} }

View File

@ -0,0 +1,197 @@
#[cfg(test)]
mod test_examples_my_func {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_my_func0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is another code block.\nyes sirrr.\nmyFunc");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_my_func1() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nmyFunc");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: myFunc\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)]
pub(crate) struct MyFunc {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: myFunc\nThis is some function.\nIt does shit."]
pub(crate) const MyFunc: MyFunc = MyFunc {};
fn boxed_my_func(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
>,
>,
> {
Box::pin(my_func(args))
}
impl crate::docs::StdLibFn for MyFunc {
fn name(&self) -> String {
"myFunc".to_string()
}
fn summary(&self) -> String {
"This is some function.".to_string()
}
fn description(&self) -> String {
"It does shit.".to_string()
}
fn tags(&self) -> Vec<String> {
vec![]
}
fn args(&self) -> Vec<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: <Option<kittycad::types::InputFormat>>::json_schema(&mut generator),
required: false,
}]
}
fn return_value(&self) -> Option<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "[SketchGroup]".to_string(),
schema: <Vec<SketchGroup>>::json_schema(&mut generator),
required: true,
})
}
fn unpublished(&self) -> bool {
false
}
fn deprecated(&self) -> bool {
false
}
fn examples(&self) -> Vec<String> {
let code_blocks = vec![
"This is another code block.\nyes sirrr.\nmyFunc",
"This is code.\nIt does other shit.\nmyFunc",
];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_my_func
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {
Box::new(self.clone())
}
}
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" myFunc"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" This is another code block."]
#[doc = r" yes sirrr."]
#[doc = r" myFunc"]
#[doc = r" ```"]
fn inner_my_func(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Vec<Box<SketchGroup>>> {
args
}

View File

@ -0,0 +1,199 @@
#[cfg(test)]
mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
#[ignore]
async fn serial_test_example_import0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is another code block.\nyes sirrr.\nimport");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
#[ignore]
async fn serial_test_example_import1() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)]
pub(crate) struct Import {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
pub(crate) const Import: Import = Import {};
fn boxed_import(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
>,
>,
> {
Box::pin(import(args))
}
impl crate::docs::StdLibFn for Import {
fn name(&self) -> String {
"import".to_string()
}
fn summary(&self) -> String {
"This is some function.".to_string()
}
fn description(&self) -> String {
"It does shit.".to_string()
}
fn tags(&self) -> Vec<String> {
vec![]
}
fn args(&self) -> Vec<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: <Option<kittycad::types::InputFormat>>::json_schema(&mut generator),
required: false,
}]
}
fn return_value(&self) -> Option<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "[SketchGroup]".to_string(),
schema: <Vec<SketchGroup>>::json_schema(&mut generator),
required: true,
})
}
fn unpublished(&self) -> bool {
false
}
fn deprecated(&self) -> bool {
false
}
fn examples(&self) -> Vec<String> {
let code_blocks = vec![
"This is another code block.\nyes sirrr.\nimport",
"This is code.\nIt does other shit.\nimport",
];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_import
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {
Box::new(self.clone())
}
}
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" import"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" This is another code block."]
#[doc = r" yes sirrr."]
#[doc = r" import"]
#[doc = r" ```"]
fn inner_import(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Vec<Box<SketchGroup>>> {
args
}

View File

@ -1,11 +1,94 @@
#[cfg(test)]
mod test_examples_line_to {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_line_to0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is another code block.\nyes sirrr.\nlineTo");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_line_to1() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nlineTo");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: lineTo"] #[doc = "Std lib function: lineTo\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct LineTo {} pub(crate) struct LineTo {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: lineTo"] #[doc = "Std lib function: lineTo\nThis is some function.\nIt does shit."]
pub(crate) const LineTo: LineTo = LineTo {}; pub(crate) const LineTo: LineTo = LineTo {};
fn boxed_line_to( fn boxed_line_to(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +108,11 @@ impl crate::docs::StdLibFn for LineTo {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -76,6 +159,24 @@ impl crate::docs::StdLibFn for LineTo {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec![
"This is another code block.\nyes sirrr.\nlineTo",
"This is code.\nIt does other shit.\nlineTo",
];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_line_to boxed_line_to
} }
@ -85,6 +186,18 @@ impl crate::docs::StdLibFn for LineTo {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" lineTo"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" This is another code block."]
#[doc = r" yes sirrr."]
#[doc = r" lineTo"]
#[doc = r" ```"]
fn inner_line_to( fn inner_line_to(
data: LineToData, data: LineToData,
sketch_group: SketchGroup, sketch_group: SketchGroup,

View File

@ -1,11 +1,94 @@
#[cfg(test)]
mod test_examples_min {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_min0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is another code block.\nyes sirrr.\nmin");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_min1() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nmin");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: min"] #[doc = "Std lib function: min\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct Min {} pub(crate) struct Min {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: min"] #[doc = "Std lib function: min\nThis is some function.\nIt does shit."]
pub(crate) const Min: Min = Min {}; pub(crate) const Min: Min = Min {};
fn boxed_min( fn boxed_min(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +108,11 @@ impl crate::docs::StdLibFn for Min {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -68,6 +151,24 @@ impl crate::docs::StdLibFn for Min {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec![
"This is another code block.\nyes sirrr.\nmin",
"This is code.\nIt does other shit.\nmin",
];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_min boxed_min
} }
@ -77,6 +178,18 @@ impl crate::docs::StdLibFn for Min {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" min"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" This is another code block."]
#[doc = r" yes sirrr."]
#[doc = r" min"]
#[doc = r" ```"]
fn inner_min(#[doc = r" The args to do shit to."] args: Vec<f64>) -> f64 { fn inner_min(#[doc = r" The args to do shit to."] args: Vec<f64>) -> f64 {
let mut min = std::f64::MAX; let mut min = std::f64::MAX;
for arg in args.iter() { for arg in args.iter() {

View File

@ -1,11 +1,54 @@
#[cfg(test)]
mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nshow");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: show"] #[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct Show {} pub(crate) struct Show {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: show"] #[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
pub(crate) const Show: Show = Show {}; pub(crate) const Show: Show = Show {};
fn boxed_show( fn boxed_show(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +68,11 @@ impl crate::docs::StdLibFn for Show {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -68,6 +111,21 @@ impl crate::docs::StdLibFn for Show {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec!["This is code.\nIt does other shit.\nshow"];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_show boxed_show
} }
@ -77,6 +135,12 @@ impl crate::docs::StdLibFn for Show {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" show"]
fn inner_show(#[doc = r" The args to do shit to."] args: Option<f64>) -> Result<Box<f64>> { fn inner_show(#[doc = r" The args to do shit to."] args: Option<f64>) -> Result<Box<f64>> {
args args
} }

View File

@ -1,11 +1,55 @@
#[cfg(test)]
mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
#[ignore]
async fn serial_test_example_import0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: import"] #[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct Import {} pub(crate) struct Import {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: import"] #[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
pub(crate) const Import: Import = Import {}; pub(crate) const Import: Import = Import {};
fn boxed_import( fn boxed_import(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +69,11 @@ impl crate::docs::StdLibFn for Import {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -68,6 +112,21 @@ impl crate::docs::StdLibFn for Import {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec!["This is code.\nIt does other shit.\nimport"];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_import boxed_import
} }
@ -77,6 +136,12 @@ impl crate::docs::StdLibFn for Import {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" import"]
fn inner_import( fn inner_import(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>, #[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Box<f64>> { ) -> Result<Box<f64>> {

View File

@ -1,11 +1,55 @@
#[cfg(test)]
mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
#[ignore]
async fn serial_test_example_import0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: import"] #[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct Import {} pub(crate) struct Import {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: import"] #[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
pub(crate) const Import: Import = Import {}; pub(crate) const Import: Import = Import {};
fn boxed_import( fn boxed_import(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +69,11 @@ impl crate::docs::StdLibFn for Import {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -68,6 +112,21 @@ impl crate::docs::StdLibFn for Import {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec!["This is code.\nIt does other shit.\nimport"];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_import boxed_import
} }
@ -77,6 +136,12 @@ impl crate::docs::StdLibFn for Import {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" import"]
fn inner_import( fn inner_import(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>, #[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Vec<Box<SketchGroup>>> { ) -> Result<Vec<Box<SketchGroup>>> {

View File

@ -1,11 +1,55 @@
#[cfg(test)]
mod test_examples_import {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
#[ignore]
async fn serial_test_example_import0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nimport");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: import"] #[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct Import {} pub(crate) struct Import {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: import"] #[doc = "Std lib function: import\nThis is some function.\nIt does shit."]
pub(crate) const Import: Import = Import {}; pub(crate) const Import: Import = Import {};
fn boxed_import( fn boxed_import(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +69,11 @@ impl crate::docs::StdLibFn for Import {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -68,6 +112,21 @@ impl crate::docs::StdLibFn for Import {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec!["This is code.\nIt does other shit.\nimport"];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_import boxed_import
} }
@ -77,6 +136,12 @@ impl crate::docs::StdLibFn for Import {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" import"]
fn inner_import( fn inner_import(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>, #[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Vec<SketchGroup>> { ) -> Result<Vec<SketchGroup>> {

View File

@ -1,11 +1,54 @@
#[cfg(test)]
mod test_examples_show {
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn serial_test_example_show0() {
let user_agent = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
let http_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60));
let ws_client = reqwest::Client::builder()
.user_agent(user_agent)
.timeout(std::time::Duration::from_secs(600))
.connect_timeout(std::time::Duration::from_secs(60))
.connection_verbose(true)
.tcp_keepalive(std::time::Duration::from_secs(600))
.http1_only();
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
let ws = client
.modeling()
.commands_ws(None, None, None, None, None, Some(false))
.await
.unwrap();
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nshow");
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut mem: crate::executor::ProgramMemory = Default::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn::EngineConnection::new(ws)
.await
.unwrap(),
)),
fs: crate::fs::FileManager::new(),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
crate::executor::execute(program, &mut mem, crate::executor::BodyType::Root, &ctx)
.await
.unwrap();
}
}
#[allow(non_camel_case_types, missing_docs)] #[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: show"] #[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)] #[ts(export)]
pub(crate) struct Show {} pub(crate) struct Show {}
#[allow(non_upper_case_globals, missing_docs)] #[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: show"] #[doc = "Std lib function: show\nThis is some function.\nIt does shit."]
pub(crate) const Show: Show = Show {}; pub(crate) const Show: Show = Show {};
fn boxed_show( fn boxed_show(
args: crate::std::Args, args: crate::std::Args,
@ -25,11 +68,11 @@ impl crate::docs::StdLibFn for Show {
} }
fn summary(&self) -> String { fn summary(&self) -> String {
"".to_string() "This is some function.".to_string()
} }
fn description(&self) -> String { fn description(&self) -> String {
"".to_string() "It does shit.".to_string()
} }
fn tags(&self) -> Vec<String> { fn tags(&self) -> Vec<String> {
@ -68,6 +111,21 @@ impl crate::docs::StdLibFn for Show {
false false
} }
fn examples(&self) -> Vec<String> {
let code_blocks = vec!["This is code.\nIt does other shit.\nshow"];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb);
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_show boxed_show
} }
@ -77,4 +135,10 @@ impl crate::docs::StdLibFn for Show {
} }
} }
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" show"]
fn inner_show(#[doc = r" The args to do shit to."] _args: Vec<f64>) {} fn inner_show(#[doc = r" The args to do shit to."] _args: Vec<f64>) {}

View File

@ -18,8 +18,8 @@ chrono = "0.4.35"
clap = { version = "4.5.2", features = ["cargo", "derive", "env", "unicode"], optional = true } clap = { version = "4.5.2", features = ["cargo", "derive", "env", "unicode"], optional = true }
dashmap = "5.5.3" dashmap = "5.5.3"
databake = { version = "0.1.7", features = ["derive"] } databake = { version = "0.1.7", features = ["derive"] }
derive-docs = { version = "0.1.10" } #derive-docs = { version = "0.1.11" }
#derive-docs = { path = "../derive-docs" } derive-docs = { path = "../derive-docs" }
futures = { version = "0.3.30" } futures = { version = "0.3.30" }
gltf-json = "1.4.0" gltf-json = "1.4.0"
kittycad = { workspace = true } kittycad = { workspace = true }

View File

@ -1,12 +1,13 @@
use std::sync::Arc;
use kittycad::types::{ModelingCmd, Point3D}; use kittycad::types::{ModelingCmd, Point3D};
use super::types::ConstraintLevel;
use crate::{ use crate::{
ast::types::{ ast::types::{
ArrayExpression, CallExpression, FormatOptions, Literal, PipeExpression, PipeSubstitution, Program, ArrayExpression, CallExpression, ConstraintLevel, FormatOptions, Literal, PipeExpression, PipeSubstitution,
VariableDeclarator, Program, VariableDeclarator,
}, },
engine::{EngineConnection, EngineManager}, engine::EngineManager,
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{Point2d, SourceRange}, executor::{Point2d, SourceRange},
}; };
@ -27,7 +28,7 @@ const EPSILON: f64 = 0.015625; // or 2^-6
/// Update the AST to reflect the new state of the program after something like /// Update the AST to reflect the new state of the program after something like
/// a move or a new line. /// a move or a new line.
pub async fn modify_ast_for_sketch( pub async fn modify_ast_for_sketch(
engine: &mut EngineConnection, engine: &Arc<Box<dyn EngineManager>>,
program: &mut Program, program: &mut Program,
// The name of the sketch. // The name of the sketch.
sketch_name: &str, sketch_name: &str,

View File

@ -30,6 +30,9 @@ pub struct StdLibFnData {
pub unpublished: bool, pub unpublished: bool,
/// If the function is deprecated. /// If the function is deprecated.
pub deprecated: bool, pub deprecated: bool,
/// Code examples.
/// These are tested and we know they compile and execute.
pub examples: Vec<String>,
} }
/// This struct defines a single argument to a stdlib function. /// This struct defines a single argument to a stdlib function.
@ -105,6 +108,9 @@ pub trait StdLibFn: std::fmt::Debug + Send + Sync {
/// If the function is deprecated. /// If the function is deprecated.
fn deprecated(&self) -> bool; fn deprecated(&self) -> bool;
/// Any example code blocks.
fn examples(&self) -> Vec<String>;
/// The function itself. /// The function itself.
fn std_lib_fn(&self) -> crate::std::StdFn; fn std_lib_fn(&self) -> crate::std::StdFn;
@ -122,6 +128,7 @@ pub trait StdLibFn: std::fmt::Debug + Send + Sync {
return_value: self.return_value(), return_value: self.return_value(),
unpublished: self.unpublished(), unpublished: self.unpublished(),
deprecated: self.deprecated(), deprecated: self.deprecated(),
examples: self.examples(),
}) })
} }
@ -560,7 +567,7 @@ mod tests {
#[test] #[test]
fn test_deserialize_function() { fn test_deserialize_function() {
let some_function_string = r#"{"type":"StdLib","func":{"name":"line","summary":"","description":"","tags":[],"returnValue":{"type":"","required":false,"name":"","schema":{}},"args":[],"unpublished":false,"deprecated":false}}"#; let some_function_string = r#"{"type":"StdLib","func":{"name":"line","summary":"","description":"","tags":[],"returnValue":{"type":"","required":false,"name":"","schema":{}},"args":[],"unpublished":false,"deprecated":false, "examples": []}}"#;
let some_function: crate::ast::types::Function = serde_json::from_str(some_function_string).unwrap(); let some_function: crate::ast::types::Function = serde_json::from_str(some_function_string).unwrap();
assert_eq!( assert_eq!(

View File

@ -1,38 +1,15 @@
//! Functions for managing engine communications. //! Functions for managing engine communications.
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
#[cfg(not(test))]
#[cfg(feature = "engine")] #[cfg(feature = "engine")]
pub mod conn; pub mod conn;
#[cfg(not(target_arch = "wasm32"))] pub mod conn_mock;
#[cfg(not(test))]
#[cfg(feature = "engine")]
pub use conn::EngineConnection;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
#[cfg(not(test))]
#[cfg(feature = "engine")] #[cfg(feature = "engine")]
pub mod conn_wasm; pub mod conn_wasm;
#[cfg(target_arch = "wasm32")]
#[cfg(not(test))]
#[cfg(feature = "engine")]
pub use conn_wasm::EngineConnection;
#[cfg(test)]
pub mod conn_mock;
#[cfg(test)]
pub use conn_mock::EngineConnection;
#[cfg(not(feature = "engine"))]
#[cfg(not(test))]
pub mod conn_mock;
use anyhow::Result;
#[cfg(not(feature = "engine"))]
#[cfg(not(test))]
pub use conn_mock::EngineConnection;
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait EngineManager: Clone { pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
/// Send a modeling command and wait for the response message. /// Send a modeling command and wait for the response message.
async fn send_modeling_cmd( async fn send_modeling_cmd(
&self, &self,

View File

@ -13,7 +13,7 @@ use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
use crate::{ use crate::{
ast::types::{BodyItem, FunctionExpression, KclNone, Value}, ast::types::{BodyItem, FunctionExpression, KclNone, Value},
engine::{EngineConnection, EngineManager}, engine::EngineManager,
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
fs::FileManager, fs::FileManager,
std::{FunctionKind, StdLib}, std::{FunctionKind, StdLib},
@ -977,30 +977,19 @@ impl Default for PipeInfo {
/// The executor context. /// The executor context.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ExecutorContext { pub struct ExecutorContext {
pub engine: EngineConnection, pub engine: Arc<Box<dyn EngineManager>>,
pub fs: FileManager, pub fs: FileManager,
pub stdlib: Arc<StdLib>, pub stdlib: Arc<StdLib>,
pub units: kittycad::types::UnitLength, pub units: kittycad::types::UnitLength,
} }
impl ExecutorContext { impl ExecutorContext {
/// Create a new default executor context.
#[cfg(test)]
pub async fn new(units: kittycad::types::UnitLength) -> Result<Self> {
Ok(Self {
engine: EngineConnection::new().await?,
fs: FileManager::new(),
stdlib: Arc::new(StdLib::new()),
units,
})
}
/// Create a new default executor context. /// Create a new default executor context.
#[cfg(not(test))] #[cfg(not(test))]
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub async fn new(ws: reqwest::Upgraded, units: kittycad::types::UnitLength) -> Result<Self> { pub async fn new(ws: reqwest::Upgraded, units: kittycad::types::UnitLength) -> Result<Self> {
Ok(Self { Ok(Self {
engine: EngineConnection::new(ws).await?, engine: Arc::new(Box::new(crate::engine::conn::EngineConnection::new(ws).await?)),
fs: FileManager::new(), fs: FileManager::new(),
stdlib: Arc::new(StdLib::new()), stdlib: Arc::new(StdLib::new()),
units, units,
@ -1290,6 +1279,8 @@ fn assign_args_to_params(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::sync::Arc;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use super::*; use super::*;
@ -1300,7 +1291,12 @@ mod tests {
let parser = crate::parser::Parser::new(tokens); let parser = crate::parser::Parser::new(tokens);
let program = parser.ast()?; let program = parser.ast()?;
let mut mem: ProgramMemory = Default::default(); let mut mem: ProgramMemory = Default::default();
let ctx = ExecutorContext::new(kittycad::types::UnitLength::Mm).await?; let ctx = ExecutorContext {
engine: Arc::new(Box::new(crate::engine::conn_mock::EngineConnection::new().await?)),
fs: crate::fs::FileManager::new(),
stdlib: Arc::new(crate::std::StdLib::new()),
units: kittycad::types::UnitLength::Mm,
};
let memory = execute(program, &mut mem, BodyType::Root, &ctx).await?; let memory = execute(program, &mut mem, BodyType::Root, &ctx).await?;
Ok(memory) Ok(memory)

View File

@ -24,13 +24,12 @@ use tower_lsp::{
LanguageServer, LanguageServer,
}; };
use self::types::{CopilotAcceptCompletionParams, CopilotCompletionTelemetry, CopilotRejectCompletionParams};
use crate::lsp::{ use crate::lsp::{
backend::Backend as _, backend::Backend as _,
copilot::types::{CopilotCompletionResponse, CopilotEditorInfo, CopilotLspCompletionParams, DocParams}, copilot::types::{CopilotCompletionResponse, CopilotEditorInfo, CopilotLspCompletionParams, DocParams},
}; };
use self::types::{CopilotAcceptCompletionParams, CopilotCompletionTelemetry, CopilotRejectCompletionParams};
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
pub struct Success { pub struct Success {
success: bool, success: bool,

View File

@ -20,6 +20,16 @@ pub async fn extrude(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Extrudes by a given amount. /// Extrudes by a given amount.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line([0, 10], %)
/// |> line([10, 0], %)
/// |> line([0, -10], %)
/// |> close(%)
/// |> extrude(5, %)
/// ```
#[stdlib { #[stdlib {
name = "extrude" name = "extrude"
}] }]
@ -180,6 +190,18 @@ pub async fn get_extrude_wall_transform(args: Args) -> Result<MemoryItem, KclErr
} }
/// Returns the extrude wall transform. /// Returns the extrude wall transform.
///
/// ```no_run
/// const box = startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line([0, 10], %)
/// |> line([10, 0], %)
/// |> line({to: [0, -10], tag: "surface"}, %)
/// |> close(%)
/// |> extrude(5, %)
///
/// const transform = getExtrudeWallTransform('surface', box)
/// ```
#[stdlib { #[stdlib {
name = "getExtrudeWallTransform" name = "getExtrudeWallTransform"
}] }]

View File

@ -44,6 +44,17 @@ pub async fn fillet(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Create fillets on tagged paths. /// Create fillets on tagged paths.
///
/// ```no_run
/// const part001 = startSketchOn('XY')
/// |> startProfileAt([0,0], %)
/// |> line({to: [0, 10], tag: "thing"}, %)
/// |> line([10, 0], %)
/// |> line({to: [0, -10], tag: "thing2"}, %)
/// |> close(%)
/// |> extrude(10, %)
/// |> fillet({radius: 2, tags: ["thing", "thing2"]}, %)
/// ```
#[stdlib { #[stdlib {
name = "fillet", name = "fillet",
}] }]
@ -115,6 +126,17 @@ pub async fn get_opposite_edge(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Get the opposite edge to the edge given. /// Get the opposite edge to the edge given.
///
/// ```no_run
/// const part001 = startSketchOn('XY')
/// |> startProfileAt([0,0], %)
/// |> line({to: [0, 10], tag: "thing"}, %)
/// |> line([10, 0], %)
/// |> line({to: [0, -10], tag: "thing2"}, %)
/// |> close(%)
/// |> extrude(10, %)
/// |> fillet({radius: 2, tags: ["thing", getOppositeEdge("thing", %)]}, %)
/// ```
#[stdlib { #[stdlib {
name = "getOppositeEdge", name = "getOppositeEdge",
}] }]
@ -173,6 +195,17 @@ pub async fn get_next_adjacent_edge(args: Args) -> Result<MemoryItem, KclError>
} }
/// Get the next adjacent edge to the edge given. /// Get the next adjacent edge to the edge given.
///
/// ```no_run
/// const part001 = startSketchOn('XY')
/// |> startProfileAt([0,0], %)
/// |> line({to: [0, 10], tag: "thing"}, %)
/// |> line({to: [10, 0], tag: "thing1"}, %)
/// |> line({to: [0, -10], tag: "thing2"}, %)
/// |> close(%)
/// |> extrude(10, %)
/// |> fillet({radius: 2, tags: [getNextAdjacentEdge("thing", %)]}, %)
/// ```
#[stdlib { #[stdlib {
name = "getNextAdjacentEdge", name = "getNextAdjacentEdge",
}] }]
@ -240,6 +273,17 @@ pub async fn get_previous_adjacent_edge(args: Args) -> Result<MemoryItem, KclErr
} }
/// Get the previous adjacent edge to the edge given. /// Get the previous adjacent edge to the edge given.
///
/// ```no_run
/// const part001 = startSketchOn('XY')
/// |> startProfileAt([0,0], %)
/// |> line({to: [0, 10], tag: "thing"}, %)
/// |> line({to: [10, 0], tag: "thing1"}, %)
/// |> line({to: [0, -10], tag: "thing2"}, %)
/// |> close(%)
/// |> extrude(10, %)
/// |> fillet({radius: 2, tags: [getPreviousAdjacentEdge("thing2", %)]}, %)
/// ```
#[stdlib { #[stdlib {
name = "getPreviousAdjacentEdge", name = "getPreviousAdjacentEdge",
}] }]

View File

@ -127,6 +127,26 @@ pub async fn import(args: Args) -> Result<MemoryItem, KclError> {
/// ///
/// Import paths are relative to the current project directory. This only works in the desktop app /// Import paths are relative to the current project directory. This only works in the desktop app
/// not in browser. /// not in browser.
///
/// ```no_run
/// const model = import("thing.obj")
/// ```
///
/// ```no_run
/// const model = import("cube.obj", {type: "obj", units: "m"})
/// ```
///
/// ```no_run
/// const model = import("my_model.gltf")
/// ```
///
/// ```no_run
/// const model = import("my_model.sldprt")
/// ```
///
/// ```no_run
/// const model = import("my_model.step")
/// ```
#[stdlib { #[stdlib {
name = "import", name = "import",
}] }]

View File

@ -19,6 +19,10 @@ pub async fn cos(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the sine of a number (in radians). /// Computes the sine of a number (in radians).
///
/// ```no_run
/// const anotherVar = cos(2*pi())
/// ```
#[stdlib { #[stdlib {
name = "cos", name = "cos",
}] }]
@ -35,6 +39,10 @@ pub async fn sin(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the sine of a number (in radians). /// Computes the sine of a number (in radians).
///
/// ```no_run
/// const myVar = sin(2*pi())
/// ```
#[stdlib { #[stdlib {
name = "sin", name = "sin",
}] }]
@ -51,6 +59,10 @@ pub async fn tan(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the tangent of a number (in radians). /// Computes the tangent of a number (in radians).
///
/// ```no_run
/// const myVar = tan(2*pi())
/// ```
#[stdlib { #[stdlib {
name = "tan", name = "tan",
}] }]
@ -66,6 +78,10 @@ pub async fn pi(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Return the value of `pi`. Archimedes constant (π). /// Return the value of `pi`. Archimedes constant (π).
///
/// ```no_run
/// const myVar = pi() * 3.0
/// ```
#[stdlib { #[stdlib {
name = "pi", name = "pi",
}] }]
@ -82,6 +98,10 @@ pub async fn sqrt(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the square root of a number. /// Computes the square root of a number.
///
/// ```no_run
/// const myVar = sqrt(4)
/// ```
#[stdlib { #[stdlib {
name = "sqrt", name = "sqrt",
}] }]
@ -98,6 +118,10 @@ pub async fn abs(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the absolute value of a number. /// Computes the absolute value of a number.
///
/// ```no_run
/// const myVar = abs(-4)
/// ```
#[stdlib { #[stdlib {
name = "abs", name = "abs",
}] }]
@ -114,6 +138,10 @@ pub async fn floor(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the largest integer less than or equal to a number. /// Computes the largest integer less than or equal to a number.
///
/// ```no_run
/// const myVar = floor(4.5)
/// ```
#[stdlib { #[stdlib {
name = "floor", name = "floor",
}] }]
@ -130,6 +158,10 @@ pub async fn ceil(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the smallest integer greater than or equal to a number. /// Computes the smallest integer greater than or equal to a number.
///
/// ```no_run
/// const myVar = ceil(4.5)
/// ```
#[stdlib { #[stdlib {
name = "ceil", name = "ceil",
}] }]
@ -146,6 +178,10 @@ pub async fn min(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the minimum of the given arguments. /// Computes the minimum of the given arguments.
///
/// ```no_run
/// const myVar = min(4, 5, 6)
/// ```
#[stdlib { #[stdlib {
name = "min", name = "min",
}] }]
@ -169,6 +205,10 @@ pub async fn max(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the maximum of the given arguments. /// Computes the maximum of the given arguments.
///
/// ```no_run
/// const myVar = max(4, 5, 6)
/// ```
#[stdlib { #[stdlib {
name = "max", name = "max",
}] }]
@ -206,6 +246,10 @@ pub async fn pow(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the number to a power. /// Computes the number to a power.
///
/// ```no_run
/// const myVar = pow(4, 2)
/// ```
#[stdlib { #[stdlib {
name = "pow", name = "pow",
}] }]
@ -222,6 +266,10 @@ pub async fn acos(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the arccosine of a number (in radians). /// Computes the arccosine of a number (in radians).
///
/// ```no_run
/// const myVar = acos(0.5)
/// ```
#[stdlib { #[stdlib {
name = "acos", name = "acos",
}] }]
@ -238,6 +286,10 @@ pub async fn asin(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the arcsine of a number (in radians). /// Computes the arcsine of a number (in radians).
///
/// ```no_run
/// const myVar = asin(0.5)
/// ```
#[stdlib { #[stdlib {
name = "asin", name = "asin",
}] }]
@ -254,6 +306,10 @@ pub async fn atan(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the arctangent of a number (in radians). /// Computes the arctangent of a number (in radians).
///
/// ```no_run
/// const myVar = atan(1.0)
/// ```
#[stdlib { #[stdlib {
name = "atan", name = "atan",
}] }]
@ -291,6 +347,10 @@ pub async fn log(args: Args) -> Result<MemoryItem, KclError> {
/// The result might not be correctly rounded owing to implementation /// The result might not be correctly rounded owing to implementation
/// details; `log2()` can produce more accurate results for base 2, /// details; `log2()` can produce more accurate results for base 2,
/// and `log10()` can produce more accurate results for base 10. /// and `log10()` can produce more accurate results for base 10.
///
/// ```no_run
/// const myVar = log(4, 2)
/// ```
#[stdlib { #[stdlib {
name = "log", name = "log",
}] }]
@ -307,6 +367,10 @@ pub async fn log2(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the base 2 logarithm of the number. /// Computes the base 2 logarithm of the number.
///
/// ```no_run
/// const myVar = log2(4)
/// ```
#[stdlib { #[stdlib {
name = "log2", name = "log2",
}] }]
@ -323,6 +387,10 @@ pub async fn log10(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the base 10 logarithm of the number. /// Computes the base 10 logarithm of the number.
///
/// ```no_run
/// const myVar = log10(4)
/// ```
#[stdlib { #[stdlib {
name = "log10", name = "log10",
}] }]
@ -339,6 +407,10 @@ pub async fn ln(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Computes the natural logarithm of the number. /// Computes the natural logarithm of the number.
///
/// ```no_run
/// const myVar = ln(4)
/// ```
#[stdlib { #[stdlib {
name = "ln", name = "ln",
}] }]
@ -354,6 +426,10 @@ pub async fn e(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Return the value of Eulers number `e`. /// Return the value of Eulers number `e`.
///
/// ```no_run
/// const myVar = e()
/// ```
#[stdlib { #[stdlib {
name = "e", name = "e",
}] }]
@ -369,6 +445,10 @@ pub async fn tau(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Return the value of `tau`. The full circle constant (τ). Equal to 2π. /// Return the value of `tau`. The full circle constant (τ). Equal to 2π.
///
/// ```no_run
/// const myVar = tau()
/// ```
#[stdlib { #[stdlib {
name = "tau", name = "tau",
}] }]
@ -377,33 +457,41 @@ fn inner_tau() -> Result<f64, KclError> {
} }
/// Converts a number from degrees to radians. /// Converts a number from degrees to radians.
pub async fn deg_to_rad(args: Args) -> Result<MemoryItem, KclError> { pub async fn to_radians(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?; let num = args.get_number()?;
let result = inner_deg_to_rad(num)?; let result = inner_to_radians(num)?;
args.make_user_val_from_f64(result) args.make_user_val_from_f64(result)
} }
/// Converts a number from degrees to radians. /// Converts a number from degrees to radians.
///
/// ```no_run
/// const myVar = toRadians(180)
/// ```
#[stdlib { #[stdlib {
name = "to_radians", name = "toRadians",
}] }]
fn inner_deg_to_rad(num: f64) -> Result<f64, KclError> { fn inner_to_radians(num: f64) -> Result<f64, KclError> {
Ok(num.to_radians()) Ok(num.to_radians())
} }
/// Converts a number from radians to degrees. /// Converts a number from radians to degrees.
pub async fn rad_to_deg(args: Args) -> Result<MemoryItem, KclError> { pub async fn to_degrees(args: Args) -> Result<MemoryItem, KclError> {
let num = args.get_number()?; let num = args.get_number()?;
let result = inner_rad_to_deg(num)?; let result = inner_to_degrees(num)?;
args.make_user_val_from_f64(result) args.make_user_val_from_f64(result)
} }
/// Converts a number from radians to degrees. /// Converts a number from radians to degrees.
///
/// ```no_run
/// const myVar = toDegrees(2 * pi())
/// ```
#[stdlib { #[stdlib {
name = "to_degrees", name = "toDegrees",
}] }]
fn inner_rad_to_deg(num: f64) -> Result<f64, KclError> { fn inner_to_degrees(num: f64) -> Result<f64, KclError> {
Ok(num.to_degrees()) Ok(num.to_degrees())
} }

View File

@ -24,7 +24,6 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
ast::types::parse_json_number_as_f64, ast::types::parse_json_number_as_f64,
docs::StdLibFn, docs::StdLibFn,
engine::EngineManager,
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{ executor::{
ExecutorContext, ExtrudeGroup, MemoryItem, Metadata, SketchGroup, SketchGroupSet, SketchSurface, SourceRange, ExecutorContext, ExtrudeGroup, MemoryItem, Metadata, SketchGroup, SketchGroupSet, SketchSurface, SourceRange,
@ -760,6 +759,10 @@ pub async fn leg_length(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the length of the given leg. /// Returns the length of the given leg.
///
/// ```no_run
/// legLen(5, 3)
/// ```
#[stdlib { #[stdlib {
name = "legLen", name = "legLen",
}] }]
@ -775,6 +778,10 @@ pub async fn leg_angle_x(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the angle of the given leg for x. /// Returns the angle of the given leg for x.
///
/// ```no_run
/// legAngX(5, 3)
/// ```
#[stdlib { #[stdlib {
name = "legAngX", name = "legAngX",
}] }]
@ -790,6 +797,10 @@ pub async fn leg_angle_y(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the angle of the given leg for y. /// Returns the angle of the given leg for y.
///
/// ```no_run
/// legAngY(5, 3)
/// ```
#[stdlib { #[stdlib {
name = "legAngY", name = "legAngY",
}] }]
@ -868,6 +879,16 @@ mod tests {
fn_docs.push_str(&signature); fn_docs.push_str(&signature);
fn_docs.push_str("\n```\n\n"); fn_docs.push_str("\n```\n\n");
if !internal_fn.examples().is_empty() {
fn_docs.push_str("#### Examples\n\n");
for example in internal_fn.examples() {
fn_docs.push_str("```kcl\n");
fn_docs.push_str(&example);
fn_docs.push_str("\n```\n\n");
}
}
fn_docs.push_str("#### Arguments\n\n"); fn_docs.push_str("#### Arguments\n\n");
for arg in internal_fn.args() { for arg in internal_fn.args() {
let (format, should_be_indented) = arg.get_type_string().unwrap(); let (format, should_be_indented) = arg.get_type_string().unwrap();

View File

@ -88,6 +88,12 @@ pub async fn pattern_linear_2d(args: Args) -> Result<MemoryItem, KclError> {
} }
/// A linear pattern on a 2D sketch. /// A linear pattern on a 2D sketch.
///
/// ```no_run
/// const part = startSketchOn('XY')
/// |> circle([0,0], 2, %)
/// |> patternLinear2d({axis: [0,1], repetitions: 12, distance: 2}, %)
/// ```
#[stdlib { #[stdlib {
name = "patternLinear2d", name = "patternLinear2d",
}] }]
@ -131,6 +137,17 @@ pub async fn pattern_linear_3d(args: Args) -> Result<MemoryItem, KclError> {
} }
/// A linear pattern on a 3D model. /// A linear pattern on a 3D model.
///
/// ```no_run
/// const part = startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line([0,1], %)
/// |> line([1, 0], %)
/// |> line([0, -1], %)
/// |> close(%)
/// |> extrude(1, %)
/// |> patternLinear3d({axis: [1, 0, 1], repetitions: 3, distance: 6}, %)
/// ```
#[stdlib { #[stdlib {
name = "patternLinear3d", name = "patternLinear3d",
}] }]
@ -296,6 +313,12 @@ pub async fn pattern_circular_2d(args: Args) -> Result<MemoryItem, KclError> {
} }
/// A circular pattern on a 2D sketch. /// A circular pattern on a 2D sketch.
///
/// ```no_run
/// const part = startSketchOn('XY')
/// |> circle([0,0], 2, %)
/// |> patternCircular2d({center: [20, 20], repetitions: 12, arcDegrees: 210, rotateDuplicates: true}, %)
/// ```
#[stdlib { #[stdlib {
name = "patternCircular2d", name = "patternCircular2d",
}] }]
@ -330,6 +353,17 @@ pub async fn pattern_circular_3d(args: Args) -> Result<MemoryItem, KclError> {
} }
/// A circular pattern on a 3D model. /// A circular pattern on a 3D model.
///
/// ```no_run
/// const part = startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line([0,1], %)
/// |> line([1, 0], %)
/// |> line([0, -1], %)
/// |> close(%)
/// |> extrude(1, %)
/// |> patternCircular3d({axis: [1,1,0], center: [10, 0, 10], repetitions: 10, arcDegrees: 360, rotateDuplicates: true}, %)
/// ```
#[stdlib { #[stdlib {
name = "patternCircular3d", name = "patternCircular3d",
}] }]

View File

@ -20,6 +20,16 @@ pub async fn segment_end_x(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the segment end of x. /// Returns the segment end of x.
///
/// ```no_run
/// startSketchOn("YZ")
/// |> startProfileAt([0, 0], %)
/// |> line({ to: [5, 0], tag: "thing" }, %)
/// |> line([5, 5], %)
/// |> line([segEndX("thing", %), 5], %)
/// |> close(%)
/// |> extrude(5, %)
/// ```
#[stdlib { #[stdlib {
name = "segEndX", name = "segEndX",
}] }]
@ -46,6 +56,16 @@ pub async fn segment_end_y(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the segment end of y. /// Returns the segment end of y.
///
/// ```no_run
/// startSketchOn("YZ")
/// |> startProfileAt([0, 0], %)
/// |> line({ to: [5, 0], tag: "thing" }, %)
/// |> line([5, 5], %)
/// |> line([segEndY("thing", %), 5], %)
/// |> close(%)
/// |> extrude(5, %)
/// ```
#[stdlib { #[stdlib {
name = "segEndY", name = "segEndY",
}] }]
@ -72,6 +92,16 @@ pub async fn last_segment_x(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the last segment of x. /// Returns the last segment of x.
///
/// ```no_run
/// startSketchOn("YZ")
/// |> startProfileAt([0, 0], %)
/// |> line({ to: [5, 0], tag: "thing" }, %)
/// |> line([5, 5], %)
/// |> line([0, lastSegX(%)], %)
/// |> close(%)
/// |> extrude(5, %)
/// ```
#[stdlib { #[stdlib {
name = "lastSegX", name = "lastSegX",
}] }]
@ -102,6 +132,16 @@ pub async fn last_segment_y(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the last segment of y. /// Returns the last segment of y.
///
/// ```no_run
/// startSketchOn("YZ")
/// |> startProfileAt([0, 0], %)
/// |> line({ to: [5, 0], tag: "thing" }, %)
/// |> line([5, 5], %)
/// |> line([0, lastSegY(%)], %)
/// |> close(%)
/// |> extrude(5, %)
/// ```
#[stdlib { #[stdlib {
name = "lastSegY", name = "lastSegY",
}] }]
@ -131,6 +171,16 @@ pub async fn segment_length(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the length of the segment. /// Returns the length of the segment.
///
/// ```no_run
/// startSketchOn("YZ")
/// |> startProfileAt([0, 0], %)
/// |> line({ to: [5, 0], tag: "thing" }, %)
/// |> line([5, 5], %)
/// |> line([0, segLen("thing", %)], %)
/// |> close(%)
/// |> extrude(5, %)
/// ```
#[stdlib { #[stdlib {
name = "segLen", name = "segLen",
}] }]
@ -160,6 +210,18 @@ pub async fn segment_angle(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Returns the angle of the segment. /// Returns the angle of the segment.
///
/// ```no_run
/// const part001 = startSketchOn('XY')
/// |> startProfileAt([4.83, 12.56], %)
/// |> line([15.1, 2.48], %)
/// |> line({ to: [3.15, -9.85], tag: 'seg01' }, %)
/// |> line([-15.17, -4.1], %)
/// |> angledLine([segAng('seg01', %), 12.35], %)
/// |> line([-13.02, 10.03], %)
/// |> close(%)
/// |> extrude(4, %)
/// ```
#[stdlib { #[stdlib {
name = "segAng", name = "segAng",
}] }]
@ -188,6 +250,17 @@ pub async fn angle_to_match_length_x(args: Args) -> Result<MemoryItem, KclError>
} }
/// Returns the angle to match the given length for x. /// Returns the angle to match the given length for x.
///
/// ```no_run
/// const part001 = startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line({ to: [1, 3.82], tag: 'seg01' }, %)
/// |> angledLineToX([
/// -angleToMatchLengthX('seg01', 10, %),
/// 5
/// ], %)
/// |> close(%)
/// ```
#[stdlib { #[stdlib {
name = "angleToMatchLengthX", name = "angleToMatchLengthX",
}] }]
@ -243,6 +316,17 @@ pub async fn angle_to_match_length_y(args: Args) -> Result<MemoryItem, KclError>
} }
/// Returns the angle to match the given length for y. /// Returns the angle to match the given length for y.
///
/// ```no_run
/// const part001 = startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line({ to: [1, 3.82], tag: 'seg01' }, %)
/// |> angledLineToX([
/// -angleToMatchLengthY('seg01', 10, %),
/// 5
/// ], %)
/// |> close(%)
/// ```
#[stdlib { #[stdlib {
name = "angleToMatchLengthY", name = "angleToMatchLengthY",
}] }]

View File

@ -128,6 +128,10 @@ impl StdLibFn for Circle {
false false
} }
fn examples(&self) -> Vec<String> {
vec![]
}
fn std_lib_fn(&self) -> crate::std::StdFn { fn std_lib_fn(&self) -> crate::std::StdFn {
todo!() todo!()
} }

View File

@ -48,6 +48,30 @@ pub async fn line_to(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw a line to a point. /// Draw a line to a point.
///
/// ```no_run
/// fn rectShape = (pos, w, l) => {
/// const rr = startSketchOn('YZ')
/// |> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
/// |> lineTo({
/// to: [pos[0] + w / 2, pos[1] - (l / 2)],
/// tag: "edge1"
/// }, %)
/// |> lineTo({
/// to: [pos[0] + w / 2, pos[1] + l / 2],
/// tag: "edge2"
/// }, %)
/// |> lineTo({
/// to: [pos[0] - (w / 2), pos[1] + l / 2],
/// tag: "edge3"
/// }, %)
/// |> close(%, "edge4")
/// return rr
/// }
///
/// // Create the mounting plate extrusion, holes, and fillets
/// const part = rectShape([0, 0], 20, 20)
/// ```
#[stdlib { #[stdlib {
name = "lineTo", name = "lineTo",
}] }]
@ -127,6 +151,18 @@ pub async fn x_line_to(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw a line to a point on the x-axis. /// Draw a line to a point on the x-axis.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> xLineTo({
/// to: 10,
/// tag: "edge1"
/// }, %)
/// |> line([10, 10], %)
/// |> close(%, "edge2")
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "xLineTo", name = "xLineTo",
}] }]
@ -156,6 +192,19 @@ pub async fn y_line_to(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw a line to a point on the y-axis. /// Draw a line to a point on the y-axis.
///
/// ```no_run
/// startSketchOn('XZ')
/// |> startProfileAt([0, 0], %)
/// |> yLineTo({
/// to: 10,
/// tag: "edge1"
/// }, %)
/// |> line([10, 10], %)
/// |> close(%, "edge2")
/// |> extrude(10, %)
/// |> fillet({radius: 2, tags: ["edge2"]}, %)
/// ```
#[stdlib { #[stdlib {
name = "yLineTo", name = "yLineTo",
}] }]
@ -200,6 +249,15 @@ pub async fn line(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw a line. /// Draw a line.
///
/// ```no_run
/// startSketchOn('-XY')
/// |> startProfileAt([0, 0], %)
/// |> line([10, 10], %)
/// |> line({to: [20, 10], tag: "edge1"}, %)
/// |> close(%, "edge2")
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "line", name = "line",
}] }]
@ -278,6 +336,15 @@ pub async fn x_line(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw a line on the x-axis. /// Draw a line on the x-axis.
///
/// ```no_run
/// startSketchOn('YZ')
/// |> startProfileAt([0, 0], %)
/// |> xLine(10, %)
/// |> line([10, 10], %)
/// |> close(%, "edge1")
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "xLine", name = "xLine",
}] }]
@ -304,6 +371,15 @@ pub async fn y_line(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw a line on the y-axis. /// Draw a line on the y-axis.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> yLine(10, %)
/// |> line([10, 10], %)
/// |> close(%, "edge1")
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "yLine", name = "yLine",
}] }]
@ -358,6 +434,20 @@ pub async fn angled_line(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw an angled line. /// Draw an angled line.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> angledLine({
/// angle: 45,
/// length: 10,
/// tag: "edge1"
/// }, %)
/// |> line([10, 10], %)
/// |> line([0, 10], %)
/// |> close(%, "edge2")
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "angledLine", name = "angledLine",
}] }]
@ -429,6 +519,20 @@ pub async fn angled_line_of_x_length(args: Args) -> Result<MemoryItem, KclError>
} }
/// Draw an angled line of a given x length. /// Draw an angled line of a given x length.
///
/// ```no_run
/// startSketchOn('XZ')
/// |> startProfileAt([0, 0], %)
/// |> angledLineOfXLength({
/// angle: 45,
/// length: 10,
/// tag: "edge1"
/// }, %)
/// |> line([10, 10], %)
/// |> line([0, 10], %)
/// |> close(%, "edge2")
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "angledLineOfXLength", name = "angledLineOfXLength",
}] }]
@ -486,6 +590,21 @@ pub async fn angled_line_to_x(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw an angled line to a given x coordinate. /// Draw an angled line to a given x coordinate.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> angledLineToX({
/// angle: 45,
/// to: 10,
/// tag: "edge1"
/// }, %)
/// |> line([10, 10], %)
/// |> line([0, 10], %)
/// |> close(%, "edge2")
/// |> extrude(10, %)
/// |> fillet({radius: 2, tags: ["edge1"]}, %)
/// ```
#[stdlib { #[stdlib {
name = "angledLineToX", name = "angledLineToX",
}] }]
@ -518,6 +637,21 @@ pub async fn angled_line_of_y_length(args: Args) -> Result<MemoryItem, KclError>
} }
/// Draw an angled line of a given y length. /// Draw an angled line of a given y length.
///
/// ```no_run
/// startSketchOn('YZ')
/// |> startProfileAt([0, 0], %)
/// |> angledLineOfYLength({
/// angle: 45,
/// length: 10,
/// tag: "edge1"
/// }, %)
/// |> line([10, 10], %)
/// |> line([0, 10], %)
/// |> close(%, "edge2")
/// |> extrude(10, %)
/// |> fillet({radius: 2, tags: ["edge1"]}, %)
/// ```
#[stdlib { #[stdlib {
name = "angledLineOfYLength", name = "angledLineOfYLength",
}] }]
@ -547,6 +681,20 @@ pub async fn angled_line_to_y(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw an angled line to a given y coordinate. /// Draw an angled line to a given y coordinate.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> angledLineToY({
/// angle: 45,
/// to: 10,
/// tag: "edge1"
/// }, %)
/// |> line([10, 10], %)
/// |> line([0, 10], %)
/// |> close(%, "edge2")
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "angledLineToY", name = "angledLineToY",
}] }]
@ -593,6 +741,22 @@ pub async fn angled_line_that_intersects(args: Args) -> Result<MemoryItem, KclEr
} }
/// Draw an angled line that intersects with a given line. /// Draw an angled line that intersects with a given line.
///
/// ```no_run
/// const part001 = startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> lineTo({to:[2, 2], tag: "yo"}, %)
/// |> lineTo([3, 1], %)
/// |> angledLineThatIntersects({
/// angle: 180,
/// intersectTag: 'yo',
/// offset: 12,
/// tag: "yo2"
/// }, %)
/// |> line([4, 0], %)
/// |> close(%, "yo3")
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "angledLineThatIntersects", name = "angledLineThatIntersects",
}] }]
@ -641,6 +805,11 @@ pub async fn start_sketch_at(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Start a sketch at a given point on the 'XY' plane. /// Start a sketch at a given point on the 'XY' plane.
///
/// ```no_run
/// startSketchAt([0, 0])
/// |> line([10, 10], %)
/// ```
#[stdlib { #[stdlib {
name = "startSketchAt", name = "startSketchAt",
}] }]
@ -785,6 +954,37 @@ pub async fn start_sketch_on(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Start a sketch on a specific plane or face. /// Start a sketch on a specific plane or face.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line([10, 10], %)
/// |> line({to: [20, 10], tag: "edge1"}, %)
/// |> close(%, "edge2")
/// ```
///
/// ```no_run
/// fn cube = (pos, scale) => {
/// const sg = startSketchOn('XY')
/// |> startProfileAt(pos, %)
/// |> line([0, scale], %)
/// |> line([scale, 0], %)
/// |> line([0, -scale], %)
/// |> close(%)
/// |> extrude(scale, %)
///
/// return sg
/// }
///
/// const box = cube([0,0], 20)
///
/// const part001 = startSketchOn(box, "start")
/// |> startProfileAt([0, 0], %)
/// |> line([10, 10], %)
/// |> line({to: [20, 10], tag: "edge1"}, %)
/// |> close(%)
/// |> extrude(20, %)
/// ```
#[stdlib { #[stdlib {
name = "startSketchOn", name = "startSketchOn",
}] }]
@ -1011,6 +1211,12 @@ pub async fn start_profile_at(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Start a profile at a given point. /// Start a profile at a given point.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line([10, 10], %)
/// ```
#[stdlib { #[stdlib {
name = "startProfileAt", name = "startProfileAt",
}] }]
@ -1081,6 +1287,22 @@ pub async fn close(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Close the current sketch. /// Close the current sketch.
///
/// ```no_run
/// startSketchOn('XZ')
/// |> startProfileAt([0, 0], %)
/// |> line([10, 10], %)
/// |> line([10, 0], %)
/// |> close(%)
/// ```
///
/// ```no_run
/// startSketchOn('YZ')
/// |> startProfileAt([0, 0], %)
/// |> line([10, 10], %)
/// |> line([10, 0], %)
/// |> close(%, "edge1")
/// ```
#[stdlib { #[stdlib {
name = "close", name = "close",
}] }]
@ -1165,6 +1387,18 @@ pub async fn arc(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw an arc. /// Draw an arc.
///
/// ```no_run
/// startSketchOn('-YZ')
/// |> startProfileAt([0, 0], %)
/// |> arc({
/// angle_start: 0,
/// angle_end: 360,
/// radius: 10,
/// tag: "edge1"
/// }, %)
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "arc", name = "arc",
}] }]
@ -1259,6 +1493,19 @@ pub async fn tangential_arc(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw an arc. /// Draw an arc.
///
/// ```no_run
/// startSketchOn('-YZ')
/// |> startProfileAt([0, 0], %)
/// |> line({to: [10, 10], tag: "edge0"}, %)
/// |> tangentialArc({
/// radius: 10,
/// offset: 90,
/// tag: "edge1"
/// }, %)
/// |> close(%)
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "tangentialArc", name = "tangentialArc",
}] }]
@ -1373,6 +1620,14 @@ pub async fn tangential_arc_to(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw an arc. /// Draw an arc.
///
/// ```no_run
/// startSketchOn('-YZ')
/// |> startProfileAt([0, 0], %)
/// |> line({to: [10, 10], tag: "edge0"}, %)
/// |> tangentialArcTo([10, 0], %)
/// |> close(%)
/// ```
#[stdlib { #[stdlib {
name = "tangentialArcTo", name = "tangentialArcTo",
}] }]
@ -1445,6 +1700,19 @@ pub async fn bezier_curve(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Draw a bezier curve. /// Draw a bezier curve.
///
/// ```no_run
/// startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> bezierCurve({
/// to: [10, 10],
/// control1: [5, 0],
/// control2: [5, 10],
/// tag: "edge1"
/// }, %)
/// |> close(%)
/// |> extrude(10, %)
/// ```
#[stdlib { #[stdlib {
name = "bezierCurve", name = "bezierCurve",
}] }]
@ -1514,6 +1782,18 @@ pub async fn hole(args: Args) -> Result<MemoryItem, KclError> {
} }
/// Use a sketch to cut a hole in another sketch. /// Use a sketch to cut a hole in another sketch.
///
/// ```no_run
/// const square = startSketchOn('XY')
/// |> startProfileAt([0, 0], %)
/// |> line([0, 10], %)
/// |> line([10, 0], %)
/// |> line([0, -10], %)
/// |> close(%)
/// |> hole(circle([2, 2], .5, startSketchOn('XY')), %)
/// |> hole(circle([2, 8], .5, startSketchOn('XY')), %)
/// |> extrude(2, %)
/// ```
#[stdlib { #[stdlib {
name = "hole", name = "hole",
}] }]

View File

@ -7,6 +7,7 @@ use std::{
use futures::stream::TryStreamExt; use futures::stream::TryStreamExt;
use gloo_utils::format::JsValueSerdeExt; use gloo_utils::format::JsValueSerdeExt;
use kcl_lib::engine::EngineManager;
use tower_lsp::{LspService, Server}; use tower_lsp::{LspService, Server};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
@ -27,12 +28,12 @@ pub async fn execute_wasm(
let mut mem: kcl_lib::executor::ProgramMemory = serde_json::from_str(memory_str).map_err(|e| e.to_string())?; let mut mem: kcl_lib::executor::ProgramMemory = serde_json::from_str(memory_str).map_err(|e| e.to_string())?;
let units = kittycad::types::UnitLength::from_str(units).map_err(|e| e.to_string())?; let units = kittycad::types::UnitLength::from_str(units).map_err(|e| e.to_string())?;
let engine = kcl_lib::engine::EngineConnection::new(engine_manager) let engine = kcl_lib::engine::conn_wasm::EngineConnection::new(engine_manager)
.await .await
.map_err(|e| format!("{:?}", e))?; .map_err(|e| format!("{:?}", e))?;
let fs = kcl_lib::fs::FileManager::new(fs_manager); let fs = kcl_lib::fs::FileManager::new(fs_manager);
let ctx = ExecutorContext { let ctx = ExecutorContext {
engine, engine: Arc::new(Box::new(engine)),
fs, fs,
stdlib: std::sync::Arc::new(kcl_lib::std::StdLib::new()), stdlib: std::sync::Arc::new(kcl_lib::std::StdLib::new()),
units, units,
@ -62,12 +63,14 @@ pub async fn modify_ast_for_sketch_wasm(
let plane: kcl_lib::executor::PlaneType = serde_json::from_str(plane_type).map_err(|e| e.to_string())?; let plane: kcl_lib::executor::PlaneType = serde_json::from_str(plane_type).map_err(|e| e.to_string())?;
let mut engine = kcl_lib::engine::EngineConnection::new(manager) let engine: Arc<Box<dyn EngineManager>> = Arc::new(Box::new(
.await kcl_lib::engine::conn_wasm::EngineConnection::new(manager)
.map_err(|e| format!("{:?}", e))?; .await
.map_err(|e| format!("{:?}", e))?,
));
let _ = kcl_lib::ast::modify::modify_ast_for_sketch( let _ = kcl_lib::ast::modify::modify_ast_for_sketch(
&mut engine, &engine,
&mut program, &mut program,
sketch_name, sketch_name,
plane, plane,

View File

@ -1,5 +1,4 @@
use anyhow::Result; use anyhow::Result;
use kcl_lib::engine::EngineManager;
/// Executes a kcl program and takes a snapshot of the result. /// Executes a kcl program and takes a snapshot of the result.
/// This returns the bytes of the snapshot. /// This returns the bytes of the snapshot.

View File

@ -1,7 +1,6 @@
use anyhow::Result; use anyhow::Result;
use kcl_lib::{ use kcl_lib::{
ast::{modify::modify_ast_for_sketch, types::Program}, ast::{modify::modify_ast_for_sketch, types::Program},
engine::EngineManager,
executor::{ExecutorContext, MemoryItem, PlaneType, SourceRange}, executor::{ExecutorContext, MemoryItem, PlaneType, SourceRange},
}; };
use kittycad::types::{ModelingCmd, Point3D}; use kittycad::types::{ModelingCmd, Point3D};
@ -105,9 +104,9 @@ async fn serial_test_modify_sketch_part001() {
name name
); );
let (mut ctx, program, sketch_id) = setup(&code, name).await.unwrap(); let (ctx, program, sketch_id) = setup(&code, name).await.unwrap();
let mut new_program = program.clone(); let mut new_program = program.clone();
let new_code = modify_ast_for_sketch(&mut ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id) let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id)
.await .await
.unwrap(); .unwrap();
@ -130,9 +129,9 @@ async fn serial_test_modify_sketch_part002() {
name name
); );
let (mut ctx, program, sketch_id) = setup(&code, name).await.unwrap(); let (ctx, program, sketch_id) = setup(&code, name).await.unwrap();
let mut new_program = program.clone(); let mut new_program = program.clone();
let new_code = modify_ast_for_sketch(&mut ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id) let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id)
.await .await
.unwrap(); .unwrap();
@ -157,9 +156,9 @@ async fn serial_test_modify_close_sketch() {
name name
); );
let (mut ctx, program, sketch_id) = setup(&code, name).await.unwrap(); let (ctx, program, sketch_id) = setup(&code, name).await.unwrap();
let mut new_program = program.clone(); let mut new_program = program.clone();
let new_code = modify_ast_for_sketch(&mut ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id) let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id)
.await .await
.unwrap(); .unwrap();
@ -183,9 +182,9 @@ async fn serial_test_modify_line_to_close_sketch() {
name name
); );
let (mut ctx, program, sketch_id) = setup(&code, name).await.unwrap(); let (ctx, program, sketch_id) = setup(&code, name).await.unwrap();
let mut new_program = program.clone(); let mut new_program = program.clone();
let new_code = modify_ast_for_sketch(&mut ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id) let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id)
.await .await
.unwrap(); .unwrap();
@ -220,9 +219,9 @@ const {} = startSketchOn("XY")
name name
); );
let (mut ctx, program, sketch_id) = setup(&code, name).await.unwrap(); let (ctx, program, sketch_id) = setup(&code, name).await.unwrap();
let mut new_program = program.clone(); let mut new_program = program.clone();
let result = modify_ast_for_sketch(&mut ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id).await; let result = modify_ast_for_sketch(&ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id).await;
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
@ -245,9 +244,9 @@ async fn serial_test_modify_line_should_close_sketch() {
name name
); );
let (mut ctx, program, sketch_id) = setup(&code, name).await.unwrap(); let (ctx, program, sketch_id) = setup(&code, name).await.unwrap();
let mut new_program = program.clone(); let mut new_program = program.clone();
let new_code = modify_ast_for_sketch(&mut ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id) let new_code = modify_ast_for_sketch(&ctx.engine, &mut new_program, name, PlaneType::XY, sketch_id)
.await .await
.unwrap(); .unwrap();