Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 43279810a5 | |||
| c61a7b605a | |||
| 3392b7e4d3 | |||
| 341202f87c |
@@ -171,7 +171,7 @@ impl App {
|
|||||||
// that asks for more width than there is would otherwise push it
|
// that asks for more width than there is would otherwise push it
|
||||||
// wider every frame.
|
// wider every frame.
|
||||||
.width_range(160.0..=460.0)
|
.width_range(160.0..=460.0)
|
||||||
.show_animated(ctx, show_files, |ui| {
|
.show(ctx, show_files, |ui| {
|
||||||
// The default theme renders unselected list rows fairly dim; bump
|
// The default theme renders unselected list rows fairly dim; bump
|
||||||
// the widget text colours so file names stay legible (especially in
|
// the widget text colours so file names stay legible (especially in
|
||||||
// dark mode) without affecting the rest of the app.
|
// dark mode) without affecting the rest of the app.
|
||||||
|
|||||||
+3
-3
@@ -61,7 +61,7 @@ impl App {
|
|||||||
self.np_status = format!("{} already exists.", parent.join(&name).display());
|
self.np_status = format!("{} already exists.", parent.join(&name).display());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let template = self.config.project_template.clone();
|
let template = self.config.effective_project_template();
|
||||||
|
|
||||||
// Check that the template directory exists
|
// Check that the template directory exists
|
||||||
if !template.is_dir() {
|
if !template.is_dir() {
|
||||||
@@ -600,8 +600,8 @@ impl App {
|
|||||||
|
|
||||||
if browse_template {
|
if browse_template {
|
||||||
let mut dialog = rfd::FileDialog::new().set_title("Choose a cookiecutter template");
|
let mut dialog = rfd::FileDialog::new().set_title("Choose a cookiecutter template");
|
||||||
if self.config.project_template.is_dir() {
|
if self.config.effective_project_template().is_dir() {
|
||||||
dialog = dialog.set_directory(&self.config.project_template);
|
dialog = dialog.set_directory(&self.config.effective_project_template());
|
||||||
}
|
}
|
||||||
if let Some(path) = dialog.pick_folder() {
|
if let Some(path) = dialog.pick_folder() {
|
||||||
self.config.project_template = path;
|
self.config.project_template = path;
|
||||||
|
|||||||
+53
-16
@@ -189,29 +189,34 @@ pub fn default_show_toolbar() -> bool {
|
|||||||
pub fn default_project_template() -> PathBuf {
|
pub fn default_project_template() -> PathBuf {
|
||||||
// Find the bundled template relative to the executable's location
|
// Find the bundled template relative to the executable's location
|
||||||
if let Ok(exe_path) = std::env::current_exe() {
|
if let Ok(exe_path) = std::env::current_exe() {
|
||||||
// The templates are at the project root level, same as Cargo.toml
|
// Walk up from the executable's directory looking for templates/snowflake/cookiecutter.json
|
||||||
// binary is typically at target/release/md-manuscript or target/debug/md-manuscript
|
// This handles various build configurations (release, debug, cargo run, installed binary)
|
||||||
// So we need to go up from target/release (or target/debug) to the project root
|
let mut current = exe_path.parent().unwrap_or_else(|| exe_path.as_path());
|
||||||
// Then look for templates/snowflake there
|
loop {
|
||||||
let candidates = [
|
// Check if current/templates/snowflake/cookiecutter.json exists
|
||||||
// Binary in target/release/ -> project root -> templates/snowflake
|
let candidate = current.join("templates/snowflake");
|
||||||
exe_path.parent().and_then(|p| p.parent()).and_then(|p| p.parent()).map(|p| p.join("templates/snowflake")),
|
if candidate.join("cookiecutter.json").is_file() {
|
||||||
// Binary in target/debug/ -> project root -> templates/snowflake
|
return candidate;
|
||||||
exe_path.parent().and_then(|p| p.parent()).map(|p| p.join("templates/snowflake")),
|
}
|
||||||
// Binary in project root (dev) -> templates/snowflake
|
// Try going up one level
|
||||||
exe_path.parent().map(|p| p.join("templates/snowflake")),
|
match current.parent() {
|
||||||
// Fallback: relative to current working directory
|
Some(parent) => current = parent,
|
||||||
std::env::current_dir().ok().map(|p| p.join("templates/snowflake")),
|
None => break,
|
||||||
];
|
}
|
||||||
for candidate in candidates.into_iter().flatten() {
|
}
|
||||||
|
|
||||||
|
// Also try relative to current working directory
|
||||||
|
if let Ok(cwd) = std::env::current_dir() {
|
||||||
|
let candidate = cwd.join("templates/snowflake");
|
||||||
if candidate.join("cookiecutter.json").is_file() {
|
if candidate.join("cookiecutter.json").is_file() {
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can't find the bundled template, panic with a clear error
|
// If we can't find the bundled template, panic with a clear error
|
||||||
// The bundled template should always be present in a properly built release
|
// The bundled template should always be present in a properly built release
|
||||||
panic!("Bundled template not found. Please ensure templates/snowflake/ exists relative to the executable.");
|
panic!("Bundled template not found. Please ensure templates/snowflake/cookiecutter.json exists relative to the executable.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default subfolder opened after generating a project: the snowflake
|
/// Default subfolder opened after generating a project: the snowflake
|
||||||
@@ -422,6 +427,17 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The project template path to use, falling back to the bundled template
|
||||||
|
/// if the saved path doesn't exist.
|
||||||
|
pub fn effective_project_template(&self) -> PathBuf {
|
||||||
|
// If the saved template path exists and has cookiecutter.json, use it
|
||||||
|
if self.project_template.join("cookiecutter.json").is_file() {
|
||||||
|
return self.project_template.clone();
|
||||||
|
}
|
||||||
|
// Otherwise fall back to the bundled template
|
||||||
|
default_project_template()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load() -> Config {
|
pub fn load() -> Config {
|
||||||
let path = config_path();
|
let path = config_path();
|
||||||
match std::fs::read_to_string(&path) {
|
match std::fs::read_to_string(&path) {
|
||||||
@@ -595,5 +611,26 @@ mod tests {
|
|||||||
// Verify it returns a valid path that contains cookiecutter.json
|
// Verify it returns a valid path that contains cookiecutter.json
|
||||||
assert!(path.join("cookiecutter.json").is_file(),
|
assert!(path.join("cookiecutter.json").is_file(),
|
||||||
"Template path {} should contain cookiecutter.json", path.display());
|
"Template path {} should contain cookiecutter.json", path.display());
|
||||||
|
|
||||||
|
// Also verify it's using the bundled template (contains "templates/snowflake")
|
||||||
|
let path_str = path.to_string_lossy();
|
||||||
|
assert!(path_str.contains("templates/snowflake"),
|
||||||
|
"Template path {} should be the bundled template", path.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bundled_template_contains_05_first_draft() {
|
||||||
|
let path = default_project_template();
|
||||||
|
let template_dir = path.join("{{ cookiecutter.project_name }}");
|
||||||
|
|
||||||
|
// Verify the template has the merged 05-First Draft folder
|
||||||
|
assert!(template_dir.join("05-First Draft").is_dir(),
|
||||||
|
"Bundled template should contain 05-First Draft directory");
|
||||||
|
|
||||||
|
// Verify it does NOT have the old separate directories
|
||||||
|
assert!(!template_dir.join("05-Plot").is_dir(),
|
||||||
|
"Bundled template should NOT contain old 05-Plot directory");
|
||||||
|
assert!(!template_dir.join("06-First Draft").is_dir(),
|
||||||
|
"Bundled template should NOT contain old 06-First Draft directory");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user