Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
d6ad4b6e66 | |||
546b4ea3b8 | |||
310932dc5a |
52
.github/workflows/cargo-bench.yml
vendored
Normal file
52
.github/workflows/cargo-bench.yml
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- .github/workflows/cargo-bench.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- .github/workflows/cargo-bench.yml
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
name: cargo bench
|
||||
jobs:
|
||||
cargo-bench:
|
||||
name: cargo bench
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use correct Rust toolchain
|
||||
shell: bash
|
||||
run: |
|
||||
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
|
||||
- name: Install rust
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: rust
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cargo install cargo-criterion
|
||||
sudo apt update
|
||||
sudo apt install -y valgrind
|
||||
- uses: boa-dev/criterion-compare-action@v3
|
||||
with:
|
||||
cwd: "rust"
|
||||
defaultFeatures: true
|
||||
# Needed. The name of the branch to compare with. This default uses the branch which is being pulled against
|
||||
branchName: ${{ github.base_ref }}
|
||||
env:
|
||||
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
|
@ -4,13 +4,28 @@ excerpt: "Documentation of settings for the KCL language and Zoo Modeling App."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
# Per-file settings
|
||||
# KCL Settings
|
||||
|
||||
There are three levels of settings available in the KittyCAD modeling application:
|
||||
|
||||
1. [User Settings](/docs/kcl/settings/user.toml): Global settings that apply to all projects, stored in `user.toml`
|
||||
2. [Project Settings](/docs/kcl/settings/project.toml): Settings specific to a project, stored in `project.toml`
|
||||
3. Per-file Settings: Settings that apply to a single KCL file, specified using the `@settings` attribute
|
||||
|
||||
## Configuration Files
|
||||
|
||||
The KittyCAD modeling app uses TOML files for configuration:
|
||||
|
||||
* **User Settings**: `user.toml` - See [complete documentation](/docs/kcl/settings/user.toml)
|
||||
* **Project Settings**: `project.toml` - See [complete documentation](/docs/kcl/settings/project.toml)
|
||||
|
||||
## Per-file settings
|
||||
|
||||
Settings which affect a single file are configured using the settings attribute.
|
||||
This must be at the top of the KCL file (comments before the attribute are permitted).
|
||||
E.g.,
|
||||
For example:
|
||||
|
||||
```
|
||||
```js
|
||||
// The settings attribute.
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
208
docs/kcl/settings/project.toml.md
Normal file
208
docs/kcl/settings/project.toml.md
Normal file
@ -0,0 +1,208 @@
|
||||
---
|
||||
title: "Project Settings"
|
||||
excerpt: "Project specific settings for the app. These live in `project.toml` in the base of the project directory. Updating the settings for the project in the app will update this file automatically. Do not edit this file manually, as it may be overwritten by the app. Manual edits can cause corruption of the settings file."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
# Project Settings
|
||||
|
||||
Project specific settings for the app. These live in `project.toml` in the base of the project directory. Updating the settings for the project in the app will update this file automatically. Do not edit this file manually, as it may be overwritten by the app. Manual edits can cause corruption of the settings file.
|
||||
|
||||
## Project Configuration Structure
|
||||
|
||||
```toml
|
||||
[settings.app]
|
||||
# Set the appearance of the application
|
||||
name = "My Awesome Project"
|
||||
|
||||
[settings.app.appearance]
|
||||
# Use dark mode theme
|
||||
theme = "dark"
|
||||
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
|
||||
color = 240.0
|
||||
|
||||
[settings.modeling]
|
||||
# Use inches as the default measurement unit
|
||||
base_unit = "in"
|
||||
|
||||
```
|
||||
|
||||
## Available Settings
|
||||
|
||||
### settings
|
||||
|
||||
|
||||
|
||||
#### app
|
||||
|
||||
The settings for the modeling app.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### appearance
|
||||
|
||||
The settings for the appearance of the app.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has further nested options. See the schema for full details.
|
||||
##### onboarding_status
|
||||
|
||||
The onboarding status of the app.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### theme_color
|
||||
|
||||
The hue of the primary theme color for the app.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### enable_ssao
|
||||
|
||||
Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### dismiss_web_banner
|
||||
|
||||
Permanently dismiss the banner warning to download the desktop app. This setting only applies to the web app. And is temporary until we have Linux support.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### stream_idle_mode
|
||||
|
||||
When the user is idle, and this is true, the stream will be torn down.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### allow_orbit_in_sketch_mode
|
||||
|
||||
When the user is idle, and this is true, the stream will be torn down.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### show_debug_panel
|
||||
|
||||
Whether to show the debug panel, which lets you see various states of the app to aid in development.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### named_views
|
||||
|
||||
Settings that affect the behavior of the command bar.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
#### modeling
|
||||
|
||||
Settings that affect the behavior while modeling.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### base_unit
|
||||
|
||||
The default unit to use in modeling dimensions.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### highlight_edges
|
||||
|
||||
Highlight edges of 3D objects?
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### show_debug_panel
|
||||
|
||||
Whether to show the debug panel, which lets you see various states of the app to aid in development. Remove this when we remove backwards compatibility with the old settings file.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### enable_ssao
|
||||
|
||||
Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
#### text_editor
|
||||
|
||||
Settings that affect the behavior of the KCL text editor.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### text_wrapping
|
||||
|
||||
Whether to wrap text in the editor or overflow with scroll.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### blinking_cursor
|
||||
|
||||
Whether to make the cursor blink in the editor.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
#### command_bar
|
||||
|
||||
Settings that affect the behavior of the command bar.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### include_settings
|
||||
|
||||
Whether to include settings in the command bar.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
|
||||
|
||||
## Complete Example
|
||||
|
||||
```toml
|
||||
[settings.app]
|
||||
# Set the appearance of the application
|
||||
name = "My Awesome Project"
|
||||
|
||||
[settings.app.appearance]
|
||||
# Use dark mode theme
|
||||
theme = "dark"
|
||||
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
|
||||
color = 240.0
|
||||
|
||||
[settings.modeling]
|
||||
# Use inches as the default measurement unit
|
||||
base_unit = "in"
|
||||
|
||||
```
|
272
docs/kcl/settings/user.toml.md
Normal file
272
docs/kcl/settings/user.toml.md
Normal file
@ -0,0 +1,272 @@
|
||||
---
|
||||
title: "User Settings"
|
||||
excerpt: "User specific settings for the app. These live in `user.toml` in the app's configuration directory. Updating the settings in the app will update this file automatically. Do not edit this file manually, as it may be overwritten by the app. Manual edits can cause corruption of the settings file."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
# User Settings
|
||||
|
||||
User specific settings for the app. These live in `user.toml` in the app's configuration directory. Updating the settings in the app will update this file automatically. Do not edit this file manually, as it may be overwritten by the app. Manual edits can cause corruption of the settings file.
|
||||
|
||||
## User Configuration Structure
|
||||
|
||||
```toml
|
||||
[settings.app]
|
||||
# Set the appearance of the application
|
||||
[settings.app.appearance]
|
||||
# Use dark mode theme
|
||||
theme = "dark"
|
||||
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
|
||||
color = 240.0
|
||||
|
||||
[settings.modeling]
|
||||
# Use millimeters as the default measurement unit
|
||||
base_unit = "mm"
|
||||
|
||||
[settings.text_editor]
|
||||
# Disable text wrapping in the editor
|
||||
text_wrapping = false
|
||||
|
||||
```
|
||||
|
||||
## Available Settings
|
||||
|
||||
### settings
|
||||
|
||||
|
||||
|
||||
#### app
|
||||
|
||||
The settings for the modeling app.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### appearance
|
||||
|
||||
The settings for the appearance of the app.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has further nested options. See the schema for full details.
|
||||
##### onboarding_status
|
||||
|
||||
The onboarding status of the app.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### project_directory
|
||||
|
||||
Backwards compatible project directory setting.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### theme
|
||||
|
||||
Backwards compatible theme setting.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### theme_color
|
||||
|
||||
The hue of the primary theme color for the app.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### enable_ssao
|
||||
|
||||
Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### dismiss_web_banner
|
||||
|
||||
Permanently dismiss the banner warning to download the desktop app. This setting only applies to the web app. And is temporary until we have Linux support.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### stream_idle_mode
|
||||
|
||||
When the user is idle, and this is true, the stream will be torn down.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### allow_orbit_in_sketch_mode
|
||||
|
||||
When the user is idle, and this is true, the stream will be torn down.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### show_debug_panel
|
||||
|
||||
Whether to show the debug panel, which lets you see various states of the app to aid in development.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
#### modeling
|
||||
|
||||
Settings that affect the behavior while modeling.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### base_unit
|
||||
|
||||
The default unit to use in modeling dimensions.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### camera_projection
|
||||
|
||||
The projection mode the camera should use while modeling.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### camera_orbit
|
||||
|
||||
The methodology the camera should use to orbit around the model.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### mouse_controls
|
||||
|
||||
The controls for how to navigate the 3D view.
|
||||
|
||||
**Possible values:** `zoo`, `onshape`, `trackpad_friendly`, `solidworks`, `nx`, `creo`, `autocad`
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### highlight_edges
|
||||
|
||||
Highlight edges of 3D objects?
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### show_debug_panel
|
||||
|
||||
Whether to show the debug panel, which lets you see various states of the app to aid in development. Remove this when we remove backwards compatibility with the old settings file.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### enable_ssao
|
||||
|
||||
Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### show_scale_grid
|
||||
|
||||
Whether or not to show a scale grid in the 3D modeling view
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
#### text_editor
|
||||
|
||||
Settings that affect the behavior of the KCL text editor.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### text_wrapping
|
||||
|
||||
Whether to wrap text in the editor or overflow with scroll.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### blinking_cursor
|
||||
|
||||
Whether to make the cursor blink in the editor.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
#### project
|
||||
|
||||
Settings that affect the behavior of project management.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### directory
|
||||
|
||||
The directory to save and load projects from.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
##### default_project_name
|
||||
|
||||
The default project name to use when creating a new project.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
#### command_bar
|
||||
|
||||
Settings that affect the behavior of the command bar.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
This setting has the following nested options:
|
||||
|
||||
##### include_settings
|
||||
|
||||
Whether to include settings in the command bar.
|
||||
|
||||
|
||||
**Default:** None
|
||||
|
||||
|
||||
|
||||
|
||||
## Complete Example
|
||||
|
||||
```toml
|
||||
[settings.app]
|
||||
# Set the appearance of the application
|
||||
[settings.app.appearance]
|
||||
# Use dark mode theme
|
||||
theme = "dark"
|
||||
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
|
||||
color = 240.0
|
||||
|
||||
[settings.modeling]
|
||||
# Use millimeters as the default measurement unit
|
||||
base_unit = "mm"
|
||||
|
||||
[settings.text_editor]
|
||||
# Disable text wrapping in the editor
|
||||
text_wrapping = false
|
||||
|
||||
```
|
12
rust/Cargo.lock
generated
12
rust/Cargo.lock
generated
@ -1813,7 +1813,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-directory-test-macro"
|
||||
version = "0.1.46"
|
||||
version = "0.1.47"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1917,6 +1917,7 @@ dependencies = [
|
||||
"tower-lsp",
|
||||
"ts-rs",
|
||||
"twenty-twenty",
|
||||
"tynm",
|
||||
"url",
|
||||
"uuid",
|
||||
"validator",
|
||||
@ -4242,6 +4243,15 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tynm"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd30d05e69d1478e13fe3e7a853409cfec82cebc2cf9b8d613b3c6b0081781ed"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
|
@ -54,6 +54,7 @@ bump-kcl-crate-versions bump='patch':
|
||||
publish-kcl version:
|
||||
git tag kcl-{{version}}
|
||||
cargo publish -p kcl-derive-docs
|
||||
cargo publish -p kcl-directory-test-macro
|
||||
cargo publish -p kcl-lib
|
||||
cargo publish -p kcl-test-server
|
||||
# We push the tag at the end of publish since pushing the tag
|
||||
|
@ -9,6 +9,11 @@ description = "Bumps versions in Cargo.toml"
|
||||
publish = false
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[[bin]]
|
||||
name = "kcl-bumper"
|
||||
path = "src/main.rs"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
|
@ -9,6 +9,7 @@ repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
Inflector = "0.11.4"
|
||||
|
@ -1,14 +1,14 @@
|
||||
[package]
|
||||
name = "kcl-directory-test-macro"
|
||||
description = "A tool for generating tests from a directory of kcl files"
|
||||
version = "0.1.46"
|
||||
version = "0.1.47"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1"
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::fs;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use std::fs;
|
||||
use syn::{parse_macro_input, LitStr};
|
||||
|
||||
/// A macro that generates test functions for each directory within a given path.
|
||||
|
@ -6,6 +6,11 @@ authors = ["KittyCAD Inc <kcl@kittycad.io>"]
|
||||
publish = false
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[[bin]]
|
||||
name = "kcl-language-server-release"
|
||||
path = "src/main.rs"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true, features = ["cargo", "derive", "env", "unicode"] }
|
||||
|
@ -10,6 +10,7 @@ license = "MIT"
|
||||
[[bin]]
|
||||
name = "kcl-language-server"
|
||||
path = "src/main.rs"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
@ -11,6 +11,14 @@ keywords = ["kcl", "KittyCAD", "CAD"]
|
||||
exclude = ["tests/*", "benches/*", "examples/*", "e2e/*", "bindings/*", "fuzz/*"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[[bin]]
|
||||
name = "kcl-lib-bin"
|
||||
path = "src/main.rs"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true, features = ["backtrace"] }
|
||||
async-recursion = "1.1.1"
|
||||
@ -33,7 +41,7 @@ http = { workspace = true }
|
||||
image = { version = "0.25.5", default-features = false, features = ["png"] }
|
||||
indexmap = { workspace = true, features = ["serde"] }
|
||||
itertools = "0.13.0"
|
||||
kcl-derive-docs = { path = "../kcl-derive-docs" }
|
||||
kcl-derive-docs = { version = "0.1", path = "../kcl-derive-docs" }
|
||||
kittycad = { workspace = true }
|
||||
kittycad-modeling-cmds = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
@ -70,6 +78,7 @@ ts-rs = { version = "10.1.0", features = [
|
||||
"no-serde-warnings",
|
||||
"serde-json-impl",
|
||||
] }
|
||||
tynm = "0.1.10"
|
||||
url = { version = "2.5.4", features = ["serde"] }
|
||||
uuid = { workspace = true, features = ["v4", "js", "serde"] }
|
||||
validator = { version = "0.20.0", features = ["derive"] }
|
||||
@ -114,7 +123,7 @@ expectorate = "1.1.0"
|
||||
handlebars = "6.3.0"
|
||||
image = { version = "0.25.5", default-features = false, features = ["png"] }
|
||||
insta = { version = "1.41.1", features = ["json", "filters", "redactions"] }
|
||||
kcl-directory-test-macro = { path = "../kcl-directory-test-macro" }
|
||||
kcl-directory-test-macro = { version = "0.1", path = "../kcl-directory-test-macro" }
|
||||
miette = { version = "7.5.0", features = ["fancy"] }
|
||||
pretty_assertions = "1.4.1"
|
||||
tokio = { version = "1.41.1", features = ["rt-multi-thread", "macros", "time"] }
|
||||
@ -140,6 +149,10 @@ required-features = ["lsp-test-util"]
|
||||
name = "executor_benchmark_criterion"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "benchmark_kcl_samples"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "executor"
|
||||
path = "e2e/executor/main.rs"
|
||||
|
95
rust/kcl-lib/benches/benchmark_kcl_samples.rs
Normal file
95
rust/kcl-lib/benches/benchmark_kcl_samples.rs
Normal file
@ -0,0 +1,95 @@
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
const IGNORE_DIRS: [&str; 2] = ["step", "screenshots"];
|
||||
|
||||
fn discover_benchmark_dirs(base_path: &Path) -> Vec<PathBuf> {
|
||||
let mut benchmark_dirs = Vec::new();
|
||||
|
||||
if let Ok(entries) = fs::read_dir(base_path) {
|
||||
for entry in entries.filter_map(Result::ok) {
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
let dir_name = path.file_name().unwrap().to_string_lossy();
|
||||
if !IGNORE_DIRS.iter().any(|&x| x == dir_name) {
|
||||
benchmark_dirs.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
benchmark_dirs
|
||||
}
|
||||
|
||||
fn find_main_kcl_file(dir_path: &Path) -> PathBuf {
|
||||
let file_path = dir_path.join("main.kcl");
|
||||
|
||||
if !file_path.exists() || !file_path.is_file() {
|
||||
panic!("Required main.kcl file not found in directory: {}", dir_path.display());
|
||||
}
|
||||
|
||||
file_path
|
||||
}
|
||||
|
||||
fn run_benchmarks(c: &mut Criterion) {
|
||||
// Specify the base directory containing benchmark subdirectories
|
||||
let base_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../public/kcl-samples");
|
||||
|
||||
if !base_dir.exists() || !base_dir.is_dir() {
|
||||
panic!("Invalid base directory: {}", base_dir.display());
|
||||
}
|
||||
|
||||
let benchmark_dirs = discover_benchmark_dirs(&base_dir);
|
||||
|
||||
let rt = Runtime::new().unwrap();
|
||||
|
||||
for dir in benchmark_dirs {
|
||||
let dir_name = dir.file_name().unwrap().to_string_lossy().to_string();
|
||||
|
||||
// Change the current directory to the benchmark directory.
|
||||
// This is necessary for the kcl-lib to correctly resolve relative paths.
|
||||
std::env::set_current_dir(&dir).unwrap();
|
||||
|
||||
// Find main.kcl file (will panic if not found)
|
||||
let input_file = find_main_kcl_file(&dir);
|
||||
|
||||
// Read the file content (panic on failure)
|
||||
let input_content = fs::read_to_string(&input_file)
|
||||
.unwrap_or_else(|e| panic!("Failed to read main.kcl in directory {}: {}", dir_name, e));
|
||||
|
||||
// Create a benchmark group for this directory
|
||||
let mut group = c.benchmark_group(&dir_name);
|
||||
group
|
||||
.sample_size(10)
|
||||
.measurement_time(std::time::Duration::from_secs(1)); // Short measurement time to keep it from running in parallel
|
||||
|
||||
let program = kcl_lib::Program::parse_no_errs(&input_content).unwrap();
|
||||
|
||||
group.bench_function("parse", |b| {
|
||||
b.iter(|| kcl_lib::Program::parse_no_errs(black_box(&input_content)).unwrap())
|
||||
});
|
||||
|
||||
group.bench_function("execute", |b| {
|
||||
b.iter(|| {
|
||||
rt.block_on(async {
|
||||
let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let mut exec_state = kcl_lib::ExecState::new(&ctx.settings);
|
||||
ctx.run(black_box(&program), &mut exec_state).await.unwrap();
|
||||
ctx.close().await;
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
group.finish();
|
||||
}
|
||||
}
|
||||
|
||||
criterion_group!(benches, run_benchmarks);
|
||||
criterion_main!(benches);
|
@ -13,7 +13,14 @@ pub fn bench_execute(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("executor");
|
||||
// Configure Criterion.rs to detect smaller differences and increase sample size to improve
|
||||
// precision and counteract the resulting noise.
|
||||
group.sample_size(10);
|
||||
group
|
||||
.sample_size(10)
|
||||
.measurement_time(std::time::Duration::from_secs(1)); // Short
|
||||
// measurement
|
||||
// time to keep
|
||||
// it from
|
||||
// running in
|
||||
// parallel
|
||||
group.bench_with_input(BenchmarkId::new("execute", name), &code, |b, &s| {
|
||||
let rt = Runtime::new().unwrap();
|
||||
// Spawn a future onto the runtime
|
||||
|
@ -857,7 +857,7 @@ part = rectShape([0, 0], 20, 20)
|
||||
};
|
||||
assert_eq!(
|
||||
err.error.message(),
|
||||
"Expected a kcl_lib::std::shapes::SketchOrSurface but found string (text)"
|
||||
"This function expected this argument to be of type SketchOrSurface but it's actually of type string (text)"
|
||||
);
|
||||
}
|
||||
|
||||
@ -2086,6 +2086,26 @@ async fn kcl_test_ensure_nothing_left_in_batch_multi_file() {
|
||||
ctx.close().await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_better_type_names() {
|
||||
let code = r#"startSketchOn('XY')
|
||||
|> circle(center = [-95.51, -74.7], radius = 262.23)
|
||||
|> appearance(metalness = 0.9)
|
||||
"#;
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm, None).await;
|
||||
|
||||
let err = match result.err() {
|
||||
Some(x) => match x {
|
||||
ExecError::Kcl(kcl_error_with_outputs) => kcl_error_with_outputs.error.message().to_owned(),
|
||||
ExecError::Connection(_) => todo!(),
|
||||
ExecError::BadPng(_) => todo!(),
|
||||
ExecError::BadExport(_) => todo!(),
|
||||
},
|
||||
None => todo!(),
|
||||
};
|
||||
assert_eq!(err, "This function expected this argument to be of type SolidSet but it's actually of type Sketch. You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_exporting_step_file() {
|
||||
// This tests export like how we do it in cli and kcl.py.
|
||||
|
232
rust/kcl-lib/src/settings/generate_settings_docs.rs
Normal file
232
rust/kcl-lib/src/settings/generate_settings_docs.rs
Normal file
@ -0,0 +1,232 @@
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use schemars::{gen::SchemaGenerator, JsonSchema};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::settings::types::{project::ProjectConfiguration, Configuration};
|
||||
|
||||
// Project settings example in TOML format
|
||||
const PROJECT_SETTINGS_EXAMPLE: &str = r#"[settings.app]
|
||||
# Set the appearance of the application
|
||||
name = "My Awesome Project"
|
||||
|
||||
[settings.app.appearance]
|
||||
# Use dark mode theme
|
||||
theme = "dark"
|
||||
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
|
||||
color = 240.0
|
||||
|
||||
[settings.modeling]
|
||||
# Use inches as the default measurement unit
|
||||
base_unit = "in"
|
||||
"#;
|
||||
|
||||
// User settings example in TOML format
|
||||
const USER_SETTINGS_EXAMPLE: &str = r#"[settings.app]
|
||||
# Set the appearance of the application
|
||||
[settings.app.appearance]
|
||||
# Use dark mode theme
|
||||
theme = "dark"
|
||||
# Set the app color to blue (240.0 = blue, 0.0 = red, 120.0 = green)
|
||||
color = 240.0
|
||||
|
||||
[settings.modeling]
|
||||
# Use millimeters as the default measurement unit
|
||||
base_unit = "mm"
|
||||
|
||||
[settings.text_editor]
|
||||
# Disable text wrapping in the editor
|
||||
text_wrapping = false
|
||||
"#;
|
||||
|
||||
const PROJECT_SETTINGS_DOC_PATH: &str = "../../docs/kcl/settings/project.toml.md";
|
||||
const USER_SETTINGS_DOC_PATH: &str = "../../docs/kcl/settings/user.toml.md";
|
||||
|
||||
fn init_handlebars() -> handlebars::Handlebars<'static> {
|
||||
let mut hbs = handlebars::Handlebars::new();
|
||||
|
||||
// Register helper to pretty-format enum values
|
||||
hbs.register_helper(
|
||||
"pretty_enum",
|
||||
Box::new(
|
||||
|h: &handlebars::Helper,
|
||||
_: &handlebars::Handlebars,
|
||||
_: &handlebars::Context,
|
||||
_: &mut handlebars::RenderContext,
|
||||
out: &mut dyn handlebars::Output|
|
||||
-> handlebars::HelperResult {
|
||||
if let Some(enum_value) = h.param(0) {
|
||||
if let Some(array) = enum_value.value().as_array() {
|
||||
let pretty_options = array
|
||||
.iter()
|
||||
.filter_map(|v| v.as_str())
|
||||
.map(|s| format!("`{}`", s))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
out.write(&pretty_options)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
out.write("No options available")?;
|
||||
Ok(())
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// Helper to format default values better
|
||||
hbs.register_helper(
|
||||
"format_default",
|
||||
Box::new(
|
||||
|h: &handlebars::Helper,
|
||||
_: &handlebars::Handlebars,
|
||||
_: &handlebars::Context,
|
||||
_: &mut handlebars::RenderContext,
|
||||
out: &mut dyn handlebars::Output|
|
||||
-> handlebars::HelperResult {
|
||||
if let Some(default) = h.param(0) {
|
||||
let val = default.value();
|
||||
match val {
|
||||
Value::Null => out.write("None")?,
|
||||
Value::Bool(b) => out.write(&b.to_string())?,
|
||||
Value::Number(n) => out.write(&n.to_string())?,
|
||||
Value::String(s) => out.write(&format!("`{}`", s))?,
|
||||
Value::Array(arr) => {
|
||||
let formatted = arr
|
||||
.iter()
|
||||
.map(|v| match v {
|
||||
Value::String(s) => format!("`{}`", s),
|
||||
_ => format!("{}", v),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
out.write(&format!("[{}]", formatted))?;
|
||||
}
|
||||
Value::Object(_) => out.write("(complex default)")?,
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
out.write("None")?;
|
||||
Ok(())
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// Register the settings template
|
||||
hbs.register_template_string("settings", include_str!("templates/settings.hbs"))
|
||||
.expect("Failed to register settings template");
|
||||
|
||||
hbs
|
||||
}
|
||||
|
||||
fn ensure_settings_dir() {
|
||||
let settings_dir = PathBuf::from("../../docs/kcl/settings");
|
||||
if !settings_dir.exists() {
|
||||
fs::create_dir_all(&settings_dir).expect("Failed to create settings directory");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_settings_docs() {
|
||||
ensure_settings_dir();
|
||||
let hbs = init_handlebars();
|
||||
|
||||
// Generate project settings documentation
|
||||
let mut settings = schemars::gen::SchemaSettings::default();
|
||||
settings.inline_subschemas = true;
|
||||
settings.meta_schema = None; // We don't need the meta schema for docs
|
||||
settings.option_nullable = false; // Important - makes Option fields show properly
|
||||
settings.option_add_null_type = false;
|
||||
|
||||
let mut generator = SchemaGenerator::new(settings.clone());
|
||||
let project_schema = ProjectConfiguration::json_schema(&mut generator);
|
||||
|
||||
// For debugging the schema:
|
||||
// fs::write("/tmp/project_schema.json", serde_json::to_string_pretty(&project_schema).unwrap())
|
||||
// .expect("Failed to write debug schema");
|
||||
|
||||
// Extract the description from the schema metadata
|
||||
let project_description = if let schemars::schema::Schema::Object(obj) = &project_schema {
|
||||
if let Some(metadata) = &obj.metadata {
|
||||
metadata.description.clone().unwrap_or_default()
|
||||
} else {
|
||||
"Project specific settings for the KittyCAD modeling app.".to_string()
|
||||
}
|
||||
} else {
|
||||
"Project specific settings for the KittyCAD modeling app.".to_string()
|
||||
};
|
||||
|
||||
// Convert the schema to our template format
|
||||
let project_data = json!({
|
||||
"title": "Project Settings",
|
||||
"description": project_description,
|
||||
"config_type": "Project Configuration",
|
||||
"file_name": "project.toml",
|
||||
"settings": json!(project_schema),
|
||||
"example": PROJECT_SETTINGS_EXAMPLE
|
||||
});
|
||||
|
||||
let project_output = hbs
|
||||
.render("settings", &project_data)
|
||||
.expect("Failed to render project settings documentation");
|
||||
|
||||
expectorate::assert_contents(PROJECT_SETTINGS_DOC_PATH, &project_output);
|
||||
|
||||
// Generate user settings documentation
|
||||
let mut generator = SchemaGenerator::new(settings);
|
||||
let user_schema = Configuration::json_schema(&mut generator);
|
||||
|
||||
// For debugging the schema:
|
||||
// fs::write("/tmp/user_schema.json", serde_json::to_string_pretty(&user_schema).unwrap())
|
||||
// .expect("Failed to write debug schema");
|
||||
|
||||
// Extract the description from the schema metadata
|
||||
let user_description = if let schemars::schema::Schema::Object(obj) = &user_schema {
|
||||
if let Some(metadata) = &obj.metadata {
|
||||
metadata.description.clone().unwrap_or_default()
|
||||
} else {
|
||||
"User-specific configuration options for the KittyCAD modeling app.".to_string()
|
||||
}
|
||||
} else {
|
||||
"User-specific configuration options for the KittyCAD modeling app.".to_string()
|
||||
};
|
||||
|
||||
// Trim any trailing periods to avoid double periods
|
||||
|
||||
let user_data = json!({
|
||||
"title": "User Settings",
|
||||
"description": user_description,
|
||||
"config_type": "User Configuration",
|
||||
"file_name": "user.toml",
|
||||
"settings": json!(user_schema),
|
||||
"example": USER_SETTINGS_EXAMPLE
|
||||
});
|
||||
|
||||
let user_output = hbs
|
||||
.render("settings", &user_data)
|
||||
.expect("Failed to render user settings documentation");
|
||||
|
||||
expectorate::assert_contents(USER_SETTINGS_DOC_PATH, &user_output);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_generate_settings_docs() {
|
||||
// First verify that our TOML examples are valid and match the expected types
|
||||
let _project_config: ProjectConfiguration = toml::from_str(PROJECT_SETTINGS_EXAMPLE)
|
||||
.expect("Project settings example is not valid according to ProjectConfiguration");
|
||||
let _user_config: Configuration = toml::from_str(USER_SETTINGS_EXAMPLE)
|
||||
.expect("User settings example is not valid according to Configuration");
|
||||
|
||||
// Expectorate will verify the output matches what we expect,
|
||||
// or update it if run with EXPECTORATE=overwrite
|
||||
generate_settings_docs();
|
||||
|
||||
// Verify files exist
|
||||
let project_path = PathBuf::from(PROJECT_SETTINGS_DOC_PATH);
|
||||
let user_path = PathBuf::from(USER_SETTINGS_DOC_PATH);
|
||||
assert!(project_path.exists(), "Project settings documentation not generated");
|
||||
assert!(user_path.exists(), "User settings documentation not generated");
|
||||
}
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
//! This module contains settings for kcl projects as well as the modeling app.
|
||||
|
||||
pub mod types;
|
||||
|
||||
#[cfg(test)]
|
||||
mod generate_settings_docs;
|
||||
|
67
rust/kcl-lib/src/settings/templates/settings.hbs
Normal file
67
rust/kcl-lib/src/settings/templates/settings.hbs
Normal file
@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "{{title}}"
|
||||
excerpt: "{{{description}}}"
|
||||
layout: manual
|
||||
---
|
||||
|
||||
# {{title}}
|
||||
|
||||
{{{description}}}
|
||||
|
||||
## {{config_type}} Structure
|
||||
|
||||
```toml
|
||||
{{{example}}}
|
||||
```
|
||||
|
||||
## Available Settings
|
||||
|
||||
{{#with settings.properties}}
|
||||
{{#each this}}
|
||||
### {{@key}}
|
||||
|
||||
{{#if metadata.description}}{{metadata.description}}{{/if}}
|
||||
|
||||
{{#with properties}}
|
||||
{{#each this}}
|
||||
#### {{@key}}
|
||||
|
||||
{{#if description}}{{description}}{{/if}}
|
||||
|
||||
{{#if enum}}
|
||||
**Possible values:** {{pretty_enum enum}}
|
||||
{{/if}}
|
||||
|
||||
**Default:** {{#if default}}{{format_default default}}{{else}}None{{/if}}
|
||||
|
||||
{{#if properties}}
|
||||
This setting has the following nested options:
|
||||
|
||||
{{#each properties}}
|
||||
##### {{@key}}
|
||||
|
||||
{{#if description}}{{description}}{{/if}}
|
||||
|
||||
{{#if enum}}
|
||||
**Possible values:** {{pretty_enum enum}}
|
||||
{{/if}}
|
||||
|
||||
**Default:** {{#if default}}{{format_default default}}{{else}}None{{/if}}
|
||||
|
||||
{{#if properties}}
|
||||
This setting has further nested options. See the schema for full details.
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{/each}}
|
||||
{{/with}}
|
||||
|
||||
{{/each}}
|
||||
{{/with}}
|
||||
|
||||
## Complete Example
|
||||
|
||||
```toml
|
||||
{{{example}}}
|
||||
```
|
@ -11,7 +11,11 @@ use validator::{Validate, ValidateRange};
|
||||
const DEFAULT_THEME_COLOR: f64 = 264.5;
|
||||
const DEFAULT_PROJECT_NAME_TEMPLATE: &str = "project-$nnn";
|
||||
|
||||
/// High level configuration.
|
||||
/// User specific settings for the app.
|
||||
/// These live in `user.toml` in the app's configuration directory.
|
||||
/// Updating the settings in the app will update this file automatically.
|
||||
/// Do not edit this file manually, as it may be overwritten by the app.
|
||||
/// Manual edits can cause corruption of the settings file.
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq, Validate)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
@ -10,7 +10,11 @@ use crate::settings::types::{
|
||||
is_default, AppColor, CommandBarSettings, DefaultTrue, FloatOrInt, OnboardingStatus, TextEditorSettings, UnitLength,
|
||||
};
|
||||
|
||||
/// High level project configuration.
|
||||
/// Project specific settings for the app.
|
||||
/// These live in `project.toml` in the base of the project directory.
|
||||
/// Updating the settings for the project in the app will update this file automatically.
|
||||
/// Do not edit this file manually, as it may be overwritten by the app.
|
||||
/// Manual edits can cause corruption of the settings file.
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, ts_rs::TS, PartialEq, Validate)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
@ -182,13 +182,22 @@ impl Args {
|
||||
}))?;
|
||||
|
||||
T::from_kcl_val(&arg.value).ok_or_else(|| {
|
||||
let expected_type_name = tynm::type_name::<T>();
|
||||
let actual_type_name = arg.value.human_friendly_type();
|
||||
let msg_base = format!("This function expected this argument to be of type {expected_type_name} but it's actually of type {actual_type_name}");
|
||||
let suggestion = match (expected_type_name.as_str(), actual_type_name) {
|
||||
("SolidSet", "Sketch") => Some(
|
||||
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
|
||||
),
|
||||
_ => None,
|
||||
};
|
||||
let message = match suggestion {
|
||||
None => msg_base,
|
||||
Some(sugg) => format!("{msg_base}. {sugg}"),
|
||||
};
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
source_ranges: arg.source_ranges(),
|
||||
message: format!(
|
||||
"Expected a {} but found {}",
|
||||
type_name::<T>(),
|
||||
arg.value.human_friendly_type()
|
||||
),
|
||||
message,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ repository = "https://github.com/kittycad/modeling-app"
|
||||
[lib]
|
||||
name = "kcl"
|
||||
crate-type = ["cdylib"]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
@ -1,50 +0,0 @@
|
||||
// Antenna
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// import constants
|
||||
import height, width, antennaBaseWidth, antennaBaseHeight, antennaTopWidth, antennaTopHeight from "globals.kcl"
|
||||
|
||||
// Calculate the origin
|
||||
origin = [-width / 2 + .45, -0.10]
|
||||
|
||||
// Create the antenna
|
||||
antennaX = origin[0]
|
||||
antennaY = origin[1]
|
||||
|
||||
antennaPlane = {
|
||||
plane = {
|
||||
origin = { x = 0, y = 0, z = height / 2 },
|
||||
xAxis = { x = 1, y = 0, z = 0 },
|
||||
yAxis = { x = 0, y = 1, z = 0 },
|
||||
zAxis = { x = 0, y = 0, z = 1 }
|
||||
}
|
||||
}
|
||||
|
||||
// Create the antenna base sketch
|
||||
sketch001 = startSketchOn(antennaPlane)
|
||||
|> startProfileAt([origin[0], origin[1]], %)
|
||||
|> line(end = [antennaBaseWidth, 0])
|
||||
|> line(end = [0, -antennaBaseHeight])
|
||||
|> line(end = [-antennaBaseWidth, 0])
|
||||
|> close()
|
||||
|
||||
// Create the antenna top sketch
|
||||
loftPlane = offsetPlane('XY', offset = height / 2 + 3)
|
||||
|
||||
sketch002 = startSketchOn(loftPlane)
|
||||
|> startProfileAt([
|
||||
origin[0] + (antennaBaseWidth - antennaTopWidth) / 2,
|
||||
origin[1] - ((antennaBaseHeight - antennaTopHeight) / 2)
|
||||
], %)
|
||||
|> xLine(length = antennaTopWidth)
|
||||
|> yLine(length = -antennaTopHeight)
|
||||
|> xLine(length = -antennaTopWidth)
|
||||
|> close()
|
||||
|
||||
// Create the antenna using a loft
|
||||
loft([sketch001, sketch002])
|
||||
|> appearance(color = "#000000")
|
@ -1,80 +0,0 @@
|
||||
// Walkie talkie body
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import constants
|
||||
import height, width, thickness, chamferLength, offset, screenWidth, screenHeight, screenYPosition, screenDepth, speakerBoxWidth, speakerBoxHeight from "globals.kcl"
|
||||
|
||||
bodySketch = startSketchOn('XZ')
|
||||
|> startProfileAt([-width / 2, height / 2], %)
|
||||
|> xLine(length = width, tag = $chamfer1)
|
||||
|> yLine(length = -height, tag = $chamfer2)
|
||||
|> xLine(length = -width, tag = $chamfer3)
|
||||
|> close(tag = $chamfer4)
|
||||
bodyExtrude = extrude(bodySketch, length = thickness)
|
||||
|> chamfer(
|
||||
length = chamferLength,
|
||||
tags = [
|
||||
getNextAdjacentEdge(chamfer1),
|
||||
getNextAdjacentEdge(chamfer2),
|
||||
getNextAdjacentEdge(chamfer3),
|
||||
getNextAdjacentEdge(chamfer4)
|
||||
]
|
||||
)
|
||||
|
||||
// Define the offset for the indentation
|
||||
sketch002 = startSketchOn(bodyExtrude, 'END')
|
||||
|> startProfileAt([
|
||||
-width / 2 + offset,
|
||||
height / 2 - (chamferLength + offset / 2 * cos(toRadians(45)))
|
||||
], %)
|
||||
|> angledLineToY({ angle = 45, to = height / 2 - offset }, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - (chamferLength + offset / 2 * cos(toRadians(45))),
|
||||
height / 2 - offset
|
||||
])
|
||||
|> angledLineToX({ angle = -45, to = width / 2 - offset }, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - offset,
|
||||
-(height / 2 - (chamferLength + offset / 2 * cos(toRadians(45))))
|
||||
])
|
||||
|> angledLineToY({
|
||||
angle = -135,
|
||||
to = -height / 2 + offset
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
-(width / 2 - (chamferLength + offset / 2 * cos(toRadians(45)))),
|
||||
-height / 2 + offset
|
||||
])
|
||||
|> angledLineToX({
|
||||
angle = -225,
|
||||
to = -width / 2 + offset
|
||||
}, %)
|
||||
|> close()
|
||||
extrude002 = extrude(sketch002, length = -0.0625)
|
||||
|
||||
// Create the pocket for the screen
|
||||
sketch003 = startSketchOn(extrude002, 'start')
|
||||
|> startProfileAt([-screenWidth / 2, screenYPosition], %)
|
||||
|> xLine(length = screenWidth, tag = $seg01)
|
||||
|> yLine(length = -screenHeight)
|
||||
|> xLine(length = -segLen(seg01))
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude003 = extrude(sketch003, length = screenDepth)
|
||||
|
||||
// Create the speaker box
|
||||
sketch004 = startSketchOn(extrude002, 'start')
|
||||
|> startProfileAt([-1.25 / 2, -.125], %)
|
||||
|> xLine(length = speakerBoxWidth)
|
||||
|> yLine(length = -speakerBoxHeight)
|
||||
|> xLine(length = -speakerBoxWidth)
|
||||
|> close()
|
||||
extrude(sketch004, length = -.5)
|
||||
|> appearance(
|
||||
color = "#277bb0",
|
||||
)
|
||||
|
@ -1,38 +0,0 @@
|
||||
// Walkie Talkie button
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import constants
|
||||
import screenHeight, buttonWidth, tolerance, buttonHeight, buttonThickness from 'globals.kcl'
|
||||
|
||||
|
||||
// Create a function for the button
|
||||
export fn button(origin, rotation, plane) {
|
||||
buttonSketch = startSketchOn(plane)
|
||||
|> startProfileAt([origin[0], origin[1]], %)
|
||||
|> angledLine({
|
||||
angle = 180 + rotation,
|
||||
length = buttonWidth
|
||||
}, %, $tag1)
|
||||
|> angledLine({
|
||||
angle = 270 + rotation,
|
||||
length = buttonHeight
|
||||
}, %, $tag2)
|
||||
|> angledLine({
|
||||
angle = 0 + rotation,
|
||||
length = buttonWidth
|
||||
}, %)
|
||||
|> close()
|
||||
buttonExtrude = extrude(buttonSketch, length = buttonThickness)
|
||||
|> chamfer(
|
||||
length = .050,
|
||||
tags = [
|
||||
getNextAdjacentEdge(tag1),
|
||||
getNextAdjacentEdge(tag2)
|
||||
]
|
||||
)
|
||||
|> appearance(color = "#ff0000")
|
||||
|
||||
return buttonExtrude
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
// Walkie talkie case
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import constants and Zoo logo
|
||||
import width, height, chamferLength, offset, screenWidth, screenHeight, screenYPosition, screenDepth, speakerBoxWidth, speakerBoxHeight, squareHoleSideLength, caseTolerance from "globals.kcl"
|
||||
import zLogo, oLogo, oLogo2 from "zoo-logo.kcl"
|
||||
|
||||
plane = offsetPlane("XZ", offset = 1)
|
||||
|
||||
fn screenHole(sketchStart) {
|
||||
sketch006 = startSketchOn(sketchStart)
|
||||
|> startProfileAt([-screenWidth / 2, screenYPosition], %)
|
||||
|> xLine(length = screenWidth)
|
||||
|> yLine(length = -screenHeight)
|
||||
|> xLine(length = -screenWidth)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
return sketch006
|
||||
}
|
||||
|
||||
fn squareHolePattern(plane, x, y) {
|
||||
fn transformX(i) {
|
||||
return { translate = [.125 * i, 0] }
|
||||
}
|
||||
fn transformY(i) {
|
||||
return { translate = [0, -.125 * i] }
|
||||
}
|
||||
squareHolePatternSketch = startSketchOn(plane)
|
||||
|> startProfileAt([-x, -y], %)
|
||||
|> line(end = [squareHoleSideLength / 2, 0])
|
||||
|> line(end = [0, -squareHoleSideLength / 2])
|
||||
|> line(end = [-squareHoleSideLength / 2, 0])
|
||||
|> close()
|
||||
|> patternTransform2d(instances = 13, transform = transformX)
|
||||
|> patternTransform2d(instances = 11, transform = transformY)
|
||||
return squareHolePatternSketch
|
||||
}
|
||||
sketch005 = startSketchOn(offsetPlane("XZ", offset = 1))
|
||||
|> startProfileAt([
|
||||
-width / 2 + offset + caseTolerance,
|
||||
height / 2 - (chamferLength + (offset + caseTolerance) / 2 * cos(toRadians(45)))
|
||||
], %)
|
||||
|> angledLineToY({
|
||||
angle = 45,
|
||||
to = height / 2 - (offset + caseTolerance)
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - (chamferLength + (offset + caseTolerance) / 2 * cos(toRadians(45))),
|
||||
height / 2 - (offset + caseTolerance)
|
||||
])
|
||||
|> angledLineToX({
|
||||
angle = -45,
|
||||
to = width / 2 - (offset + caseTolerance)
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - (offset + caseTolerance),
|
||||
-(height / 2 - (chamferLength + (offset + caseTolerance) / 2 * cos(toRadians(45))))
|
||||
])
|
||||
|> angledLineToY({
|
||||
angle = -135,
|
||||
to = -height / 2 + offset + caseTolerance
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
-(width / 2 - (chamferLength + (offset + caseTolerance) / 2 * cos(toRadians(45)))),
|
||||
-height / 2 + offset + caseTolerance
|
||||
])
|
||||
|> angledLineToX({
|
||||
angle = -225,
|
||||
to = -width / 2 + offset + caseTolerance
|
||||
}, %)
|
||||
|> close()
|
||||
|> hole(screenHole(plane), %)
|
||||
|> hole(squareHolePattern(plane, .75, .125), %)
|
||||
|> hole(zLogo(plane, [-.30, -1.825], .20), %)
|
||||
|> hole(oLogo(plane, [-.075, -1.825], .20), %)
|
||||
|> hole(oLogo2(plane, [-.075, -1.825], .20), %)
|
||||
|> hole(oLogo(plane, [.175, -1.825], .20), %)
|
||||
|> hole(oLogo2(plane, [.175, -1.825], .20), %)
|
||||
|
||||
extrude(sketch005, length = -0.0625)
|
||||
|> appearance(color = '#D0FF01', metalness = 0, roughness = 50)
|
@ -1,42 +0,0 @@
|
||||
// Global constants for the walkie talkie
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// body
|
||||
export height = 4
|
||||
export width = 2.5
|
||||
export thickness = 1
|
||||
export chamferLength = .325
|
||||
export offset = .125
|
||||
export screenWidth = 1.75
|
||||
export screenHeight = 1
|
||||
export screenYPosition = height / 2 - 0.75
|
||||
export screenDepth = -.0625
|
||||
export speakerBoxWidth = 1.25
|
||||
export speakerBoxHeight = 1.25
|
||||
|
||||
// antenna
|
||||
export antennaBaseWidth = .5
|
||||
export antennaBaseHeight = .25
|
||||
export antennaTopWidth = .30
|
||||
export antennaTopHeight = .05
|
||||
|
||||
// button
|
||||
export buttonWidth = .15
|
||||
export tolerance = 0.020
|
||||
export buttonHeight = screenHeight / 2 - tolerance
|
||||
export buttonThickness = .040
|
||||
|
||||
// case
|
||||
export squareHoleSideLength = 0.0625
|
||||
export caseTolerance = 0.010
|
||||
|
||||
// knob
|
||||
export knobDiameter = .5
|
||||
export knobHeight = .25
|
||||
export knobRadius = 0.050
|
||||
|
||||
// talk-button
|
||||
export talkButtonSideLength = 0.5
|
||||
export talkButtonHeight = 0.050
|
@ -1,38 +0,0 @@
|
||||
// Walkie talkie knob
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import constants
|
||||
import width, thickness, height, knobDiameter, knobHeight, knobRadius from "globals.kcl"
|
||||
|
||||
// Define the plane for the knob
|
||||
knobPlane = {
|
||||
plane = {
|
||||
origin = {
|
||||
x = width / 2 - 0.70,
|
||||
y = -thickness / 2,
|
||||
z = height / 2
|
||||
},
|
||||
xAxis = { x = 1, y = 0, z = 0 },
|
||||
yAxis = { x = 0, y = 0, z = 1 },
|
||||
zAxis = { x = 0, y = 1, z = 0 }
|
||||
}
|
||||
}
|
||||
|
||||
// Create the knob sketch and revolve
|
||||
startSketchOn(knobPlane)
|
||||
|> startProfileAt([0.0001, 0], %)
|
||||
|> xLine(length = knobDiameter / 2)
|
||||
|> yLine(length = knobHeight - 0.05)
|
||||
|> arc({
|
||||
angleStart = 0,
|
||||
angleEnd = 90,
|
||||
radius = .05
|
||||
}, %)
|
||||
|> xLine(endAbsolute = 0.0001)
|
||||
|> close()
|
||||
|> revolve({ axis = "Y" }, %)
|
||||
|> appearance(color = '#D0FF01', metalness = 90, roughness = 50)
|
@ -1,50 +0,0 @@
|
||||
// Walkie Talkie
|
||||
// A portable, handheld two-way radio device that allows users to communicate wirelessly over short to medium distances. It operates on specific radio frequencies and features a push-to-talk button for transmitting messages, making it ideal for quick and reliable communication in outdoor, work, or emergency settings.
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parts and constants
|
||||
import 'body.kcl'
|
||||
import 'antenna.kcl'
|
||||
import 'case.kcl'
|
||||
import 'talk-button.kcl' as talkButton
|
||||
import 'knob.kcl'
|
||||
import button from "button.kcl"
|
||||
import width, height, thickness, screenWidth, screenHeight, screenYPosition, tolerance from "globals.kcl"
|
||||
|
||||
// Import the body
|
||||
body
|
||||
|
||||
// Import the case
|
||||
case
|
||||
|
||||
// Import the antenna
|
||||
antenna
|
||||
|
||||
// Import the buttons
|
||||
button([
|
||||
-(screenWidth / 2 + tolerance),
|
||||
screenYPosition
|
||||
], 0, offsetPlane("XZ", offset = thickness))
|
||||
button([
|
||||
-(screenWidth / 2 + tolerance),
|
||||
screenYPosition - (screenHeight / 2)
|
||||
], 0, offsetPlane("XZ", offset = thickness))
|
||||
button([
|
||||
screenWidth / 2 + tolerance,
|
||||
screenYPosition - screenHeight
|
||||
], 180, offsetPlane("XZ", offset = thickness))
|
||||
button([
|
||||
screenWidth / 2 + tolerance,
|
||||
screenYPosition - (screenHeight / 2)
|
||||
], 180, offsetPlane("XZ", offset = thickness))
|
||||
|
||||
// Import the talk button
|
||||
talkButton
|
||||
|
||||
// Import the frequency knob
|
||||
knob
|
||||
|
||||
|
||||
|
@ -1,46 +0,0 @@
|
||||
// Walkie talkie talk button
|
||||
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
|
||||
// Import constants
|
||||
import width, thickness, talkButtonSideLength, talkButtonHeight from "globals.kcl"
|
||||
|
||||
talkButtonPlane = {
|
||||
plane = {
|
||||
origin = {
|
||||
x = width / 2,
|
||||
y = -thickness / 2,
|
||||
z = .5
|
||||
},
|
||||
xAxis = { x = 0, y = 1, z = 0 },
|
||||
yAxis = { x = 0, y = 0, z = 1 },
|
||||
zAxis = { x = 1, y = 0, z = 0 }
|
||||
}
|
||||
}
|
||||
|
||||
// Create the talk button sketch
|
||||
talkButtonSketch = startSketchOn(talkButtonPlane)
|
||||
|> startProfileAt([
|
||||
-talkButtonSideLength / 2,
|
||||
talkButtonSideLength / 2
|
||||
], %)
|
||||
|> xLine(length = talkButtonSideLength, tag = $tag1)
|
||||
|> yLine(length = -talkButtonSideLength, tag = $tag2)
|
||||
|> xLine(length = -talkButtonSideLength, tag = $tag3)
|
||||
|> close(tag = $tag4)
|
||||
|
||||
// Create the talk button and apply fillets
|
||||
extrude(talkButtonSketch, length = talkButtonHeight)
|
||||
|> fillet(
|
||||
radius = 0.050,
|
||||
tags = [
|
||||
getNextAdjacentEdge(tag1),
|
||||
getNextAdjacentEdge(tag2),
|
||||
getNextAdjacentEdge(tag3),
|
||||
getNextAdjacentEdge(tag4)
|
||||
]
|
||||
)
|
||||
|> appearance(color = '#D0FF01', metalness = 90, roughness = 90)
|
@ -1,83 +0,0 @@
|
||||
// Zoo logo
|
||||
|
||||
// Define a function to draw the ZOO "Z"
|
||||
export fn zLogo(surface, origin, scale) {
|
||||
zSketch = surface
|
||||
|> startProfileAt([
|
||||
0 + origin[0],
|
||||
0.15 * scale + origin[1]
|
||||
], %)
|
||||
|> yLine(length = -0.15 * scale)
|
||||
|> xLine(length = 0.15 * scale)
|
||||
|> angledLineToX({
|
||||
angle = 47.15,
|
||||
to = 0.3 * scale + origin[0]
|
||||
}, %, $seg1)
|
||||
|> yLine(endAbsolute = 0 + origin[1], tag = $seg3)
|
||||
|> xLine(length = 0.63 * scale)
|
||||
|> yLine(length = 0.225 * scale)
|
||||
|> xLine(length = -0.57 * scale)
|
||||
|> angledLineToX({
|
||||
angle = 47.15,
|
||||
to = 0.93 * scale + origin[0]
|
||||
}, %)
|
||||
|> yLine(length = 0.15 * scale)
|
||||
|> xLine(length = -0.15 * scale)
|
||||
|> angledLine({
|
||||
angle = 47.15,
|
||||
length = -segLen(seg1)
|
||||
}, %, $seg2)
|
||||
|> yLine(length = segLen(seg3))
|
||||
|> xLine(endAbsolute = 0 + origin[0])
|
||||
|> yLine(length = -0.225 * scale)
|
||||
|> angledLineThatIntersects({
|
||||
angle = 0,
|
||||
intersectTag = seg2,
|
||||
offset = 0
|
||||
}, %)
|
||||
|> close()
|
||||
return zSketch
|
||||
}
|
||||
|
||||
// Define a function to draw the ZOO "O"
|
||||
export fn oLogo(surface, origin, scale) {
|
||||
oSketch001 = surface
|
||||
|> startProfileAt([
|
||||
.788 * scale + origin[0],
|
||||
.921 * scale + origin[1]
|
||||
], %)
|
||||
|> arc({
|
||||
angleStart = 47.15 + 6,
|
||||
angleEnd = 47.15 - 6 + 180,
|
||||
radius = .525 * scale
|
||||
}, %)
|
||||
|> angledLine({ angle = 47.15, length = .24 * scale }, %)
|
||||
|> arc({
|
||||
angleStart = 47.15 - 11 + 180,
|
||||
angleEnd = 47.15 + 11,
|
||||
radius = .288 * scale
|
||||
}, %)
|
||||
|> close()
|
||||
return oSketch001
|
||||
}
|
||||
|
||||
export fn oLogo2(surface, origin, scale) {
|
||||
oSketch002 = surface
|
||||
|> startProfileAt([
|
||||
.16 * scale + origin[0],
|
||||
.079 * scale + origin[1]
|
||||
], %)
|
||||
|> arc({
|
||||
angleStart = 47.15 + 6 - 180,
|
||||
angleEnd = 47.15 - 6,
|
||||
radius = .525 * scale
|
||||
}, %)
|
||||
|> angledLine({ angle = 47.15, length = -.24 * scale }, %)
|
||||
|> arc({
|
||||
angleStart = 47.15 - 11,
|
||||
angleEnd = 47.15 + 11 - 180,
|
||||
radius = .288 * scale
|
||||
}, %)
|
||||
|> close()
|
||||
return oSketch002
|
||||
}
|
@ -10,7 +10,15 @@ kcl_dir = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)), "..", "..", "kcl-lib"
|
||||
)
|
||||
lego_file = os.path.join(kcl_dir, "e2e", "executor", "inputs", "lego.kcl")
|
||||
walkie_talkie_dir = os.path.join(files_dir, "walkie-talkie")
|
||||
walkie_talkie_dir = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)),
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"public",
|
||||
"kcl-samples",
|
||||
"walkie-talkie",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
@ -5,6 +5,9 @@ version = "0.1.47"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.95"
|
||||
hyper = { version = "0.14.29", features = ["http1", "server", "tcp"] }
|
||||
|
@ -8,10 +8,12 @@ repository = "https://github.com/KittyCAD/modeling-app"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[[bin]]
|
||||
name = "kcl-to-core"
|
||||
path = "src/tool.rs"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
@ -8,6 +8,7 @@ publish = false
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
bench = false
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
bson = { version = "2.13.0", features = ["uuid-1", "chrono"] }
|
||||
|
Reference in New Issue
Block a user