markdown · 17710 bytes Raw Blame History

Fortress Integration Plan

Version: 1.0 Last Updated: 2025-01-05


Overview

This document details how to integrate the Fortress file navigator into fac for workspace and file navigation. Fortress is a Fortran-based dual-pane file explorer located at ../fortress/.

Goal: Embed Fortress functionality into fac as a modal UI component triggered by Ctrl-O.

Approach: Copy and adapt Fortress modules rather than shelling out to external process.

Rationale:

  • Single binary (no external dependencies)
  • Full control over UI integration
  • Shared terminal state management
  • Better performance (no process spawning)

Fortress Repository Structure

../fortress/
├── app/
│   ├── main.f90                           # Main program (don't copy)
│   ├── filesystem/
│   │   ├── directory_module.f90           # ✅ Directory operations
│   │   └── path_utils_module.f90          # ✅ Path manipulation
│   ├── terminal/
│   │   ├── terminal_module.f90            # ⚠️  Adapt for fac's terminal
│   │   └── input_module.f90               # ⚠️  May need adaptation
│   └── ui/
│       ├── dual_pane_module.f90           # ✅ Dual-pane rendering
│       ├── navigation_module.f90          # ✅ Navigation logic
│       └── selection_module.f90           # ✅ File/dir selection
├── src/
│   └── (library code if any)
└── fpm.toml

Modules to Copy

Phase 1: Core Navigation (Minimum Viable)

1. filesystem/directory_module.f90

Purpose: Directory listing, stat operations, file type detection

Key Functions:

  • list_directory(path, entries, count) - Get directory contents
  • is_directory(path) - Check if path is directory
  • is_file(path) - Check if path is regular file
  • get_parent_directory(path) - Navigate up
  • resolve_path(path) - Canonicalize paths
  • path_exists(path) - Check existence

Changes Needed: None (should be portable)

Dependencies: Standard Fortran, possibly POSIX C bindings

Copy To: src/fortress/filesystem/directory_module.f90


2. filesystem/path_utils_module.f90

Purpose: Path string manipulation

Key Functions:

  • join_paths(base, relative) - Combine paths
  • basename(path) - Extract filename
  • dirname(path) - Extract directory
  • normalize_path(path) - Remove . and ..
  • expand_tilde(path) - Expand ~ to home directory

Changes Needed: Verify home directory detection works with fac's environment

Dependencies: None (pure Fortran string manipulation)

Copy To: src/fortress/filesystem/path_utils_module.f90


3. ui/dual_pane_module.f90

Purpose: Render dual-pane display (parent 30% | current 70%)

Key Functions:

  • render_dual_pane(parent_entries, current_entries, selected_index, width, height)
  • format_entry(entry, is_selected, is_directory) - Format single line
  • calculate_layout(total_width) - Determine pane widths

Changes Needed:

  • Use fac's terminal_io_module for output instead of Fortress's
  • Adapt to fac's color scheme constants
  • Ensure coordinate system matches fac's (1-based)

Dependencies:

  • directory_module (for entry types)
  • fac's terminal_io_module (for output)

Copy To: src/fortress/ui/dual_pane_module.f90


4. ui/navigation_module.f90

Purpose: Handle navigation logic and key input

Key Functions:

  • navigate_up() - Move cursor up
  • navigate_down() - Move cursor down
  • navigate_into() - Enter directory (→ or Enter)
  • navigate_back() - Go to parent (←)
  • jump_to_home() - Navigate to home (~)
  • jump_to_root() - Navigate to root (/)

Changes Needed:

  • Use fac's input_handler_module for key input
  • Adapt key codes to match fac's constants
  • Integrate with fac's event loop

Dependencies:

  • directory_module (for directory operations)
  • fac's input_handler_module (for key input)

Copy To: src/fortress/ui/navigation_module.f90


5. ui/selection_module.f90

Purpose: Handle selection and return value

Key Functions:

  • select_current() - Return selected path
  • cancel_selection() - Return empty (ESC pressed)
  • get_selection_type() - Determine if file or directory

Changes Needed: None (pure logic)

Dependencies:

  • directory_module (for type checking)

Copy To: src/fortress/ui/selection_module.f90


Phase 1: Exclusions (For Now)

These Fortress features will NOT be included in Phase 1:

Git Integration

  • git_ops_module.f90 - Git status indicators
  • Rationale: fac's fuss menu already has git integration; fortress doesn't need it
  • Future: Maybe add git status to fortress in Phase 7

Fuzzy Search (fzf)

  • Any fzf integration code
  • Rationale: Adds complexity; not critical for MVP
  • Future: Phase 7 polish

Multiselect

  • Multiselect/bulk operations
  • Rationale: Not needed for workspace switching
  • Future: Maybe later for opening multiple files

Bookmarks (if separate from favorites)

  • Fortress-specific bookmarks
  • Rationale: fac has its own favorites system
  • Future: Integrate with fac's favorites.json

Integration Architecture

New Module: navigator_module.f90

This is the main integration point that fac will call.

Location: src/fortress/navigator_module.f90

Purpose: Provide high-level API for fac to invoke fortress navigation

API:

module navigator_module
    use directory_module
    use dual_pane_module
    use navigation_module
    use selection_module
    implicit none

contains
    ! Main entry point for Ctrl-O
    subroutine open_fortress_navigator(selected_path, selection_type, cancelled, &
                                       initial_path)
        character(len=:), allocatable, intent(out) :: selected_path
        character(len=*), intent(out) :: selection_type  ! 'file' or 'directory'
        logical, intent(out) :: cancelled
        character(len=*), intent(in), optional :: initial_path

        ! Implementation:
        ! 1. Save current terminal state
        ! 2. Initialize fortress UI
        ! 3. Enter navigation loop
        ! 4. On selection: populate selected_path and selection_type
        ! 5. On ESC: set cancelled = .true.
        ! 6. Restore terminal state
        ! 7. Return to fac
    end subroutine

    ! Entry point for welcome menu (favorites/recents) - Phase 5
    subroutine open_fortress_welcome(selected_path, selection_type, cancelled)
        character(len=:), allocatable, intent(out) :: selected_path
        character(len=*), intent(out) :: selection_type
        logical, intent(out) :: cancelled

        ! Implementation for Phase 5
    end subroutine
end module

Terminal State Management

Challenge

fac already manages terminal state (raw mode, cursor, alternate screen). Fortress needs to work within this context.

Solution: Shared Terminal Module

Strategy: Make fortress use fac's existing terminal infrastructure.

fac's Terminal Modules:

  • src/terminal/raw_mode_module.f90 - Raw mode management
  • src/terminal/terminal_io_module.f90 - Output (colors, cursor, clear)
  • src/terminal/input_handler_module.f90 - Input (key codes, escape sequences)

Fortress Adaptation:

  1. Replace fortress's terminal output calls with fac's terminal_io_module
  2. Use fac's key code constants
  3. No need to enter/exit raw mode (already in raw mode)
  4. Save/restore cursor position before/after fortress UI

Example Adaptation:

! Fortress original:
call fortress_terminal_write_at(row, col, text)

! Adapted for fac:
call terminal_move_cursor(row, col)
call terminal_write(text)

Key Input Adaptation

Fortress Key Codes → fac Key Codes

Map fortress input handling to fac's constants:

Key Fortress Code fac Code Notes
KEY_UP Check input_handler_module Arrow keys
KEY_DOWN Check input_handler_module Arrow keys
KEY_RIGHT Check input_handler_module Arrow keys
KEY_LEFT Check input_handler_module Arrow keys
Enter CHAR_NEWLINE char(10) or CHAR_NEWLINE Standard
ESC CHAR_ESC char(27) Standard
q 'q' 'q' Standard
~ '~' '~' Jump to home
/ '/' '/' Jump to root
8 '8' '8' Toggle favorites/recents (Phase 5)
f 'f' 'f' Add to favorites (Phase 5)

Action: During copy, replace fortress key constants with fac equivalents.


Color Scheme Integration

Fortress Colors

Fortress likely has its own color definitions (e.g., selected = cyan, directory = blue).

fac Colors

fac has colors defined in terminal_io_module.f90:

  • Cursor line highlight
  • Selection highlight
  • Status bar colors
  • Tab colors (normal vs orphan)

Strategy

  1. Phase 1: Use fortress's original color scheme (minimal changes)
  2. Phase 7: Unify with fac's color palette for consistency

Note: Ensure colors are defined as named constants, not hardcoded ANSI codes.


Directory Structure After Integration

src/
├── fortress/
│   ├── filesystem/
│   │   ├── directory_module.f90
│   │   └── path_utils_module.f90
│   └── ui/
│       ├── dual_pane_module.f90
│       ├── navigation_module.f90
│       ├── selection_module.f90
│       └── navigator_module.f90       # NEW: Integration layer
├── terminal/
│   ├── raw_mode_module.f90
│   ├── terminal_io_module.f90
│   └── input_handler_module.f90
├── commands/
│   └── command_handler_module.f90     # Add Ctrl-O handler here
├── editor_state_module.f90
└── ...

Build Order (Makefile)

Module dependencies determine build order:

# Fortress modules (no dependencies)
src/fortress/filesystem/path_utils_module.f90

# Fortress modules (depends on path_utils)
src/fortress/filesystem/directory_module.f90

# Fortress UI modules (depends on filesystem + fac terminal)
src/fortress/ui/dual_pane_module.f90
src/fortress/ui/navigation_module.f90
src/fortress/ui/selection_module.f90

# Navigator integration (depends on all fortress modules)
src/fortress/navigator_module.f90

# Command handler (depends on navigator)
src/commands/command_handler_module.f90

# Main (depends on everything)
app/main.f90

Action: Add these to SOURCES in Makefile in correct order.


Integration Points in fac

1. Command Handler (Ctrl-O)

File: src/commands/command_handler_module.f90

Add:

use navigator_module

! In handle_key function:
else if (key_input == CTRL_O) then
    call handle_fortress_navigator(editor, buffer)
end if

subroutine handle_fortress_navigator(editor, buffer)
    type(editor_state_t), intent(inout) :: editor
    type(text_buffer_t), intent(inout) :: buffer
    character(len=:), allocatable :: selected_path
    character(len=256) :: selection_type
    logical :: cancelled

    ! Get current directory as starting point
    ! (from workspace path or buffer's file directory)

    call open_fortress_navigator(selected_path, selection_type, cancelled)

    if (.not. cancelled) then
        if (trim(selection_type) == 'directory') then
            ! Switch to that workspace
            call switch_workspace(editor, selected_path)
        else if (trim(selection_type) == 'file') then
            ! Open as orphan tab
            call open_orphan_tab(editor, selected_path)
        end if
    end if

    ! Re-render main UI
    call render_screen(editor, buffer)
end subroutine

2. Workspace Switching (Phase 2)

File: src/workspace/workspace_module.f90 (to be created)

API:

subroutine switch_workspace(editor, new_workspace_path)
    type(editor_state_t), intent(inout) :: editor
    character(len=*), intent(in) :: new_workspace_path

    ! 1. Prompt to save current workspace dirty buffers
    ! 2. Save current workspace state
    ! 3. Load new workspace state
    ! 4. Restore tabs/panes/positions
end subroutine

3. Orphan Tab Creation (Phase 3)

File: src/tabs/tab_manager_module.f90 (existing)

Add:

subroutine create_orphan_tab(editor, file_path)
    type(editor_state_t), intent(inout) :: editor
    character(len=*), intent(in) :: file_path

    ! 1. Create new tab
    ! 2. Mark as orphan (orphan flag)
    ! 3. Load file
    ! 4. Set tab label to basename
    ! 5. Set tab color to greyish
end subroutine

State Management

Entering Fortress Navigator

Before showing fortress UI:

  1. Save current cursor position: call terminal_get_cursor(saved_row, saved_col)
  2. Clear screen or enter alternate screen: call terminal_clear_screen()
  3. Hide fac's status bar
  4. Initialize fortress state (current directory, selection index)

Exiting Fortress Navigator

After user selection or cancellation:

  1. Clear fortress UI
  2. Restore fac's screen: call render_screen(editor, buffer)
  3. Restore cursor position (if needed)
  4. Return control to main loop

No Need To:

  • Enter/exit raw mode (already in raw mode)
  • Change terminal settings (fac already configured)

Error Handling

Directory Access Errors

  • Permission denied: Show error message in fortress UI, stay in current directory
  • Directory deleted: Fall back to parent or home directory

File Open Errors

  • Permission denied: Show error in fac status bar, don't create tab
  • File too large: Prompt user to confirm before loading

Path Resolution Errors

  • Symlink loops: Detect and break, show error
  • Invalid paths: Fallback to current directory

Testing Strategy

Unit Tests (Per Module)

directory_module:

  • List directory with various paths (., .., ~, /)
  • Handle nonexistent directories
  • Detect file types correctly
  • Resolve paths correctly

navigation_module:

  • Navigate up/down with boundaries
  • Enter directories
  • Go to parent
  • Jump to home/root

dual_pane_module:

  • Render with various terminal widths
  • Handle empty directories
  • Handle directories with many entries (scrolling)
  • Format entries correctly (colors, icons)

Integration Tests

Test 1: Basic Navigation

./fac test.txt
# Press Ctrl-O
# Should see dual-pane navigator
# Navigate with arrows
# Press ESC
# Should return to editor

Test 2: Directory Selection

./fac test.txt
# Press Ctrl-O
# Navigate to a directory
# Press Enter on directory
# Should switch to workspace mode (Phase 2)

Test 3: File Selection

./fac test.txt  # In workspace mode
# Press Ctrl-O
# Navigate to file outside workspace
# Press Enter on file
# Should open as orphan tab

Test 4: Edge Cases

  • Navigate to root (/)
  • Navigate to home (~)
  • Navigate to nonexistent directory (should handle gracefully)
  • Cancel with ESC (should return to editor unchanged)

Performance Considerations

Directory Listing

  • Large directories: Limit display to visible entries + buffer (e.g., 1000 entries max)
  • Lazy loading: Only stat entries when needed (not all 10k files upfront)

Rendering

  • Only redraw changed panes: Track dirty state
  • Batch terminal output: Use single write call per frame

Path Operations

  • Cache directory listings: Don't re-scan on every cursor move
  • Invalidate cache: Only on directory change or explicit refresh

Phase 1 Completion Criteria

Fortress integration is complete for Phase 1 when:

  • ✅ All fortress modules copied and adapted
  • navigator_module.f90 created with clean API
  • ✅ Ctrl-O opens dual-pane navigator
  • ✅ Can navigate filesystem with arrow keys
  • ✅ Can enter directories (→ or Enter)
  • ✅ Can go to parent (←)
  • ✅ Can jump to home (~) and root (/)
  • ✅ Can cancel (ESC) and return to editor
  • ✅ Selecting directory returns path correctly
  • ✅ Selecting file returns path correctly
  • ✅ No regressions in fac's existing features
  • ✅ Build system updated (Makefile)
  • ✅ Basic tests pass

Not Required for Phase 1:

  • Favorites/recents (Phase 5)
  • Git integration
  • Fuzzy search
  • Multiselect
  • Workspace switching (that's Phase 2)
  • Orphan tab creation (that's Phase 3)

Debugging Tips

Terminal State Debugging

  • Use /tmp/fortress_debug.txt for logging (not stdout/stderr)
  • Log cursor positions, key inputs, navigation state

Visual Debugging

  • Add visual markers for debugging (e.g., border characters)
  • Temporarily show state in header line

Common Issues

  • Cursor disappears: Check if fortress is hiding cursor (should use fac's cursor management)
  • Colors wrong: Verify ANSI codes match expectations
  • Keys not working: Check key code constants match
  • Rendering artifacts: Ensure screen clearing before redraw

Future Enhancements (Post-Phase 1)

Phase 5: Favorites & Recents

  • Add favorites_module.f90 to load/save favorites
  • Integrate with navigator_module
  • Add keybindings ('8' toggle, 'f' add favorite)

Phase 7: Polish

  • Add git status indicators (use fuss menu's git module)
  • Add fuzzy search (optional fzf integration)
  • Unify color scheme with fac
  • Performance optimization
  • Add icons for file types (if UTF-8 safe)

  • WORKSPACE_VISION.md - Overall design vision
  • workspace_spec.md - JSON schema for workspace.json
  • config_spec.md - favorites.json and recents.json formats (next doc)
  • WORKSPACE_ROADMAP.md - Implementation phases

End of Integration Plan

View source
1 # Fortress Integration Plan
2
3 **Version**: 1.0
4 **Last Updated**: 2025-01-05
5
6 ---
7
8 ## Overview
9
10 This document details how to integrate the Fortress file navigator into fac for workspace and file navigation. Fortress is a Fortran-based dual-pane file explorer located at `../fortress/`.
11
12 **Goal**: Embed Fortress functionality into fac as a modal UI component triggered by Ctrl-O.
13
14 **Approach**: Copy and adapt Fortress modules rather than shelling out to external process.
15
16 **Rationale**:
17 - Single binary (no external dependencies)
18 - Full control over UI integration
19 - Shared terminal state management
20 - Better performance (no process spawning)
21
22 ---
23
24 ## Fortress Repository Structure
25
26 ```
27 ../fortress/
28 ├── app/
29 │ ├── main.f90 # Main program (don't copy)
30 │ ├── filesystem/
31 │ │ ├── directory_module.f90 # ✅ Directory operations
32 │ │ └── path_utils_module.f90 # ✅ Path manipulation
33 │ ├── terminal/
34 │ │ ├── terminal_module.f90 # ⚠️ Adapt for fac's terminal
35 │ │ └── input_module.f90 # ⚠️ May need adaptation
36 │ └── ui/
37 │ ├── dual_pane_module.f90 # ✅ Dual-pane rendering
38 │ ├── navigation_module.f90 # ✅ Navigation logic
39 │ └── selection_module.f90 # ✅ File/dir selection
40 ├── src/
41 │ └── (library code if any)
42 └── fpm.toml
43 ```
44
45 ---
46
47 ## Modules to Copy
48
49 ### Phase 1: Core Navigation (Minimum Viable)
50
51 #### 1. `filesystem/directory_module.f90`
52 **Purpose**: Directory listing, stat operations, file type detection
53
54 **Key Functions**:
55 - `list_directory(path, entries, count)` - Get directory contents
56 - `is_directory(path)` - Check if path is directory
57 - `is_file(path)` - Check if path is regular file
58 - `get_parent_directory(path)` - Navigate up
59 - `resolve_path(path)` - Canonicalize paths
60 - `path_exists(path)` - Check existence
61
62 **Changes Needed**: None (should be portable)
63
64 **Dependencies**: Standard Fortran, possibly POSIX C bindings
65
66 **Copy To**: `src/fortress/filesystem/directory_module.f90`
67
68 ---
69
70 #### 2. `filesystem/path_utils_module.f90`
71 **Purpose**: Path string manipulation
72
73 **Key Functions**:
74 - `join_paths(base, relative)` - Combine paths
75 - `basename(path)` - Extract filename
76 - `dirname(path)` - Extract directory
77 - `normalize_path(path)` - Remove `.` and `..`
78 - `expand_tilde(path)` - Expand `~` to home directory
79
80 **Changes Needed**: Verify home directory detection works with fac's environment
81
82 **Dependencies**: None (pure Fortran string manipulation)
83
84 **Copy To**: `src/fortress/filesystem/path_utils_module.f90`
85
86 ---
87
88 #### 3. `ui/dual_pane_module.f90`
89 **Purpose**: Render dual-pane display (parent 30% | current 70%)
90
91 **Key Functions**:
92 - `render_dual_pane(parent_entries, current_entries, selected_index, width, height)`
93 - `format_entry(entry, is_selected, is_directory)` - Format single line
94 - `calculate_layout(total_width)` - Determine pane widths
95
96 **Changes Needed**:
97 - Use fac's `terminal_io_module` for output instead of Fortress's
98 - Adapt to fac's color scheme constants
99 - Ensure coordinate system matches fac's (1-based)
100
101 **Dependencies**:
102 - `directory_module` (for entry types)
103 - fac's `terminal_io_module` (for output)
104
105 **Copy To**: `src/fortress/ui/dual_pane_module.f90`
106
107 ---
108
109 #### 4. `ui/navigation_module.f90`
110 **Purpose**: Handle navigation logic and key input
111
112 **Key Functions**:
113 - `navigate_up()` - Move cursor up
114 - `navigate_down()` - Move cursor down
115 - `navigate_into()` - Enter directory (→ or Enter)
116 - `navigate_back()` - Go to parent (←)
117 - `jump_to_home()` - Navigate to home (~)
118 - `jump_to_root()` - Navigate to root (/)
119
120 **Changes Needed**:
121 - Use fac's `input_handler_module` for key input
122 - Adapt key codes to match fac's constants
123 - Integrate with fac's event loop
124
125 **Dependencies**:
126 - `directory_module` (for directory operations)
127 - fac's `input_handler_module` (for key input)
128
129 **Copy To**: `src/fortress/ui/navigation_module.f90`
130
131 ---
132
133 #### 5. `ui/selection_module.f90`
134 **Purpose**: Handle selection and return value
135
136 **Key Functions**:
137 - `select_current()` - Return selected path
138 - `cancel_selection()` - Return empty (ESC pressed)
139 - `get_selection_type()` - Determine if file or directory
140
141 **Changes Needed**: None (pure logic)
142
143 **Dependencies**:
144 - `directory_module` (for type checking)
145
146 **Copy To**: `src/fortress/ui/selection_module.f90`
147
148 ---
149
150 ### Phase 1: Exclusions (For Now)
151
152 These Fortress features will NOT be included in Phase 1:
153
154 #### Git Integration
155 - `git_ops_module.f90` - Git status indicators
156 - **Rationale**: fac's fuss menu already has git integration; fortress doesn't need it
157 - **Future**: Maybe add git status to fortress in Phase 7
158
159 #### Fuzzy Search (fzf)
160 - Any fzf integration code
161 - **Rationale**: Adds complexity; not critical for MVP
162 - **Future**: Phase 7 polish
163
164 #### Multiselect
165 - Multiselect/bulk operations
166 - **Rationale**: Not needed for workspace switching
167 - **Future**: Maybe later for opening multiple files
168
169 #### Bookmarks (if separate from favorites)
170 - Fortress-specific bookmarks
171 - **Rationale**: fac has its own favorites system
172 - **Future**: Integrate with fac's favorites.json
173
174 ---
175
176 ## Integration Architecture
177
178 ### New Module: `navigator_module.f90`
179
180 This is the main integration point that fac will call.
181
182 **Location**: `src/fortress/navigator_module.f90`
183
184 **Purpose**: Provide high-level API for fac to invoke fortress navigation
185
186 **API**:
187 ```fortran
188 module navigator_module
189 use directory_module
190 use dual_pane_module
191 use navigation_module
192 use selection_module
193 implicit none
194
195 contains
196 ! Main entry point for Ctrl-O
197 subroutine open_fortress_navigator(selected_path, selection_type, cancelled, &
198 initial_path)
199 character(len=:), allocatable, intent(out) :: selected_path
200 character(len=*), intent(out) :: selection_type ! 'file' or 'directory'
201 logical, intent(out) :: cancelled
202 character(len=*), intent(in), optional :: initial_path
203
204 ! Implementation:
205 ! 1. Save current terminal state
206 ! 2. Initialize fortress UI
207 ! 3. Enter navigation loop
208 ! 4. On selection: populate selected_path and selection_type
209 ! 5. On ESC: set cancelled = .true.
210 ! 6. Restore terminal state
211 ! 7. Return to fac
212 end subroutine
213
214 ! Entry point for welcome menu (favorites/recents) - Phase 5
215 subroutine open_fortress_welcome(selected_path, selection_type, cancelled)
216 character(len=:), allocatable, intent(out) :: selected_path
217 character(len=*), intent(out) :: selection_type
218 logical, intent(out) :: cancelled
219
220 ! Implementation for Phase 5
221 end subroutine
222 end module
223 ```
224
225 ---
226
227 ## Terminal State Management
228
229 ### Challenge
230 fac already manages terminal state (raw mode, cursor, alternate screen). Fortress needs to work within this context.
231
232 ### Solution: Shared Terminal Module
233
234 **Strategy**: Make fortress use fac's existing terminal infrastructure.
235
236 **fac's Terminal Modules**:
237 - `src/terminal/raw_mode_module.f90` - Raw mode management
238 - `src/terminal/terminal_io_module.f90` - Output (colors, cursor, clear)
239 - `src/terminal/input_handler_module.f90` - Input (key codes, escape sequences)
240
241 **Fortress Adaptation**:
242 1. Replace fortress's terminal output calls with fac's `terminal_io_module`
243 2. Use fac's key code constants
244 3. No need to enter/exit raw mode (already in raw mode)
245 4. Save/restore cursor position before/after fortress UI
246
247 **Example Adaptation**:
248 ```fortran
249 ! Fortress original:
250 call fortress_terminal_write_at(row, col, text)
251
252 ! Adapted for fac:
253 call terminal_move_cursor(row, col)
254 call terminal_write(text)
255 ```
256
257 ---
258
259 ## Key Input Adaptation
260
261 ### Fortress Key Codes → fac Key Codes
262
263 Map fortress input handling to fac's constants:
264
265 | Key | Fortress Code | fac Code | Notes |
266 |-----|---------------|----------|-------|
267 | ↑ | `KEY_UP` | Check `input_handler_module` | Arrow keys |
268 | ↓ | `KEY_DOWN` | Check `input_handler_module` | Arrow keys |
269 | → | `KEY_RIGHT` | Check `input_handler_module` | Arrow keys |
270 | ← | `KEY_LEFT` | Check `input_handler_module` | Arrow keys |
271 | Enter | `CHAR_NEWLINE` | `char(10)` or `CHAR_NEWLINE` | Standard |
272 | ESC | `CHAR_ESC` | `char(27)` | Standard |
273 | q | `'q'` | `'q'` | Standard |
274 | ~ | `'~'` | `'~'` | Jump to home |
275 | / | `'/'` | `'/'` | Jump to root |
276 | 8 | `'8'` | `'8'` | Toggle favorites/recents (Phase 5) |
277 | f | `'f'` | `'f'` | Add to favorites (Phase 5) |
278
279 **Action**: During copy, replace fortress key constants with fac equivalents.
280
281 ---
282
283 ## Color Scheme Integration
284
285 ### Fortress Colors
286 Fortress likely has its own color definitions (e.g., selected = cyan, directory = blue).
287
288 ### fac Colors
289 fac has colors defined in `terminal_io_module.f90`:
290 - Cursor line highlight
291 - Selection highlight
292 - Status bar colors
293 - Tab colors (normal vs orphan)
294
295 ### Strategy
296 1. **Phase 1**: Use fortress's original color scheme (minimal changes)
297 2. **Phase 7**: Unify with fac's color palette for consistency
298
299 **Note**: Ensure colors are defined as named constants, not hardcoded ANSI codes.
300
301 ---
302
303 ## Directory Structure After Integration
304
305 ```
306 src/
307 ├── fortress/
308 │ ├── filesystem/
309 │ │ ├── directory_module.f90
310 │ │ └── path_utils_module.f90
311 │ └── ui/
312 │ ├── dual_pane_module.f90
313 │ ├── navigation_module.f90
314 │ ├── selection_module.f90
315 │ └── navigator_module.f90 # NEW: Integration layer
316 ├── terminal/
317 │ ├── raw_mode_module.f90
318 │ ├── terminal_io_module.f90
319 │ └── input_handler_module.f90
320 ├── commands/
321 │ └── command_handler_module.f90 # Add Ctrl-O handler here
322 ├── editor_state_module.f90
323 └── ...
324 ```
325
326 ---
327
328 ## Build Order (Makefile)
329
330 Module dependencies determine build order:
331
332 ```makefile
333 # Fortress modules (no dependencies)
334 src/fortress/filesystem/path_utils_module.f90
335
336 # Fortress modules (depends on path_utils)
337 src/fortress/filesystem/directory_module.f90
338
339 # Fortress UI modules (depends on filesystem + fac terminal)
340 src/fortress/ui/dual_pane_module.f90
341 src/fortress/ui/navigation_module.f90
342 src/fortress/ui/selection_module.f90
343
344 # Navigator integration (depends on all fortress modules)
345 src/fortress/navigator_module.f90
346
347 # Command handler (depends on navigator)
348 src/commands/command_handler_module.f90
349
350 # Main (depends on everything)
351 app/main.f90
352 ```
353
354 **Action**: Add these to `SOURCES` in Makefile in correct order.
355
356 ---
357
358 ## Integration Points in fac
359
360 ### 1. Command Handler (Ctrl-O)
361
362 **File**: `src/commands/command_handler_module.f90`
363
364 **Add**:
365 ```fortran
366 use navigator_module
367
368 ! In handle_key function:
369 else if (key_input == CTRL_O) then
370 call handle_fortress_navigator(editor, buffer)
371 end if
372
373 subroutine handle_fortress_navigator(editor, buffer)
374 type(editor_state_t), intent(inout) :: editor
375 type(text_buffer_t), intent(inout) :: buffer
376 character(len=:), allocatable :: selected_path
377 character(len=256) :: selection_type
378 logical :: cancelled
379
380 ! Get current directory as starting point
381 ! (from workspace path or buffer's file directory)
382
383 call open_fortress_navigator(selected_path, selection_type, cancelled)
384
385 if (.not. cancelled) then
386 if (trim(selection_type) == 'directory') then
387 ! Switch to that workspace
388 call switch_workspace(editor, selected_path)
389 else if (trim(selection_type) == 'file') then
390 ! Open as orphan tab
391 call open_orphan_tab(editor, selected_path)
392 end if
393 end if
394
395 ! Re-render main UI
396 call render_screen(editor, buffer)
397 end subroutine
398 ```
399
400 ### 2. Workspace Switching (Phase 2)
401
402 **File**: `src/workspace/workspace_module.f90` (to be created)
403
404 **API**:
405 ```fortran
406 subroutine switch_workspace(editor, new_workspace_path)
407 type(editor_state_t), intent(inout) :: editor
408 character(len=*), intent(in) :: new_workspace_path
409
410 ! 1. Prompt to save current workspace dirty buffers
411 ! 2. Save current workspace state
412 ! 3. Load new workspace state
413 ! 4. Restore tabs/panes/positions
414 end subroutine
415 ```
416
417 ### 3. Orphan Tab Creation (Phase 3)
418
419 **File**: `src/tabs/tab_manager_module.f90` (existing)
420
421 **Add**:
422 ```fortran
423 subroutine create_orphan_tab(editor, file_path)
424 type(editor_state_t), intent(inout) :: editor
425 character(len=*), intent(in) :: file_path
426
427 ! 1. Create new tab
428 ! 2. Mark as orphan (orphan flag)
429 ! 3. Load file
430 ! 4. Set tab label to basename
431 ! 5. Set tab color to greyish
432 end subroutine
433 ```
434
435 ---
436
437 ## State Management
438
439 ### Entering Fortress Navigator
440
441 **Before showing fortress UI**:
442 1. Save current cursor position: `call terminal_get_cursor(saved_row, saved_col)`
443 2. Clear screen or enter alternate screen: `call terminal_clear_screen()`
444 3. Hide fac's status bar
445 4. Initialize fortress state (current directory, selection index)
446
447 ### Exiting Fortress Navigator
448
449 **After user selection or cancellation**:
450 1. Clear fortress UI
451 2. Restore fac's screen: `call render_screen(editor, buffer)`
452 3. Restore cursor position (if needed)
453 4. Return control to main loop
454
455 **No Need To**:
456 - Enter/exit raw mode (already in raw mode)
457 - Change terminal settings (fac already configured)
458
459 ---
460
461 ## Error Handling
462
463 ### Directory Access Errors
464 - **Permission denied**: Show error message in fortress UI, stay in current directory
465 - **Directory deleted**: Fall back to parent or home directory
466
467 ### File Open Errors
468 - **Permission denied**: Show error in fac status bar, don't create tab
469 - **File too large**: Prompt user to confirm before loading
470
471 ### Path Resolution Errors
472 - **Symlink loops**: Detect and break, show error
473 - **Invalid paths**: Fallback to current directory
474
475 ---
476
477 ## Testing Strategy
478
479 ### Unit Tests (Per Module)
480
481 **directory_module**:
482 - List directory with various paths (., .., ~, /)
483 - Handle nonexistent directories
484 - Detect file types correctly
485 - Resolve paths correctly
486
487 **navigation_module**:
488 - Navigate up/down with boundaries
489 - Enter directories
490 - Go to parent
491 - Jump to home/root
492
493 **dual_pane_module**:
494 - Render with various terminal widths
495 - Handle empty directories
496 - Handle directories with many entries (scrolling)
497 - Format entries correctly (colors, icons)
498
499 ### Integration Tests
500
501 **Test 1: Basic Navigation**
502 ```bash
503 ./fac test.txt
504 # Press Ctrl-O
505 # Should see dual-pane navigator
506 # Navigate with arrows
507 # Press ESC
508 # Should return to editor
509 ```
510
511 **Test 2: Directory Selection**
512 ```bash
513 ./fac test.txt
514 # Press Ctrl-O
515 # Navigate to a directory
516 # Press Enter on directory
517 # Should switch to workspace mode (Phase 2)
518 ```
519
520 **Test 3: File Selection**
521 ```bash
522 ./fac test.txt # In workspace mode
523 # Press Ctrl-O
524 # Navigate to file outside workspace
525 # Press Enter on file
526 # Should open as orphan tab
527 ```
528
529 **Test 4: Edge Cases**
530 - Navigate to root (/)
531 - Navigate to home (~)
532 - Navigate to nonexistent directory (should handle gracefully)
533 - Cancel with ESC (should return to editor unchanged)
534
535 ---
536
537 ## Performance Considerations
538
539 ### Directory Listing
540 - **Large directories**: Limit display to visible entries + buffer (e.g., 1000 entries max)
541 - **Lazy loading**: Only stat entries when needed (not all 10k files upfront)
542
543 ### Rendering
544 - **Only redraw changed panes**: Track dirty state
545 - **Batch terminal output**: Use single write call per frame
546
547 ### Path Operations
548 - **Cache directory listings**: Don't re-scan on every cursor move
549 - **Invalidate cache**: Only on directory change or explicit refresh
550
551 ---
552
553 ## Phase 1 Completion Criteria
554
555 Fortress integration is complete for Phase 1 when:
556
557 - ✅ All fortress modules copied and adapted
558 -`navigator_module.f90` created with clean API
559 - ✅ Ctrl-O opens dual-pane navigator
560 - ✅ Can navigate filesystem with arrow keys
561 - ✅ Can enter directories (→ or Enter)
562 - ✅ Can go to parent (←)
563 - ✅ Can jump to home (~) and root (/)
564 - ✅ Can cancel (ESC) and return to editor
565 - ✅ Selecting directory returns path correctly
566 - ✅ Selecting file returns path correctly
567 - ✅ No regressions in fac's existing features
568 - ✅ Build system updated (Makefile)
569 - ✅ Basic tests pass
570
571 **Not Required for Phase 1**:
572 - Favorites/recents (Phase 5)
573 - Git integration
574 - Fuzzy search
575 - Multiselect
576 - Workspace switching (that's Phase 2)
577 - Orphan tab creation (that's Phase 3)
578
579 ---
580
581 ## Debugging Tips
582
583 ### Terminal State Debugging
584 - Use `/tmp/fortress_debug.txt` for logging (not stdout/stderr)
585 - Log cursor positions, key inputs, navigation state
586
587 ### Visual Debugging
588 - Add visual markers for debugging (e.g., border characters)
589 - Temporarily show state in header line
590
591 ### Common Issues
592 - **Cursor disappears**: Check if fortress is hiding cursor (should use fac's cursor management)
593 - **Colors wrong**: Verify ANSI codes match expectations
594 - **Keys not working**: Check key code constants match
595 - **Rendering artifacts**: Ensure screen clearing before redraw
596
597 ---
598
599 ## Future Enhancements (Post-Phase 1)
600
601 ### Phase 5: Favorites & Recents
602 - Add `favorites_module.f90` to load/save favorites
603 - Integrate with navigator_module
604 - Add keybindings ('8' toggle, 'f' add favorite)
605
606 ### Phase 7: Polish
607 - Add git status indicators (use fuss menu's git module)
608 - Add fuzzy search (optional fzf integration)
609 - Unify color scheme with fac
610 - Performance optimization
611 - Add icons for file types (if UTF-8 safe)
612
613 ---
614
615 ## Related Documents
616
617 - `WORKSPACE_VISION.md` - Overall design vision
618 - `workspace_spec.md` - JSON schema for workspace.json
619 - `config_spec.md` - favorites.json and recents.json formats (next doc)
620 - `WORKSPACE_ROADMAP.md` - Implementation phases
621
622 ---
623
624 **End of Integration Plan**