Iteration 4b: save / save as / new / load with project switching
Adds the rest of the track-2 lifecycle commands (ADR-0015 §11) and the project-switching machinery they need at runtime. Temp vs named distinction: replaced the fragile naming heuristic with an explicit `[temp]` marker in the directory pattern (`<YYYYMMDD>-[temp]-<word>-<word>-<word>`). validate_user_name already rejects brackets, so user-typed names can never collide with a temp marker. The status bar shows `[TEMP] <Display Name>` for temp projects; the prettifier strips both the date and the marker so display names are clean. save / save as: temp project's `save` opens a path-entry modal (acts as save as); named project's `save` reports "already auto-saved; use `save as`". `save as` always prompts. Relative names resolve under <data-root>/projects/; absolute paths used as-is. Copy excludes the per-process lock file; everything else (.db, yaml, csvs, history.log) is copied. new: closes current project, creates a fresh auto-named temp, switches. load: opens a picker. List sub-mode shows projects in the active data root, sorted newest-first by project.yaml mtime; arrow keys navigate, Enter loads, `b` switches to a path-entry sub-mode for projects elsewhere, Esc cancels. Empty data root jumps straight to path entry. Runtime: `Session` holds Option<Project> + Option<Database> so project switches can drop old (releasing lock + stopping worker) before opening new -- required for the "load my own current project" case. `perform_switch` handles Load / SaveAs / NewTemp uniformly. Tests: 332 passing (270 lib + 9 + 5 + 6 + 16 new + 9 + 17), 0 failing, 0 skipped. Clippy clean.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#[must_use]
|
||||
pub fn prettify(dirname: &str) -> String {
|
||||
let trimmed = strip_date_prefix(dirname);
|
||||
let trimmed = strip_temp_marker(trimmed);
|
||||
let words = split_into_words(trimmed);
|
||||
words
|
||||
.into_iter()
|
||||
@@ -29,6 +30,14 @@ pub fn prettify(dirname: &str) -> String {
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
/// Strip a leading `[temp]-` segment if present. Temp project
|
||||
/// directory names look like `20260507-[temp]-water-buffalo-skating`
|
||||
/// after `strip_date_prefix`, this removes the marker so the
|
||||
/// display name reduces to just the three random words.
|
||||
fn strip_temp_marker(s: &str) -> &str {
|
||||
s.strip_prefix("[temp]-").unwrap_or(s)
|
||||
}
|
||||
|
||||
/// Strip a leading `YYYYMMDD-` if present. Eight ASCII digits
|
||||
/// followed by a single `-` are required; anything else is
|
||||
/// returned unchanged.
|
||||
@@ -123,6 +132,14 @@ mod tests {
|
||||
assert_eq!(prettify("20260507-water-buffalo-skating"), "Water Buffalo Skating");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strips_date_and_temp_marker() {
|
||||
assert_eq!(
|
||||
prettify("20260507-[temp]-water-buffalo-skating"),
|
||||
"Water Buffalo Skating",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handles_pascal_case() {
|
||||
assert_eq!(prettify("MyOrders"), "My Orders");
|
||||
|
||||
Reference in New Issue
Block a user