Merge branch 'main' into pierremtb/issue5301-Expose-the-sectional-argument-in-the-Sweep-command-flow
This commit is contained in:
@ -3,6 +3,7 @@ import { HomePageFixture } from './fixtures/homePageFixture'
|
||||
import { getUtils } from './test-utils'
|
||||
import { EngineCommand } from 'lang/std/artifactGraph'
|
||||
import { uuidv4 } from 'lib/utils'
|
||||
import { SceneFixture } from './fixtures/sceneFixture'
|
||||
|
||||
test.describe(
|
||||
'Can create sketches on all planes and their back sides',
|
||||
@ -11,16 +12,17 @@ test.describe(
|
||||
const sketchOnPlaneAndBackSideTest = async (
|
||||
page: Page,
|
||||
homePage: HomePageFixture,
|
||||
scene: SceneFixture,
|
||||
plane: string,
|
||||
clickCoords: { x: number; y: number }
|
||||
) => {
|
||||
const u = await getUtils(page)
|
||||
const PUR = 400 / 37.5 //pixeltoUnitRatio
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
// FIXME: Cannot use scene.waitForExecutionDone() since there is no KCL code
|
||||
await page.waitForTimeout(10000)
|
||||
const XYPlanRed: [number, number, number] = [98, 50, 51]
|
||||
await scene.expectPixelColor(XYPlanRed, { x: 700, y: 300 }, 15)
|
||||
|
||||
await u.openDebugPanel()
|
||||
|
||||
const coord =
|
||||
@ -43,7 +45,7 @@ test.describe(
|
||||
},
|
||||
}
|
||||
|
||||
const code = `sketch001 = startSketchOn('${plane}')profile001 = startProfileAt([0.9, -1.22], sketch001)`
|
||||
const code = `sketch001 = startSketchOn('${plane}')profile001 = startProfileAt([0.91, -1.22], sketch001)`
|
||||
|
||||
await u.openDebugPanel()
|
||||
|
||||
@ -56,17 +58,14 @@ test.describe(
|
||||
|
||||
await u.closeDebugPanel()
|
||||
await page.mouse.click(clickCoords.x, clickCoords.y)
|
||||
await page.waitForTimeout(300) // wait for animation
|
||||
await page.waitForTimeout(600) // wait for animation
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'line Line', exact: true })
|
||||
).toBeVisible()
|
||||
|
||||
// draw a line
|
||||
const startXPx = 600
|
||||
|
||||
await u.closeDebugPanel()
|
||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||
await page.mouse.click(707, 393)
|
||||
|
||||
await expect(page.locator('.cm-content')).toHaveText(code)
|
||||
|
||||
@ -81,49 +80,50 @@ test.describe(
|
||||
await u.clearCommandLogs()
|
||||
await u.removeCurrentCode()
|
||||
}
|
||||
test('XY', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(
|
||||
page,
|
||||
homePage,
|
||||
'XY',
|
||||
{ x: 600, y: 388 } // red plane
|
||||
// { x: 600, y: 400 }, // red plane // clicks grid helper and that causes problems, should fix so that these coords work too.
|
||||
)
|
||||
})
|
||||
|
||||
test('YZ', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, 'YZ', {
|
||||
x: 700,
|
||||
y: 250,
|
||||
}) // green plane
|
||||
})
|
||||
const planeConfigs = [
|
||||
{
|
||||
plane: 'XY',
|
||||
coords: { x: 600, y: 388 },
|
||||
description: 'red plane',
|
||||
},
|
||||
{
|
||||
plane: 'YZ',
|
||||
coords: { x: 700, y: 250 },
|
||||
description: 'green plane',
|
||||
},
|
||||
{
|
||||
plane: 'XZ',
|
||||
coords: { x: 684, y: 427 },
|
||||
description: 'blue plane',
|
||||
},
|
||||
{
|
||||
plane: '-XY',
|
||||
coords: { x: 600, y: 118 },
|
||||
description: 'back of red plane',
|
||||
},
|
||||
{
|
||||
plane: '-YZ',
|
||||
coords: { x: 700, y: 219 },
|
||||
description: 'back of green plane',
|
||||
},
|
||||
{
|
||||
plane: '-XZ',
|
||||
coords: { x: 700, y: 80 },
|
||||
description: 'back of blue plane',
|
||||
},
|
||||
]
|
||||
|
||||
test('XZ', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, '-XZ', {
|
||||
x: 700,
|
||||
y: 80,
|
||||
}) // blue plane
|
||||
})
|
||||
|
||||
test('-XY', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, '-XY', {
|
||||
x: 600,
|
||||
y: 118,
|
||||
}) // back of red plane
|
||||
})
|
||||
|
||||
test('-YZ', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, '-YZ', {
|
||||
x: 700,
|
||||
y: 219,
|
||||
}) // back of green plan
|
||||
})
|
||||
|
||||
test('-XZ', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, 'XZ', {
|
||||
x: 700,
|
||||
y: 427,
|
||||
}) // back of blue plane
|
||||
})
|
||||
for (const config of planeConfigs) {
|
||||
test(config.plane, async ({ page, homePage, scene }) => {
|
||||
await sketchOnPlaneAndBackSideTest(
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
config.plane,
|
||||
config.coords
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@ -629,6 +629,39 @@ extrude001 = extrude(sketch001, length = 50)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test(`Toolbar doesn't show modeling tools during sketch plane selection animation`, async ({
|
||||
page,
|
||||
homePage,
|
||||
toolbar,
|
||||
}) => {
|
||||
await test.step('Load an empty file', async () => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem('persistCode', '')
|
||||
})
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
})
|
||||
|
||||
const toolBarMode = () =>
|
||||
page.locator('[data-currentMode]').getAttribute('data-currentMode')
|
||||
|
||||
await test.step('Start sketch and select a plane', async () => {
|
||||
await expect.poll(toolBarMode).toEqual('modeling')
|
||||
// Click the start sketch button
|
||||
await toolbar.startSketchPlaneSelection()
|
||||
|
||||
// Click on a default plane at position [700, 200]
|
||||
await page.mouse.click(700, 200)
|
||||
|
||||
// Check that the modeling toolbar doesn't appear during the animation
|
||||
// The animation typically takes around 500ms, so we'll check for a second
|
||||
await expect.poll(toolBarMode, { timeout: 1000 }).not.toEqual('modeling')
|
||||
|
||||
// After animation completes, we should see the sketching toolbar
|
||||
await expect.poll(toolBarMode).toEqual('sketching')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
async function clickExportButton(page: Page) {
|
||||
|
||||
@ -167,7 +167,10 @@ export function Toolbar({
|
||||
}, [currentMode, disableAllButtons, configCallbackProps])
|
||||
|
||||
return (
|
||||
<menu className="max-w-full whitespace-nowrap rounded-b px-2 py-1 bg-chalkboard-10 dark:bg-chalkboard-90 relative border border-chalkboard-30 dark:border-chalkboard-80 border-t-0 shadow-sm">
|
||||
<menu
|
||||
data-currentMode={currentMode}
|
||||
className="max-w-full whitespace-nowrap rounded-b px-2 py-1 bg-chalkboard-10 dark:bg-chalkboard-90 relative border border-chalkboard-30 dark:border-chalkboard-80 border-t-0 shadow-sm"
|
||||
>
|
||||
<ul
|
||||
{...props}
|
||||
ref={toolbarButtonsRef}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
.editor {
|
||||
@apply text-base flex-1;
|
||||
@apply text-base flex-1 overflow-auto;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.editor :global(.cm-editor) {
|
||||
|
||||
@ -12,7 +12,6 @@ import {
|
||||
get_kcl_version,
|
||||
make_default_planes,
|
||||
coredump,
|
||||
toml_stringify,
|
||||
default_app_settings,
|
||||
parse_app_settings,
|
||||
parse_project_settings,
|
||||
@ -21,6 +20,8 @@ import {
|
||||
clear_scene_and_bust_cache,
|
||||
kcl_settings,
|
||||
change_kcl_settings,
|
||||
serialize_project_configuration,
|
||||
serialize_configuration,
|
||||
reloadModule,
|
||||
} from 'lib/wasm_lib_wrapper'
|
||||
|
||||
@ -636,10 +637,6 @@ export async function coreDump(
|
||||
}
|
||||
}
|
||||
|
||||
export function tomlStringify(toml: any): string | Error {
|
||||
return toml_stringify(JSON.stringify(toml))
|
||||
}
|
||||
|
||||
export function defaultAppSettings(): DeepPartial<Configuration> | Error {
|
||||
return default_app_settings()
|
||||
}
|
||||
@ -786,3 +783,27 @@ export function unitAngToUnitAngle(input: UnitAng): UnitAngle {
|
||||
export function getKclVersion(): string {
|
||||
return get_kcl_version()
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a project configuration to a TOML string.
|
||||
*/
|
||||
export function serializeConfiguration(configuration: any): string | Error {
|
||||
try {
|
||||
return serialize_configuration(configuration)
|
||||
} catch (e: any) {
|
||||
return new Error(`Error serializing configuration: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a project configuration to a TOML string.
|
||||
*/
|
||||
export function serializeProjectConfiguration(
|
||||
configuration: any
|
||||
): string | Error {
|
||||
try {
|
||||
return serialize_project_configuration(configuration)
|
||||
} catch (e: any) {
|
||||
return new Error(`Error serializing project configuration: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,8 @@ import {
|
||||
initPromise,
|
||||
parseAppSettings,
|
||||
parseProjectSettings,
|
||||
tomlStringify,
|
||||
serializeConfiguration,
|
||||
serializeProjectConfiguration,
|
||||
} from 'lang/wasm'
|
||||
import { mouseControlsToCameraSystem } from 'lib/cameraControls'
|
||||
import { BROWSER_PROJECT_NAME } from 'lib/constants'
|
||||
@ -131,7 +132,7 @@ export function readLocalStorageAppSettingsFile():
|
||||
} catch (e) {
|
||||
const settings = defaultAppSettings()
|
||||
if (err(settings)) return settings
|
||||
const tomlStr = tomlStringify(settings)
|
||||
const tomlStr = serializeConfiguration(settings)
|
||||
if (err(tomlStr)) return tomlStr
|
||||
|
||||
localStorage.setItem(localStorageAppSettingsPath(), tomlStr)
|
||||
@ -152,7 +153,7 @@ function readLocalStorageProjectSettingsFile():
|
||||
const projectSettings = parseProjectSettings(stored)
|
||||
if (err(projectSettings)) {
|
||||
const settings = defaultProjectSettings()
|
||||
const tomlStr = tomlStringify(settings)
|
||||
const tomlStr = serializeProjectConfiguration(settings)
|
||||
if (err(tomlStr)) return tomlStr
|
||||
|
||||
localStorage.setItem(localStorageProjectSettingsPath(), tomlStr)
|
||||
@ -229,7 +230,7 @@ export async function saveSettings(
|
||||
|
||||
// Get the user settings.
|
||||
const jsAppSettings = getChangedSettingsAtLevel(allSettings, 'user')
|
||||
const appTomlString = tomlStringify({ settings: jsAppSettings })
|
||||
const appTomlString = serializeConfiguration({ settings: jsAppSettings })
|
||||
if (err(appTomlString)) return
|
||||
|
||||
// Write the app settings.
|
||||
@ -246,7 +247,9 @@ export async function saveSettings(
|
||||
|
||||
// Get the project settings.
|
||||
const jsProjectSettings = getChangedSettingsAtLevel(allSettings, 'project')
|
||||
const projectTomlString = tomlStringify({ settings: jsProjectSettings })
|
||||
const projectTomlString = serializeProjectConfiguration({
|
||||
settings: jsProjectSettings,
|
||||
})
|
||||
if (err(projectTomlString)) return
|
||||
|
||||
// Write the project settings.
|
||||
|
||||
@ -56,7 +56,12 @@ export type ToolbarItemResolved = Omit<
|
||||
export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
||||
modeling: {
|
||||
check: (state) =>
|
||||
!(state.matches('Sketch') || state.matches('Sketch no face')),
|
||||
!(
|
||||
state.matches('Sketch') ||
|
||||
state.matches('Sketch no face') ||
|
||||
state.matches('animating to existing sketch') ||
|
||||
state.matches('animating to plane')
|
||||
),
|
||||
items: [
|
||||
{
|
||||
id: 'sketch',
|
||||
@ -330,7 +335,10 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
||||
},
|
||||
sketching: {
|
||||
check: (state) =>
|
||||
state.matches('Sketch') || state.matches('Sketch no face'),
|
||||
state.matches('Sketch') ||
|
||||
state.matches('Sketch no face') ||
|
||||
state.matches('animating to existing sketch') ||
|
||||
state.matches('animating to plane'),
|
||||
items: [
|
||||
{
|
||||
id: 'sketch-exit',
|
||||
|
||||
@ -19,7 +19,6 @@ import {
|
||||
get_tangential_arc_to_info as GetTangentialArcToInfo,
|
||||
make_default_planes as MakeDefaultPlanes,
|
||||
coredump as CoreDump,
|
||||
toml_stringify as TomlStringify,
|
||||
default_app_settings as DefaultAppSettings,
|
||||
parse_app_settings as ParseAppSettings,
|
||||
parse_project_settings as ParseProjectSettings,
|
||||
@ -29,6 +28,8 @@ import {
|
||||
kcl_settings as KclSettings,
|
||||
change_kcl_settings as ChangeKclSettings,
|
||||
get_kcl_version as GetKclVersion,
|
||||
serialize_configuration as SerializeConfiguration,
|
||||
serialize_project_configuration as SerializeProjectConfiguration,
|
||||
} from '../wasm-lib/pkg/wasm_lib'
|
||||
|
||||
type ModuleType = typeof import('../wasm-lib/pkg/wasm_lib')
|
||||
@ -86,9 +87,6 @@ export const make_default_planes: typeof MakeDefaultPlanes = (...args) => {
|
||||
export const coredump: typeof CoreDump = (...args) => {
|
||||
return getModule().coredump(...args)
|
||||
}
|
||||
export const toml_stringify: typeof TomlStringify = (...args) => {
|
||||
return getModule().toml_stringify(...args)
|
||||
}
|
||||
export const default_app_settings: typeof DefaultAppSettings = (...args) => {
|
||||
return getModule().default_app_settings(...args)
|
||||
}
|
||||
@ -122,3 +120,12 @@ export const change_kcl_settings: typeof ChangeKclSettings = (...args) => {
|
||||
export const get_kcl_version: typeof GetKclVersion = () => {
|
||||
return getModule().get_kcl_version()
|
||||
}
|
||||
export const serialize_configuration: typeof SerializeConfiguration = (
|
||||
...args
|
||||
) => {
|
||||
return getModule().serialize_configuration(...args)
|
||||
}
|
||||
export const serialize_project_configuration: typeof SerializeProjectConfiguration =
|
||||
(...args) => {
|
||||
return getModule().serialize_project_configuration(...args)
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ impl KclErrorWithOutputs {
|
||||
source_files: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn into_miette_report_with_outputs(self, code: &str) -> anyhow::Result<ReportWithOutputs> {
|
||||
pub fn into_miette_report_with_outputs(self) -> anyhow::Result<ReportWithOutputs> {
|
||||
let mut source_ranges = self.error.source_ranges();
|
||||
|
||||
// Pop off the first source range to get the filename.
|
||||
@ -162,33 +162,23 @@ impl KclErrorWithOutputs {
|
||||
.source_files
|
||||
.get(&first_source_range.module_id())
|
||||
.cloned()
|
||||
.unwrap_or(ModuleSource {
|
||||
source: code.to_string(),
|
||||
path: self
|
||||
.filenames
|
||||
.get(&first_source_range.module_id())
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"Could not find filename for module id: {:?}",
|
||||
first_source_range.module_id()
|
||||
)
|
||||
})?
|
||||
.clone(),
|
||||
});
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"Could not find source file for module id: {:?}",
|
||||
first_source_range.module_id()
|
||||
)
|
||||
})?;
|
||||
let filename = source.path.to_string();
|
||||
let kcl_source = source.source.to_string();
|
||||
|
||||
let mut related = Vec::new();
|
||||
for source_range in source_ranges {
|
||||
let module_id = source_range.module_id();
|
||||
let source = self.source_files.get(&module_id).cloned().unwrap_or(ModuleSource {
|
||||
source: code.to_string(),
|
||||
path: self
|
||||
.filenames
|
||||
.get(&module_id)
|
||||
.ok_or_else(|| anyhow::anyhow!("Could not find filename for module id: {:?}", module_id))?
|
||||
.clone(),
|
||||
});
|
||||
let source = self
|
||||
.source_files
|
||||
.get(&module_id)
|
||||
.cloned()
|
||||
.ok_or_else(|| anyhow::anyhow!("Could not find source file for module id: {:?}", module_id))?;
|
||||
let error = self.error.override_source_ranges(vec![source_range]);
|
||||
let report = Report {
|
||||
error,
|
||||
|
||||
@ -34,7 +34,7 @@ use crate::{
|
||||
},
|
||||
fs::FileManager,
|
||||
modules::{ModuleId, ModulePath},
|
||||
parsing::ast::types::{Expr, ImportPath, Node, NodeRef, Program},
|
||||
parsing::ast::types::{Expr, ImportPath, NodeRef},
|
||||
settings::types::UnitLength,
|
||||
source_range::SourceRange,
|
||||
std::StdLib,
|
||||
@ -532,7 +532,7 @@ impl ExecutorContext {
|
||||
}
|
||||
}
|
||||
|
||||
let result = self.inner_run(&program.ast, &mut exec_state, true).await?;
|
||||
let result = self.inner_run(&program, &mut exec_state, true).await?;
|
||||
|
||||
// Restore any temporary variables, then save any newly created variables back to
|
||||
// memory in case another run wants to use them. Note this is just saved to the preserved
|
||||
@ -585,9 +585,15 @@ impl ExecutorContext {
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
(true, program.ast)
|
||||
(true, program)
|
||||
} else {
|
||||
(clear_scene, changed_program)
|
||||
(
|
||||
clear_scene,
|
||||
crate::Program {
|
||||
ast: changed_program,
|
||||
original_file_contents: program.original_file_contents,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
CacheResult::NoAction(true) => {
|
||||
@ -608,7 +614,7 @@ impl ExecutorContext {
|
||||
|
||||
return Ok(old_state.to_wasm_outcome(result_env));
|
||||
}
|
||||
(true, program.ast)
|
||||
(true, program)
|
||||
}
|
||||
CacheResult::NoAction(false) => return Ok(old_state.to_wasm_outcome(result_env)),
|
||||
};
|
||||
@ -636,7 +642,7 @@ impl ExecutorContext {
|
||||
self.send_clear_scene(&mut exec_state, Default::default())
|
||||
.await
|
||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||
(program.ast, exec_state, false)
|
||||
(program, exec_state, false)
|
||||
};
|
||||
|
||||
let result = self.inner_run(&program, &mut exec_state, preserve_mem).await;
|
||||
@ -650,7 +656,7 @@ impl ExecutorContext {
|
||||
|
||||
// Save this as the last successful execution to the cache.
|
||||
cache::write_old_ast(OldAstState {
|
||||
ast: program,
|
||||
ast: program.ast,
|
||||
exec_state: exec_state.clone(),
|
||||
settings: self.settings.clone(),
|
||||
result_env: result.0,
|
||||
@ -691,18 +697,19 @@ impl ExecutorContext {
|
||||
self.send_clear_scene(exec_state, Default::default())
|
||||
.await
|
||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||
self.inner_run(&program.ast, exec_state, false).await
|
||||
self.inner_run(program, exec_state, false).await
|
||||
}
|
||||
|
||||
/// Perform the execution of a program. Accept all possible parameters and
|
||||
/// output everything.
|
||||
async fn inner_run(
|
||||
&self,
|
||||
program: &Node<Program>,
|
||||
program: &crate::Program,
|
||||
exec_state: &mut ExecState,
|
||||
preserve_mem: bool,
|
||||
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
||||
let _stats = crate::log::LogPerfStats::new("Interpretation");
|
||||
exec_state.add_root_module_contents(program);
|
||||
|
||||
// Re-apply the settings, in case the cache was busted.
|
||||
self.engine
|
||||
@ -711,7 +718,7 @@ impl ExecutorContext {
|
||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||
|
||||
let env_ref = self
|
||||
.execute_and_build_graph(program, exec_state, preserve_mem)
|
||||
.execute_and_build_graph(&program.ast, exec_state, preserve_mem)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
|
||||
|
||||
@ -182,8 +182,27 @@ impl ExecState {
|
||||
self.global.path_to_source_id.insert(path.clone(), id);
|
||||
}
|
||||
|
||||
pub(crate) fn add_root_module_contents(&mut self, program: &crate::Program) {
|
||||
let root_id = ModuleId::default();
|
||||
// Get the path for the root module.
|
||||
let path = self
|
||||
.global
|
||||
.path_to_source_id
|
||||
.iter()
|
||||
.find(|(_, v)| **v == root_id)
|
||||
.unwrap()
|
||||
.0
|
||||
.clone();
|
||||
self.add_id_to_source(
|
||||
root_id,
|
||||
ModuleSource {
|
||||
path,
|
||||
source: program.original_file_contents.to_string(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn add_id_to_source(&mut self, id: ModuleId, source: ModuleSource) {
|
||||
debug_assert!(!self.global.id_to_source.contains_key(&id));
|
||||
self.global.id_to_source.insert(id, source.clone());
|
||||
}
|
||||
|
||||
@ -251,8 +270,6 @@ impl GlobalState {
|
||||
global
|
||||
.path_to_source_id
|
||||
.insert(ModulePath::Local { value: root_path }, root_id);
|
||||
// Ideally we'd have a way to set the root module's source here, but
|
||||
// we don't have a way to get the source from the executor settings.
|
||||
global
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +134,11 @@ use crate::log::{log, logln};
|
||||
pub struct Program {
|
||||
#[serde(flatten)]
|
||||
pub ast: parsing::ast::types::Node<parsing::ast::types::Program>,
|
||||
// The ui doesn't need to know about this.
|
||||
// It's purely used for saving the contents of the original file, so we can use it for errors.
|
||||
// Because in the case of the root file, we don't want to read the file from disk again.
|
||||
#[serde(skip)]
|
||||
pub original_file_contents: String,
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "lsp-test-util"))]
|
||||
@ -147,7 +152,13 @@ impl Program {
|
||||
let tokens = parsing::token::lex(input, module_id)?;
|
||||
let (ast, errs) = parsing::parse_tokens(tokens).0?;
|
||||
|
||||
Ok((ast.map(|ast| Program { ast }), errs))
|
||||
Ok((
|
||||
ast.map(|ast| Program {
|
||||
ast,
|
||||
original_file_contents: input.to_string(),
|
||||
}),
|
||||
errs,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn parse_no_errs(input: &str) -> Result<Program, KclError> {
|
||||
@ -155,7 +166,10 @@ impl Program {
|
||||
let tokens = parsing::token::lex(input, module_id)?;
|
||||
let ast = parsing::parse_tokens(tokens).parse_errs_as_err()?;
|
||||
|
||||
Ok(Program { ast })
|
||||
Ok(Program {
|
||||
ast,
|
||||
original_file_contents: input.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compute_digest(&mut self) -> parsing::ast::digest::Digest {
|
||||
@ -168,9 +182,10 @@ impl Program {
|
||||
}
|
||||
|
||||
/// Change the meta settings for the kcl file.
|
||||
pub fn change_meta_settings(&mut self, settings: crate::MetaSettings) -> Result<Self, KclError> {
|
||||
pub fn change_meta_settings(&self, settings: crate::MetaSettings) -> Result<Self, KclError> {
|
||||
Ok(Self {
|
||||
ast: self.ast.change_meta_settings(settings)?,
|
||||
original_file_contents: self.original_file_contents.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -192,12 +207,6 @@ impl Program {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<parsing::ast::types::Node<parsing::ast::types::Program>> for Program {
|
||||
fn from(ast: parsing::ast::types::Node<parsing::ast::types::Program>) -> Program {
|
||||
Self { ast }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_f64_to_usize(f: f64) -> Option<usize> {
|
||||
let i = f as usize;
|
||||
|
||||
@ -46,7 +46,7 @@ use crate::{
|
||||
errors::Suggestion,
|
||||
lsp::{backend::Backend as _, util::IntoDiagnostic},
|
||||
parsing::{
|
||||
ast::types::{Expr, Node, VariableKind},
|
||||
ast::types::{Expr, VariableKind},
|
||||
token::TokenStream,
|
||||
PIPE_OPERATOR,
|
||||
},
|
||||
@ -102,7 +102,7 @@ pub struct Backend {
|
||||
/// Token maps.
|
||||
pub(super) token_map: DashMap<String, TokenStream>,
|
||||
/// AST maps.
|
||||
pub ast_map: DashMap<String, Node<crate::parsing::ast::types::Program>>,
|
||||
pub ast_map: DashMap<String, crate::Program>,
|
||||
/// Current code.
|
||||
pub code_map: DashMap<String, Vec<u8>>,
|
||||
/// Diagnostics.
|
||||
@ -327,11 +327,17 @@ impl crate::lsp::backend::Backend for Backend {
|
||||
// this if it backfires and only hork the LSP.
|
||||
ast.compute_digest();
|
||||
|
||||
// Save it as a program.
|
||||
let ast = crate::Program {
|
||||
ast,
|
||||
original_file_contents: params.text.clone(),
|
||||
};
|
||||
|
||||
// Check if the ast changed.
|
||||
let ast_changed = match self.ast_map.get(&filename) {
|
||||
Some(old_ast) => {
|
||||
// Check if the ast changed.
|
||||
*old_ast != ast
|
||||
*old_ast.ast != *ast.ast
|
||||
}
|
||||
None => true,
|
||||
};
|
||||
@ -346,7 +352,7 @@ impl crate::lsp::backend::Backend for Backend {
|
||||
// Update the symbols map.
|
||||
self.symbols_map.insert(
|
||||
params.uri.to_string(),
|
||||
ast.get_lsp_symbols(¶ms.text).unwrap_or_default(),
|
||||
ast.ast.get_lsp_symbols(¶ms.text).unwrap_or_default(),
|
||||
);
|
||||
|
||||
// Update our semantic tokens.
|
||||
@ -361,14 +367,14 @@ impl crate::lsp::backend::Backend for Backend {
|
||||
// Only send the notification if we can execute.
|
||||
// Otherwise it confuses the client.
|
||||
self.client
|
||||
.send_notification::<custom_notifications::AstUpdated>(ast.clone())
|
||||
.send_notification::<custom_notifications::AstUpdated>(ast.ast.clone())
|
||||
.await;
|
||||
}
|
||||
|
||||
// Execute the code if we have an executor context.
|
||||
// This function automatically executes if we should & updates the diagnostics if we got
|
||||
// errors.
|
||||
if self.execute(¶ms, &ast.into()).await.is_err() {
|
||||
if self.execute(¶ms, &ast).await.is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -421,7 +427,7 @@ impl Backend {
|
||||
let token_modifiers_bitset = if let Some(ast) = self.ast_map.get(params.uri.as_str()) {
|
||||
let token_index = Arc::new(Mutex::new(token_type_index));
|
||||
let modifier_index: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
|
||||
crate::walk::walk(&ast, |node: crate::walk::Node| {
|
||||
crate::walk::walk(&ast.ast, |node: crate::walk::Node| {
|
||||
let Ok(node_range): Result<SourceRange, _> = (&node).try_into() else {
|
||||
return Ok(true);
|
||||
};
|
||||
@ -1021,7 +1027,7 @@ impl LanguageServer for Backend {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let Some(hover) = ast.get_hover_value_for_position(pos, current_code) else {
|
||||
let Some(hover) = ast.ast.get_hover_value_for_position(pos, current_code) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
@ -1150,13 +1156,13 @@ impl LanguageServer for Backend {
|
||||
};
|
||||
|
||||
let position = position_to_char_index(params.text_document_position.position, current_code);
|
||||
if ast.get_non_code_meta_for_position(position).is_some() {
|
||||
if ast.ast.get_non_code_meta_for_position(position).is_some() {
|
||||
// If we are in a code comment we don't want to show completions.
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Get the completion items for the ast.
|
||||
let Ok(variables) = ast.completion_items() else {
|
||||
let Ok(variables) = ast.ast.completion_items() else {
|
||||
return Ok(Some(CompletionResponse::Array(completions)));
|
||||
};
|
||||
|
||||
@ -1211,7 +1217,7 @@ impl LanguageServer for Backend {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let Some(value) = ast.get_expr_for_position(pos) else {
|
||||
let Some(value) = ast.ast.get_expr_for_position(pos) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
@ -1360,7 +1366,7 @@ impl LanguageServer for Backend {
|
||||
};
|
||||
|
||||
// Get the folding ranges.
|
||||
let folding_ranges = ast.get_lsp_folding_ranges();
|
||||
let folding_ranges = ast.ast.get_lsp_folding_ranges();
|
||||
|
||||
if folding_ranges.is_empty() {
|
||||
return Ok(None);
|
||||
|
||||
@ -1138,7 +1138,7 @@ fn myFn = (param1) => {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Send semantic tokens request.
|
||||
let semantic_tokens = server
|
||||
@ -2251,7 +2251,7 @@ part001 = cube([0,0], 20)
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert_eq!(ast.body.len(), 2);
|
||||
assert_eq!(ast.ast.body.len(), 2);
|
||||
|
||||
// Send change file.
|
||||
server
|
||||
@ -2428,7 +2428,7 @@ async fn kcl_test_kcl_lsp_full_to_empty_file_updates_ast_and_memory() {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Send change file.
|
||||
server
|
||||
@ -2450,7 +2450,7 @@ async fn kcl_test_kcl_lsp_full_to_empty_file_updates_ast_and_memory() {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert_eq!(ast, default_hashed);
|
||||
assert_eq!(ast.ast, default_hashed);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
@ -2479,7 +2479,7 @@ async fn kcl_test_kcl_lsp_code_unchanged_but_has_diagnostics_reexecute() {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2506,11 +2506,15 @@ async fn kcl_test_kcl_lsp_code_unchanged_but_has_diagnostics_reexecute() {
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
|
||||
|
||||
// Clear the ast and memory.
|
||||
server
|
||||
.ast_map
|
||||
.insert("file:///test.kcl".to_string(), Node::<Program>::default());
|
||||
server.ast_map.insert(
|
||||
"file:///test.kcl".to_string(),
|
||||
crate::Program {
|
||||
ast: Default::default(),
|
||||
original_file_contents: Default::default(),
|
||||
},
|
||||
);
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert_eq!(ast, Node::<Program>::default());
|
||||
assert_eq!(ast.ast, Node::<Program>::default());
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
@ -2529,7 +2533,7 @@ async fn kcl_test_kcl_lsp_code_unchanged_but_has_diagnostics_reexecute() {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2561,7 +2565,7 @@ async fn kcl_test_kcl_lsp_code_and_ast_unchanged_but_has_diagnostics_reexecute()
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2604,7 +2608,7 @@ async fn kcl_test_kcl_lsp_code_and_ast_unchanged_but_has_diagnostics_reexecute()
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2636,7 +2640,7 @@ async fn kcl_test_kcl_lsp_code_and_ast_units_unchanged_but_has_diagnostics_reexe
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2682,7 +2686,7 @@ async fn kcl_test_kcl_lsp_code_and_ast_units_unchanged_but_has_diagnostics_reexe
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2714,7 +2718,7 @@ async fn kcl_test_kcl_lsp_code_and_ast_units_unchanged_but_has_memory_reexecute_
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2739,7 +2743,7 @@ async fn kcl_test_kcl_lsp_code_and_ast_units_unchanged_but_has_memory_reexecute_
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2771,7 +2775,7 @@ async fn kcl_test_kcl_lsp_cant_execute_set() {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2795,7 +2799,7 @@ async fn kcl_test_kcl_lsp_cant_execute_set() {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2831,7 +2835,7 @@ async fn kcl_test_kcl_lsp_cant_execute_set() {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != default_hashed);
|
||||
assert!(ast.ast != default_hashed);
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2862,7 +2866,7 @@ async fn kcl_test_kcl_lsp_cant_execute_set() {
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have no diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||
@ -2995,7 +2999,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have one diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
|
||||
@ -3016,7 +3020,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have one diagnostics.
|
||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
|
||||
@ -3109,7 +3113,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
@ -3128,7 +3132,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have diagnostics.
|
||||
|
||||
@ -3168,7 +3172,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Send change file, but the code is the same.
|
||||
server
|
||||
@ -3195,7 +3199,7 @@ NEW_LINT = 1"#
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Assure we have diagnostics.
|
||||
|
||||
@ -3302,7 +3306,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
||||
@ -3389,7 +3393,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
||||
@ -3428,7 +3432,7 @@ part001 = startSketchOn('XY')
|
||||
|
||||
// Get the ast.
|
||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
||||
assert!(ast != Node::<Program>::default());
|
||||
assert!(ast.ast != Node::<Program>::default());
|
||||
|
||||
// Get the symbols map.
|
||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
||||
|
||||
@ -182,9 +182,7 @@ pub async fn modify_ast_for_sketch(
|
||||
let recasted = program.ast.recast(&FormatOptions::default(), 0);
|
||||
|
||||
// Re-parse the ast so we get the correct source ranges.
|
||||
*program = crate::parsing::parse_str(&recasted, module_id)
|
||||
.parse_errs_as_err()?
|
||||
.into();
|
||||
program.ast = crate::parsing::parse_str(&recasted, module_id).parse_errs_as_err()?;
|
||||
|
||||
Ok(recasted)
|
||||
}
|
||||
|
||||
@ -275,7 +275,7 @@ impl Node<Program> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn change_meta_settings(&mut self, settings: crate::execution::MetaSettings) -> Result<Self, KclError> {
|
||||
pub fn change_meta_settings(&self, settings: crate::execution::MetaSettings) -> Result<Self, KclError> {
|
||||
let mut new_program = self.clone();
|
||||
let mut found = false;
|
||||
for node in &mut new_program.inner_attrs {
|
||||
@ -4035,7 +4035,7 @@ startSketchOn('XY')"#;
|
||||
let some_program_string = r#"@settings(defaultLengthUnit = inch)
|
||||
|
||||
startSketchOn('XY')"#;
|
||||
let mut program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
||||
let program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
||||
let result = program.meta_settings().unwrap();
|
||||
assert!(result.is_some());
|
||||
let meta_settings = result.unwrap();
|
||||
@ -4077,7 +4077,7 @@ startSketchOn('XY')
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_parse_get_meta_settings_nothing_to_mm() {
|
||||
let some_program_string = r#"startSketchOn('XY')"#;
|
||||
let mut program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
||||
let program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
||||
let result = program.meta_settings().unwrap();
|
||||
assert!(result.is_none());
|
||||
|
||||
|
||||
@ -84,10 +84,14 @@ async fn execute(test_name: &str, render_to_png: bool) {
|
||||
let Ok(ast) = ast_res else {
|
||||
return;
|
||||
};
|
||||
let ast = crate::Program {
|
||||
ast,
|
||||
original_file_contents: read("input.kcl", test_name),
|
||||
};
|
||||
|
||||
// Run the program.
|
||||
let exec_res = crate::test_server::execute_and_snapshot_ast(
|
||||
ast.into(),
|
||||
ast,
|
||||
crate::settings::types::UnitLength::Mm,
|
||||
Some(Path::new("tests").join(test_name).join("input.kcl").to_owned()),
|
||||
)
|
||||
@ -132,10 +136,7 @@ async fn execute(test_name: &str, render_to_png: bool) {
|
||||
Box::new(miette::MietteHandlerOpts::new().show_related_errors_as_nested().build())
|
||||
}))
|
||||
.unwrap();
|
||||
let report = error
|
||||
.clone()
|
||||
.into_miette_report_with_outputs(&read("input.kcl", test_name))
|
||||
.unwrap();
|
||||
let report = error.clone().into_miette_report_with_outputs().unwrap();
|
||||
let report = miette::Report::new(report);
|
||||
if previously_passed {
|
||||
eprintln!("This test case failed, but it previously passed. If this is intended, and the test should actually be failing now, please delete kcl/{ok_path_str} and other associated passing artifacts");
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
//! Wasm bindings for `kcl`.
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod toml;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod wasm;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub use toml::*;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub use wasm::*;
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
//! Functions for interacting with TOML files.
|
||||
//! We do this in rust because the Javascript TOML libraries are actual trash.
|
||||
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn toml_stringify(json: &str) -> Result<String, String> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let value: serde_json::Value = serde_json::from_str(json).map_err(|e| e.to_string())?;
|
||||
|
||||
toml::to_string_pretty(&value).map_err(|e| e.to_string())
|
||||
}
|
||||
@ -483,9 +483,9 @@ pub fn parse_project_settings(toml_str: &str) -> Result<JsValue, String> {
|
||||
JsValue::from_serde(&settings).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Serialize the project settings.
|
||||
/// Serialize the configuration settings.
|
||||
#[wasm_bindgen]
|
||||
pub fn serialize_project_settings(val: JsValue) -> Result<JsValue, String> {
|
||||
pub fn serialize_configuration(val: JsValue) -> Result<JsValue, String> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let config: kcl_lib::Configuration = val.into_serde().map_err(|e| e.to_string())?;
|
||||
@ -497,6 +497,20 @@ pub fn serialize_project_settings(val: JsValue) -> Result<JsValue, String> {
|
||||
Ok(JsValue::from_str(&toml_str))
|
||||
}
|
||||
|
||||
/// Serialize the project configuration settings.
|
||||
#[wasm_bindgen]
|
||||
pub fn serialize_project_configuration(val: JsValue) -> Result<JsValue, String> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let config: kcl_lib::ProjectConfiguration = val.into_serde().map_err(|e| e.to_string())?;
|
||||
|
||||
let toml_str = toml::to_string_pretty(&config).map_err(|e| e.to_string())?;
|
||||
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
|
||||
// gloo-serialize crate instead.
|
||||
Ok(JsValue::from_str(&toml_str))
|
||||
}
|
||||
|
||||
static ALLOWED_DECODING_FORMATS: &[data_encoding::Encoding] = &[
|
||||
data_encoding::BASE64,
|
||||
data_encoding::BASE64URL,
|
||||
@ -561,7 +575,7 @@ pub fn change_kcl_settings(code: &str, settings_str: &str) -> Result<String, Str
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let settings: kcl_lib::MetaSettings = serde_json::from_str(settings_str).map_err(|e| e.to_string())?;
|
||||
let mut program = Program::parse_no_errs(code).map_err(|e| e.to_string())?;
|
||||
let program = Program::parse_no_errs(code).map_err(|e| e.to_string())?;
|
||||
|
||||
let new_program = program.change_meta_settings(settings).map_err(|e| e.to_string())?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user