From c0329c8e450a213455c28f7c7f4aa27877475cab Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Sat, 15 Aug 2026 17:43:19 +0800 Subject: [PATCH 1/2] chore: add esp32h2 to init chip options, bump to 0.1.0 rmk-template gained esp32h2 and esp32h2_split templates, but 'rmkit init' had no way to pick them. 0.1.0 rather than 0.0.22: the layout subcommands are a new surface, and the 0.0.x series predates the rmk-rs migration. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/chip.rs | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0cd4992..a66c79b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1785,7 +1785,7 @@ dependencies = [ [[package]] name = "rmkit" -version = "0.0.21" +version = "0.1.0" dependencies = [ "cargo_metadata", "cargo_toml", diff --git a/Cargo.toml b/Cargo.toml index 0b73b62..970a617 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rmkit" -version = "0.0.21" +version = "0.1.0" edition = "2021" homepage = "https://github.com/rmk-rs/rmkit" repository = "https://github.com/rmk-rs/rmkit" diff --git a/src/chip.rs b/src/chip.rs index 84bc386..e558580 100644 --- a/src/chip.rs +++ b/src/chip.rs @@ -27,6 +27,7 @@ pub(crate) fn get_chip_options(split: bool) -> Vec<&'static str> { "Pi Pico W", "esp32c3", "esp32c6", + "esp32h2", "esp32s3", ] } else { @@ -41,6 +42,7 @@ pub(crate) fn get_chip_options(split: bool) -> Vec<&'static str> { "esp32c3", "esp32s3", "esp32c6", + "esp32h2", "nice!nano_v2", "XIAO BLE", "nice!nano", From 9286a6192afe48827e3d3e376cf8b19e5d1570f4 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Mon, 17 Aug 2026 11:17:59 +0800 Subject: [PATCH 2/2] feat(create): use the user's Cargo.toml / memory.x next to keyboard.toml as-is MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A `Cargo.toml` or `memory.x` sitting next to keyboard.toml replaces the template's copy verbatim, so a project can add rmk features, pin dependencies, or change the flash layout without touching the template or the cloud build workflow. When the user provides Cargo.toml, rmkit no longer adjusts the rmk feature list — keyboard.toml/feature mismatches are reported by rmk-macro at build time. Claude-Session: https://claude.ai/code/session_01YPLK88rkh5jqoHmRUdAvUN --- README.md | 2 ++ src/args.rs | 3 ++- src/main.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e54173b..87224bc 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ Now rmkit can be used to generate RMK project directly from `keyboard.toml` and rmkit create --keyboard-toml-path keyboard.toml --vial-json-path vial.json ``` + A `Cargo.toml` or `memory.x` next to `keyboard.toml` replaces the template's copy as-is — use it to add Cargo features, pin dependencies, or change the flash layout. When you provide `Cargo.toml`, rmkit no longer adjusts the `rmk` features for you. + 3. Or, you can create RMK project from project template ``` diff --git a/src/args.rs b/src/args.rs index 0f433bf..8d8eec8 100644 --- a/src/args.rs +++ b/src/args.rs @@ -11,7 +11,8 @@ pub struct Args { pub enum Commands { /// Create a new RMK project from keyboard.toml and vial.json Create { - /// Path to keyboard.toml file + /// Path to keyboard.toml file. A Cargo.toml or memory.x next to it + /// replaces the template's copy verbatim. #[arg(long)] keyboard_toml_path: Option, diff --git a/src/main.rs b/src/main.rs index 56e108d..80a7cf7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -106,14 +106,42 @@ async fn create_project( )?; fs::copy(&vial_json_path, project_info.target_dir.join("vial.json"))?; + // A Cargo.toml / memory.x next to keyboard.toml is the user's, verbatim + let user_dir = Path::new(&keyboard_toml_path) + .parent() + .unwrap_or(Path::new("")); + let cargo_toml_user_owned = copy_user_owned_files(user_dir, &project_info.target_dir)?; + // Post-process - post_process(project_info)?; + post_process(project_info, cargo_toml_user_owned)?; Ok(()) } +/// Files that replace the template's copy when they sit next to keyboard.toml +const USER_OWNED_FILES: [&str; 2] = ["Cargo.toml", "memory.x"]; + +/// Copy the user's own project files over the generated project. Returns whether +/// Cargo.toml was among them — the user then owns the feature list too. +fn copy_user_owned_files(user_dir: &Path, target_dir: &Path) -> Result> { + let mut cargo_toml_user_owned = false; + for name in USER_OWNED_FILES { + let src = user_dir.join(name); + if !src.is_file() { + continue; + } + fs::copy(&src, target_dir.join(name))?; + println!("📄 Using {} (replaces the template's)", src.display()); + cargo_toml_user_owned |= name == "Cargo.toml"; + } + Ok(cargo_toml_user_owned) +} + /// Postprocessing after generating project -fn post_process(project_info: ProjectInfo) -> Result<(), Box> { +fn post_process( + project_info: ProjectInfo, + cargo_toml_user_owned: bool, +) -> Result<(), Box> { // Replace {{ project_name }} in toml/json files replace_in_folder( &project_info, @@ -139,6 +167,13 @@ fn post_process(project_info: ProjectInfo) -> Result<(), Box> { &project_info.uf2_key, )?; + // The user's Cargo.toml is used as-is; keyboard.toml/feature mismatches are + // reported by rmk-macro at build time. + if cargo_toml_user_owned { + println!("Skipping rmk feature adjustments: Cargo.toml is user-provided"); + return Ok(()); + } + // Disable some default features if !project_info.disabled_default_feature.is_empty() { let metadata = MetadataCommand::new() @@ -279,7 +314,7 @@ async fn init_project( } // Post-process - post_process(project_info)?; + post_process(project_info, false)?; Ok(()) } @@ -596,3 +631,36 @@ fn enable_rmk_features(target_dir: &PathBuf, features: Vec) -> Result<() Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn user_owned_files_replace_template_copies() { + let root = std::env::temp_dir().join(format!("rmkit_user_owned_{}", std::process::id())); + let (user_dir, target_dir) = (root.join("user"), root.join("target")); + fs::create_dir_all(&user_dir).unwrap(); + fs::create_dir_all(&target_dir).unwrap(); + fs::write(target_dir.join("Cargo.toml"), "template").unwrap(); + fs::write(target_dir.join("memory.x"), "template").unwrap(); + let generated = |name: &str| fs::read_to_string(target_dir.join(name)).unwrap(); + + // Nothing next to keyboard.toml: template files stay, Cargo.toml is not user-owned + assert!(!copy_user_owned_files(&user_dir, &target_dir).unwrap()); + assert_eq!(generated("Cargo.toml"), "template"); + + // Only memory.x provided: it replaces the template's, Cargo.toml is still rmkit's + fs::write(user_dir.join("memory.x"), "user").unwrap(); + assert!(!copy_user_owned_files(&user_dir, &target_dir).unwrap()); + assert_eq!(generated("memory.x"), "user"); + assert_eq!(generated("Cargo.toml"), "template"); + + // Cargo.toml provided: replaced verbatim and reported as user-owned + fs::write(user_dir.join("Cargo.toml"), "user").unwrap(); + assert!(copy_user_owned_files(&user_dir, &target_dir).unwrap()); + assert_eq!(generated("Cargo.toml"), "user"); + + fs::remove_dir_all(&root).unwrap(); + } +}