fortrangoingonforty/fortress / 07219b0

Browse files

totally scrap old approach. minimal two pane working

Authored by espadonne
SHA
07219b06f5d5cb6a7ef2c5ec79a3c32f7008e5a4
Parents
83516a6
Tree
fd6614d

9 changed files

StatusFile+-
M src/filesystem/operations.f90 13 8
A src/fortress_clean.f90 278 0
A src/fortress_v2.f90 289 0
M src/main.f90 2 2
A src/simple_main.f90 119 0
A src/test_right_pane.f90 31 0
M src/ui/panes.f90 40 56
A src/ui/panes_buffered.f90 169 0
A src/ui/panes_debug.f90 88 0
src/filesystem/operations.f90modified
@@ -22,7 +22,7 @@ contains
22
         type(file_entry), dimension(MAX_FILES) :: entries
22
         type(file_entry), dimension(MAX_FILES) :: entries
23
         character(len=MAX_PATH) :: temp_file
23
         character(len=MAX_PATH) :: temp_file
24
         character(len=MAX_PATH) :: line, full_path
24
         character(len=MAX_PATH) :: line, full_path
25
-        integer :: unit, ios, count, i
25
+        integer :: unit, ios, count, i, cmd_stat
26
 
26
 
27
         ! Initialize entries
27
         ! Initialize entries
28
         do i = 1, MAX_FILES
28
         do i = 1, MAX_FILES
@@ -31,11 +31,15 @@ contains
31
             entries(i)%size = 0
31
             entries(i)%size = 0
32
         end do
32
         end do
33
 
33
 
34
-        ! Create a temporary file to store ls output
34
+        ! Create a temporary file to store ls output in HOME directory
35
-        temp_file = "/tmp/fortress_ls_temp.txt"
35
+        ! This should work even in raw terminal mode
36
+        call get_environment_variable("HOME", temp_file)
37
+        temp_file = trim(temp_file) // "/.fortress_ls_temp.txt"
36
 
38
 
37
-        ! Use ls -1 for simpler parsing
39
+        ! Use ls -1 for simpler parsing with error checking
38
-        call execute_command_line("ls -1a '" // trim(path) // "' > " // trim(temp_file), wait=.true.)
40
+        ! Use explicit sh to ensure it works in raw terminal mode
41
+        call execute_command_line("sh -c 'ls -1a """ // trim(path) // """ > " // trim(temp_file) // " 2>&1'", &
42
+                                 exitstat=cmd_stat, wait=.true.)
39
 
43
 
40
         ! Open and read the temp file
44
         ! Open and read the temp file
41
         open(newunit=unit, file=temp_file, status='old', action='read', iostat=ios)
45
         open(newunit=unit, file=temp_file, status='old', action='read', iostat=ios)
@@ -94,7 +98,7 @@ contains
94
         is_dir = .false.
98
         is_dir = .false.
95
 
99
 
96
         ! Use test command to check if it's a directory
100
         ! Use test command to check if it's a directory
97
-        call execute_command_line("test -d '" // trim(path) // "'", &
101
+        call execute_command_line("sh -c 'test -d """ // trim(path) // """'", &
98
                                   exitstat=stat, wait=.true.)
102
                                   exitstat=stat, wait=.true.)
99
         is_dir = (stat == 0)
103
         is_dir = (stat == 0)
100
     end function is_directory
104
     end function is_directory
@@ -105,8 +109,9 @@ contains
105
         integer :: unit, ios
109
         integer :: unit, ios
106
 
110
 
107
         ! Create a temporary file to store pwd output
111
         ! Create a temporary file to store pwd output
108
-        temp_file = "/tmp/fortress_pwd_temp.txt"
112
+        call get_environment_variable("HOME", temp_file)
109
-        call execute_command_line("pwd > " // trim(temp_file), wait=.true.)
113
+        temp_file = trim(temp_file) // "/.fortress_pwd_temp.txt"
114
+        call execute_command_line("sh -c 'pwd > " // trim(temp_file) // "'", wait=.true.)
110
 
115
 
111
         ! Read the current directory
116
         ! Read the current directory
112
         open(newunit=unit, file=temp_file, status='old', action='read', iostat=ios)
117
         open(newunit=unit, file=temp_file, status='old', action='read', iostat=ios)
src/fortress_clean.f90added
@@ -0,0 +1,278 @@
1
+program fortress_clean
2
+    use iso_fortran_env, only: output_unit, error_unit
3
+    implicit none
4
+
5
+    ! Constants
6
+    integer, parameter :: MAX_PATH = 512
7
+    integer, parameter :: MAX_FILES = 500
8
+    character(len=*), parameter :: ESC = char(27)
9
+    character(len=*), parameter :: CLEAR = ESC // "[2J" // ESC // "[H"
10
+    character(len=*), parameter :: BOLD = ESC // "[1m"
11
+    character(len=*), parameter :: DIM = ESC // "[2m"
12
+    character(len=*), parameter :: REVERSE = ESC // "[7m"
13
+    character(len=*), parameter :: RESET = ESC // "[0m"
14
+
15
+    ! Variables
16
+    character(len=MAX_PATH) :: current_dir, parent_dir, temp_dir
17
+    character(len=MAX_PATH), dimension(MAX_FILES) :: current_files, parent_files
18
+    logical, dimension(MAX_FILES) :: current_is_dir, parent_is_dir
19
+    integer :: current_count, parent_count
20
+    integer :: selected = 1
21
+    integer :: parent_selected = -1
22
+    character(len=1) :: key
23
+    logical :: running = .true.
24
+    integer :: i, rows, cols
25
+
26
+    ! Initialize
27
+    current_dir = get_pwd()
28
+    parent_dir = get_parent_path(current_dir)
29
+
30
+    ! Setup terminal
31
+    call execute_command_line("stty -icanon -echo min 1 time 0 2>/dev/null")
32
+
33
+    ! Main loop
34
+    do while (running)
35
+        ! Get files
36
+        call get_file_list(current_dir, current_files, current_is_dir, current_count)
37
+        call get_file_list(parent_dir, parent_files, parent_is_dir, parent_count)
38
+
39
+        ! Find current dir in parent
40
+        parent_selected = find_in_parent(current_dir, parent_files, parent_count)
41
+
42
+        ! Get terminal size
43
+        call get_term_size(rows, cols)
44
+
45
+        ! Draw interface
46
+        write(output_unit, '(a)', advance='no') CLEAR
47
+        call draw_interface(rows, cols)
48
+
49
+        ! Get input
50
+        read(*, '(a1)', advance='no') key
51
+
52
+        ! Handle input
53
+        select case(ichar(key))
54
+        case(27)  ! ESC sequence
55
+            call read_arrow_key(key)
56
+            select case(key)
57
+            case('A')  ! Up
58
+                if (selected > 1) selected = selected - 1
59
+            case('B')  ! Down
60
+                if (selected < current_count) selected = selected + 1
61
+            case('C')  ! Right - enter
62
+                if (current_is_dir(selected)) then
63
+                    if (trim(current_files(selected)) == "..") then
64
+                        temp_dir = current_dir
65
+                        current_dir = parent_dir
66
+                        parent_dir = get_parent_path(current_dir)
67
+                        selected = max(1, find_in_parent(temp_dir, current_files, MAX_FILES))
68
+                    else if (trim(current_files(selected)) /= ".") then
69
+                        parent_dir = current_dir
70
+                        current_dir = join_path(current_dir, current_files(selected))
71
+                        selected = 1
72
+                    end if
73
+                end if
74
+            case('D')  ! Left - back
75
+                if (current_dir /= "/") then
76
+                    temp_dir = current_dir
77
+                    current_dir = parent_dir
78
+                    parent_dir = get_parent_path(current_dir)
79
+                    selected = max(1, find_in_parent(temp_dir, current_files, MAX_FILES))
80
+                end if
81
+            end select
82
+        case(113, 81)  ! 'q' or 'Q'
83
+            running = .false.
84
+        end select
85
+    end do
86
+
87
+    ! Cleanup
88
+    call execute_command_line("stty icanon echo 2>/dev/null")
89
+    write(output_unit, '(a)', advance='no') CLEAR
90
+    write(output_unit, '(a)') "Thanks for using FORTRESS!"
91
+
92
+contains
93
+
94
+    function get_pwd() result(path)
95
+        character(len=MAX_PATH) :: path
96
+        integer :: unit, ios
97
+
98
+        call execute_command_line("pwd > .fortress_pwd 2>/dev/null", wait=.true.)
99
+        open(newunit=unit, file=".fortress_pwd", status='old', iostat=ios)
100
+        if (ios == 0) then
101
+            read(unit, '(a)') path
102
+            close(unit)
103
+        else
104
+            path = "."
105
+        end if
106
+        call execute_command_line("rm -f .fortress_pwd 2>/dev/null")
107
+    end function get_pwd
108
+
109
+    function get_parent_path(path) result(parent)
110
+        character(len=*), intent(in) :: path
111
+        character(len=MAX_PATH) :: parent
112
+        integer :: pos
113
+
114
+        pos = index(path, "/", back=.true.)
115
+        if (pos > 1) then
116
+            parent = path(1:pos-1)
117
+        else if (pos == 1) then
118
+            parent = "/"
119
+        else
120
+            parent = "."
121
+        end if
122
+    end function get_parent_path
123
+
124
+    function join_path(base, name) result(full)
125
+        character(len=*), intent(in) :: base, name
126
+        character(len=MAX_PATH) :: full
127
+
128
+        if (base == "/") then
129
+            full = "/" // trim(name)
130
+        else
131
+            full = trim(base) // "/" // trim(name)
132
+        end if
133
+    end function join_path
134
+
135
+    function find_in_parent(dir, files, count) result(idx)
136
+        character(len=*), intent(in) :: dir
137
+        character(len=*), dimension(*), intent(in) :: files
138
+        integer, intent(in) :: count
139
+        integer :: idx, pos
140
+        character(len=256) :: basename
141
+
142
+        pos = index(dir, "/", back=.true.)
143
+        if (pos > 0) then
144
+            basename = dir(pos+1:)
145
+        else
146
+            basename = dir
147
+        end if
148
+
149
+        do idx = 1, count
150
+            if (trim(files(idx)) == trim(basename)) return
151
+        end do
152
+        idx = 1
153
+    end function find_in_parent
154
+
155
+    subroutine get_file_list(dir, files, is_dir, count)
156
+        character(len=*), intent(in) :: dir
157
+        character(len=*), dimension(*), intent(out) :: files
158
+        logical, dimension(*), intent(out) :: is_dir
159
+        integer, intent(out) :: count
160
+        integer :: unit, ios, stat
161
+        character(len=MAX_PATH) :: fullpath
162
+
163
+        call execute_command_line("ls -1a '" // trim(dir) // "' > .fortress_ls 2>/dev/null", wait=.true.)
164
+
165
+        open(newunit=unit, file=".fortress_ls", status='old', iostat=ios)
166
+        if (ios /= 0) then
167
+            count = 0
168
+            return
169
+        end if
170
+
171
+        count = 0
172
+        do
173
+            count = count + 1
174
+            if (count > MAX_FILES) exit
175
+            read(unit, '(a)', iostat=ios) files(count)
176
+            if (ios /= 0) then
177
+                count = count - 1
178
+                exit
179
+            end if
180
+
181
+            fullpath = join_path(dir, files(count))
182
+            call execute_command_line("test -d '" // trim(fullpath) // "'", exitstat=stat, wait=.true.)
183
+            is_dir(count) = (stat == 0)
184
+        end do
185
+
186
+        close(unit)
187
+        call execute_command_line("rm -f .fortress_ls 2>/dev/null")
188
+    end subroutine get_file_list
189
+
190
+    subroutine get_term_size(r, c)
191
+        integer, intent(out) :: r, c
192
+        integer :: unit, ios
193
+
194
+        call execute_command_line("tput lines > .fortress_size 2>/dev/null", wait=.true.)
195
+        open(newunit=unit, file=".fortress_size", status='old', iostat=ios)
196
+        if (ios == 0) then
197
+            read(unit, *) r
198
+            close(unit)
199
+        else
200
+            r = 24
201
+        end if
202
+
203
+        call execute_command_line("tput cols > .fortress_size 2>/dev/null", wait=.true.)
204
+        open(newunit=unit, file=".fortress_size", status='old', iostat=ios)
205
+        if (ios == 0) then
206
+            read(unit, *) c
207
+            close(unit)
208
+        else
209
+            c = 80
210
+        end if
211
+
212
+        call execute_command_line("rm -f .fortress_size 2>/dev/null")
213
+    end subroutine get_term_size
214
+
215
+    subroutine draw_interface(r, c)
216
+        integer, intent(in) :: r, c
217
+        integer :: left_w, i
218
+        character(len=256) :: fname
219
+
220
+        left_w = c * 3 / 10
221
+
222
+        ! Header
223
+        write(output_unit, '(a)') BOLD // "FORTRESS" // RESET // " - " // trim(current_dir)
224
+
225
+        ! Files
226
+        do i = 1, min(r-3, max(parent_count, current_count))
227
+            ! Parent pane
228
+            if (i <= parent_count) then
229
+                fname = parent_files(i)
230
+                if (parent_is_dir(i) .and. fname /= "." .and. fname /= "..") then
231
+                    fname = trim(fname) // "/"
232
+                end if
233
+                if (i == parent_selected) then
234
+                    write(output_unit, '(a)', advance='no') DIM // BOLD // fname(1:min(len_trim(fname),left_w)) // RESET
235
+                else
236
+                    write(output_unit, '(a)', advance='no') DIM // fname(1:min(len_trim(fname),left_w)) // RESET
237
+                end if
238
+                write(output_unit, '(a)', advance='no') repeat(" ", max(0, left_w - len_trim(fname)))
239
+            else
240
+                write(output_unit, '(a)', advance='no') repeat(" ", left_w)
241
+            end if
242
+
243
+            ! Separator
244
+            write(output_unit, '(a)', advance='no') " │ "
245
+
246
+            ! Current pane
247
+            if (i <= current_count) then
248
+                fname = current_files(i)
249
+                if (current_is_dir(i) .and. fname /= "." .and. fname /= "..") then
250
+                    fname = trim(fname) // "/"
251
+                end if
252
+                if (i == selected) then
253
+                    write(output_unit, '(a)') REVERSE // trim(fname) // RESET
254
+                else
255
+                    write(output_unit, '(a)') trim(fname)
256
+                end if
257
+            else
258
+                write(output_unit, *)
259
+            end if
260
+        end do
261
+
262
+        ! Footer
263
+        write(output_unit, '(a,i0,a)') DIM // "↑↓:nav →:enter ←:back q:quit [", selected, "/" // trim(adjustl(char(current_count))) // "]" // RESET
264
+    end subroutine draw_interface
265
+
266
+    subroutine read_arrow_key(k)
267
+        character(len=1), intent(out) :: k
268
+        character(len=1) :: ch
269
+
270
+        read(*, '(a1)', advance='no') ch
271
+        if (ch == '[') then
272
+            read(*, '(a1)', advance='no') k
273
+        else
274
+            k = ch
275
+        end if
276
+    end subroutine read_arrow_key
277
+
278
+end program fortress_clean
src/fortress_v2.f90added
@@ -0,0 +1,289 @@
1
+program fortress_v2
2
+    use iso_fortran_env, only: output_unit
3
+    implicit none
4
+
5
+    ! File entry type
6
+    type :: file_entry
7
+        character(len=256) :: name = ""
8
+        logical :: is_dir = .false.
9
+    end type file_entry
10
+
11
+    ! Constants
12
+    integer, parameter :: MAX_FILES = 200
13
+    character(len=*), parameter :: ESC = char(27)
14
+
15
+    ! State variables
16
+    type(file_entry), dimension(MAX_FILES) :: current_files, parent_files
17
+    integer :: current_count, parent_count
18
+    integer :: selected = 1
19
+    character(len=512) :: current_path, parent_path
20
+    logical :: running = .true.
21
+    character(len=10) :: key
22
+    integer :: rows, cols
23
+    integer :: i
24
+
25
+    ! Initialize
26
+    call get_cwd(current_path)
27
+    call get_parent(current_path, parent_path)
28
+
29
+    ! Setup terminal
30
+    call system("stty -icanon -echo min 1 time 0")
31
+    call get_terminal_size(rows, cols)
32
+
33
+    ! Main loop
34
+    do while (running)
35
+        ! Get directory contents
36
+        call list_dir(current_path, current_files, current_count)
37
+        call list_dir(parent_path, parent_files, parent_count)
38
+
39
+        ! Draw screen
40
+        call clear_screen()
41
+        call draw_header(current_path)
42
+        call draw_panes(parent_files, parent_count, current_files, current_count, selected, rows, cols)
43
+        call draw_footer()
44
+
45
+        ! Get keyboard input
46
+        call get_key(key)
47
+
48
+        ! Handle input
49
+        select case(trim(key))
50
+        case('A')  ! Up arrow
51
+            if (selected > 1) selected = selected - 1
52
+        case('B')  ! Down arrow
53
+            if (selected < current_count) selected = selected + 1
54
+        case('C')  ! Right arrow - enter directory
55
+            if (selected <= current_count .and. current_files(selected)%is_dir) then
56
+                if (trim(current_files(selected)%name) /= ".") then
57
+                    call change_dir(current_path, current_files(selected)%name, parent_path)
58
+                    selected = 1
59
+                end if
60
+            end if
61
+        case('D')  ! Left arrow - go to parent
62
+            if (trim(current_path) /= "/") then
63
+                current_path = parent_path
64
+                call get_parent(current_path, parent_path)
65
+                selected = 1
66
+            end if
67
+        case('q', 'Q')
68
+            running = .false.
69
+        end select
70
+    end do
71
+
72
+    ! Cleanup
73
+    call system("stty icanon echo")
74
+    call clear_screen()
75
+    write(output_unit, '(a)') "Thanks for using FORTRESS v2!"
76
+
77
+contains
78
+
79
+    subroutine get_cwd(path)
80
+        character(len=*), intent(out) :: path
81
+        integer :: unit, ios
82
+
83
+        call execute_command_line("pwd > pwd_temp.txt", wait=.true.)
84
+        open(newunit=unit, file="pwd_temp.txt", status='old', iostat=ios)
85
+        if (ios == 0) then
86
+            read(unit, '(a)') path
87
+            close(unit)
88
+        else
89
+            path = "."
90
+        end if
91
+        call execute_command_line("rm -f pwd_temp.txt", wait=.false.)
92
+    end subroutine get_cwd
93
+
94
+    subroutine get_parent(path, parent)
95
+        character(len=*), intent(in) :: path
96
+        character(len=*), intent(out) :: parent
97
+        integer :: last_slash
98
+
99
+        last_slash = index(path, '/', back=.true.)
100
+        if (last_slash > 1) then
101
+            parent = path(1:last_slash-1)
102
+        else
103
+            parent = "/"
104
+        end if
105
+    end subroutine get_parent
106
+
107
+    subroutine change_dir(current, new_name, parent)
108
+        character(len=*), intent(inout) :: current
109
+        character(len=*), intent(in) :: new_name
110
+        character(len=*), intent(inout) :: parent
111
+
112
+        if (trim(new_name) == "..") then
113
+            if (trim(current) /= "/") then
114
+                parent = current
115
+                call get_parent(current, parent)
116
+                current = parent
117
+                call get_parent(current, parent)
118
+            end if
119
+        else
120
+            parent = current
121
+            if (trim(current) == "/") then
122
+                current = "/" // trim(new_name)
123
+            else
124
+                current = trim(current) // "/" // trim(new_name)
125
+            end if
126
+        end if
127
+    end subroutine change_dir
128
+
129
+    subroutine list_dir(path, files, count)
130
+        character(len=*), intent(in) :: path
131
+        type(file_entry), dimension(MAX_FILES), intent(out) :: files
132
+        integer, intent(out) :: count
133
+        integer :: unit, ios
134
+        character(len=512) :: cmd
135
+
136
+        ! Initialize
137
+        files%name = ""
138
+        files%is_dir = .false.
139
+
140
+        ! List files
141
+        write(cmd, '(a)') "ls -1a " // trim(path) // " 2>/dev/null > ls_temp.txt"
142
+        call execute_command_line(trim(cmd), wait=.true.)
143
+
144
+        open(newunit=unit, file="ls_temp.txt", status='old', iostat=ios)
145
+        if (ios /= 0) then
146
+            count = 0
147
+            return
148
+        end if
149
+
150
+        count = 0
151
+        do
152
+            count = count + 1
153
+            if (count > MAX_FILES) exit
154
+            read(unit, '(a)', iostat=ios) files(count)%name
155
+            if (ios /= 0) then
156
+                count = count - 1
157
+                exit
158
+            end if
159
+            ! Check if directory
160
+            call is_directory(path, files(count)%name, files(count)%is_dir)
161
+        end do
162
+
163
+        close(unit)
164
+        call execute_command_line("rm -f ls_temp.txt", wait=.false.)
165
+    end subroutine list_dir
166
+
167
+    subroutine is_directory(base_path, name, is_dir)
168
+        character(len=*), intent(in) :: base_path, name
169
+        logical, intent(out) :: is_dir
170
+        character(len=512) :: full_path
171
+        integer :: stat
172
+
173
+        if (trim(base_path) == "/") then
174
+            full_path = "/" // trim(name)
175
+        else
176
+            full_path = trim(base_path) // "/" // trim(name)
177
+        end if
178
+
179
+        call execute_command_line("test -d '" // trim(full_path) // "'", &
180
+                                 exitstat=stat, wait=.true.)
181
+        is_dir = (stat == 0)
182
+    end subroutine is_directory
183
+
184
+    subroutine get_terminal_size(rows, cols)
185
+        integer, intent(out) :: rows, cols
186
+        integer :: unit, ios
187
+
188
+        call execute_command_line("tput lines > size_temp.txt", wait=.true.)
189
+        open(newunit=unit, file="size_temp.txt", status='old', iostat=ios)
190
+        if (ios == 0) then
191
+            read(unit, *) rows
192
+            close(unit)
193
+        else
194
+            rows = 24
195
+        end if
196
+
197
+        call execute_command_line("tput cols > size_temp.txt", wait=.true.)
198
+        open(newunit=unit, file="size_temp.txt", status='old', iostat=ios)
199
+        if (ios == 0) then
200
+            read(unit, *) cols
201
+            close(unit)
202
+        else
203
+            cols = 80
204
+        end if
205
+
206
+        call execute_command_line("rm -f size_temp.txt", wait=.false.)
207
+    end subroutine get_terminal_size
208
+
209
+    subroutine clear_screen()
210
+        write(output_unit, '(a)', advance='no') ESC // "[2J" // ESC // "[H"
211
+    end subroutine clear_screen
212
+
213
+    subroutine draw_header(path)
214
+        character(len=*), intent(in) :: path
215
+        write(output_unit, '(a)') ESC // "[1m" // "FORTRESS v2" // ESC // "[0m - " // trim(path)
216
+        write(output_unit, '(a)') repeat("=", 70)
217
+    end subroutine draw_header
218
+
219
+    subroutine draw_panes(p_files, p_count, c_files, c_count, sel, rows, cols)
220
+        type(file_entry), dimension(*), intent(in) :: p_files, c_files
221
+        integer, intent(in) :: p_count, c_count, sel, rows, cols
222
+        integer :: i
223
+        integer :: left_width, right_width
224
+        character(len=30) :: left_text
225
+        character(len=50) :: right_text
226
+
227
+        left_width = cols * 3 / 10
228
+        right_width = cols - left_width - 3
229
+
230
+        do i = 1, min(rows - 5, max(p_count, c_count))
231
+            ! Left pane
232
+            if (i <= p_count) then
233
+                left_text = p_files(i)%name
234
+                if (p_files(i)%is_dir .and. trim(left_text) /= "." .and. trim(left_text) /= "..") then
235
+                    left_text = trim(left_text) // "/"
236
+                end if
237
+                if (len_trim(left_text) > left_width) then
238
+                    left_text = left_text(1:left_width-3) // "..."
239
+                end if
240
+                write(output_unit, '(a)', advance='no') ESC // "[2m" // left_text(1:left_width) // ESC // "[0m"
241
+            else
242
+                write(output_unit, '(a)', advance='no') repeat(" ", left_width)
243
+            end if
244
+
245
+            ! Separator
246
+            write(output_unit, '(a)', advance='no') " | "
247
+
248
+            ! Right pane
249
+            if (i <= c_count) then
250
+                right_text = c_files(i)%name
251
+                if (c_files(i)%is_dir .and. trim(right_text) /= "." .and. trim(right_text) /= "..") then
252
+                    right_text = trim(right_text) // "/"
253
+                end if
254
+
255
+                if (i == sel) then
256
+                    write(output_unit, '(a)') ESC // "[7m" // trim(right_text) // ESC // "[0m"
257
+                else
258
+                    write(output_unit, '(a)') trim(right_text)
259
+                end if
260
+            else
261
+                write(output_unit, *)
262
+            end if
263
+        end do
264
+    end subroutine draw_panes
265
+
266
+    subroutine draw_footer()
267
+        write(output_unit, *)
268
+        write(output_unit, '(a)') ESC // "[2m" // "↑↓: navigate | →: enter | ←: back | q: quit" // ESC // "[0m"
269
+    end subroutine draw_footer
270
+
271
+    subroutine get_key(key)
272
+        character(len=*), intent(out) :: key
273
+        character(len=1) :: ch
274
+
275
+        key = ""
276
+        read(*, '(a1)', advance='no', iostat=i) ch
277
+
278
+        if (ch == ESC) then
279
+            read(*, '(a1)', advance='no', iostat=i) ch
280
+            if (ch == '[') then
281
+                read(*, '(a1)', advance='no', iostat=i) ch
282
+                key = ch
283
+            end if
284
+        else
285
+            key = ch
286
+        end if
287
+    end subroutine get_key
288
+
289
+end program fortress_v2
src/main.f90modified
@@ -4,7 +4,7 @@ program fortress_main
4
     use terminal_input, only: get_key, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_ENTER, KEY_QUIT
4
     use terminal_input, only: get_key, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_ENTER, KEY_QUIT
5
     use filesystem_ops, only: list_directory, get_parent_dir, get_current_dir, is_directory, &
5
     use filesystem_ops, only: list_directory, get_parent_dir, get_current_dir, is_directory, &
6
                               file_entry, MAX_FILES
6
                               file_entry, MAX_FILES
7
-    use ui_panes, only: draw_panes, update_selection
7
+    use ui_panes_buffered, only: draw_panes_buffered
8
 
8
 
9
     implicit none
9
     implicit none
10
 
10
 
@@ -69,7 +69,7 @@ program fortress_main
69
             needs_full_redraw = .false.
69
             needs_full_redraw = .false.
70
         end if
70
         end if
71
 
71
 
72
-        call draw_panes(parent_dir, current_dir, selected_index, parent_selected_index)
72
+        call draw_panes_buffered(parent_dir, current_dir, selected_index, parent_selected_index)
73
 
73
 
74
         key = get_key()
74
         key = get_key()
75
 
75
 
src/simple_main.f90added
@@ -0,0 +1,119 @@
1
+program simple_fortress
2
+    use iso_fortran_env, only: output_unit, input_unit
3
+    implicit none
4
+
5
+    character(len=256) :: current_path
6
+    character(len=256) :: parent_path
7
+    character(len=256), dimension(100) :: files
8
+    character(len=256), dimension(100) :: parent_files
9
+    integer :: num_files, num_parent_files
10
+    integer :: selected = 1
11
+    integer :: i
12
+    character(len=1) :: key
13
+    logical :: running = .true.
14
+
15
+    ! Start in current directory
16
+    current_path = "."
17
+    parent_path = ".."
18
+
19
+    ! Main loop
20
+    do while (running)
21
+        ! Get file lists
22
+        call get_files(current_path, files, num_files)
23
+        call get_files(parent_path, parent_files, num_parent_files)
24
+
25
+        ! Clear screen (simple way)
26
+        write(output_unit, '(a)') char(27) // "[2J" // char(27) // "[H"
27
+
28
+        ! Draw header
29
+        write(output_unit, '(a)') "FORTRESS - Simple File Browser"
30
+        write(output_unit, '(a)') "=============================="
31
+        write(output_unit, *)
32
+
33
+        ! Draw files in two columns
34
+        write(output_unit, '(a)') "Parent Directory          | Current Directory"
35
+        write(output_unit, '(a)') "------------------------- | -------------------------"
36
+
37
+        do i = 1, max(num_parent_files, num_files)
38
+            if (i <= num_parent_files) then
39
+                write(output_unit, '(a25)', advance='no') adjustl(parent_files(i))
40
+            else
41
+                write(output_unit, '(a25)', advance='no') " "
42
+            end if
43
+
44
+            write(output_unit, '(a)', advance='no') " | "
45
+
46
+            if (i <= num_files) then
47
+                if (i == selected) then
48
+                    write(output_unit, '(a)') "> " // trim(files(i))
49
+                else
50
+                    write(output_unit, '(a)') "  " // trim(files(i))
51
+                end if
52
+            else
53
+                write(output_unit, *)
54
+            end if
55
+        end do
56
+
57
+        ! Show controls
58
+        write(output_unit, *)
59
+        write(output_unit, '(a)') "Controls: j=down, k=up, q=quit"
60
+        write(output_unit, '(a)', advance='no') "Command: "
61
+
62
+        ! Get input
63
+        read(input_unit, '(a1)') key
64
+
65
+        select case(key)
66
+        case('j', 'J')
67
+            if (selected < num_files) selected = selected + 1
68
+        case('k', 'K')
69
+            if (selected > 1) selected = selected - 1
70
+        case('q', 'Q')
71
+            running = .false.
72
+        end select
73
+    end do
74
+
75
+    write(output_unit, '(a)') "Goodbye!"
76
+
77
+contains
78
+
79
+    subroutine get_files(path, file_list, count)
80
+        character(len=*), intent(in) :: path
81
+        character(len=256), dimension(100), intent(out) :: file_list
82
+        integer, intent(out) :: count
83
+
84
+        character(len=512) :: cmd
85
+        character(len=256) :: temp_file
86
+        integer :: unit, ios
87
+
88
+        ! Create temp file name
89
+        temp_file = "temp_files.txt"
90
+
91
+        ! List files to temp file
92
+        write(cmd, '(a)') "ls -1 " // trim(path) // " > " // trim(temp_file) // " 2>/dev/null"
93
+        call execute_command_line(cmd, wait=.true.)
94
+
95
+        ! Read files
96
+        open(newunit=unit, file=temp_file, status='old', iostat=ios)
97
+        if (ios /= 0) then
98
+            count = 0
99
+            return
100
+        end if
101
+
102
+        count = 0
103
+        do
104
+            count = count + 1
105
+            if (count > 100) exit
106
+            read(unit, '(a)', iostat=ios) file_list(count)
107
+            if (ios /= 0) then
108
+                count = count - 1
109
+                exit
110
+            end if
111
+        end do
112
+
113
+        close(unit)
114
+
115
+        ! Clean up
116
+        call execute_command_line("rm -f " // trim(temp_file), wait=.false.)
117
+    end subroutine get_files
118
+
119
+end program simple_fortress
src/test_right_pane.f90added
@@ -0,0 +1,31 @@
1
+program test_right_pane
2
+    use terminal_screen, only: init_screen, cleanup_screen, clear_screen
3
+    use ui_panes_buffered, only: draw_panes_buffered
4
+
5
+    implicit none
6
+    character(len=256) :: current_dir, parent_dir
7
+
8
+    ! Set test directories
9
+    current_dir = "."
10
+    parent_dir = ".."
11
+
12
+    ! Initialize screen
13
+    call init_screen()
14
+    call clear_screen()
15
+
16
+    ! Draw the panes with buffered rendering
17
+    write(*, '(a)') "Testing buffered rendering - both panes should show files:"
18
+    write(*, *)
19
+
20
+    call draw_panes_buffered(parent_dir, current_dir, 2, 1)
21
+
22
+    ! Wait for user input
23
+    write(*, *)
24
+    write(*, '(a)') "Press Enter to exit test..."
25
+    read(*, *)
26
+
27
+    ! Cleanup
28
+    call cleanup_screen()
29
+    write(*, '(a)') "Test complete - if you saw files in both panes, buffered rendering works!"
30
+
31
+end program test_right_pane
src/ui/panes.f90modified
@@ -81,103 +81,87 @@ contains
81
         character(len=*), intent(in) :: dir_path
81
         character(len=*), intent(in) :: dir_path
82
         logical, intent(in) :: is_dimmed
82
         logical, intent(in) :: is_dimmed
83
         type(file_entry), dimension(MAX_FILES) :: files
83
         type(file_entry), dimension(MAX_FILES) :: files
84
-        integer :: i, row, j, actual_width
84
+        integer :: i, row, col_pos
85
-        character(len=256) :: display_name
85
+        character(len=256) :: fname
86
 
86
 
87
         files = list_directory(dir_path)
87
         files = list_directory(dir_path)
88
 
88
 
89
-        ! Ensure width is reasonable
90
-        actual_width = min(width, 68)  ! Limit to reasonable size
91
-
92
         row = start_row
89
         row = start_row
93
         do i = 1, min(MAX_FILES, height)
90
         do i = 1, min(MAX_FILES, height)
94
             if (len_trim(files(i)%name) == 0) exit
91
             if (len_trim(files(i)%name) == 0) exit
95
             if (row > start_row + height - 1) exit
92
             if (row > start_row + height - 1) exit
96
 
93
 
94
+            ! Move to position
97
             call move_cursor(row, start_col)
95
             call move_cursor(row, start_col)
98
 
96
 
99
-            ! Format display name
97
+            ! Get filename
100
-            display_name = trim(files(i)%name)
98
+            fname = files(i)%name
101
 
99
 
102
-            ! Add slash for directories (except . and ..)
100
+            ! Add slash for directories (not for . and ..)
103
             if (files(i)%is_dir) then
101
             if (files(i)%is_dir) then
104
-                if (trim(display_name) /= "." .and. trim(display_name) /= "..") then
102
+                if (trim(fname) /= "." .and. trim(fname) /= "..") then
105
-                    display_name = trim(display_name) // "/"
103
+                    fname = trim(fname) // "/"
106
                 end if
104
                 end if
107
             end if
105
             end if
108
 
106
 
109
             ! Truncate if too long
107
             ! Truncate if too long
110
-            if (len_trim(display_name) > actual_width - 1) then
108
+            if (len_trim(fname) > width - 2) then
111
-                display_name = display_name(1:actual_width-4) // "..."
109
+                fname = fname(1:width-5) // "..."
112
             end if
110
             end if
113
 
111
 
114
-            ! Draw the file entry
112
+            ! Draw the entry with proper colors
115
             if (i == selected .and. .not. is_dimmed) then
113
             if (i == selected .and. .not. is_dimmed) then
116
-                ! Active pane selection - highlight bar
114
+                ! Active selection - highlight whole line
117
-                ! Build the complete line first
118
-                if (files(i)%is_dir) then
119
-                    write(output_unit, '(a)', advance='no') REVERSE // BLUE // trim(display_name)
120
-                    ! Pad to fill the selection bar
121
-                    do j = len_trim(display_name) + 1, actual_width - 1
122
-                        write(output_unit, '(a1)', advance='no') ' '
123
-                    end do
124
-                    write(output_unit, '(a)', advance='no') RESET
125
-                else
126
-                    write(output_unit, '(a)', advance='no') REVERSE // trim(display_name)
127
-                    ! Pad to fill the selection bar
128
-                    do j = len_trim(display_name) + 1, actual_width - 1
129
-                        write(output_unit, '(a1)', advance='no') ' '
130
-                    end do
131
-                    write(output_unit, '(a)', advance='no') RESET
132
-                end if
133
-            else if (i == selected .and. is_dimmed) then
134
-                ! Dimmed pane selection - subtle highlight
135
                 if (files(i)%is_dir) then
115
                 if (files(i)%is_dir) then
136
-                    write(output_unit, '(a)', advance='no') DIM // BLUE // BOLD // &
116
+                    write(output_unit, '(a)', advance='no') REVERSE // BLUE // trim(fname) // RESET
137
-                        display_name(1:len_trim(display_name)) // RESET
138
                 else
117
                 else
139
-                    write(output_unit, '(a)', advance='no') DIM // BOLD // &
118
+                    write(output_unit, '(a)', advance='no') REVERSE // trim(fname) // RESET
140
-                        display_name(1:len_trim(display_name)) // RESET
141
                 end if
119
                 end if
142
-                ! Clear rest of line
120
+                ! Pad the rest of the line
143
-                do j = len_trim(display_name) + 1, actual_width - 1
121
+                do col_pos = len_trim(fname) + 1, min(width - 1, 70)
144
-                    write(output_unit, '(a)', advance='no') ' '
122
+                    write(output_unit, '(a)', advance='no') REVERSE // ' ' // RESET
145
                 end do
123
                 end do
146
             else
124
             else
147
-                ! Normal display
125
+                ! Normal or dimmed entry
148
                 if (is_dimmed) then
126
                 if (is_dimmed) then
149
-                    ! Dimmed pane
127
+                    if (i == selected) then
150
-                    if (files(i)%is_dir) then
128
+                        ! Dimmed selection
151
-                        write(output_unit, '(a)', advance='no') DIM // BLUE // &
129
+                        if (files(i)%is_dir) then
152
-                            display_name(1:len_trim(display_name)) // RESET
130
+                            write(output_unit, '(a)', advance='no') DIM // BOLD // BLUE // trim(fname) // RESET
131
+                        else
132
+                            write(output_unit, '(a)', advance='no') DIM // BOLD // trim(fname) // RESET
133
+                        end if
153
                     else
134
                     else
154
-                        write(output_unit, '(a)', advance='no') DIM // &
135
+                        ! Dimmed normal
155
-                            display_name(1:len_trim(display_name)) // RESET
136
+                        if (files(i)%is_dir) then
137
+                            write(output_unit, '(a)', advance='no') DIM // BLUE // trim(fname) // RESET
138
+                        else
139
+                            write(output_unit, '(a)', advance='no') DIM // trim(fname) // RESET
140
+                        end if
156
                     end if
141
                     end if
157
                 else
142
                 else
158
-                    ! Active pane
143
+                    ! Active pane, normal entry
159
                     if (files(i)%is_dir) then
144
                     if (files(i)%is_dir) then
160
-                        write(output_unit, '(a)', advance='no') BLUE // &
145
+                        write(output_unit, '(a)', advance='no') BLUE // trim(fname) // RESET
161
-                            display_name(1:len_trim(display_name)) // RESET
162
                     else
146
                     else
163
-                        write(output_unit, '(a)', advance='no') &
147
+                        write(output_unit, '(a)', advance='no') trim(fname)
164
-                            display_name(1:len_trim(display_name))
165
                     end if
148
                     end if
166
                 end if
149
                 end if
150
+
167
                 ! Clear rest of line
151
                 ! Clear rest of line
168
-                do j = len_trim(display_name) + 1, actual_width - 1
152
+                do col_pos = len_trim(fname) + 1, min(width - 1, 70)
169
-                    write(output_unit, '(a)', advance='no') ' '
153
+                    write(output_unit, '(a1)', advance='no') ' '
170
                 end do
154
                 end do
171
             end if
155
             end if
172
 
156
 
173
             row = row + 1
157
             row = row + 1
174
         end do
158
         end do
175
 
159
 
176
-        ! Clear any remaining rows in this pane
160
+        ! Clear any remaining rows
177
         do while (row <= start_row + height - 1)
161
         do while (row <= start_row + height - 1)
178
             call move_cursor(row, start_col)
162
             call move_cursor(row, start_col)
179
-            do j = 1, actual_width - 1
163
+            do col_pos = 1, min(width - 1, 70)
180
-                write(output_unit, '(a)', advance='no') ' '
164
+                write(output_unit, '(a1)', advance='no') ' '
181
             end do
165
             end do
182
             row = row + 1
166
             row = row + 1
183
         end do
167
         end do
src/ui/panes_buffered.f90added
@@ -0,0 +1,169 @@
1
+module ui_panes_buffered
2
+    use iso_fortran_env, only: output_unit, error_unit
3
+    use terminal_screen, only: move_cursor, get_terminal_size
4
+    use filesystem_ops, only: file_entry, list_directory, MAX_FILES
5
+    implicit none
6
+    private
7
+
8
+    public :: draw_panes_buffered
9
+
10
+    ! ANSI color codes
11
+    character(len=*), parameter :: ESC = char(27)
12
+    character(len=*), parameter :: RESET = ESC // "[0m"
13
+    character(len=*), parameter :: BOLD = ESC // "[1m"
14
+    character(len=*), parameter :: DIM = ESC // "[2m"
15
+    character(len=*), parameter :: REVERSE = ESC // "[7m"
16
+    character(len=*), parameter :: BLUE = ESC // "[34m"
17
+
18
+contains
19
+
20
+    subroutine draw_panes_buffered(parent_dir, current_dir, selected_index, parent_selected)
21
+        character(len=*), intent(in) :: parent_dir, current_dir
22
+        integer, intent(in) :: selected_index
23
+        integer, intent(in), optional :: parent_selected
24
+        integer :: rows, cols
25
+        integer :: left_width, right_width
26
+        integer :: i
27
+        integer :: parent_sel
28
+        ! Handle optional parent selection
29
+        if (present(parent_selected)) then
30
+            parent_sel = parent_selected
31
+        else
32
+            parent_sel = -1
33
+        end if
34
+
35
+        call get_terminal_size(rows, cols)
36
+
37
+        ! Calculate pane widths (30/70 split)
38
+        left_width = cols * 3 / 10
39
+        right_width = cols - left_width - 1  ! -1 for separator
40
+
41
+        ! Draw header
42
+        call move_cursor(1, 1)
43
+        write(output_unit, '(a)') BOLD // "FORTRESS" // RESET // " - " // trim(current_dir)
44
+
45
+        ! Draw both panes
46
+        call draw_both_panes(2, left_width, right_width, rows - 2, &
47
+                            parent_dir, current_dir, parent_sel, selected_index)
48
+
49
+        ! Draw footer
50
+        call move_cursor(rows, 1)
51
+        write(output_unit, '(a)') DIM // "↑↓:navigate  →:enter  ←:back  Ctrl-Q:quit" // RESET
52
+
53
+        flush(output_unit)
54
+    end subroutine draw_panes_buffered
55
+
56
+    subroutine draw_both_panes(start_row, left_width, right_width, height, &
57
+                              parent_dir, current_dir, parent_sel, current_sel)
58
+        integer, intent(in) :: start_row, left_width, right_width, height
59
+        character(len=*), intent(in) :: parent_dir, current_dir
60
+        integer, intent(in) :: parent_sel, current_sel
61
+
62
+        type(file_entry), dimension(MAX_FILES) :: parent_files, current_files
63
+        integer :: row, i, j, file_count
64
+        character(len=256) :: left_text, right_text
65
+
66
+        ! Get files for both directories
67
+        parent_files = list_directory(parent_dir)
68
+        current_files = list_directory(current_dir)
69
+
70
+        ! Count current files
71
+        file_count = 0
72
+        do i = 1, MAX_FILES
73
+            if (len_trim(current_files(i)%name) == 0) exit
74
+            file_count = i
75
+        end do
76
+
77
+        ! Draw each row
78
+        do row = start_row, start_row + height - 1
79
+            i = row - start_row + 1
80
+
81
+            ! Build left pane text
82
+            left_text = ""
83
+            if (i <= MAX_FILES .and. len_trim(parent_files(i)%name) > 0) then
84
+                left_text = format_file_entry(parent_files(i), i == parent_sel, .true., left_width)
85
+            end if
86
+
87
+            ! Build right pane text
88
+            right_text = ""
89
+            if (i <= MAX_FILES .and. len_trim(current_files(i)%name) > 0) then
90
+                right_text = format_file_entry(current_files(i), i == current_sel, .false., right_width)
91
+            end if
92
+
93
+            ! Build complete line
94
+            call move_cursor(row, 1)
95
+
96
+            ! Write left pane
97
+            write(output_unit, '(a)', advance='no') left_text
98
+
99
+            ! Pad to separator
100
+            do j = len_trim(left_text) + 1, left_width
101
+                write(output_unit, '(a1)', advance='no') ' '
102
+            end do
103
+
104
+            ! Write separator
105
+            write(output_unit, '(a)', advance='no') DIM // "│" // RESET
106
+
107
+            ! Write right pane
108
+            write(output_unit, '(a)', advance='no') right_text
109
+
110
+            ! Clear rest of line
111
+            do j = len_trim(right_text) + 1, right_width
112
+                write(output_unit, '(a1)', advance='no') ' '
113
+            end do
114
+        end do
115
+    end subroutine draw_both_panes
116
+
117
+    function format_file_entry(entry, is_selected, is_dimmed, max_width) result(formatted)
118
+        type(file_entry), intent(in) :: entry
119
+        logical, intent(in) :: is_selected, is_dimmed
120
+        integer, intent(in) :: max_width
121
+        character(len=512) :: formatted
122
+        character(len=256) :: name
123
+
124
+
125
+        name = entry%name
126
+        if (entry%is_dir .and. trim(name) /= "." .and. trim(name) /= "..") then
127
+            name = trim(name) // "/"
128
+        end if
129
+
130
+        ! Truncate if needed
131
+        if (len_trim(name) > max_width - 1) then
132
+            name = name(1:max_width-4) // "..."
133
+        end if
134
+
135
+        ! Format with colors
136
+        if (is_selected .and. .not. is_dimmed) then
137
+            ! Active selection
138
+            if (entry%is_dir) then
139
+                formatted = REVERSE // BLUE // trim(name) // RESET
140
+            else
141
+                formatted = REVERSE // trim(name) // RESET
142
+            end if
143
+        else if (is_dimmed) then
144
+            ! Dimmed pane
145
+            if (is_selected) then
146
+                if (entry%is_dir) then
147
+                    formatted = DIM // BOLD // BLUE // trim(name) // RESET
148
+                else
149
+                    formatted = DIM // BOLD // trim(name) // RESET
150
+                end if
151
+            else
152
+                if (entry%is_dir) then
153
+                    formatted = DIM // BLUE // trim(name) // RESET
154
+                else
155
+                    formatted = DIM // trim(name) // RESET
156
+                end if
157
+            end if
158
+        else
159
+            ! Normal active pane
160
+            if (entry%is_dir) then
161
+                formatted = BLUE // trim(name) // RESET
162
+            else
163
+                formatted = trim(name)
164
+            end if
165
+        end if
166
+
167
+    end function format_file_entry
168
+
169
+end module ui_panes_buffered
src/ui/panes_debug.f90added
@@ -0,0 +1,88 @@
1
+module ui_panes_debug
2
+    use iso_fortran_env, only: output_unit, error_unit
3
+    use terminal_screen, only: move_cursor, get_terminal_size
4
+    use filesystem_ops, only: file_entry, list_directory, MAX_FILES
5
+    implicit none
6
+    private
7
+
8
+    public :: draw_file_list_debug
9
+
10
+    ! ANSI color codes
11
+    character(len=*), parameter :: ESC = char(27)
12
+    character(len=*), parameter :: RESET = ESC // "[0m"
13
+    character(len=*), parameter :: BLUE = ESC // "[34m"
14
+    character(len=*), parameter :: REVERSE = ESC // "[7m"
15
+    character(len=*), parameter :: DIM = ESC // "[2m"
16
+    character(len=*), parameter :: BOLD = ESC // "[1m"
17
+
18
+contains
19
+
20
+    subroutine draw_file_list_debug(start_row, start_col, width, height, dir_path, selected, is_dimmed)
21
+        integer, intent(in) :: start_row, start_col, width, height, selected
22
+        character(len=*), intent(in) :: dir_path
23
+        logical, intent(in) :: is_dimmed
24
+        type(file_entry), dimension(MAX_FILES) :: files
25
+        integer :: i, row, col_pos, file_count
26
+        character(len=256) :: fname
27
+
28
+        ! Debug info
29
+        write(error_unit, *) "=== draw_file_list_debug ==="
30
+        write(error_unit, *) "start_row=", start_row, " start_col=", start_col
31
+        write(error_unit, *) "width=", width, " height=", height
32
+        write(error_unit, *) "dir_path='", trim(dir_path), "'"
33
+        write(error_unit, *) "selected=", selected, " is_dimmed=", is_dimmed
34
+
35
+        files = list_directory(dir_path)
36
+
37
+        ! Count files
38
+        file_count = 0
39
+        do i = 1, MAX_FILES
40
+            if (len_trim(files(i)%name) == 0) exit
41
+            file_count = i
42
+        end do
43
+        write(error_unit, *) "Files found: ", file_count
44
+
45
+        row = start_row
46
+        do i = 1, min(MAX_FILES, height)
47
+            if (len_trim(files(i)%name) == 0) exit
48
+            if (row > start_row + height - 1) exit
49
+
50
+            ! Move to position
51
+            call move_cursor(row, start_col)
52
+
53
+            ! Get filename
54
+            fname = files(i)%name
55
+
56
+            write(error_unit, '(a,i0,a,a,a,l1)') "File ", i, ": '", trim(fname), "' is_dir=", files(i)%is_dir
57
+
58
+            ! Add slash for directories (not for . and ..)
59
+            if (files(i)%is_dir) then
60
+                if (trim(fname) /= "." .and. trim(fname) /= "..") then
61
+                    fname = trim(fname) // "/"
62
+                end if
63
+            end if
64
+
65
+            ! Truncate if too long
66
+            if (len_trim(fname) > width - 2) then
67
+                fname = fname(1:width-5) // "..."
68
+            end if
69
+
70
+            write(error_unit, '(a,i0,a,i0,a,a)') "Writing at row ", row, " col ", start_col, ": ", trim(fname)
71
+
72
+            ! Simple write for debugging
73
+            if (i == selected .and. .not. is_dimmed) then
74
+                write(output_unit, '(a)', advance='no') REVERSE // trim(fname) // RESET
75
+            else if (files(i)%is_dir) then
76
+                write(output_unit, '(a)', advance='no') BLUE // trim(fname) // RESET
77
+            else
78
+                write(output_unit, '(a)', advance='no') trim(fname)
79
+            end if
80
+
81
+            row = row + 1
82
+        end do
83
+
84
+        write(error_unit, *) "=== end draw_file_list_debug ==="
85
+        flush(error_unit)
86
+    end subroutine draw_file_list_debug
87
+
88
+end module ui_panes_debug