Compare commits
1 Commits
v0.13.0
...
achalmers/
Author | SHA1 | Date | |
---|---|---|---|
c9e27ffb95 |
@ -4,6 +4,8 @@ import { EngineCommand } from '../../src/lang/std/engineConnection'
|
|||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { getUtils } from './test-utils'
|
import { getUtils } from './test-utils'
|
||||||
import waitOn from 'wait-on'
|
import waitOn from 'wait-on'
|
||||||
|
import { Models } from '@kittycad/lib'
|
||||||
|
import fsp from 'fs/promises'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
|
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
|
||||||
@ -84,26 +86,26 @@ test('Basic sketch', async ({ page }) => {
|
|||||||
|
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
||||||
|
|
||||||
const startAt = '[18.26, -24.63]'
|
const startAt = '[10.97, -14.79]'
|
||||||
const num = '18.43'
|
const tenish = '11.07'
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('-XZ')
|
.toHaveText(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt(${startAt}, %)
|
|> startProfileAt(${startAt}, %)
|
||||||
|> line([${num}, 0], %)`)
|
|> line([${tenish}, 0], %)`)
|
||||||
|
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('-XZ')
|
.toHaveText(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt(${startAt}, %)
|
|> startProfileAt(${startAt}, %)
|
||||||
|> line([${num}, 0], %)
|
|> line([${tenish}, 0], %)
|
||||||
|> line([0, ${num}], %)`)
|
|> line([0, ${tenish}], %)`)
|
||||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('-XZ')
|
.toHaveText(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt(${startAt}, %)
|
|> startProfileAt(${startAt}, %)
|
||||||
|> line([${num}, 0], %)
|
|> line([${tenish}, 0], %)
|
||||||
|> line([0, ${num}], %)
|
|> line([0, ${tenish}], %)
|
||||||
|> line([-36.69, 0], %)`)
|
|> line([-22.04, 0], %)`)
|
||||||
|
|
||||||
// deselect line tool
|
// deselect line tool
|
||||||
await u.doAndWaitForCmd(
|
await u.doAndWaitForCmd(
|
||||||
@ -131,8 +133,8 @@ test('Basic sketch', async ({ page }) => {
|
|||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('-XZ')
|
.toHaveText(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt(${startAt}, %)
|
|> startProfileAt(${startAt}, %)
|
||||||
|> line({ to: [${num}, 0], tag: 'seg01' }, %)
|
|> line({ to: [${tenish}, 0], tag: 'seg01' }, %)
|
||||||
|> line([0, ${num}], %)
|
|> line([0, ${tenish}], %)
|
||||||
|> angledLine([180, segLen('seg01', %)], %)`)
|
|> angledLine([180, segLen('seg01', %)], %)`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -181,26 +183,6 @@ test('if you write invalid kcl you get inlined errors', async ({ page }) => {
|
|||||||
|
|
||||||
// wait for .cm-lint-marker-error not to be visible
|
// wait for .cm-lint-marker-error not to be visible
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||||
|
|
||||||
// let's check we get an error when defining the same variable twice
|
|
||||||
await page.getByText('const bottomAng = 25').click()
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type("// Let's define the same thing twice")
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type('const topAng = 42')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-lintRange.cm-lintRange-error')).toBeVisible()
|
|
||||||
|
|
||||||
await page.locator('.cm-lintRange.cm-lintRange-error').hover()
|
|
||||||
await expect(page.locator('.cm-diagnosticText')).toBeVisible()
|
|
||||||
await expect(page.getByText('Cannot redefine topAng')).toBeVisible()
|
|
||||||
|
|
||||||
const secondTopAng = await page.getByText('topAng').first()
|
|
||||||
await secondTopAng?.dblclick()
|
|
||||||
await page.keyboard.type('otherAng')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('executes on load', async ({ page, context }) => {
|
test('executes on load', async ({ page, context }) => {
|
||||||
@ -506,27 +488,27 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|
|||||||
|
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
||||||
|
|
||||||
const startAt = '[18.26, -24.63]'
|
const startAt = '[10.97, -14.79]'
|
||||||
const num = '18.43'
|
const tenish = '11.07'
|
||||||
const num2 = '36.69'
|
const twentyish = '22.04'
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('-XZ')
|
.toHaveText(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt(${startAt}, %)
|
|> startProfileAt(${startAt}, %)
|
||||||
|> line([${num}, 0], %)`)
|
|> line([${tenish}, 0], %)`)
|
||||||
|
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('-XZ')
|
.toHaveText(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt(${startAt}, %)
|
|> startProfileAt(${startAt}, %)
|
||||||
|> line([${num}, 0], %)
|
|> line([${tenish}, 0], %)
|
||||||
|> line([0, ${num}], %)`)
|
|> line([0, ${tenish}], %)`)
|
||||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||||
await expect(page.locator('.cm-content'))
|
await expect(page.locator('.cm-content'))
|
||||||
.toHaveText(`const part001 = startSketchOn('-XZ')
|
.toHaveText(`const part001 = startSketchOn('-XZ')
|
||||||
|> startProfileAt(${startAt}, %)
|
|> startProfileAt(${startAt}, %)
|
||||||
|> line([${num}, 0], %)
|
|> line([${tenish}, 0], %)
|
||||||
|> line([0, ${num}], %)
|
|> line([0, ${tenish}], %)
|
||||||
|> line([-${num2}, 0], %)`)
|
|> line([-${twentyish}, 0], %)`)
|
||||||
|
|
||||||
// deselect line tool
|
// deselect line tool
|
||||||
await u.doAndWaitForCmd(
|
await u.doAndWaitForCmd(
|
||||||
@ -579,7 +561,7 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|
|||||||
|
|
||||||
// check the same selection again by putting cursor in code first then selecting axis
|
// check the same selection again by putting cursor in code first then selecting axis
|
||||||
await u.doAndWaitForCmd(
|
await u.doAndWaitForCmd(
|
||||||
() => page.getByText(` |> line([-${num2}, 0], %)`).click(),
|
() => page.getByText(` |> line([-${twentyish}, 0], %)`).click(),
|
||||||
'select_clear',
|
'select_clear',
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
@ -594,7 +576,7 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
|
|||||||
|
|
||||||
// select segment in editor than another segment in scene and check there are two cursors
|
// select segment in editor than another segment in scene and check there are two cursors
|
||||||
await u.doAndWaitForCmd(
|
await u.doAndWaitForCmd(
|
||||||
() => page.getByText(` |> line([-${num2}, 0], %)`).click(),
|
() => page.getByText(` |> line([-${twentyish}, 0], %)`).click(),
|
||||||
'select_clear',
|
'select_clear',
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
@ -45,7 +45,7 @@ test('change camera, show planes', async ({ page, context }) => {
|
|||||||
type: 'default_camera_look_at',
|
type: 'default_camera_look_at',
|
||||||
center: { x: 0, y: 0, z: 0 },
|
center: { x: 0, y: 0, z: 0 },
|
||||||
up: { x: 0, y: 0, z: 1 },
|
up: { x: 0, y: 0, z: 1 },
|
||||||
vantage: { x: 0, y: 85, z: 85 },
|
vantage: { x: 0, y: 50, z: 50 },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Binary file not shown.
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
Binary file not shown.
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 53 KiB |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "untitled-app",
|
"name": "untitled-app",
|
||||||
"version": "0.13.0",
|
"version": "0.12.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.10.2",
|
"@codemirror/autocomplete": "^6.10.2",
|
||||||
@ -134,7 +134,7 @@
|
|||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
"prettier": "^2.8.0",
|
"prettier": "^2.8.0",
|
||||||
"setimmediate": "^1.0.5",
|
"setimmediate": "^1.0.5",
|
||||||
"tailwindcss": "^3.3.6",
|
"tailwindcss": "^3.3.5",
|
||||||
"vite": "^4.5.0",
|
"vite": "^4.5.0",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-tsconfig-paths": "^4.2.1",
|
"vite-tsconfig-paths": "^4.2.1",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "kittycad-modeling",
|
"productName": "kittycad-modeling",
|
||||||
"version": "0.13.0"
|
"version": "0.12.0"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
@ -1216,7 +1216,7 @@ export class EngineCommandManager {
|
|||||||
type: 'modeling_cmd_req',
|
type: 'modeling_cmd_req',
|
||||||
cmd: {
|
cmd: {
|
||||||
type: 'make_plane',
|
type: 'make_plane',
|
||||||
size: 100,
|
size: 60,
|
||||||
origin: { x: 0, y: 0, z: 0 },
|
origin: { x: 0, y: 0, z: 0 },
|
||||||
x_axis,
|
x_axis,
|
||||||
y_axis,
|
y_axis,
|
||||||
|
@ -1,36 +1,23 @@
|
|||||||
use crate::{ExecutionError, Value};
|
use crate::{ExecutionError, NumericValue, Value};
|
||||||
|
|
||||||
/// Types that can be written to or read from KCEP program memory,
|
/// Types that can be written to or read from KCEP program memory,
|
||||||
/// but require multiple values to store.
|
/// but require multiple values to store.
|
||||||
/// They get laid out into multiple consecutive memory addresses.
|
/// They get laid out into multiple consecutive memory addresses.
|
||||||
pub trait Composite: Sized {
|
pub trait Composite<const SIZE: usize>: Sized {
|
||||||
/// How many memory addresses are required to store this value?
|
|
||||||
const SIZE: usize;
|
|
||||||
/// Store the value in memory.
|
/// Store the value in memory.
|
||||||
fn into_parts(self) -> Vec<Value>;
|
fn into_parts(self) -> [Value; SIZE];
|
||||||
/// Read the value from memory.
|
/// Read the value from memory.
|
||||||
fn from_parts(values: Vec<Value>) -> Result<Self, ExecutionError>;
|
fn from_parts(values: [Value; SIZE]) -> Result<Self, ExecutionError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Composite for kittycad::types::Point3D {
|
impl Composite<3> for kittycad::types::Point3D {
|
||||||
fn into_parts(self) -> Vec<Value> {
|
fn into_parts(self) -> [Value; 3] {
|
||||||
let points = [self.x, self.y, self.z];
|
let points = [self.x, self.y, self.z];
|
||||||
points
|
points.map(NumericValue::Float).map(Value::NumericValue)
|
||||||
.into_iter()
|
|
||||||
.map(|x| Value::NumericValue(crate::NumericValue::Float(x)))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SIZE: usize = 3;
|
fn from_parts(values: [Value; 3]) -> Result<Self, ExecutionError> {
|
||||||
|
let [x, y, z] = values;
|
||||||
fn from_parts(values: Vec<Value>) -> Result<Self, ExecutionError> {
|
|
||||||
let n = values.len();
|
|
||||||
let Ok([x, y, z]): Result<[Value; 3], _> = values.try_into() else {
|
|
||||||
return Err(ExecutionError::MemoryWrongSize {
|
|
||||||
actual: n,
|
|
||||||
expected: Self::SIZE,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let x = x.try_into()?;
|
let x = x.try_into()?;
|
||||||
let y = y.try_into()?;
|
let y = y.try_into()?;
|
||||||
let z = z.try_into()?;
|
let z = z.try_into()?;
|
||||||
|
@ -48,7 +48,7 @@ impl Memory {
|
|||||||
|
|
||||||
/// Store a composite value (i.e. a value which takes up multiple addresses in memory).
|
/// Store a composite value (i.e. a value which takes up multiple addresses in memory).
|
||||||
/// Store its parts in consecutive memory addresses starting at `start`.
|
/// Store its parts in consecutive memory addresses starting at `start`.
|
||||||
pub fn set_composite<T: Composite>(&mut self, composite_value: T, start: Address) {
|
pub fn set_composite<T: Composite<{ N }>, const N: usize>(&mut self, composite_value: T, start: Address) {
|
||||||
let parts = composite_value.into_parts().into_iter();
|
let parts = composite_value.into_parts().into_iter();
|
||||||
for (value, addr) in parts.zip(start.0..) {
|
for (value, addr) in parts.zip(start.0..) {
|
||||||
self.0.insert(addr, value);
|
self.0.insert(addr, value);
|
||||||
@ -57,17 +57,14 @@ impl Memory {
|
|||||||
|
|
||||||
/// Get a composite value (i.e. a value which takes up multiple addresses in memory).
|
/// Get a composite value (i.e. a value which takes up multiple addresses in memory).
|
||||||
/// Its parts are stored in consecutive memory addresses starting at `start`.
|
/// Its parts are stored in consecutive memory addresses starting at `start`.
|
||||||
pub fn get_composite<T: Composite>(&self, start: Address) -> Result<T, ExecutionError> {
|
pub fn get_composite<T: Composite<{ N }>, const N: usize>(&self, start: Address) -> Result<T, ExecutionError> {
|
||||||
let addrs = start.0..start.0 + T::SIZE;
|
let addrs: [Address; N] = core::array::from_fn(|i| Address(i + start.0));
|
||||||
let values: Vec<Value> = addrs
|
let values: [Value; N] = arr_res_to_res_array(addrs.map(|addr| {
|
||||||
.into_iter()
|
self.get(&addr)
|
||||||
.map(|a| {
|
.map(|x| x.to_owned())
|
||||||
let addr = Address(a);
|
.ok_or(ExecutionError::MemoryEmpty { addr })
|
||||||
self.get(&addr)
|
}))?;
|
||||||
.map(|x| x.to_owned())
|
|
||||||
.ok_or(ExecutionError::MemoryEmpty { addr })
|
|
||||||
})
|
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
T::from_parts(values)
|
T::from_parts(values)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,3 +273,17 @@ pub enum ExecutionError {
|
|||||||
#[error("Wrong size of memory trying to read value from KCEP program memory: got {actual} but wanted {expected}")]
|
#[error("Wrong size of memory trying to read value from KCEP program memory: got {actual} but wanted {expected}")]
|
||||||
MemoryWrongSize { expected: usize, actual: usize },
|
MemoryWrongSize { expected: usize, actual: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Take an array of result and return a result of array.
|
||||||
|
/// If all members of the array are Ok(T), returns Ok with an array of the T values.
|
||||||
|
/// If any member of the array was Err(E), return Err with the first E value.
|
||||||
|
fn arr_res_to_res_array<T, E, const N: usize>(arr: [Result<T, E>; N]) -> Result<[T; N], E> {
|
||||||
|
let mut out = core::array::from_fn(|_| None);
|
||||||
|
for (i, res) in arr.enumerate() {
|
||||||
|
out[i] = match res {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(out.map(|opt| opt.unwrap()))
|
||||||
|
}
|
||||||
|
@ -7698,10 +7698,10 @@ swr@^2.2.2:
|
|||||||
client-only "^0.0.1"
|
client-only "^0.0.1"
|
||||||
use-sync-external-store "^1.2.0"
|
use-sync-external-store "^1.2.0"
|
||||||
|
|
||||||
tailwindcss@^3.3.6:
|
tailwindcss@^3.3.5:
|
||||||
version "3.3.6"
|
version "3.3.5"
|
||||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.6.tgz#4dd7986bf4902ad385d90d45fd4b2fa5fab26d5f"
|
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.5.tgz#22a59e2fbe0ecb6660809d9cc5f3976b077be3b8"
|
||||||
integrity sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw==
|
integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@alloc/quick-lru" "^5.2.0"
|
"@alloc/quick-lru" "^5.2.0"
|
||||||
arg "^5.0.2"
|
arg "^5.0.2"
|
||||||
|
Reference in New Issue
Block a user