Coverage for src/secchi/workspace/state.py: 100%
24 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-04 22:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-04 22:15 +0000
1"""Pure state transitions for workspace navigation and lazy loading."""
3from __future__ import annotations
5from dataclasses import dataclass, field
7from secchi.models import PackageRef
10@dataclass
11class WorkspaceState:
12 """Track selection and per-project loading without depending on Textual."""
14 selected_ref: PackageRef | None = None
15 loaded_projects: set[str] = field(default_factory=set)
16 loading_projects: set[str] = field(default_factory=set)
18 def select(self, ref: PackageRef) -> None:
19 self.selected_ref = ref
21 def should_load(self, project_name: str, *, force: bool = False) -> bool:
22 """Return whether a project fetch may start now."""
23 if project_name in self.loading_projects:
24 return False
25 return force or project_name not in self.loaded_projects
27 def begin_load(self, project_name: str, *, force: bool = False) -> bool:
28 """Mark a project as loading, returning false when it should be skipped."""
29 if not self.should_load(project_name, force=force):
30 return False
31 self.loading_projects.add(project_name)
32 return True
34 def finish_load(self, project_name: str) -> None:
35 """Mark a project as loaded after a successful or partial fetch."""
36 self.loading_projects.discard(project_name)
37 self.loaded_projects.add(project_name)
39 def cancel_load(self, project_name: str) -> None:
40 """Clear an in-flight marker when a fetch is cancelled or fails to start."""
41 self.loading_projects.discard(project_name)