Workspace Mode Implementation Roadmap
Vision: Transform fac into a workspace-aware editor with persistent state and Fortress-based navigation.
Timeline: 7 phases, estimated 15-20 sessions total
Phase 0: Planning & Design
Duration: 1 session Objective: Document architecture and create foundational specs
Tasks
- Define workspace data structures
- Design
.fac/directory structure - Design
~/.config/fac/structure - Create workspace.json schema
- Create favorites.json schema
- Document Fortress integration points
- Plan module dependencies
Deliverables
docs/
workspace_spec.md # Workspace JSON format
fortress_integration.md # How fortress modules integrate
config_spec.md # Config file formats
Files to Create
docs/workspace_spec.mddocs/fortress_integration.mddocs/config_spec.md
Success Criteria
- ✅ Clear data structure specifications
- ✅ Agreed-upon file formats
- ✅ Module integration plan documented
Phase 1: Fortress Navigator Foundation
Duration: 3-4 sessions Objective: Build basic dual-pane file/directory navigator (Ctrl-O)
Tasks
- Copy fortress filesystem modules into fac
src/fortress/filesystem/(directory reading, path handling)
- Copy fortress terminal modules
src/fortress/terminal/(rendering utilities)
- Adapt fortress UI for embedded mode
src/fortress/ui/(dual-pane display, navigation)
- Implement dual-pane rendering
- Left pane: parent directory (30%)
- Right pane: current directory (70%)
- Add navigation keybindings
- ↑/↓: Move cursor
- →: Enter directory
- ←: Go to parent
- ~/: Jump to home/root
- q: Cancel/exit
- Enter: Select (return selection)
- Add Ctrl-O keybinding to main editor
- Modal Fortress UI (takes over screen, returns selection)
Files to Create
src/fortress/
filesystem/
directory_module.f90 # Read dirs, list files
path_utils_module.f90 # Path manipulation
terminal/
fortress_render_module.f90 # Rendering utilities
ui/
dual_pane_module.f90 # Dual-pane display
navigator_module.f90 # Main navigation logic
Files to Modify
src/commands/command_handler_module.f90(add Ctrl-O handler)Makefile(add fortress modules to build)
Success Criteria
- ✅ Ctrl-O opens dual-pane navigator
- ✅ Can navigate filesystem
- ✅ Selecting directory returns path
- ✅ Selecting file returns path
- ✅ ESC/q cancels and returns to editor
- ✅ Visual styling matches fac aesthetic
Testing Checkpoints
- Navigate to various directories
- Test with long file lists (scrolling)
- Test with deep directory trees
- Test cancellation (ESC)
Phase 2: Workspace Detection & Configuration
Duration: 2-3 sessions Objective: Detect workspace directories, create/load workspace configs
Tasks
- Create workspace detection logic
- Check for
.fac/workspace.jsonin directory - Hash path for config file lookup
- Check for
- Implement workspace config directory structure
~/.config/fac/ favorites.json recents.json .fac/ # In workspace root workspace.json backups/ - Create workspace module
workspace_init()- detect or create workspaceworkspace_load()- load workspace.jsonworkspace_save()- save current stateworkspace_exists()- check if path has workspace
- Command line argument parsing
fac(no args) → open Fortress welcome menufac .→ load/create workspace for cwdfac /path/to/dir→ load/create workspacefac file.txt→ check parent for workspace, else single-file mode
- Create empty workspace with default state
- Basic save/load (no tabs/panes yet, just metadata)
Files to Create
src/workspace/
workspace_module.f90 # Core workspace logic
workspace_config_module.f90 # JSON serialization
workspace_detection_module.f90 # Path checking
Files to Modify
app/main.f90(parse args, detect workspace mode)src/editor_state_module.f90(add workspace_path field)
Success Criteria
- ✅
fac .creates.fac/workspace.json - ✅
fac /existing/workspaceloads existing config - ✅
fac file.txtworks as before (single-file mode) - ✅
fac(no args) opens Fortress welcome (placeholder for now) - ✅ Workspace state persists across runs
Testing Checkpoints
- Create workspace in empty directory
- Load existing workspace
- Verify single-file mode unchanged
- Check
.fac/directory creation
Phase 3: State Serialization (Tabs & Panes)
Duration: 3-4 sessions Objective: Persist and restore all editor state
Tasks
- Design workspace.json schema
{ "version": "1.0", "workspace_path": "/home/user/project", "last_opened": "2025-01-05T10:30:00Z", "tabs": [ { "label": "main.f90", "panes": [ { "file": "src/main.f90", "cursor": {"line": 42, "col": 10}, "viewport": {"line": 30, "col": 1}, "modified": false } ], "split_type": "none|vertical|horizontal", "active_pane": 0 } ], "orphan_tabs": [ { "file": "/etc/hosts", "cursor": {"line": 1, "col": 1}, "viewport": {"line": 1, "col": 1} } ], "active_tab": 0, "fuss_mode": { "active": true, "width": 30 } } - Implement tab serialization
- Serialize tab list, labels, active index
- Implement pane serialization
- Serialize pane splits, layout, active pane
- Implement cursor/viewport serialization
- Save position per file
- Implement deserialization (reverse of above)
- Add orphan tab tracking
- Mark tabs as orphan vs workspace
- Different color in tab bar (greyish)
- Call save on quit
- Call load on workspace open
- Handle relative vs absolute paths
- Store workspace files as relative paths
- Store orphan files as absolute paths
Files to Create
src/workspace/
tab_serializer_module.f90 # Tab state save/load
pane_serializer_module.f90 # Pane state save/load
Files to Modify
src/workspace/workspace_module.f90(save/load implementation)src/editor_state_module.f90(add orphan flag to tabs)src/terminal/renderer_module.f90(orphan tab color)app/main.f90(call save on quit, load on open)
Success Criteria
- ✅ Quit fac with 3 tabs → reopen → 3 tabs restored
- ✅ Split panes → quit → reopen → splits preserved
- ✅ Cursor at line 50 → quit → reopen → cursor at line 50
- ✅ Orphan tabs show in different color
- ✅ Workspace files use relative paths
- ✅ Orphan files use absolute paths
Testing Checkpoints
- Create complex workspace (multiple tabs, splits)
- Edit files, move cursors
- Quit and reopen
- Verify exact state restoration
- Test orphan tab creation via Fortress
Phase 4: Backup System
Duration: 2 sessions Objective: Auto-backup dirty buffers, restore with diff option
Tasks
- Create backup directory structure
.fac/ backups/ main.f90.bak test.f90.bak .backup-metadata.json - Implement backup on quit
- Detect modified buffers
- Prompt per file: "Save main.f90? [y/n/c]"
- If 'n', create backup file
- Write backup with timestamp in metadata
- Implement backup detection on open
- Check for backup files in
.fac/backups/ - Compare timestamps (backup vs disk file)
- Check for backup files in
- Implement restore prompt
- For each backup: "[r]estore / [i]gnore / [d]iff?"
- 'd' shows diff (use system diff or built-in)
- Implement diff viewer
- Simple side-by-side or unified diff
- Or shell out to
diffcommand
- Backup cleanup
- Delete backup after successful restore
- Or keep for N days (config option)
Files to Create
src/workspace/
backup_module.f90 # Backup creation/restoration
diff_viewer_module.f90 # Simple diff display (optional)
Files to Modify
src/workspace/workspace_module.f90(backup on quit/load)app/main.f90(call backup logic)
Success Criteria
- ✅ Quit with unsaved file → prompted to save
- ✅ Choose 'n' → backup created
- ✅ Reopen workspace → prompted to restore backup
- ✅ 'd' shows diff between backup and disk
- ✅ 'r' restores backup
- ✅ 'i' ignores backup
- ✅ Metadata tracks backup timestamps
Testing Checkpoints
- Edit file, don't save, quit
- Verify backup created
- Modify file on disk (external editor)
- Reopen workspace
- Verify diff shows both changes
- Test restore, test ignore
Phase 5: Favorites & Recents
Duration: 2 sessions Objective: Track favorite/recent workspaces, Fortress welcome menu
Tasks
- Create favorites system
~/.config/fac/ favorites.json { "favorites": [ {"path": "/home/user/project", "label": "My Project"}, {"path": "/home/user/scripts", "label": "Scripts"} ] } - Create recents system
~/.config/fac/ recents.json { "recents": [ {"path": "/home/user/project", "last_opened": "2025-01-05T10:30:00Z"}, {"path": "/home/user/other", "last_opened": "2025-01-04T09:15:00Z"} ] } - Update recents on workspace open
- Add current workspace to recents
- Keep most recent 10-20 entries
- Implement Fortress welcome menu
- Press '8' to toggle between favorites/recents view
- Two separate panes/dialogs
- Favorites pane: list favorites, keybind to add/remove ('f')
- Recents pane: list by most recent first
- Navigate with ↑/↓, Enter to select
- Implement
fac(no args) behavior- Launch Fortress welcome menu
- Select favorite/recent → load workspace
- Or navigate filesystem to find new workspace
- Add keybind in Fortress to add current dir to favorites ('f')
- Add keybind to remove favorite ('r' or 'x')
Files to Create
src/workspace/
favorites_module.f90 # Manage favorites
recents_module.f90 # Manage recents
src/fortress/ui/
welcome_menu_module.f90 # Favorites/recents display
Files to Modify
src/fortress/ui/navigator_module.f90(add '8' toggle, 'f' favorite)src/workspace/workspace_module.f90(update recents on open)app/main.f90(no args → welcome menu)
Success Criteria
- ✅
facopens welcome menu with favorites/recents - ✅ Press '8' toggles between favorites and recents views
- ✅ Selecting from list opens that workspace
- ✅ 'f' in Fortress adds directory to favorites
- ✅ Recents automatically updated on workspace open
- ✅ Most recent workspaces appear first
Testing Checkpoints
- Run
facwith no args - Verify favorites/recents display
- Add favorite, verify persists
- Open workspace, verify appears in recents
- Toggle between views with '8'
Phase 6: Workspace Switching & Integration
Duration: 2-3 sessions Objective: Connect all pieces, handle workspace switching
Tasks
- Implement workspace switching flow
- Ctrl-O in workspace → Fortress navigator
- Select directory → save current workspace
- Load new workspace (or create if new)
- Restore tabs/panes/state
- Handle orphan tab creation
- Fortress select file → open in new tab
- Mark tab as orphan
- Style with grey/subtle color
- Don't persist orphan tabs in workspace.json
- OR persist in separate "orphan_tabs" array (decided in Phase 3)
- Implement save prompts on switch
- Before switching workspace
- For each dirty buffer: "Save file? [y/n/c]"
- 'c' cancels workspace switch
- Handle edge cases
- Missing files in workspace.json
- Show warning: "File not found: src/missing.f90"
- Skip that tab, continue loading others
- Deleted workspace directory
- Detect and remove from recents
- Corrupted workspace.json
- Fallback to empty workspace
- Log error
- Missing files in workspace.json
- Update file tree (Ctrl-B) for workspace mode
- Show workspace root (not parent of first file)
- Update tree when switching workspaces
Files to Modify
src/fortress/ui/navigator_module.f90(return file vs dir)src/workspace/workspace_module.f90(switch logic)src/commands/command_handler_module.f90(Ctrl-O handler)src/workspace/file_tree_module.f90(workspace root)app/main.f90(orchestrate switching)
Success Criteria
- ✅ Ctrl-O from workspace opens Fortress
- ✅ Selecting new directory switches workspace
- ✅ Current workspace saved before switch
- ✅ New workspace loaded with all state
- ✅ Dirty buffers prompt to save before switch
- ✅ Orphan tabs work correctly
- ✅ Missing files handled gracefully
- ✅ File tree shows workspace root
Testing Checkpoints
- Create two workspaces with different files
- Switch between them via Fortress
- Verify state saves/loads correctly
- Test with dirty buffers
- Test missing file handling
Phase 7: Polish, Testing & Documentation
Duration: 2 sessions Objective: Bug fixes, edge cases, user testing
Tasks
- Performance optimization
- Large workspaces (100+ files)
- Deep directory trees in Fortress
- Visual polish
- Orphan tab color (grey/subtle)
- Fortress UI styling
- Welcome menu appearance
- Error handling
- Permissions errors
- Disk full
- Invalid JSON
- Edge case testing
- Symlinks in workspace
- Very long file paths
- Unicode in filenames/paths
- Binary files in backups
- Documentation
- Update README.md
- Update --help output
- Create WORKSPACE.md guide
- Add examples
- User testing
- Real-world projects
- Multiple sessions
- Collect feedback
- Fix any cursor/rendering bugs that emerge
- Remove debug logging
Files to Create
WORKSPACE.md(user guide)
Files to Modify
README.md(document workspace features)app/main.f90(update --help)
Success Criteria
- ✅ All features working smoothly
- ✅ No regressions in existing features
- ✅ Performance acceptable on large projects
- ✅ Documentation complete
- ✅ Ready for release
Testing Checkpoints
- Test with Linux kernel source (large workspace)
- Test with multiple nested directories
- Test workspace switching under load
- Test all edge cases
- User acceptance testing
Module Dependency Graph
app/main.f90
├── workspace_module.f90
│ ├── workspace_config_module.f90
│ ├── workspace_detection_module.f90
│ ├── tab_serializer_module.f90
│ ├── pane_serializer_module.f90
│ ├── backup_module.f90
│ ├── favorites_module.f90
│ └── recents_module.f90
│
└── fortress/
├── filesystem/
│ ├── directory_module.f90
│ └── path_utils_module.f90
├── terminal/
│ └── fortress_render_module.f90
└── ui/
├── dual_pane_module.f90
├── navigator_module.f90
└── welcome_menu_module.f90
Risk Mitigation
Cursor/Rendering Bugs
Risk: New pane/tab logic breaks cursor positioning Mitigation:
- Test after each phase
- Keep parity tests from current build
- Incremental changes, test often
State Corruption
Risk: Corrupted workspace.json breaks workspace Mitigation:
- JSON validation on load
- Fallback to empty workspace
- Keep backup of last-good workspace.json
Performance
Risk: Large workspaces slow down editor Mitigation:
- Lazy load tabs (don't load all buffers at once)
- Profile and optimize
- Set reasonable limits (e.g., max 50 tabs)
Backwards Compatibility
Risk: Breaking existing fac usage Mitigation:
- Single-file mode must work unchanged
- Feature flags during development
- Extensive testing of non-workspace mode
Success Metrics
Phase Completion:
- All tasks in phase completed
- Success criteria met
- Tests passing
- No regressions
Overall Success:
faclaunches welcome menufac .creates/loads workspace- Ctrl-O navigates to workspaces/files
- Tabs/panes/cursors persist across sessions
- Orphan tabs work as expected
- Favorites/recents work
- Backups restore correctly
- Documentation complete
- No bugs in existing features
Timeline Estimate
- Phase 0: 1 session (4-6 hours)
- Phase 1: 3-4 sessions (12-16 hours)
- Phase 2: 2-3 sessions (8-12 hours)
- Phase 3: 3-4 sessions (12-16 hours)
- Phase 4: 2 sessions (8-10 hours)
- Phase 5: 2 sessions (8-10 hours)
- Phase 6: 2-3 sessions (8-12 hours)
- Phase 7: 2 sessions (8-10 hours)
Total: ~15-20 sessions (~60-80 hours)
Next Steps
- Review this roadmap
- Make any adjustments
- Begin Phase 0 (Planning & Design)
- Create specification documents
- Start Phase 1 (Fortress Navigator)
Ready to proceed? 🚀
View source
| 1 | # Workspace Mode Implementation Roadmap |
| 2 | |
| 3 | **Vision**: Transform fac into a workspace-aware editor with persistent state and Fortress-based navigation. |
| 4 | |
| 5 | **Timeline**: 7 phases, estimated 15-20 sessions total |
| 6 | |
| 7 | --- |
| 8 | |
| 9 | ## Phase 0: Planning & Design |
| 10 | **Duration**: 1 session |
| 11 | **Objective**: Document architecture and create foundational specs |
| 12 | |
| 13 | ### Tasks |
| 14 | - [x] Define workspace data structures |
| 15 | - [ ] Design `.fac/` directory structure |
| 16 | - [ ] Design `~/.config/fac/` structure |
| 17 | - [ ] Create workspace.json schema |
| 18 | - [ ] Create favorites.json schema |
| 19 | - [ ] Document Fortress integration points |
| 20 | - [ ] Plan module dependencies |
| 21 | |
| 22 | ### Deliverables |
| 23 | ``` |
| 24 | docs/ |
| 25 | workspace_spec.md # Workspace JSON format |
| 26 | fortress_integration.md # How fortress modules integrate |
| 27 | config_spec.md # Config file formats |
| 28 | ``` |
| 29 | |
| 30 | ### Files to Create |
| 31 | - `docs/workspace_spec.md` |
| 32 | - `docs/fortress_integration.md` |
| 33 | - `docs/config_spec.md` |
| 34 | |
| 35 | ### Success Criteria |
| 36 | - ✅ Clear data structure specifications |
| 37 | - ✅ Agreed-upon file formats |
| 38 | - ✅ Module integration plan documented |
| 39 | |
| 40 | --- |
| 41 | |
| 42 | ## Phase 1: Fortress Navigator Foundation |
| 43 | **Duration**: 3-4 sessions |
| 44 | **Objective**: Build basic dual-pane file/directory navigator (Ctrl-O) |
| 45 | |
| 46 | ### Tasks |
| 47 | - [ ] Copy fortress filesystem modules into fac |
| 48 | - `src/fortress/filesystem/` (directory reading, path handling) |
| 49 | - [ ] Copy fortress terminal modules |
| 50 | - `src/fortress/terminal/` (rendering utilities) |
| 51 | - [ ] Adapt fortress UI for embedded mode |
| 52 | - `src/fortress/ui/` (dual-pane display, navigation) |
| 53 | - [ ] Implement dual-pane rendering |
| 54 | - Left pane: parent directory (30%) |
| 55 | - Right pane: current directory (70%) |
| 56 | - [ ] Add navigation keybindings |
| 57 | - ↑/↓: Move cursor |
| 58 | - →: Enter directory |
| 59 | - ←: Go to parent |
| 60 | - ~/: Jump to home/root |
| 61 | - q: Cancel/exit |
| 62 | - Enter: Select (return selection) |
| 63 | - [ ] Add Ctrl-O keybinding to main editor |
| 64 | - [ ] Modal Fortress UI (takes over screen, returns selection) |
| 65 | |
| 66 | ### Files to Create |
| 67 | ``` |
| 68 | src/fortress/ |
| 69 | filesystem/ |
| 70 | directory_module.f90 # Read dirs, list files |
| 71 | path_utils_module.f90 # Path manipulation |
| 72 | terminal/ |
| 73 | fortress_render_module.f90 # Rendering utilities |
| 74 | ui/ |
| 75 | dual_pane_module.f90 # Dual-pane display |
| 76 | navigator_module.f90 # Main navigation logic |
| 77 | ``` |
| 78 | |
| 79 | ### Files to Modify |
| 80 | - `src/commands/command_handler_module.f90` (add Ctrl-O handler) |
| 81 | - `Makefile` (add fortress modules to build) |
| 82 | |
| 83 | ### Success Criteria |
| 84 | - ✅ Ctrl-O opens dual-pane navigator |
| 85 | - ✅ Can navigate filesystem |
| 86 | - ✅ Selecting directory returns path |
| 87 | - ✅ Selecting file returns path |
| 88 | - ✅ ESC/q cancels and returns to editor |
| 89 | - ✅ Visual styling matches fac aesthetic |
| 90 | |
| 91 | ### Testing Checkpoints |
| 92 | - Navigate to various directories |
| 93 | - Test with long file lists (scrolling) |
| 94 | - Test with deep directory trees |
| 95 | - Test cancellation (ESC) |
| 96 | |
| 97 | --- |
| 98 | |
| 99 | ## Phase 2: Workspace Detection & Configuration |
| 100 | **Duration**: 2-3 sessions |
| 101 | **Objective**: Detect workspace directories, create/load workspace configs |
| 102 | |
| 103 | ### Tasks |
| 104 | - [ ] Create workspace detection logic |
| 105 | - Check for `.fac/workspace.json` in directory |
| 106 | - Hash path for config file lookup |
| 107 | - [ ] Implement workspace config directory structure |
| 108 | ``` |
| 109 | ~/.config/fac/ |
| 110 | favorites.json |
| 111 | recents.json |
| 112 | .fac/ # In workspace root |
| 113 | workspace.json |
| 114 | backups/ |
| 115 | ``` |
| 116 | - [ ] Create workspace module |
| 117 | - `workspace_init()` - detect or create workspace |
| 118 | - `workspace_load()` - load workspace.json |
| 119 | - `workspace_save()` - save current state |
| 120 | - `workspace_exists()` - check if path has workspace |
| 121 | - [ ] Command line argument parsing |
| 122 | - `fac` (no args) → open Fortress welcome menu |
| 123 | - `fac .` → load/create workspace for cwd |
| 124 | - `fac /path/to/dir` → load/create workspace |
| 125 | - `fac file.txt` → check parent for workspace, else single-file mode |
| 126 | - [ ] Create empty workspace with default state |
| 127 | - [ ] Basic save/load (no tabs/panes yet, just metadata) |
| 128 | |
| 129 | ### Files to Create |
| 130 | ``` |
| 131 | src/workspace/ |
| 132 | workspace_module.f90 # Core workspace logic |
| 133 | workspace_config_module.f90 # JSON serialization |
| 134 | workspace_detection_module.f90 # Path checking |
| 135 | ``` |
| 136 | |
| 137 | ### Files to Modify |
| 138 | - `app/main.f90` (parse args, detect workspace mode) |
| 139 | - `src/editor_state_module.f90` (add workspace_path field) |
| 140 | |
| 141 | ### Success Criteria |
| 142 | - ✅ `fac .` creates `.fac/workspace.json` |
| 143 | - ✅ `fac /existing/workspace` loads existing config |
| 144 | - ✅ `fac file.txt` works as before (single-file mode) |
| 145 | - ✅ `fac` (no args) opens Fortress welcome (placeholder for now) |
| 146 | - ✅ Workspace state persists across runs |
| 147 | |
| 148 | ### Testing Checkpoints |
| 149 | - Create workspace in empty directory |
| 150 | - Load existing workspace |
| 151 | - Verify single-file mode unchanged |
| 152 | - Check `.fac/` directory creation |
| 153 | |
| 154 | --- |
| 155 | |
| 156 | ## Phase 3: State Serialization (Tabs & Panes) |
| 157 | **Duration**: 3-4 sessions |
| 158 | **Objective**: Persist and restore all editor state |
| 159 | |
| 160 | ### Tasks |
| 161 | - [ ] Design workspace.json schema |
| 162 | ```json |
| 163 | { |
| 164 | "version": "1.0", |
| 165 | "workspace_path": "/home/user/project", |
| 166 | "last_opened": "2025-01-05T10:30:00Z", |
| 167 | "tabs": [ |
| 168 | { |
| 169 | "label": "main.f90", |
| 170 | "panes": [ |
| 171 | { |
| 172 | "file": "src/main.f90", |
| 173 | "cursor": {"line": 42, "col": 10}, |
| 174 | "viewport": {"line": 30, "col": 1}, |
| 175 | "modified": false |
| 176 | } |
| 177 | ], |
| 178 | "split_type": "none|vertical|horizontal", |
| 179 | "active_pane": 0 |
| 180 | } |
| 181 | ], |
| 182 | "orphan_tabs": [ |
| 183 | { |
| 184 | "file": "/etc/hosts", |
| 185 | "cursor": {"line": 1, "col": 1}, |
| 186 | "viewport": {"line": 1, "col": 1} |
| 187 | } |
| 188 | ], |
| 189 | "active_tab": 0, |
| 190 | "fuss_mode": { |
| 191 | "active": true, |
| 192 | "width": 30 |
| 193 | } |
| 194 | } |
| 195 | ``` |
| 196 | - [ ] Implement tab serialization |
| 197 | - Serialize tab list, labels, active index |
| 198 | - [ ] Implement pane serialization |
| 199 | - Serialize pane splits, layout, active pane |
| 200 | - [ ] Implement cursor/viewport serialization |
| 201 | - Save position per file |
| 202 | - [ ] Implement deserialization (reverse of above) |
| 203 | - [ ] Add orphan tab tracking |
| 204 | - Mark tabs as orphan vs workspace |
| 205 | - Different color in tab bar (greyish) |
| 206 | - [ ] Call save on quit |
| 207 | - [ ] Call load on workspace open |
| 208 | - [ ] Handle relative vs absolute paths |
| 209 | - Store workspace files as relative paths |
| 210 | - Store orphan files as absolute paths |
| 211 | |
| 212 | ### Files to Create |
| 213 | ``` |
| 214 | src/workspace/ |
| 215 | tab_serializer_module.f90 # Tab state save/load |
| 216 | pane_serializer_module.f90 # Pane state save/load |
| 217 | ``` |
| 218 | |
| 219 | ### Files to Modify |
| 220 | - `src/workspace/workspace_module.f90` (save/load implementation) |
| 221 | - `src/editor_state_module.f90` (add orphan flag to tabs) |
| 222 | - `src/terminal/renderer_module.f90` (orphan tab color) |
| 223 | - `app/main.f90` (call save on quit, load on open) |
| 224 | |
| 225 | ### Success Criteria |
| 226 | - ✅ Quit fac with 3 tabs → reopen → 3 tabs restored |
| 227 | - ✅ Split panes → quit → reopen → splits preserved |
| 228 | - ✅ Cursor at line 50 → quit → reopen → cursor at line 50 |
| 229 | - ✅ Orphan tabs show in different color |
| 230 | - ✅ Workspace files use relative paths |
| 231 | - ✅ Orphan files use absolute paths |
| 232 | |
| 233 | ### Testing Checkpoints |
| 234 | - Create complex workspace (multiple tabs, splits) |
| 235 | - Edit files, move cursors |
| 236 | - Quit and reopen |
| 237 | - Verify exact state restoration |
| 238 | - Test orphan tab creation via Fortress |
| 239 | |
| 240 | --- |
| 241 | |
| 242 | ## Phase 4: Backup System |
| 243 | **Duration**: 2 sessions |
| 244 | **Objective**: Auto-backup dirty buffers, restore with diff option |
| 245 | |
| 246 | ### Tasks |
| 247 | - [ ] Create backup directory structure |
| 248 | ``` |
| 249 | .fac/ |
| 250 | backups/ |
| 251 | main.f90.bak |
| 252 | test.f90.bak |
| 253 | .backup-metadata.json |
| 254 | ``` |
| 255 | - [ ] Implement backup on quit |
| 256 | - Detect modified buffers |
| 257 | - Prompt per file: "Save main.f90? [y/n/c]" |
| 258 | - If 'n', create backup file |
| 259 | - Write backup with timestamp in metadata |
| 260 | - [ ] Implement backup detection on open |
| 261 | - Check for backup files in `.fac/backups/` |
| 262 | - Compare timestamps (backup vs disk file) |
| 263 | - [ ] Implement restore prompt |
| 264 | - For each backup: "[r]estore / [i]gnore / [d]iff?" |
| 265 | - 'd' shows diff (use system diff or built-in) |
| 266 | - [ ] Implement diff viewer |
| 267 | - Simple side-by-side or unified diff |
| 268 | - Or shell out to `diff` command |
| 269 | - [ ] Backup cleanup |
| 270 | - Delete backup after successful restore |
| 271 | - Or keep for N days (config option) |
| 272 | |
| 273 | ### Files to Create |
| 274 | ``` |
| 275 | src/workspace/ |
| 276 | backup_module.f90 # Backup creation/restoration |
| 277 | diff_viewer_module.f90 # Simple diff display (optional) |
| 278 | ``` |
| 279 | |
| 280 | ### Files to Modify |
| 281 | - `src/workspace/workspace_module.f90` (backup on quit/load) |
| 282 | - `app/main.f90` (call backup logic) |
| 283 | |
| 284 | ### Success Criteria |
| 285 | - ✅ Quit with unsaved file → prompted to save |
| 286 | - ✅ Choose 'n' → backup created |
| 287 | - ✅ Reopen workspace → prompted to restore backup |
| 288 | - ✅ 'd' shows diff between backup and disk |
| 289 | - ✅ 'r' restores backup |
| 290 | - ✅ 'i' ignores backup |
| 291 | - ✅ Metadata tracks backup timestamps |
| 292 | |
| 293 | ### Testing Checkpoints |
| 294 | - Edit file, don't save, quit |
| 295 | - Verify backup created |
| 296 | - Modify file on disk (external editor) |
| 297 | - Reopen workspace |
| 298 | - Verify diff shows both changes |
| 299 | - Test restore, test ignore |
| 300 | |
| 301 | --- |
| 302 | |
| 303 | ## Phase 5: Favorites & Recents |
| 304 | **Duration**: 2 sessions |
| 305 | **Objective**: Track favorite/recent workspaces, Fortress welcome menu |
| 306 | |
| 307 | ### Tasks |
| 308 | - [ ] Create favorites system |
| 309 | ``` |
| 310 | ~/.config/fac/ |
| 311 | favorites.json |
| 312 | { |
| 313 | "favorites": [ |
| 314 | {"path": "/home/user/project", "label": "My Project"}, |
| 315 | {"path": "/home/user/scripts", "label": "Scripts"} |
| 316 | ] |
| 317 | } |
| 318 | ``` |
| 319 | - [ ] Create recents system |
| 320 | ``` |
| 321 | ~/.config/fac/ |
| 322 | recents.json |
| 323 | { |
| 324 | "recents": [ |
| 325 | {"path": "/home/user/project", "last_opened": "2025-01-05T10:30:00Z"}, |
| 326 | {"path": "/home/user/other", "last_opened": "2025-01-04T09:15:00Z"} |
| 327 | ] |
| 328 | } |
| 329 | ``` |
| 330 | - [ ] Update recents on workspace open |
| 331 | - Add current workspace to recents |
| 332 | - Keep most recent 10-20 entries |
| 333 | - [ ] Implement Fortress welcome menu |
| 334 | - Press '8' to toggle between favorites/recents view |
| 335 | - Two separate panes/dialogs |
| 336 | - Favorites pane: list favorites, keybind to add/remove ('f') |
| 337 | - Recents pane: list by most recent first |
| 338 | - Navigate with ↑/↓, Enter to select |
| 339 | - [ ] Implement `fac` (no args) behavior |
| 340 | - Launch Fortress welcome menu |
| 341 | - Select favorite/recent → load workspace |
| 342 | - Or navigate filesystem to find new workspace |
| 343 | - [ ] Add keybind in Fortress to add current dir to favorites ('f') |
| 344 | - [ ] Add keybind to remove favorite ('r' or 'x') |
| 345 | |
| 346 | ### Files to Create |
| 347 | ``` |
| 348 | src/workspace/ |
| 349 | favorites_module.f90 # Manage favorites |
| 350 | recents_module.f90 # Manage recents |
| 351 | src/fortress/ui/ |
| 352 | welcome_menu_module.f90 # Favorites/recents display |
| 353 | ``` |
| 354 | |
| 355 | ### Files to Modify |
| 356 | - `src/fortress/ui/navigator_module.f90` (add '8' toggle, 'f' favorite) |
| 357 | - `src/workspace/workspace_module.f90` (update recents on open) |
| 358 | - `app/main.f90` (no args → welcome menu) |
| 359 | |
| 360 | ### Success Criteria |
| 361 | - ✅ `fac` opens welcome menu with favorites/recents |
| 362 | - ✅ Press '8' toggles between favorites and recents views |
| 363 | - ✅ Selecting from list opens that workspace |
| 364 | - ✅ 'f' in Fortress adds directory to favorites |
| 365 | - ✅ Recents automatically updated on workspace open |
| 366 | - ✅ Most recent workspaces appear first |
| 367 | |
| 368 | ### Testing Checkpoints |
| 369 | - Run `fac` with no args |
| 370 | - Verify favorites/recents display |
| 371 | - Add favorite, verify persists |
| 372 | - Open workspace, verify appears in recents |
| 373 | - Toggle between views with '8' |
| 374 | |
| 375 | --- |
| 376 | |
| 377 | ## Phase 6: Workspace Switching & Integration |
| 378 | **Duration**: 2-3 sessions |
| 379 | **Objective**: Connect all pieces, handle workspace switching |
| 380 | |
| 381 | ### Tasks |
| 382 | - [ ] Implement workspace switching flow |
| 383 | - Ctrl-O in workspace → Fortress navigator |
| 384 | - Select directory → save current workspace |
| 385 | - Load new workspace (or create if new) |
| 386 | - Restore tabs/panes/state |
| 387 | - [ ] Handle orphan tab creation |
| 388 | - Fortress select file → open in new tab |
| 389 | - Mark tab as orphan |
| 390 | - Style with grey/subtle color |
| 391 | - Don't persist orphan tabs in workspace.json |
| 392 | - OR persist in separate "orphan_tabs" array (decided in Phase 3) |
| 393 | - [ ] Implement save prompts on switch |
| 394 | - Before switching workspace |
| 395 | - For each dirty buffer: "Save file? [y/n/c]" |
| 396 | - 'c' cancels workspace switch |
| 397 | - [ ] Handle edge cases |
| 398 | - Missing files in workspace.json |
| 399 | - Show warning: "File not found: src/missing.f90" |
| 400 | - Skip that tab, continue loading others |
| 401 | - Deleted workspace directory |
| 402 | - Detect and remove from recents |
| 403 | - Corrupted workspace.json |
| 404 | - Fallback to empty workspace |
| 405 | - Log error |
| 406 | - [ ] Update file tree (Ctrl-B) for workspace mode |
| 407 | - Show workspace root (not parent of first file) |
| 408 | - Update tree when switching workspaces |
| 409 | |
| 410 | ### Files to Modify |
| 411 | - `src/fortress/ui/navigator_module.f90` (return file vs dir) |
| 412 | - `src/workspace/workspace_module.f90` (switch logic) |
| 413 | - `src/commands/command_handler_module.f90` (Ctrl-O handler) |
| 414 | - `src/workspace/file_tree_module.f90` (workspace root) |
| 415 | - `app/main.f90` (orchestrate switching) |
| 416 | |
| 417 | ### Success Criteria |
| 418 | - ✅ Ctrl-O from workspace opens Fortress |
| 419 | - ✅ Selecting new directory switches workspace |
| 420 | - ✅ Current workspace saved before switch |
| 421 | - ✅ New workspace loaded with all state |
| 422 | - ✅ Dirty buffers prompt to save before switch |
| 423 | - ✅ Orphan tabs work correctly |
| 424 | - ✅ Missing files handled gracefully |
| 425 | - ✅ File tree shows workspace root |
| 426 | |
| 427 | ### Testing Checkpoints |
| 428 | - Create two workspaces with different files |
| 429 | - Switch between them via Fortress |
| 430 | - Verify state saves/loads correctly |
| 431 | - Test with dirty buffers |
| 432 | - Test missing file handling |
| 433 | |
| 434 | --- |
| 435 | |
| 436 | ## Phase 7: Polish, Testing & Documentation |
| 437 | **Duration**: 2 sessions |
| 438 | **Objective**: Bug fixes, edge cases, user testing |
| 439 | |
| 440 | ### Tasks |
| 441 | - [ ] Performance optimization |
| 442 | - Large workspaces (100+ files) |
| 443 | - Deep directory trees in Fortress |
| 444 | - [ ] Visual polish |
| 445 | - Orphan tab color (grey/subtle) |
| 446 | - Fortress UI styling |
| 447 | - Welcome menu appearance |
| 448 | - [ ] Error handling |
| 449 | - Permissions errors |
| 450 | - Disk full |
| 451 | - Invalid JSON |
| 452 | - [ ] Edge case testing |
| 453 | - Symlinks in workspace |
| 454 | - Very long file paths |
| 455 | - Unicode in filenames/paths |
| 456 | - Binary files in backups |
| 457 | - [ ] Documentation |
| 458 | - Update README.md |
| 459 | - Update --help output |
| 460 | - Create WORKSPACE.md guide |
| 461 | - Add examples |
| 462 | - [ ] User testing |
| 463 | - Real-world projects |
| 464 | - Multiple sessions |
| 465 | - Collect feedback |
| 466 | - [ ] Fix any cursor/rendering bugs that emerge |
| 467 | - [ ] Remove debug logging |
| 468 | |
| 469 | ### Files to Create |
| 470 | - `WORKSPACE.md` (user guide) |
| 471 | |
| 472 | ### Files to Modify |
| 473 | - `README.md` (document workspace features) |
| 474 | - `app/main.f90` (update --help) |
| 475 | |
| 476 | ### Success Criteria |
| 477 | - ✅ All features working smoothly |
| 478 | - ✅ No regressions in existing features |
| 479 | - ✅ Performance acceptable on large projects |
| 480 | - ✅ Documentation complete |
| 481 | - ✅ Ready for release |
| 482 | |
| 483 | ### Testing Checkpoints |
| 484 | - Test with Linux kernel source (large workspace) |
| 485 | - Test with multiple nested directories |
| 486 | - Test workspace switching under load |
| 487 | - Test all edge cases |
| 488 | - User acceptance testing |
| 489 | |
| 490 | --- |
| 491 | |
| 492 | ## Module Dependency Graph |
| 493 | |
| 494 | ``` |
| 495 | app/main.f90 |
| 496 | ├── workspace_module.f90 |
| 497 | │ ├── workspace_config_module.f90 |
| 498 | │ ├── workspace_detection_module.f90 |
| 499 | │ ├── tab_serializer_module.f90 |
| 500 | │ ├── pane_serializer_module.f90 |
| 501 | │ ├── backup_module.f90 |
| 502 | │ ├── favorites_module.f90 |
| 503 | │ └── recents_module.f90 |
| 504 | │ |
| 505 | └── fortress/ |
| 506 | ├── filesystem/ |
| 507 | │ ├── directory_module.f90 |
| 508 | │ └── path_utils_module.f90 |
| 509 | ├── terminal/ |
| 510 | │ └── fortress_render_module.f90 |
| 511 | └── ui/ |
| 512 | ├── dual_pane_module.f90 |
| 513 | ├── navigator_module.f90 |
| 514 | └── welcome_menu_module.f90 |
| 515 | ``` |
| 516 | |
| 517 | --- |
| 518 | |
| 519 | ## Risk Mitigation |
| 520 | |
| 521 | ### Cursor/Rendering Bugs |
| 522 | **Risk**: New pane/tab logic breaks cursor positioning |
| 523 | **Mitigation**: |
| 524 | - Test after each phase |
| 525 | - Keep parity tests from current build |
| 526 | - Incremental changes, test often |
| 527 | |
| 528 | ### State Corruption |
| 529 | **Risk**: Corrupted workspace.json breaks workspace |
| 530 | **Mitigation**: |
| 531 | - JSON validation on load |
| 532 | - Fallback to empty workspace |
| 533 | - Keep backup of last-good workspace.json |
| 534 | |
| 535 | ### Performance |
| 536 | **Risk**: Large workspaces slow down editor |
| 537 | **Mitigation**: |
| 538 | - Lazy load tabs (don't load all buffers at once) |
| 539 | - Profile and optimize |
| 540 | - Set reasonable limits (e.g., max 50 tabs) |
| 541 | |
| 542 | ### Backwards Compatibility |
| 543 | **Risk**: Breaking existing fac usage |
| 544 | **Mitigation**: |
| 545 | - Single-file mode must work unchanged |
| 546 | - Feature flags during development |
| 547 | - Extensive testing of non-workspace mode |
| 548 | |
| 549 | --- |
| 550 | |
| 551 | ## Success Metrics |
| 552 | |
| 553 | **Phase Completion:** |
| 554 | - All tasks in phase completed |
| 555 | - Success criteria met |
| 556 | - Tests passing |
| 557 | - No regressions |
| 558 | |
| 559 | **Overall Success:** |
| 560 | - `fac` launches welcome menu |
| 561 | - `fac .` creates/loads workspace |
| 562 | - Ctrl-O navigates to workspaces/files |
| 563 | - Tabs/panes/cursors persist across sessions |
| 564 | - Orphan tabs work as expected |
| 565 | - Favorites/recents work |
| 566 | - Backups restore correctly |
| 567 | - Documentation complete |
| 568 | - No bugs in existing features |
| 569 | |
| 570 | --- |
| 571 | |
| 572 | ## Timeline Estimate |
| 573 | |
| 574 | - **Phase 0**: 1 session (4-6 hours) |
| 575 | - **Phase 1**: 3-4 sessions (12-16 hours) |
| 576 | - **Phase 2**: 2-3 sessions (8-12 hours) |
| 577 | - **Phase 3**: 3-4 sessions (12-16 hours) |
| 578 | - **Phase 4**: 2 sessions (8-10 hours) |
| 579 | - **Phase 5**: 2 sessions (8-10 hours) |
| 580 | - **Phase 6**: 2-3 sessions (8-12 hours) |
| 581 | - **Phase 7**: 2 sessions (8-10 hours) |
| 582 | |
| 583 | **Total**: ~15-20 sessions (~60-80 hours) |
| 584 | |
| 585 | --- |
| 586 | |
| 587 | ## Next Steps |
| 588 | |
| 589 | 1. Review this roadmap |
| 590 | 2. Make any adjustments |
| 591 | 3. Begin Phase 0 (Planning & Design) |
| 592 | 4. Create specification documents |
| 593 | 5. Start Phase 1 (Fortress Navigator) |
| 594 | |
| 595 | Ready to proceed? 🚀 |