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 { getUtils } from './test-utils'
|
||||||
import { EngineCommand } from 'lang/std/artifactGraph'
|
import { EngineCommand } from 'lang/std/artifactGraph'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
|
import { SceneFixture } from './fixtures/sceneFixture'
|
||||||
|
|
||||||
test.describe(
|
test.describe(
|
||||||
'Can create sketches on all planes and their back sides',
|
'Can create sketches on all planes and their back sides',
|
||||||
@ -11,16 +12,17 @@ test.describe(
|
|||||||
const sketchOnPlaneAndBackSideTest = async (
|
const sketchOnPlaneAndBackSideTest = async (
|
||||||
page: Page,
|
page: Page,
|
||||||
homePage: HomePageFixture,
|
homePage: HomePageFixture,
|
||||||
|
scene: SceneFixture,
|
||||||
plane: string,
|
plane: string,
|
||||||
clickCoords: { x: number; y: number }
|
clickCoords: { x: number; y: number }
|
||||||
) => {
|
) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||||
|
|
||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
// FIXME: Cannot use scene.waitForExecutionDone() since there is no KCL code
|
const XYPlanRed: [number, number, number] = [98, 50, 51]
|
||||||
await page.waitForTimeout(10000)
|
await scene.expectPixelColor(XYPlanRed, { x: 700, y: 300 }, 15)
|
||||||
|
|
||||||
await u.openDebugPanel()
|
await u.openDebugPanel()
|
||||||
|
|
||||||
const coord =
|
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()
|
await u.openDebugPanel()
|
||||||
|
|
||||||
@ -56,17 +58,14 @@ test.describe(
|
|||||||
|
|
||||||
await u.closeDebugPanel()
|
await u.closeDebugPanel()
|
||||||
await page.mouse.click(clickCoords.x, clickCoords.y)
|
await page.mouse.click(clickCoords.x, clickCoords.y)
|
||||||
await page.waitForTimeout(300) // wait for animation
|
await page.waitForTimeout(600) // wait for animation
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('button', { name: 'line Line', exact: true })
|
page.getByRole('button', { name: 'line Line', exact: true })
|
||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
|
|
||||||
// draw a line
|
|
||||||
const startXPx = 600
|
|
||||||
|
|
||||||
await u.closeDebugPanel()
|
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)
|
await expect(page.locator('.cm-content')).toHaveText(code)
|
||||||
|
|
||||||
@ -81,49 +80,50 @@ test.describe(
|
|||||||
await u.clearCommandLogs()
|
await u.clearCommandLogs()
|
||||||
await u.removeCurrentCode()
|
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 }) => {
|
const planeConfigs = [
|
||||||
await sketchOnPlaneAndBackSideTest(page, homePage, 'YZ', {
|
{
|
||||||
x: 700,
|
plane: 'XY',
|
||||||
y: 250,
|
coords: { x: 600, y: 388 },
|
||||||
}) // green plane
|
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 }) => {
|
for (const config of planeConfigs) {
|
||||||
await sketchOnPlaneAndBackSideTest(page, homePage, '-XZ', {
|
test(config.plane, async ({ page, homePage, scene }) => {
|
||||||
x: 700,
|
await sketchOnPlaneAndBackSideTest(
|
||||||
y: 80,
|
page,
|
||||||
}) // blue plane
|
homePage,
|
||||||
})
|
scene,
|
||||||
|
config.plane,
|
||||||
test('-XY', async ({ page, homePage }) => {
|
config.coords
|
||||||
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
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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) {
|
async function clickExportButton(page: Page) {
|
||||||
|
|||||||
@ -167,7 +167,10 @@ export function Toolbar({
|
|||||||
}, [currentMode, disableAllButtons, configCallbackProps])
|
}, [currentMode, disableAllButtons, configCallbackProps])
|
||||||
|
|
||||||
return (
|
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
|
<ul
|
||||||
{...props}
|
{...props}
|
||||||
ref={toolbarButtonsRef}
|
ref={toolbarButtonsRef}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
.editor {
|
.editor {
|
||||||
@apply text-base flex-1;
|
@apply text-base flex-1 overflow-auto;
|
||||||
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor :global(.cm-editor) {
|
.editor :global(.cm-editor) {
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import {
|
|||||||
get_kcl_version,
|
get_kcl_version,
|
||||||
make_default_planes,
|
make_default_planes,
|
||||||
coredump,
|
coredump,
|
||||||
toml_stringify,
|
|
||||||
default_app_settings,
|
default_app_settings,
|
||||||
parse_app_settings,
|
parse_app_settings,
|
||||||
parse_project_settings,
|
parse_project_settings,
|
||||||
@ -21,6 +20,8 @@ import {
|
|||||||
clear_scene_and_bust_cache,
|
clear_scene_and_bust_cache,
|
||||||
kcl_settings,
|
kcl_settings,
|
||||||
change_kcl_settings,
|
change_kcl_settings,
|
||||||
|
serialize_project_configuration,
|
||||||
|
serialize_configuration,
|
||||||
reloadModule,
|
reloadModule,
|
||||||
} from 'lib/wasm_lib_wrapper'
|
} 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 {
|
export function defaultAppSettings(): DeepPartial<Configuration> | Error {
|
||||||
return default_app_settings()
|
return default_app_settings()
|
||||||
}
|
}
|
||||||
@ -786,3 +783,27 @@ export function unitAngToUnitAngle(input: UnitAng): UnitAngle {
|
|||||||
export function getKclVersion(): string {
|
export function getKclVersion(): string {
|
||||||
return get_kcl_version()
|
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,
|
initPromise,
|
||||||
parseAppSettings,
|
parseAppSettings,
|
||||||
parseProjectSettings,
|
parseProjectSettings,
|
||||||
tomlStringify,
|
serializeConfiguration,
|
||||||
|
serializeProjectConfiguration,
|
||||||
} from 'lang/wasm'
|
} from 'lang/wasm'
|
||||||
import { mouseControlsToCameraSystem } from 'lib/cameraControls'
|
import { mouseControlsToCameraSystem } from 'lib/cameraControls'
|
||||||
import { BROWSER_PROJECT_NAME } from 'lib/constants'
|
import { BROWSER_PROJECT_NAME } from 'lib/constants'
|
||||||
@ -131,7 +132,7 @@ export function readLocalStorageAppSettingsFile():
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
const settings = defaultAppSettings()
|
const settings = defaultAppSettings()
|
||||||
if (err(settings)) return settings
|
if (err(settings)) return settings
|
||||||
const tomlStr = tomlStringify(settings)
|
const tomlStr = serializeConfiguration(settings)
|
||||||
if (err(tomlStr)) return tomlStr
|
if (err(tomlStr)) return tomlStr
|
||||||
|
|
||||||
localStorage.setItem(localStorageAppSettingsPath(), tomlStr)
|
localStorage.setItem(localStorageAppSettingsPath(), tomlStr)
|
||||||
@ -152,7 +153,7 @@ function readLocalStorageProjectSettingsFile():
|
|||||||
const projectSettings = parseProjectSettings(stored)
|
const projectSettings = parseProjectSettings(stored)
|
||||||
if (err(projectSettings)) {
|
if (err(projectSettings)) {
|
||||||
const settings = defaultProjectSettings()
|
const settings = defaultProjectSettings()
|
||||||
const tomlStr = tomlStringify(settings)
|
const tomlStr = serializeProjectConfiguration(settings)
|
||||||
if (err(tomlStr)) return tomlStr
|
if (err(tomlStr)) return tomlStr
|
||||||
|
|
||||||
localStorage.setItem(localStorageProjectSettingsPath(), tomlStr)
|
localStorage.setItem(localStorageProjectSettingsPath(), tomlStr)
|
||||||
@ -229,7 +230,7 @@ export async function saveSettings(
|
|||||||
|
|
||||||
// Get the user settings.
|
// Get the user settings.
|
||||||
const jsAppSettings = getChangedSettingsAtLevel(allSettings, 'user')
|
const jsAppSettings = getChangedSettingsAtLevel(allSettings, 'user')
|
||||||
const appTomlString = tomlStringify({ settings: jsAppSettings })
|
const appTomlString = serializeConfiguration({ settings: jsAppSettings })
|
||||||
if (err(appTomlString)) return
|
if (err(appTomlString)) return
|
||||||
|
|
||||||
// Write the app settings.
|
// Write the app settings.
|
||||||
@ -246,7 +247,9 @@ export async function saveSettings(
|
|||||||
|
|
||||||
// Get the project settings.
|
// Get the project settings.
|
||||||
const jsProjectSettings = getChangedSettingsAtLevel(allSettings, 'project')
|
const jsProjectSettings = getChangedSettingsAtLevel(allSettings, 'project')
|
||||||
const projectTomlString = tomlStringify({ settings: jsProjectSettings })
|
const projectTomlString = serializeProjectConfiguration({
|
||||||
|
settings: jsProjectSettings,
|
||||||
|
})
|
||||||
if (err(projectTomlString)) return
|
if (err(projectTomlString)) return
|
||||||
|
|
||||||
// Write the project settings.
|
// Write the project settings.
|
||||||
|
|||||||
@ -56,7 +56,12 @@ export type ToolbarItemResolved = Omit<
|
|||||||
export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
||||||
modeling: {
|
modeling: {
|
||||||
check: (state) =>
|
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: [
|
items: [
|
||||||
{
|
{
|
||||||
id: 'sketch',
|
id: 'sketch',
|
||||||
@ -330,7 +335,10 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
},
|
},
|
||||||
sketching: {
|
sketching: {
|
||||||
check: (state) =>
|
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: [
|
items: [
|
||||||
{
|
{
|
||||||
id: 'sketch-exit',
|
id: 'sketch-exit',
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import {
|
|||||||
get_tangential_arc_to_info as GetTangentialArcToInfo,
|
get_tangential_arc_to_info as GetTangentialArcToInfo,
|
||||||
make_default_planes as MakeDefaultPlanes,
|
make_default_planes as MakeDefaultPlanes,
|
||||||
coredump as CoreDump,
|
coredump as CoreDump,
|
||||||
toml_stringify as TomlStringify,
|
|
||||||
default_app_settings as DefaultAppSettings,
|
default_app_settings as DefaultAppSettings,
|
||||||
parse_app_settings as ParseAppSettings,
|
parse_app_settings as ParseAppSettings,
|
||||||
parse_project_settings as ParseProjectSettings,
|
parse_project_settings as ParseProjectSettings,
|
||||||
@ -29,6 +28,8 @@ import {
|
|||||||
kcl_settings as KclSettings,
|
kcl_settings as KclSettings,
|
||||||
change_kcl_settings as ChangeKclSettings,
|
change_kcl_settings as ChangeKclSettings,
|
||||||
get_kcl_version as GetKclVersion,
|
get_kcl_version as GetKclVersion,
|
||||||
|
serialize_configuration as SerializeConfiguration,
|
||||||
|
serialize_project_configuration as SerializeProjectConfiguration,
|
||||||
} from '../wasm-lib/pkg/wasm_lib'
|
} from '../wasm-lib/pkg/wasm_lib'
|
||||||
|
|
||||||
type ModuleType = typeof import('../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) => {
|
export const coredump: typeof CoreDump = (...args) => {
|
||||||
return getModule().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) => {
|
export const default_app_settings: typeof DefaultAppSettings = (...args) => {
|
||||||
return getModule().default_app_settings(...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 = () => {
|
export const get_kcl_version: typeof GetKclVersion = () => {
|
||||||
return getModule().get_kcl_version()
|
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(),
|
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();
|
let mut source_ranges = self.error.source_ranges();
|
||||||
|
|
||||||
// Pop off the first source range to get the filename.
|
// Pop off the first source range to get the filename.
|
||||||
@ -162,33 +162,23 @@ impl KclErrorWithOutputs {
|
|||||||
.source_files
|
.source_files
|
||||||
.get(&first_source_range.module_id())
|
.get(&first_source_range.module_id())
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or(ModuleSource {
|
.ok_or_else(|| {
|
||||||
source: code.to_string(),
|
anyhow::anyhow!(
|
||||||
path: self
|
"Could not find source file for module id: {:?}",
|
||||||
.filenames
|
first_source_range.module_id()
|
||||||
.get(&first_source_range.module_id())
|
)
|
||||||
.ok_or_else(|| {
|
})?;
|
||||||
anyhow::anyhow!(
|
|
||||||
"Could not find filename for module id: {:?}",
|
|
||||||
first_source_range.module_id()
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.clone(),
|
|
||||||
});
|
|
||||||
let filename = source.path.to_string();
|
let filename = source.path.to_string();
|
||||||
let kcl_source = source.source.to_string();
|
let kcl_source = source.source.to_string();
|
||||||
|
|
||||||
let mut related = Vec::new();
|
let mut related = Vec::new();
|
||||||
for source_range in source_ranges {
|
for source_range in source_ranges {
|
||||||
let module_id = source_range.module_id();
|
let module_id = source_range.module_id();
|
||||||
let source = self.source_files.get(&module_id).cloned().unwrap_or(ModuleSource {
|
let source = self
|
||||||
source: code.to_string(),
|
.source_files
|
||||||
path: self
|
.get(&module_id)
|
||||||
.filenames
|
.cloned()
|
||||||
.get(&module_id)
|
.ok_or_else(|| anyhow::anyhow!("Could not find source file for module id: {:?}", module_id))?;
|
||||||
.ok_or_else(|| anyhow::anyhow!("Could not find filename for module id: {:?}", module_id))?
|
|
||||||
.clone(),
|
|
||||||
});
|
|
||||||
let error = self.error.override_source_ranges(vec![source_range]);
|
let error = self.error.override_source_ranges(vec![source_range]);
|
||||||
let report = Report {
|
let report = Report {
|
||||||
error,
|
error,
|
||||||
|
|||||||
@ -34,7 +34,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
fs::FileManager,
|
fs::FileManager,
|
||||||
modules::{ModuleId, ModulePath},
|
modules::{ModuleId, ModulePath},
|
||||||
parsing::ast::types::{Expr, ImportPath, Node, NodeRef, Program},
|
parsing::ast::types::{Expr, ImportPath, NodeRef},
|
||||||
settings::types::UnitLength,
|
settings::types::UnitLength,
|
||||||
source_range::SourceRange,
|
source_range::SourceRange,
|
||||||
std::StdLib,
|
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
|
// 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
|
// memory in case another run wants to use them. Note this is just saved to the preserved
|
||||||
@ -585,9 +585,15 @@ impl ExecutorContext {
|
|||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
(true, program.ast)
|
(true, program)
|
||||||
} else {
|
} else {
|
||||||
(clear_scene, changed_program)
|
(
|
||||||
|
clear_scene,
|
||||||
|
crate::Program {
|
||||||
|
ast: changed_program,
|
||||||
|
original_file_contents: program.original_file_contents,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CacheResult::NoAction(true) => {
|
CacheResult::NoAction(true) => {
|
||||||
@ -608,7 +614,7 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
return Ok(old_state.to_wasm_outcome(result_env));
|
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)),
|
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())
|
self.send_clear_scene(&mut exec_state, Default::default())
|
||||||
.await
|
.await
|
||||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
.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;
|
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.
|
// Save this as the last successful execution to the cache.
|
||||||
cache::write_old_ast(OldAstState {
|
cache::write_old_ast(OldAstState {
|
||||||
ast: program,
|
ast: program.ast,
|
||||||
exec_state: exec_state.clone(),
|
exec_state: exec_state.clone(),
|
||||||
settings: self.settings.clone(),
|
settings: self.settings.clone(),
|
||||||
result_env: result.0,
|
result_env: result.0,
|
||||||
@ -691,18 +697,19 @@ impl ExecutorContext {
|
|||||||
self.send_clear_scene(exec_state, Default::default())
|
self.send_clear_scene(exec_state, Default::default())
|
||||||
.await
|
.await
|
||||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
.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
|
/// Perform the execution of a program. Accept all possible parameters and
|
||||||
/// output everything.
|
/// output everything.
|
||||||
async fn inner_run(
|
async fn inner_run(
|
||||||
&self,
|
&self,
|
||||||
program: &Node<Program>,
|
program: &crate::Program,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
preserve_mem: bool,
|
preserve_mem: bool,
|
||||||
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
||||||
let _stats = crate::log::LogPerfStats::new("Interpretation");
|
let _stats = crate::log::LogPerfStats::new("Interpretation");
|
||||||
|
exec_state.add_root_module_contents(program);
|
||||||
|
|
||||||
// Re-apply the settings, in case the cache was busted.
|
// Re-apply the settings, in case the cache was busted.
|
||||||
self.engine
|
self.engine
|
||||||
@ -711,7 +718,7 @@ impl ExecutorContext {
|
|||||||
.map_err(KclErrorWithOutputs::no_outputs)?;
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
||||||
|
|
||||||
let env_ref = self
|
let env_ref = self
|
||||||
.execute_and_build_graph(program, exec_state, preserve_mem)
|
.execute_and_build_graph(&program.ast, exec_state, preserve_mem)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
|
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);
|
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) {
|
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());
|
self.global.id_to_source.insert(id, source.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,8 +270,6 @@ impl GlobalState {
|
|||||||
global
|
global
|
||||||
.path_to_source_id
|
.path_to_source_id
|
||||||
.insert(ModulePath::Local { value: root_path }, root_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
|
global
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,6 +134,11 @@ use crate::log::{log, logln};
|
|||||||
pub struct Program {
|
pub struct Program {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub ast: parsing::ast::types::Node<parsing::ast::types::Program>,
|
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"))]
|
#[cfg(any(test, feature = "lsp-test-util"))]
|
||||||
@ -147,7 +152,13 @@ impl Program {
|
|||||||
let tokens = parsing::token::lex(input, module_id)?;
|
let tokens = parsing::token::lex(input, module_id)?;
|
||||||
let (ast, errs) = parsing::parse_tokens(tokens).0?;
|
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> {
|
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 tokens = parsing::token::lex(input, module_id)?;
|
||||||
let ast = parsing::parse_tokens(tokens).parse_errs_as_err()?;
|
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 {
|
pub fn compute_digest(&mut self) -> parsing::ast::digest::Digest {
|
||||||
@ -168,9 +182,10 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Change the meta settings for the kcl file.
|
/// 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 {
|
Ok(Self {
|
||||||
ast: self.ast.change_meta_settings(settings)?,
|
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]
|
#[inline]
|
||||||
fn try_f64_to_usize(f: f64) -> Option<usize> {
|
fn try_f64_to_usize(f: f64) -> Option<usize> {
|
||||||
let i = f as usize;
|
let i = f as usize;
|
||||||
|
|||||||
@ -46,7 +46,7 @@ use crate::{
|
|||||||
errors::Suggestion,
|
errors::Suggestion,
|
||||||
lsp::{backend::Backend as _, util::IntoDiagnostic},
|
lsp::{backend::Backend as _, util::IntoDiagnostic},
|
||||||
parsing::{
|
parsing::{
|
||||||
ast::types::{Expr, Node, VariableKind},
|
ast::types::{Expr, VariableKind},
|
||||||
token::TokenStream,
|
token::TokenStream,
|
||||||
PIPE_OPERATOR,
|
PIPE_OPERATOR,
|
||||||
},
|
},
|
||||||
@ -102,7 +102,7 @@ pub struct Backend {
|
|||||||
/// Token maps.
|
/// Token maps.
|
||||||
pub(super) token_map: DashMap<String, TokenStream>,
|
pub(super) token_map: DashMap<String, TokenStream>,
|
||||||
/// AST maps.
|
/// AST maps.
|
||||||
pub ast_map: DashMap<String, Node<crate::parsing::ast::types::Program>>,
|
pub ast_map: DashMap<String, crate::Program>,
|
||||||
/// Current code.
|
/// Current code.
|
||||||
pub code_map: DashMap<String, Vec<u8>>,
|
pub code_map: DashMap<String, Vec<u8>>,
|
||||||
/// Diagnostics.
|
/// Diagnostics.
|
||||||
@ -327,11 +327,17 @@ impl crate::lsp::backend::Backend for Backend {
|
|||||||
// this if it backfires and only hork the LSP.
|
// this if it backfires and only hork the LSP.
|
||||||
ast.compute_digest();
|
ast.compute_digest();
|
||||||
|
|
||||||
|
// Save it as a program.
|
||||||
|
let ast = crate::Program {
|
||||||
|
ast,
|
||||||
|
original_file_contents: params.text.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
// Check if the ast changed.
|
// Check if the ast changed.
|
||||||
let ast_changed = match self.ast_map.get(&filename) {
|
let ast_changed = match self.ast_map.get(&filename) {
|
||||||
Some(old_ast) => {
|
Some(old_ast) => {
|
||||||
// Check if the ast changed.
|
// Check if the ast changed.
|
||||||
*old_ast != ast
|
*old_ast.ast != *ast.ast
|
||||||
}
|
}
|
||||||
None => true,
|
None => true,
|
||||||
};
|
};
|
||||||
@ -346,7 +352,7 @@ impl crate::lsp::backend::Backend for Backend {
|
|||||||
// Update the symbols map.
|
// Update the symbols map.
|
||||||
self.symbols_map.insert(
|
self.symbols_map.insert(
|
||||||
params.uri.to_string(),
|
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.
|
// Update our semantic tokens.
|
||||||
@ -361,14 +367,14 @@ impl crate::lsp::backend::Backend for Backend {
|
|||||||
// Only send the notification if we can execute.
|
// Only send the notification if we can execute.
|
||||||
// Otherwise it confuses the client.
|
// Otherwise it confuses the client.
|
||||||
self.client
|
self.client
|
||||||
.send_notification::<custom_notifications::AstUpdated>(ast.clone())
|
.send_notification::<custom_notifications::AstUpdated>(ast.ast.clone())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the code if we have an executor context.
|
// Execute the code if we have an executor context.
|
||||||
// This function automatically executes if we should & updates the diagnostics if we got
|
// This function automatically executes if we should & updates the diagnostics if we got
|
||||||
// errors.
|
// errors.
|
||||||
if self.execute(¶ms, &ast.into()).await.is_err() {
|
if self.execute(¶ms, &ast).await.is_err() {
|
||||||
return;
|
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_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 token_index = Arc::new(Mutex::new(token_type_index));
|
||||||
let modifier_index: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
|
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 {
|
let Ok(node_range): Result<SourceRange, _> = (&node).try_into() else {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
};
|
};
|
||||||
@ -1021,7 +1027,7 @@ impl LanguageServer for Backend {
|
|||||||
return Ok(None);
|
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);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1150,13 +1156,13 @@ impl LanguageServer for Backend {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let position = position_to_char_index(params.text_document_position.position, current_code);
|
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.
|
// If we are in a code comment we don't want to show completions.
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the completion items for the ast.
|
// 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)));
|
return Ok(Some(CompletionResponse::Array(completions)));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1211,7 +1217,7 @@ impl LanguageServer for Backend {
|
|||||||
return Ok(None);
|
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);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1360,7 +1366,7 @@ impl LanguageServer for Backend {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get the folding ranges.
|
// 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() {
|
if folding_ranges.is_empty() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
|||||||
@ -1138,7 +1138,7 @@ fn myFn = (param1) => {
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Send semantic tokens request.
|
||||||
let semantic_tokens = server
|
let semantic_tokens = server
|
||||||
@ -2251,7 +2251,7 @@ part001 = cube([0,0], 20)
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Send change file.
|
||||||
server
|
server
|
||||||
@ -2428,7 +2428,7 @@ async fn kcl_test_kcl_lsp_full_to_empty_file_updates_ast_and_memory() {
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Send change file.
|
||||||
server
|
server
|
||||||
@ -2450,7 +2450,7 @@ async fn kcl_test_kcl_lsp_full_to_empty_file_updates_ast_and_memory() {
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
@ -2479,7 +2479,7 @@ async fn kcl_test_kcl_lsp_code_unchanged_but_has_diagnostics_reexecute() {
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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);
|
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
|
||||||
|
|
||||||
// Clear the ast and memory.
|
// Clear the ast and memory.
|
||||||
server
|
server.ast_map.insert(
|
||||||
.ast_map
|
"file:///test.kcl".to_string(),
|
||||||
.insert("file:///test.kcl".to_string(), Node::<Program>::default());
|
crate::Program {
|
||||||
|
ast: Default::default(),
|
||||||
|
original_file_contents: Default::default(),
|
||||||
|
},
|
||||||
|
);
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Send change file, but the code is the same.
|
||||||
server
|
server
|
||||||
@ -2529,7 +2533,7 @@ async fn kcl_test_kcl_lsp_code_unchanged_but_has_diagnostics_reexecute() {
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
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.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have no diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 0);
|
||||||
@ -2995,7 +2999,7 @@ part001 = startSketchOn('XY')
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have one diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
|
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
|
||||||
@ -3016,7 +3020,7 @@ part001 = startSketchOn('XY')
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have one diagnostics.
|
||||||
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
|
assert_diagnostic_count(server.diagnostics_map.get("file:///test.kcl").as_deref(), 1);
|
||||||
@ -3109,7 +3113,7 @@ part001 = startSketchOn('XY')
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Send change file, but the code is the same.
|
||||||
server
|
server
|
||||||
@ -3128,7 +3132,7 @@ part001 = startSketchOn('XY')
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have diagnostics.
|
||||||
|
|
||||||
@ -3168,7 +3172,7 @@ part001 = startSketchOn('XY')
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Send change file, but the code is the same.
|
||||||
server
|
server
|
||||||
@ -3195,7 +3199,7 @@ NEW_LINT = 1"#
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Assure we have diagnostics.
|
||||||
|
|
||||||
@ -3302,7 +3306,7 @@ part001 = startSketchOn('XY')
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Get the symbols map.
|
||||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
||||||
@ -3389,7 +3393,7 @@ part001 = startSketchOn('XY')
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Get the symbols map.
|
||||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
||||||
@ -3428,7 +3432,7 @@ part001 = startSketchOn('XY')
|
|||||||
|
|
||||||
// Get the ast.
|
// Get the ast.
|
||||||
let ast = server.ast_map.get("file:///test.kcl").unwrap().clone();
|
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.
|
// Get the symbols map.
|
||||||
let symbols_map = server.symbols_map.get("file:///test.kcl").unwrap().clone();
|
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);
|
let recasted = program.ast.recast(&FormatOptions::default(), 0);
|
||||||
|
|
||||||
// Re-parse the ast so we get the correct source ranges.
|
// Re-parse the ast so we get the correct source ranges.
|
||||||
*program = crate::parsing::parse_str(&recasted, module_id)
|
program.ast = crate::parsing::parse_str(&recasted, module_id).parse_errs_as_err()?;
|
||||||
.parse_errs_as_err()?
|
|
||||||
.into();
|
|
||||||
|
|
||||||
Ok(recasted)
|
Ok(recasted)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -275,7 +275,7 @@ impl Node<Program> {
|
|||||||
Ok(None)
|
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 new_program = self.clone();
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
for node in &mut new_program.inner_attrs {
|
for node in &mut new_program.inner_attrs {
|
||||||
@ -4035,7 +4035,7 @@ startSketchOn('XY')"#;
|
|||||||
let some_program_string = r#"@settings(defaultLengthUnit = inch)
|
let some_program_string = r#"@settings(defaultLengthUnit = inch)
|
||||||
|
|
||||||
startSketchOn('XY')"#;
|
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();
|
let result = program.meta_settings().unwrap();
|
||||||
assert!(result.is_some());
|
assert!(result.is_some());
|
||||||
let meta_settings = result.unwrap();
|
let meta_settings = result.unwrap();
|
||||||
@ -4077,7 +4077,7 @@ startSketchOn('XY')
|
|||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_parse_get_meta_settings_nothing_to_mm() {
|
async fn test_parse_get_meta_settings_nothing_to_mm() {
|
||||||
let some_program_string = r#"startSketchOn('XY')"#;
|
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();
|
let result = program.meta_settings().unwrap();
|
||||||
assert!(result.is_none());
|
assert!(result.is_none());
|
||||||
|
|
||||||
|
|||||||
@ -84,10 +84,14 @@ async fn execute(test_name: &str, render_to_png: bool) {
|
|||||||
let Ok(ast) = ast_res else {
|
let Ok(ast) = ast_res else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
let ast = crate::Program {
|
||||||
|
ast,
|
||||||
|
original_file_contents: read("input.kcl", test_name),
|
||||||
|
};
|
||||||
|
|
||||||
// Run the program.
|
// Run the program.
|
||||||
let exec_res = crate::test_server::execute_and_snapshot_ast(
|
let exec_res = crate::test_server::execute_and_snapshot_ast(
|
||||||
ast.into(),
|
ast,
|
||||||
crate::settings::types::UnitLength::Mm,
|
crate::settings::types::UnitLength::Mm,
|
||||||
Some(Path::new("tests").join(test_name).join("input.kcl").to_owned()),
|
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())
|
Box::new(miette::MietteHandlerOpts::new().show_related_errors_as_nested().build())
|
||||||
}))
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let report = error
|
let report = error.clone().into_miette_report_with_outputs().unwrap();
|
||||||
.clone()
|
|
||||||
.into_miette_report_with_outputs(&read("input.kcl", test_name))
|
|
||||||
.unwrap();
|
|
||||||
let report = miette::Report::new(report);
|
let report = miette::Report::new(report);
|
||||||
if previously_passed {
|
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");
|
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`.
|
//! Wasm bindings for `kcl`.
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
mod toml;
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
mod wasm;
|
mod wasm;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
pub use toml::*;
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub use wasm::*;
|
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())
|
JsValue::from_serde(&settings).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize the project settings.
|
/// Serialize the configuration settings.
|
||||||
#[wasm_bindgen]
|
#[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();
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
let config: kcl_lib::Configuration = val.into_serde().map_err(|e| e.to_string())?;
|
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))
|
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] = &[
|
static ALLOWED_DECODING_FORMATS: &[data_encoding::Encoding] = &[
|
||||||
data_encoding::BASE64,
|
data_encoding::BASE64,
|
||||||
data_encoding::BASE64URL,
|
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();
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
let settings: kcl_lib::MetaSettings = serde_json::from_str(settings_str).map_err(|e| e.to_string())?;
|
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())?;
|
let new_program = program.change_meta_settings(settings).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user