@@ -40,6 +40,8 @@ contains |
| 40 | integer :: left_w, i, parent_idx, current_idx, vis_h, display_len | 40 | integer :: left_w, i, parent_idx, current_idx, vis_h, display_len |
| 41 | character(len=256) :: fname | 41 | character(len=256) :: fname |
| 42 | character(len=20) :: color_code | 42 | character(len=20) :: color_code |
| | 43 | + character(len=600) :: footer_text |
| | 44 | + integer :: footer_len |
| 43 | | 45 | |
| 44 | left_w = c * 3 / 10 | 46 | left_w = c * 3 / 10 |
| 45 | vis_h = r - top_padding - 4 ! Visible height with buffer to prevent scrolling | 47 | vis_h = r - top_padding - 4 ! Visible height with buffer to prevent scrolling |
@@ -227,18 +229,28 @@ contains |
| 227 | end do | 229 | end do |
| 228 | | 230 | |
| 229 | ! Footer - help text only (status moved to header) | 231 | ! Footer - help text only (status moved to header) |
| | 232 | + ! Build footer text and truncate to prevent wrapping which causes screen scroll |
| 230 | if (move_mode) then | 233 | if (move_mode) then |
| 231 | - write(output_unit, '(a)') DIM // "↑↓:next/prev dir →:enter dir ←:parent ~:home /:root v:move here q:cancel" // RESET | 234 | + footer_text = DIM // "↑↓:next/prev dir →:enter dir ←:parent ~:home /:root v:move here q:cancel" // RESET |
| 232 | else if (selection_count > 0) then | 235 | else if (selection_count > 0) then |
| 233 | - ! Selection mode footer - show multi-select help | 236 | + footer_text = DIM // "Ctrl-D:deselect Space:toggle Shift+↑↓:block y:copy x:cut p:paste r:delete | " // RESET // & |
| 234 | - write(output_unit, '(a)') DIM // "Ctrl-D:deselect Space:toggle Shift+↑↓:block y:copy x:cut p:paste r:delete | " // RESET // & | | |
| 235 | DIM // "→:enter ←:back ~:home /:root c:cd q:quit" // RESET | 237 | DIM // "→:enter ←:back ~:home /:root c:cd q:quit" // RESET |
| 236 | else if (in_git_repo) then | 238 | else if (in_git_repo) then |
| 237 | - write(output_unit, '(a)') DIM // "Space:select Shift+↑↓:block | ↑↓:nav →:enter ←:back ~:home /:root s:search 8:favorites *:star o:open n:rename r:remove v:move y:copy x:cut p:paste .:hidden a:add u:unstage m:commit d:diff f:fetch l:pull h:push c:cd q:quit" // RESET | 239 | + footer_text = DIM // "Space:select Shift+↑↓:block | ↑↓:nav →:enter ←:back ~:home /:root s:search 8:favorites *:star o:open n:rename r:remove v:move y:copy x:cut p:paste .:hidden a:add u:unstage m:commit d:diff f:fetch l:pull h:push c:cd q:quit" // RESET |
| 238 | else | 240 | else |
| 239 | - write(output_unit, '(a)') DIM // "Space:select Shift+↑↓:block | ↑↓:nav →:enter ←:back ~:home /:root s:search 8:favorites *:star o:open n:rename r:remove v:move y:copy x:cut p:paste .:hidden c:cd q:quit" // RESET | 241 | + footer_text = DIM // "Space:select Shift+↑↓:block | ↑↓:nav →:enter ←:back ~:home /:root s:search 8:favorites *:star o:open n:rename r:remove v:move y:copy x:cut p:paste .:hidden c:cd q:quit" // RESET |
| 240 | end if | 242 | end if |
| 241 | | 243 | |
| | 244 | + ! Truncate footer to terminal width - CRITICAL to prevent wrapping which causes screen scroll |
| | 245 | + ! Conservative truncation: assume ANSI codes are ~30% of string, so truncate to ~130% of terminal width |
| | 246 | + footer_len = len_trim(footer_text) |
| | 247 | + if (footer_len > (c * 13 / 10)) then |
| | 248 | + footer_text = footer_text(1:c * 13 / 10) |
| | 249 | + end if |
| | 250 | + |
| | 251 | + ! Write footer WITHOUT newline (newline on last row causes wrap which scrolls screen up) |
| | 252 | + write(output_unit, '(a)', advance='no') trim(footer_text) |
| | 253 | + |
| 242 | contains | 254 | contains |
| 243 | function itoa(n) result(str) | 255 | function itoa(n) result(str) |
| 244 | integer, intent(in) :: n | 256 | integer, intent(in) :: n |