Tabs Implementation Plan for Facsimile
Overview
Add full tab support to facsimile, bridging the gap between GUI and terminal editors. Each tab represents an independent file buffer with its own cursor state and undo history.
Requirements
Core Features
- Multiple file buffers open simultaneously
- Tab bar at top of screen showing all open tabs
- Active tab highlighted visually
- Each tab maintains independent state:
- Buffer content
- Cursor position(s)
- Undo/redo history
- Viewport position
- File path
Keybindings
-
alt-1throughalt-9: Jump to tab 1-9 -
ctrl-alt-left: Previous tab (with wrap-around) -
ctrl-alt-right: Next tab (with wrap-around) - Check for conflicts with existing bindings (DONE - no conflicts)
Fuss Integration
- Opening file in fuss mode creates new tab by default
- New tab becomes active immediately
- Fuss mode persists (already implemented)
UI/UX
- Tab bar shows:
[1: file1.txt] [2: file2.f90*] [3: README.md] - Active tab uses reverse video (char(27) // '[7m')
- Modified files indicated with
*suffix - Tab bar takes 1 row at top
- Adjust editor viewport to account for tab bar (starts at row 2)
- Tab bar updates automatically when switching tabs
Architecture Design
Data Structures
Tab Type (new)
type :: tab_t
character(len=:), allocatable :: filename
type(buffer_t) :: buffer
type(cursor_t), allocatable :: cursors(:)
integer :: active_cursor
integer :: viewport_line
integer :: viewport_column
logical :: modified
end type tab_t
Editor State Updates
type(tab_t), allocatable :: tabs(:)
integer :: active_tab_index
integer :: max_tabs = 10 ! Support up to 10 tabs initially
File Changes
src/editor_state_module.f90
- Add tab_t type definition
- Add tabs array and active_tab_index to editor_state_t
- Add procedures: create_tab, switch_tab, close_tab
src/terminal/renderer_module.f90
- Add render_tab_bar() subroutine
- Adjust main viewport to start at row 2 instead of row 1
- Update render_screen() to call render_tab_bar()
src/commands/command_handler_module.f90
- Add alt-1 through alt-9 handlers
- Add ctrl-alt-left/right handlers
- Modify open_file_in_editor() to create new tab
- Add save/restore logic for tab switching
src/buffer_module.f90
- Ensure buffer can be deep-copied for tab state
- May need clone_buffer() function
Implementation Phases
Phase 1: Core Tab Infrastructure
- Define tab_t type
- Add tabs array to editor state
- Create basic tab management functions:
create_new_tab(editor, filename)switch_to_tab(editor, tab_index)get_current_tab(editor)
Phase 2: Tab Bar Rendering
- Implement
render_tab_bar() - Display tab index and filename
- Highlight active tab
- Show modification indicator
- Adjust viewport for tab bar
Phase 3: Navigation Keybindings
- Parse alt- key sequences
- Implement tab switching logic
- Add ctrl-alt-left/right navigation
- Save/restore cursor and viewport state
Phase 4: Fuss Integration
- Modify
open_file_in_editor()to create tab - Set new tab as active
- Test opening multiple files from fuss
Phase 5: Polish & Documentation
- Update ctrl-? help menu
- Test edge cases (max tabs, closing tabs, etc.)
- Handle unsaved changes warnings
- Performance testing with many tabs
Edge Cases to Handle
- Opening same file in multiple tabs (allow or prevent?)
- Maximum tab limit (10 initially)
- Tab overflow (show scroll indicator if >10 tabs?)
- Closing active tab (switch to next/previous)
- Closing all tabs (keep at least one empty buffer?)
- Modified file indicator updates
- Tab bar width overflow (truncate long filenames)
Testing Plan
Manual Tests
- Create 3 tabs, verify each has independent buffer
- Switch between tabs with alt-1, alt-2, alt-3
- Navigate with ctrl-alt-left/right
- Open files from fuss, verify new tabs created
- Modify files in different tabs, verify * indicator
- Close tabs, verify proper cleanup
Integration Tests
- Tab switching preserves cursor position
- Tab switching preserves undo history
- Fuss mode works correctly with multiple tabs open
- Tab bar updates when files modified
- Keybindings don't conflict with existing shortcuts
Success Criteria
- Can open 10 files in separate tabs
- Each tab maintains independent state
- Alt- switches tabs instantly
- Ctrl-alt-left/right cycles through tabs
- Tab bar clearly shows which tab is active
- Opening file from fuss creates new tab
- Modified files show * indicator in tab bar
- Help menu documents all tab features
- No performance degradation with 10 tabs open
Future Enhancements (Not in Scope)
- Tab reordering (drag/drop or keyboard)
- Split panes (horizontal/vertical)
- Tab groups or sessions
- Persistent tab state between sessions
- Tab close keybinding (ctrl-w?)
- New empty tab keybinding (ctrl-t?)
View source
| 1 | # Tabs Implementation Plan for Facsimile |
| 2 | |
| 3 | ## Overview |
| 4 | Add full tab support to facsimile, bridging the gap between GUI and terminal editors. Each tab represents an independent file buffer with its own cursor state and undo history. |
| 5 | |
| 6 | ## Requirements |
| 7 | |
| 8 | ### Core Features |
| 9 | - [x] Multiple file buffers open simultaneously |
| 10 | - [x] Tab bar at top of screen showing all open tabs |
| 11 | - [x] Active tab highlighted visually |
| 12 | - [x] Each tab maintains independent state: |
| 13 | - Buffer content |
| 14 | - Cursor position(s) |
| 15 | - Undo/redo history |
| 16 | - Viewport position |
| 17 | - File path |
| 18 | |
| 19 | ### Keybindings |
| 20 | - [x] `alt-1` through `alt-9`: Jump to tab 1-9 |
| 21 | - [x] `ctrl-alt-left`: Previous tab (with wrap-around) |
| 22 | - [x] `ctrl-alt-right`: Next tab (with wrap-around) |
| 23 | - [x] Check for conflicts with existing bindings (DONE - no conflicts) |
| 24 | |
| 25 | ### Fuss Integration |
| 26 | - [x] Opening file in fuss mode creates new tab by default |
| 27 | - [x] New tab becomes active immediately |
| 28 | - [x] Fuss mode persists (already implemented) |
| 29 | |
| 30 | ### UI/UX |
| 31 | - [x] Tab bar shows: `[1: file1.txt] [2: file2.f90*] [3: README.md]` |
| 32 | - [x] Active tab uses reverse video (char(27) // '[7m') |
| 33 | - [x] Modified files indicated with `*` suffix |
| 34 | - [x] Tab bar takes 1 row at top |
| 35 | - [x] Adjust editor viewport to account for tab bar (starts at row 2) |
| 36 | - [x] Tab bar updates automatically when switching tabs |
| 37 | |
| 38 | ## Architecture Design |
| 39 | |
| 40 | ### Data Structures |
| 41 | |
| 42 | #### Tab Type (new) |
| 43 | ```fortran |
| 44 | type :: tab_t |
| 45 | character(len=:), allocatable :: filename |
| 46 | type(buffer_t) :: buffer |
| 47 | type(cursor_t), allocatable :: cursors(:) |
| 48 | integer :: active_cursor |
| 49 | integer :: viewport_line |
| 50 | integer :: viewport_column |
| 51 | logical :: modified |
| 52 | end type tab_t |
| 53 | ``` |
| 54 | |
| 55 | #### Editor State Updates |
| 56 | ```fortran |
| 57 | type(tab_t), allocatable :: tabs(:) |
| 58 | integer :: active_tab_index |
| 59 | integer :: max_tabs = 10 ! Support up to 10 tabs initially |
| 60 | ``` |
| 61 | |
| 62 | ### File Changes |
| 63 | |
| 64 | #### src/editor_state_module.f90 |
| 65 | - Add tab_t type definition |
| 66 | - Add tabs array and active_tab_index to editor_state_t |
| 67 | - Add procedures: create_tab, switch_tab, close_tab |
| 68 | |
| 69 | #### src/terminal/renderer_module.f90 |
| 70 | - Add render_tab_bar() subroutine |
| 71 | - Adjust main viewport to start at row 2 instead of row 1 |
| 72 | - Update render_screen() to call render_tab_bar() |
| 73 | |
| 74 | #### src/commands/command_handler_module.f90 |
| 75 | - Add alt-1 through alt-9 handlers |
| 76 | - Add ctrl-alt-left/right handlers |
| 77 | - Modify open_file_in_editor() to create new tab |
| 78 | - Add save/restore logic for tab switching |
| 79 | |
| 80 | #### src/buffer_module.f90 |
| 81 | - Ensure buffer can be deep-copied for tab state |
| 82 | - May need clone_buffer() function |
| 83 | |
| 84 | ## Implementation Phases |
| 85 | |
| 86 | ### Phase 1: Core Tab Infrastructure |
| 87 | 1. Define tab_t type |
| 88 | 2. Add tabs array to editor state |
| 89 | 3. Create basic tab management functions: |
| 90 | - `create_new_tab(editor, filename)` |
| 91 | - `switch_to_tab(editor, tab_index)` |
| 92 | - `get_current_tab(editor)` |
| 93 | |
| 94 | ### Phase 2: Tab Bar Rendering |
| 95 | 1. Implement `render_tab_bar()` |
| 96 | 2. Display tab index and filename |
| 97 | 3. Highlight active tab |
| 98 | 4. Show modification indicator |
| 99 | 5. Adjust viewport for tab bar |
| 100 | |
| 101 | ### Phase 3: Navigation Keybindings |
| 102 | 1. Parse alt-<number> key sequences |
| 103 | 2. Implement tab switching logic |
| 104 | 3. Add ctrl-alt-left/right navigation |
| 105 | 4. Save/restore cursor and viewport state |
| 106 | |
| 107 | ### Phase 4: Fuss Integration |
| 108 | 1. Modify `open_file_in_editor()` to create tab |
| 109 | 2. Set new tab as active |
| 110 | 3. Test opening multiple files from fuss |
| 111 | |
| 112 | ### Phase 5: Polish & Documentation |
| 113 | 1. Update ctrl-? help menu |
| 114 | 2. Test edge cases (max tabs, closing tabs, etc.) |
| 115 | 3. Handle unsaved changes warnings |
| 116 | 4. Performance testing with many tabs |
| 117 | |
| 118 | ## Edge Cases to Handle |
| 119 | |
| 120 | - Opening same file in multiple tabs (allow or prevent?) |
| 121 | - Maximum tab limit (10 initially) |
| 122 | - Tab overflow (show scroll indicator if >10 tabs?) |
| 123 | - Closing active tab (switch to next/previous) |
| 124 | - Closing all tabs (keep at least one empty buffer?) |
| 125 | - Modified file indicator updates |
| 126 | - Tab bar width overflow (truncate long filenames) |
| 127 | |
| 128 | ## Testing Plan |
| 129 | |
| 130 | ### Manual Tests |
| 131 | 1. Create 3 tabs, verify each has independent buffer |
| 132 | 2. Switch between tabs with alt-1, alt-2, alt-3 |
| 133 | 3. Navigate with ctrl-alt-left/right |
| 134 | 4. Open files from fuss, verify new tabs created |
| 135 | 5. Modify files in different tabs, verify * indicator |
| 136 | 6. Close tabs, verify proper cleanup |
| 137 | |
| 138 | ### Integration Tests |
| 139 | 1. Tab switching preserves cursor position |
| 140 | 2. Tab switching preserves undo history |
| 141 | 3. Fuss mode works correctly with multiple tabs open |
| 142 | 4. Tab bar updates when files modified |
| 143 | 5. Keybindings don't conflict with existing shortcuts |
| 144 | |
| 145 | ## Success Criteria |
| 146 | |
| 147 | - [ ] Can open 10 files in separate tabs |
| 148 | - [ ] Each tab maintains independent state |
| 149 | - [ ] Alt-<number> switches tabs instantly |
| 150 | - [ ] Ctrl-alt-left/right cycles through tabs |
| 151 | - [ ] Tab bar clearly shows which tab is active |
| 152 | - [ ] Opening file from fuss creates new tab |
| 153 | - [ ] Modified files show * indicator in tab bar |
| 154 | - [ ] Help menu documents all tab features |
| 155 | - [ ] No performance degradation with 10 tabs open |
| 156 | |
| 157 | ## Future Enhancements (Not in Scope) |
| 158 | |
| 159 | - Tab reordering (drag/drop or keyboard) |
| 160 | - Split panes (horizontal/vertical) |
| 161 | - Tab groups or sessions |
| 162 | - Persistent tab state between sessions |
| 163 | - Tab close keybinding (ctrl-w?) |
| 164 | - New empty tab keybinding (ctrl-t?) |