generate the settings docs (#5740)

* generate the settings docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fmt

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* Update docs/kcl/settings.md

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2025-03-10 18:59:10 -07:00
committed by GitHub
parent 310932dc5a
commit 546b4ea3b8
9 changed files with 812 additions and 6 deletions

View File

@ -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)

View 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"
```

View 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
```

View File

@ -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.

View 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");
}
}

View File

@ -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;

View 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}}}
```

View File

@ -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")]

View File

@ -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")]