Phases 0-1 + Sprint A: module split, CLI layer, org-refresh fix, hygiene
- LICENSE (MIT) + README truth-pass; docs/cli.md CLI contract - CLI subcommands (src/cli_cmds/) per "TUI for users, CLI for users+AI" - Hub/detail refactor: keymap dispatch, modal split, action enum, BgMsg bus - Fix: org repos were never refreshed (owner==username match); refresh now parallel — 49 repos in ~11s, surfaced 70 previously invisible PRs - Fix: 3 date bugs in detail/git.rs (format-local, Local::now, 1y month math) - Stash indicator + [m] actions, session persistence, gh CLI token fallback - Legacy UI modules removed; plan/ docs (roadmap, audit, debate, handoff)
This commit is contained in:
1 parent
5787b14880
commit
0468c032c6
100 files changed
+11614
-9840
No files matched your search
@@ -0,0 +1,48 @@
|
||||
//! Session persistence (`~/.vulp/session.toml`): remembers the active tab
|
||||
//! and the repo under the cursor between runs. Deliberately tiny — filters
|
||||
//! and text search are NOT restored (surprising UX), only "where was I".
|
||||
|
||||
use super::state::Tab;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
pub struct Session {
|
||||
#[serde(default)]
|
||||
pub tab: u8,
|
||||
#[serde(default)]
|
||||
pub cursor_repo_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
fn path() -> PathBuf {
|
||||
dirs::home_dir().unwrap_or_else(|| PathBuf::from("~")).join(".vulp").join("session.toml")
|
||||
}
|
||||
|
||||
pub fn tab_to_u8(tab: Tab) -> u8 {
|
||||
match tab {
|
||||
Tab::Overview => 0, Tab::Repos => 1, Tab::Projects => 2, Tab::Todos => 3,
|
||||
Tab::PRs => 4, Tab::Issues => 5, Tab::Stats => 6, Tab::Activity => 7,
|
||||
Tab::HubSettings => 8,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn u8_to_tab(v: u8) -> Tab {
|
||||
match v {
|
||||
1 => Tab::Repos, 2 => Tab::Projects, 3 => Tab::Todos, 4 => Tab::PRs,
|
||||
5 => Tab::Issues, 6 => Tab::Stats, 7 => Tab::Activity, 8 => Tab::HubSettings,
|
||||
_ => Tab::Overview,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load() -> Session {
|
||||
let p = path();
|
||||
if !p.exists() { return Session::default(); }
|
||||
toml::from_str(&std::fs::read_to_string(p).unwrap_or_default()).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn save(tab: Tab, cursor_repo_path: Option<PathBuf>) {
|
||||
let s = Session { tab: tab_to_u8(tab), cursor_repo_path };
|
||||
let p = path();
|
||||
if let Some(d) = p.parent() { let _ = std::fs::create_dir_all(d); }
|
||||
if let Ok(body) = toml::to_string_pretty(&s) { let _ = std::fs::write(p, body); }
|
||||
}
|
||||
Reference in new issue
Block a user