throw error on both ranges (#2428)
* highlight both ranges Signed-off-by: Jess Frazelle <github@jessfraz.com> * add playwright test Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -424,6 +424,80 @@ test('if you write invalid kcl you get inlined errors', async ({ page }) => {
|
|||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('error with 2 source ranges gets 2 diagnostics', async ({ page }) => {
|
||||||
|
const u = getUtils(page)
|
||||||
|
await page.addInitScript(async () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'persistCode',
|
||||||
|
`const length = .750
|
||||||
|
const width = 0.500
|
||||||
|
const height = 0.500
|
||||||
|
const dia = 4
|
||||||
|
|
||||||
|
fn squareHole = (l, w) => {
|
||||||
|
const squareHoleSketch = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-width / 2, -length / 2], %)
|
||||||
|
|> lineTo([width / 2, -length / 2], %)
|
||||||
|
|> lineTo([width / 2, length / 2], %)
|
||||||
|
|> lineTo([-width / 2, length / 2], %)
|
||||||
|
|> close(%)
|
||||||
|
return squareHoleSketch
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
await page.setViewportSize({ width: 1000, height: 500 })
|
||||||
|
await page.goto('/')
|
||||||
|
const lspStartPromise = page.waitForEvent('console', async (message) => {
|
||||||
|
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
|
||||||
|
// but that doesn't seem to make it to the console for macos/safari :(
|
||||||
|
if (message.text().includes('start kcl lsp')) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
await page.goto('/')
|
||||||
|
await u.waitForAuthSkipAppStart()
|
||||||
|
await lspStartPromise
|
||||||
|
|
||||||
|
await u.openDebugPanel()
|
||||||
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||||
|
await u.closeDebugPanel()
|
||||||
|
|
||||||
|
// check no error to begin with
|
||||||
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||||
|
|
||||||
|
// Click on the bottom of the code editor to add a new line
|
||||||
|
await page.click('.cm-content')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('ArrowDown')
|
||||||
|
await page.keyboard.press('Enter')
|
||||||
|
await page.keyboard.type(`const extrusion = startSketchOn('XY')
|
||||||
|
|> circle([0, 0], dia/2, %)
|
||||||
|
|> hole(squareHole(length, width, height), %)
|
||||||
|
|> extrude(height, %)`)
|
||||||
|
|
||||||
|
// error in gutter
|
||||||
|
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
|
||||||
|
await page.hover('.cm-lint-marker-error:first-child')
|
||||||
|
await expect(page.getByText('Expected 2 arguments, got 3')).toBeVisible()
|
||||||
|
|
||||||
|
// Make sure there are two diagnostics
|
||||||
|
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(2)
|
||||||
|
})
|
||||||
|
|
||||||
test('if your kcl gets an error from the engine it is inlined', async ({
|
test('if your kcl gets an error from the engine it is inlined', async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -1214,7 +1214,11 @@ impl CallExpression {
|
|||||||
let func = memory.get(&fn_name, self.into())?;
|
let func = memory.get(&fn_name, self.into())?;
|
||||||
let result = func
|
let result = func
|
||||||
.call_fn(fn_args, memory.clone(), ctx.clone())
|
.call_fn(fn_args, memory.clone(), ctx.clone())
|
||||||
.await?
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
// Add the call expression to the source ranges.
|
||||||
|
e.add_source_ranges(vec![self.into()])
|
||||||
|
})?
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
KclError::UndefinedValue(KclErrorDetails {
|
KclError::UndefinedValue(KclErrorDetails {
|
||||||
message: format!("Result of user-defined function {} is undefined", fn_name),
|
message: format!("Result of user-defined function {} is undefined", fn_name),
|
||||||
|
@ -142,6 +142,25 @@ impl KclError {
|
|||||||
|
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_source_ranges(&self, source_ranges: Vec<SourceRange>) -> Self {
|
||||||
|
let mut new = self.clone();
|
||||||
|
match &mut new {
|
||||||
|
KclError::Lexical(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::Syntax(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::Semantic(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::Type(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::Unimplemented(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::Unexpected(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::ValueAlreadyDefined(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::UndefinedValue(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::InvalidExpression(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::Engine(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
KclError::Internal(e) => e.source_ranges.extend(source_ranges),
|
||||||
|
}
|
||||||
|
|
||||||
|
new
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is different than to_string() in that it will serialize the Error
|
/// This is different than to_string() in that it will serialize the Error
|
||||||
|
@ -2081,3 +2081,34 @@ const secondSketch = startSketchOn(part001, '')
|
|||||||
r#"type: KclErrorDetails { source_ranges: [SourceRange([272, 298])], message: "Expected a non-empty tag for the face to sketch on" }"#
|
r#"type: KclErrorDetails { source_ranges: [SourceRange([272, 298])], message: "Expected a non-empty tag for the face to sketch on" }"#
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn serial_test_error_user_function_wrong_args() {
|
||||||
|
let code = r#"const length = .750
|
||||||
|
const width = 0.500
|
||||||
|
const height = 0.500
|
||||||
|
const dia = 4
|
||||||
|
|
||||||
|
fn squareHole = (l, w) => {
|
||||||
|
const squareHoleSketch = startSketchOn('XY')
|
||||||
|
|> startProfileAt([-width / 2, -length / 2], %)
|
||||||
|
|> lineTo([width / 2, -length / 2], %)
|
||||||
|
|> lineTo([width / 2, length / 2], %)
|
||||||
|
|> lineTo([-width / 2, length / 2], %)
|
||||||
|
|> close(%)
|
||||||
|
return squareHoleSketch
|
||||||
|
}
|
||||||
|
|
||||||
|
const extrusion = startSketchOn('XY')
|
||||||
|
|> circle([0, 0], dia/2, %)
|
||||||
|
|> hole(squareHole(length, width, height), %)
|
||||||
|
|> extrude(height, %)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = execute_and_snapshot(code, kcl_lib::settings::types::UnitLength::Mm).await;
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result.err().unwrap().to_string(),
|
||||||
|
r#"semantic: KclErrorDetails { source_ranges: [SourceRange([92, 364]), SourceRange([444, 477])], message: "Expected 2 arguments, got 3" }"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user