@@ -9,23 +9,28 @@ module workspace_symbols_panel_module |
| 9 | 9 | public :: show_workspace_symbols_panel, hide_workspace_symbols_panel |
| 10 | 10 | public :: is_workspace_symbols_panel_visible, workspace_symbols_panel_handle_key |
| 11 | 11 | public :: set_workspace_symbols, get_selected_symbol |
| 12 | | - public :: render_workspace_symbols_panel |
| 12 | + public :: render_workspace_symbols_panel, get_search_query |
| 13 | + public :: add_search_char, delete_search_char, clear_search |
| 13 | 14 | |
| 14 | 15 | integer, parameter :: MAX_SYMBOLS = 1000 |
| 15 | | - integer, parameter :: MAX_VISIBLE = 15 |
| 16 | 16 | |
| 17 | 17 | type :: workspace_symbol_t |
| 18 | 18 | character(len=:), allocatable :: name |
| 19 | 19 | character(len=:), allocatable :: kind_name ! "Function", "Class", etc. |
| 20 | 20 | character(len=:), allocatable :: container_name |
| 21 | 21 | character(len=:), allocatable :: file_uri |
| 22 | + character(len=:), allocatable :: file_path ! Extracted from URI |
| 22 | 23 | integer :: line = 0 |
| 23 | | - integer :: character = 0 |
| 24 | + integer :: column = 0 |
| 25 | + integer :: kind = 0 |
| 24 | 26 | integer :: score = 0 ! For fuzzy matching |
| 25 | 27 | end type workspace_symbol_t |
| 26 | 28 | |
| 27 | 29 | type :: workspace_symbols_panel_t |
| 28 | 30 | logical :: visible = .false. |
| 31 | + integer :: panel_width = 60 |
| 32 | + integer :: panel_start_col = 1 |
| 33 | + integer :: max_visible = 20 |
| 29 | 34 | type(workspace_symbol_t), allocatable :: all_symbols(:) |
| 30 | 35 | integer :: num_symbols = 0 |
| 31 | 36 | type(workspace_symbol_t), allocatable :: filtered_symbols(:) |
@@ -34,6 +39,7 @@ module workspace_symbols_panel_module |
| 34 | 39 | integer :: scroll_offset = 0 |
| 35 | 40 | character(len=256) :: search_query = '' |
| 36 | 41 | integer :: search_pos = 0 |
| 42 | + logical :: needs_lsp_query = .false. ! Flag to trigger LSP request |
| 37 | 43 | end type workspace_symbols_panel_t |
| 38 | 44 | |
| 39 | 45 | contains |
@@ -48,6 +54,7 @@ contains |
| 48 | 54 | panel%scroll_offset = 0 |
| 49 | 55 | panel%search_query = '' |
| 50 | 56 | panel%search_pos = 0 |
| 57 | + panel%needs_lsp_query = .false. |
| 51 | 58 | |
| 52 | 59 | allocate(panel%all_symbols(MAX_SYMBOLS)) |
| 53 | 60 | allocate(panel%filtered_symbols(MAX_SYMBOLS)) |
@@ -63,6 +70,7 @@ contains |
| 63 | 70 | if (allocated(panel%all_symbols(i)%kind_name)) deallocate(panel%all_symbols(i)%kind_name) |
| 64 | 71 | if (allocated(panel%all_symbols(i)%container_name)) deallocate(panel%all_symbols(i)%container_name) |
| 65 | 72 | if (allocated(panel%all_symbols(i)%file_uri)) deallocate(panel%all_symbols(i)%file_uri) |
| 73 | + if (allocated(panel%all_symbols(i)%file_path)) deallocate(panel%all_symbols(i)%file_path) |
| 66 | 74 | end do |
| 67 | 75 | deallocate(panel%all_symbols) |
| 68 | 76 | end if |
@@ -70,17 +78,22 @@ contains |
| 70 | 78 | if (allocated(panel%filtered_symbols)) deallocate(panel%filtered_symbols) |
| 71 | 79 | end subroutine cleanup_workspace_symbols_panel |
| 72 | 80 | |
| 73 | | - subroutine show_workspace_symbols_panel(panel) |
| 81 | + subroutine show_workspace_symbols_panel(panel, screen_width, screen_height) |
| 74 | 82 | type(workspace_symbols_panel_t), intent(inout) :: panel |
| 83 | + integer, intent(in) :: screen_width, screen_height |
| 75 | 84 | |
| 76 | 85 | panel%visible = .true. |
| 86 | + panel%panel_width = min(70, screen_width / 2) |
| 87 | + panel%panel_start_col = screen_width - panel%panel_width + 1 |
| 88 | + panel%max_visible = screen_height - 5 ! Room for header, search, hints |
| 77 | 89 | panel%search_query = '' |
| 78 | 90 | panel%search_pos = 0 |
| 79 | 91 | panel%selected_index = 1 |
| 80 | 92 | panel%scroll_offset = 0 |
| 93 | + panel%needs_lsp_query = .true. ! Request initial symbols |
| 81 | 94 | |
| 82 | 95 | ! Initially show all symbols |
| 83 | | - call filter_symbols(panel, '') |
| 96 | + call filter_symbols(panel) |
| 84 | 97 | end subroutine show_workspace_symbols_panel |
| 85 | 98 | |
| 86 | 99 | subroutine hide_workspace_symbols_panel(panel) |
@@ -94,6 +107,47 @@ contains |
| 94 | 107 | visible = panel%visible |
| 95 | 108 | end function is_workspace_symbols_panel_visible |
| 96 | 109 | |
| 110 | + function get_search_query(panel) result(query) |
| 111 | + type(workspace_symbols_panel_t), intent(in) :: panel |
| 112 | + character(len=:), allocatable :: query |
| 113 | + if (panel%search_pos > 0) then |
| 114 | + query = trim(panel%search_query(1:panel%search_pos)) |
| 115 | + else |
| 116 | + query = '' |
| 117 | + end if |
| 118 | + end function get_search_query |
| 119 | + |
| 120 | + subroutine add_search_char(panel, ch) |
| 121 | + type(workspace_symbols_panel_t), intent(inout) :: panel |
| 122 | + character, intent(in) :: ch |
| 123 | + |
| 124 | + if (panel%search_pos < 255) then |
| 125 | + panel%search_pos = panel%search_pos + 1 |
| 126 | + panel%search_query(panel%search_pos:panel%search_pos) = ch |
| 127 | + panel%needs_lsp_query = .true. |
| 128 | + call filter_symbols(panel) |
| 129 | + end if |
| 130 | + end subroutine add_search_char |
| 131 | + |
| 132 | + subroutine delete_search_char(panel) |
| 133 | + type(workspace_symbols_panel_t), intent(inout) :: panel |
| 134 | + |
| 135 | + if (panel%search_pos > 0) then |
| 136 | + panel%search_query(panel%search_pos:panel%search_pos) = ' ' |
| 137 | + panel%search_pos = panel%search_pos - 1 |
| 138 | + panel%needs_lsp_query = .true. |
| 139 | + call filter_symbols(panel) |
| 140 | + end if |
| 141 | + end subroutine delete_search_char |
| 142 | + |
| 143 | + subroutine clear_search(panel) |
| 144 | + type(workspace_symbols_panel_t), intent(inout) :: panel |
| 145 | + panel%search_query = '' |
| 146 | + panel%search_pos = 0 |
| 147 | + panel%needs_lsp_query = .true. |
| 148 | + call filter_symbols(panel) |
| 149 | + end subroutine clear_search |
| 150 | + |
| 97 | 151 | subroutine set_workspace_symbols(panel, symbols, count) |
| 98 | 152 | type(workspace_symbols_panel_t), intent(inout) :: panel |
| 99 | 153 | type(workspace_symbol_t), intent(in) :: symbols(:) |
@@ -104,26 +158,68 @@ contains |
| 104 | 158 | panel%num_symbols = copy_count |
| 105 | 159 | |
| 106 | 160 | do i = 1, copy_count |
| 107 | | - panel%all_symbols(i) = symbols(i) |
| 161 | + ! Deep copy each symbol |
| 162 | + if (allocated(panel%all_symbols(i)%name)) deallocate(panel%all_symbols(i)%name) |
| 163 | + if (allocated(symbols(i)%name)) then |
| 164 | + allocate(character(len=len(symbols(i)%name)) :: panel%all_symbols(i)%name) |
| 165 | + panel%all_symbols(i)%name = symbols(i)%name |
| 166 | + end if |
| 167 | + |
| 168 | + if (allocated(panel%all_symbols(i)%kind_name)) deallocate(panel%all_symbols(i)%kind_name) |
| 169 | + if (allocated(symbols(i)%kind_name)) then |
| 170 | + allocate(character(len=len(symbols(i)%kind_name)) :: panel%all_symbols(i)%kind_name) |
| 171 | + panel%all_symbols(i)%kind_name = symbols(i)%kind_name |
| 172 | + end if |
| 173 | + |
| 174 | + if (allocated(panel%all_symbols(i)%container_name)) deallocate(panel%all_symbols(i)%container_name) |
| 175 | + if (allocated(symbols(i)%container_name)) then |
| 176 | + allocate(character(len=len(symbols(i)%container_name)) :: panel%all_symbols(i)%container_name) |
| 177 | + panel%all_symbols(i)%container_name = symbols(i)%container_name |
| 178 | + end if |
| 179 | + |
| 180 | + if (allocated(panel%all_symbols(i)%file_uri)) deallocate(panel%all_symbols(i)%file_uri) |
| 181 | + if (allocated(symbols(i)%file_uri)) then |
| 182 | + allocate(character(len=len(symbols(i)%file_uri)) :: panel%all_symbols(i)%file_uri) |
| 183 | + panel%all_symbols(i)%file_uri = symbols(i)%file_uri |
| 184 | + end if |
| 185 | + |
| 186 | + if (allocated(panel%all_symbols(i)%file_path)) deallocate(panel%all_symbols(i)%file_path) |
| 187 | + if (allocated(symbols(i)%file_path)) then |
| 188 | + allocate(character(len=len(symbols(i)%file_path)) :: panel%all_symbols(i)%file_path) |
| 189 | + panel%all_symbols(i)%file_path = symbols(i)%file_path |
| 190 | + end if |
| 191 | + |
| 192 | + panel%all_symbols(i)%line = symbols(i)%line |
| 193 | + panel%all_symbols(i)%column = symbols(i)%column |
| 194 | + panel%all_symbols(i)%kind = symbols(i)%kind |
| 195 | + panel%all_symbols(i)%score = symbols(i)%score |
| 108 | 196 | end do |
| 109 | 197 | |
| 110 | 198 | ! Refilter with current query |
| 111 | | - call filter_symbols(panel, trim(panel%search_query(1:panel%search_pos))) |
| 199 | + call filter_symbols(panel) |
| 112 | 200 | end subroutine set_workspace_symbols |
| 113 | 201 | |
| 114 | | - subroutine filter_symbols(panel, query) |
| 202 | + subroutine filter_symbols(panel) |
| 115 | 203 | type(workspace_symbols_panel_t), intent(inout) :: panel |
| 116 | | - character(len=*), intent(in) :: query |
| 204 | + character(len=:), allocatable :: query |
| 117 | 205 | integer :: i, score |
| 118 | 206 | |
| 207 | + if (panel%search_pos > 0) then |
| 208 | + query = trim(panel%search_query(1:panel%search_pos)) |
| 209 | + else |
| 210 | + query = '' |
| 211 | + end if |
| 212 | + |
| 119 | 213 | panel%num_filtered = 0 |
| 120 | 214 | |
| 121 | 215 | do i = 1, panel%num_symbols |
| 122 | | - score = fuzzy_match_score(panel%all_symbols(i)%name, query) |
| 123 | | - if (score > 0) then |
| 124 | | - panel%num_filtered = panel%num_filtered + 1 |
| 125 | | - panel%filtered_symbols(panel%num_filtered) = panel%all_symbols(i) |
| 126 | | - panel%filtered_symbols(panel%num_filtered)%score = score |
| 216 | + if (allocated(panel%all_symbols(i)%name)) then |
| 217 | + score = fuzzy_match_score(panel%all_symbols(i)%name, query) |
| 218 | + if (score > 0) then |
| 219 | + panel%num_filtered = panel%num_filtered + 1 |
| 220 | + panel%filtered_symbols(panel%num_filtered) = panel%all_symbols(i) |
| 221 | + panel%filtered_symbols(panel%num_filtered)%score = score |
| 222 | + end if |
| 127 | 223 | end if |
| 128 | 224 | end do |
| 129 | 225 | |
@@ -225,110 +321,212 @@ contains |
| 225 | 321 | |
| 226 | 322 | if (panel%num_filtered > 0 .and. panel%selected_index <= panel%num_filtered) then |
| 227 | 323 | sym = panel%filtered_symbols(panel%selected_index) |
| 228 | | - else |
| 229 | | - sym%file_uri = '' |
| 230 | 324 | end if |
| 231 | 325 | end function get_selected_symbol |
| 232 | 326 | |
| 233 | | - subroutine workspace_symbols_panel_handle_key(panel, key, handled) |
| 327 | + function workspace_symbols_panel_handle_key(panel, key) result(handled) |
| 234 | 328 | type(workspace_symbols_panel_t), intent(inout) :: panel |
| 235 | 329 | character(len=*), intent(in) :: key |
| 236 | | - logical, intent(out) :: handled |
| 330 | + logical :: handled |
| 237 | 331 | |
| 238 | | - handled = .true. |
| 332 | + handled = .false. |
| 333 | + if (.not. panel%visible) return |
| 239 | 334 | |
| 240 | | - select case(key) |
| 241 | | - case('up', 'ctrl-k', 'k') |
| 242 | | - if (panel%selected_index > 1) then |
| 243 | | - panel%selected_index = panel%selected_index - 1 |
| 244 | | - if (panel%selected_index < panel%scroll_offset + 1) then |
| 245 | | - panel%scroll_offset = panel%selected_index - 1 |
| 335 | + select case(trim(key)) |
| 336 | + case('j', 'down', 'ctrl-n') |
| 337 | + ! Always handle to clamp at boundary |
| 338 | + handled = .true. |
| 339 | + if (panel%selected_index < panel%num_filtered) then |
| 340 | + panel%selected_index = panel%selected_index + 1 |
| 341 | + if (panel%selected_index > panel%scroll_offset + panel%max_visible) then |
| 342 | + panel%scroll_offset = panel%selected_index - panel%max_visible |
| 246 | 343 | end if |
| 247 | 344 | end if |
| 248 | 345 | |
| 249 | | - case('down', 'ctrl-j', 'j') |
| 250 | | - if (panel%selected_index < panel%num_filtered) then |
| 251 | | - panel%selected_index = panel%selected_index + 1 |
| 252 | | - if (panel%selected_index > panel%scroll_offset + MAX_VISIBLE) then |
| 253 | | - panel%scroll_offset = panel%selected_index - MAX_VISIBLE |
| 346 | + case('k', 'up', 'ctrl-p') |
| 347 | + ! Always handle to clamp at boundary |
| 348 | + handled = .true. |
| 349 | + if (panel%selected_index > 1) then |
| 350 | + panel%selected_index = panel%selected_index - 1 |
| 351 | + if (panel%selected_index <= panel%scroll_offset) then |
| 352 | + panel%scroll_offset = max(0, panel%selected_index - 1) |
| 254 | 353 | end if |
| 255 | 354 | end if |
| 256 | 355 | |
| 257 | | - case('esc') |
| 356 | + case('ctrl-u') |
| 357 | + ! Clear search |
| 358 | + call clear_search(panel) |
| 359 | + handled = .true. |
| 360 | + |
| 361 | + case('esc', 'escape') |
| 258 | 362 | call hide_workspace_symbols_panel(panel) |
| 363 | + handled = .true. |
| 364 | + |
| 365 | + case('enter') |
| 366 | + ! Signal to jump - handled by command_handler |
| 367 | + handled = .true. |
| 368 | + |
| 369 | + case('backspace', 'ctrl-h') |
| 370 | + call delete_search_char(panel) |
| 371 | + handled = .true. |
| 259 | 372 | |
| 260 | 373 | case default |
| 261 | | - handled = .false. |
| 374 | + ! Check if it's a printable character for search |
| 375 | + if (len_trim(key) == 1) then |
| 376 | + if (iachar(key(1:1)) >= 32 .and. iachar(key(1:1)) < 127) then |
| 377 | + call add_search_char(panel, key(1:1)) |
| 378 | + handled = .true. |
| 379 | + end if |
| 380 | + end if |
| 262 | 381 | end select |
| 263 | | - end subroutine workspace_symbols_panel_handle_key |
| 382 | + end function workspace_symbols_panel_handle_key |
| 264 | 383 | |
| 265 | | - subroutine render_workspace_symbols_panel(panel, screen_rows) |
| 384 | + subroutine render_workspace_symbols_panel(panel, screen_height) |
| 266 | 385 | type(workspace_symbols_panel_t), intent(in) :: panel |
| 267 | | - integer, intent(in) :: screen_rows |
| 268 | | - integer :: i, visible_start, visible_end, row |
| 269 | | - character(len=256) :: line, kind_tag, container_info |
| 270 | | - type(workspace_symbol_t) :: sym |
| 386 | + integer, intent(in) :: screen_height |
| 387 | + integer :: row, i, start_idx, end_idx |
| 388 | + character(len=256) :: line, file_info |
| 389 | + character(len=1), parameter :: ESC = char(27) |
| 271 | 390 | |
| 272 | 391 | if (.not. panel%visible) return |
| 273 | 392 | |
| 274 | | - ! Clear and draw header |
| 275 | | - call terminal_move_cursor(screen_rows - MAX_VISIBLE - 2, 1) |
| 276 | | - call terminal_write(repeat(' ', 120)) |
| 277 | | - call terminal_move_cursor(screen_rows - MAX_VISIBLE - 2, 1) |
| 278 | | - call terminal_write('Workspace Symbols (type to search, Esc to cancel)') |
| 393 | + ! Draw title bar with background color |
| 394 | + row = 1 |
| 395 | + call terminal_move_cursor(row, panel%panel_start_col) |
| 396 | + call terminal_write(ESC // '[48;5;237m' // ESC // '[1m') ! Dark bg, bold |
| 397 | + line = " Workspace Symbols" |
| 398 | + if (panel%num_filtered > 0) then |
| 399 | + write(line, '(A,I0,A)') trim(line) // " (", panel%num_filtered, ")" |
| 400 | + end if |
| 401 | + call terminal_write(line(1:min(len_trim(line), panel%panel_width))) |
| 402 | + call terminal_write(repeat(" ", max(0, panel%panel_width - len_trim(line)))) |
| 403 | + call terminal_write(ESC // '[0m') |
| 404 | + |
| 405 | + ! Draw search input |
| 406 | + row = 2 |
| 407 | + call terminal_move_cursor(row, panel%panel_start_col) |
| 408 | + call terminal_write(ESC // '[48;5;236m') ! Slightly lighter for input |
| 409 | + if (panel%search_pos > 0) then |
| 410 | + line = " > " // trim(panel%search_query(1:panel%search_pos)) |
| 411 | + else |
| 412 | + line = " > " // ESC // '[90m' // "(type to filter)" // ESC // '[0m' // ESC // '[48;5;236m' |
| 413 | + end if |
| 414 | + call terminal_write(line(1:min(len_trim(line), panel%panel_width))) |
| 415 | + call terminal_write(repeat(" ", max(0, panel%panel_width - len_trim(line)))) |
| 416 | + call terminal_write(ESC // '[0m') |
| 279 | 417 | |
| 280 | | - ! Draw search query |
| 281 | | - call terminal_move_cursor(screen_rows - MAX_VISIBLE - 1, 1) |
| 282 | | - call terminal_write(repeat(' ', 120)) |
| 283 | | - call terminal_move_cursor(screen_rows - MAX_VISIBLE - 1, 1) |
| 284 | | - call terminal_write('> ' // trim(panel%search_query)) |
| 418 | + ! Draw separator |
| 419 | + row = 3 |
| 420 | + call terminal_move_cursor(row, panel%panel_start_col) |
| 421 | + call terminal_write(ESC // '[48;5;237m' // repeat("-", panel%panel_width) // ESC // '[0m') |
| 285 | 422 | |
| 286 | 423 | ! Calculate visible range |
| 287 | | - visible_start = panel%scroll_offset + 1 |
| 288 | | - visible_end = min(visible_start + MAX_VISIBLE - 1, panel%num_filtered) |
| 424 | + start_idx = panel%scroll_offset + 1 |
| 425 | + end_idx = min(panel%scroll_offset + panel%max_visible, panel%num_filtered) |
| 426 | + |
| 427 | + ! Render symbols |
| 428 | + if (panel%num_filtered > 0) then |
| 429 | + do i = start_idx, end_idx |
| 430 | + row = row + 1 |
| 431 | + call terminal_move_cursor(row, panel%panel_start_col) |
| 432 | + |
| 433 | + ! Background color based on selection |
| 434 | + if (i == panel%selected_index) then |
| 435 | + call terminal_write(ESC // '[48;5;240m') ! Highlight |
| 436 | + else |
| 437 | + call terminal_write(ESC // '[48;5;235m') ! Normal |
| 438 | + end if |
| 289 | 439 | |
| 290 | | - ! Draw symbols |
| 291 | | - row = screen_rows - MAX_VISIBLE |
| 292 | | - do i = visible_start, visible_end |
| 293 | | - sym = panel%filtered_symbols(i) |
| 440 | + ! Build display line: icon + name + file:line |
| 441 | + line = " " |
| 294 | 442 | |
| 295 | | - call terminal_move_cursor(row, 1) |
| 296 | | - call terminal_write(repeat(' ', 120)) |
| 297 | | - call terminal_move_cursor(row, 1) |
| 443 | + ! Add kind indicator |
| 444 | + if (allocated(panel%filtered_symbols(i)%kind_name)) then |
| 445 | + line = trim(line) // "[" // trim(panel%filtered_symbols(i)%kind_name(1:min(3, len_trim(panel%filtered_symbols(i)%kind_name)))) // "] " |
| 446 | + else |
| 447 | + line = trim(line) // " " |
| 448 | + end if |
| 298 | 449 | |
| 299 | | - ! Build line with kind, name, and container |
| 300 | | - if (len_trim(sym%kind_name) > 0) then |
| 301 | | - write(kind_tag, '(A,A,A)') '[', trim(sym%kind_name), '] ' |
| 302 | | - else |
| 303 | | - kind_tag = '' |
| 304 | | - end if |
| 450 | + ! Add symbol name |
| 451 | + if (allocated(panel%filtered_symbols(i)%name)) then |
| 452 | + line = trim(line) // trim(panel%filtered_symbols(i)%name) |
| 453 | + end if |
| 305 | 454 | |
| 306 | | - if (len_trim(sym%container_name) > 0) then |
| 307 | | - write(container_info, '(A,A)') ' in ', trim(sym%container_name) |
| 308 | | - else |
| 309 | | - container_info = '' |
| 310 | | - end if |
| 455 | + ! Add file info on selected item |
| 456 | + if (i == panel%selected_index) then |
| 457 | + if (allocated(panel%filtered_symbols(i)%file_path)) then |
| 458 | + write(file_info, '(A,A,A,I0)') " (", & |
| 459 | + trim(get_basename(panel%filtered_symbols(i)%file_path)), & |
| 460 | + ":", panel%filtered_symbols(i)%line |
| 461 | + file_info = trim(file_info) // ")" |
| 462 | + if (len_trim(line) + len_trim(file_info) < panel%panel_width - 1) then |
| 463 | + line = trim(line) // ESC // '[90m' // trim(file_info) // ESC // '[0m' // ESC // '[48;5;240m' |
| 464 | + end if |
| 465 | + end if |
| 466 | + end if |
| 311 | 467 | |
| 312 | | - if (i == panel%selected_index) then |
| 313 | | - ! Highlight selected item |
| 314 | | - write(line, '(A,A,A,A)') '> ', trim(kind_tag), trim(sym%name), trim(container_info) |
| 468 | + ! Write line and pad |
| 469 | + call terminal_write(line(1:min(len_trim(line), panel%panel_width))) |
| 470 | + call terminal_write(repeat(" ", max(0, panel%panel_width - len_trim(line)))) |
| 471 | + call terminal_write(ESC // '[0m') |
| 472 | + end do |
| 473 | + |
| 474 | + ! Fill empty rows |
| 475 | + do while (row < screen_height - 1) |
| 476 | + row = row + 1 |
| 477 | + call terminal_move_cursor(row, panel%panel_start_col) |
| 478 | + call terminal_write(ESC // '[48;5;235m' // repeat(" ", panel%panel_width) // ESC // '[0m') |
| 479 | + end do |
| 480 | + else |
| 481 | + ! No symbols message |
| 482 | + row = row + 1 |
| 483 | + call terminal_move_cursor(row, panel%panel_start_col) |
| 484 | + call terminal_write(ESC // '[48;5;235m' // ESC // '[90m') |
| 485 | + if (panel%search_pos == 0) then |
| 486 | + line = " Type to search..." |
| 487 | + else if (panel%num_symbols == 0) then |
| 488 | + line = " Searching..." |
| 315 | 489 | else |
| 316 | | - write(line, '(A,A,A,A)') ' ', trim(kind_tag), trim(sym%name), trim(container_info) |
| 490 | + line = " No matching symbols" |
| 317 | 491 | end if |
| 492 | + call terminal_write(line(1:min(len_trim(line), panel%panel_width))) |
| 493 | + call terminal_write(repeat(" ", max(0, panel%panel_width - len_trim(line)))) |
| 494 | + call terminal_write(ESC // '[0m') |
| 495 | + |
| 496 | + do while (row < screen_height - 1) |
| 497 | + row = row + 1 |
| 498 | + call terminal_move_cursor(row, panel%panel_start_col) |
| 499 | + call terminal_write(ESC // '[48;5;235m' // repeat(" ", panel%panel_width) // ESC // '[0m') |
| 500 | + end do |
| 501 | + end if |
| 318 | 502 | |
| 319 | | - call terminal_write(trim(line)) |
| 320 | | - row = row + 1 |
| 321 | | - end do |
| 503 | + ! Draw hint bar at bottom |
| 504 | + call terminal_move_cursor(screen_height, panel%panel_start_col) |
| 505 | + call terminal_write(ESC // '[48;5;237m' // ESC // '[90m') |
| 506 | + line = " Enter:open Esc:close Ctrl-U:clear" |
| 507 | + call terminal_write(line(1:min(len_trim(line), panel%panel_width))) |
| 508 | + call terminal_write(repeat(" ", max(0, panel%panel_width - len_trim(line)))) |
| 509 | + call terminal_write(ESC // '[0m') |
| 510 | + end subroutine render_workspace_symbols_panel |
| 322 | 511 | |
| 323 | | - ! Clear remaining lines |
| 324 | | - do while (row <= screen_rows) |
| 325 | | - call terminal_move_cursor(row, 1) |
| 326 | | - call terminal_write(repeat(' ', 120)) |
| 327 | | - row = row + 1 |
| 512 | + function get_basename(path) result(basename) |
| 513 | + character(len=*), intent(in) :: path |
| 514 | + character(len=256) :: basename |
| 515 | + integer :: i, last_slash |
| 516 | + |
| 517 | + last_slash = 0 |
| 518 | + do i = len_trim(path), 1, -1 |
| 519 | + if (path(i:i) == '/') then |
| 520 | + last_slash = i |
| 521 | + exit |
| 522 | + end if |
| 328 | 523 | end do |
| 329 | 524 | |
| 330 | | - ! Position cursor at end of search query |
| 331 | | - call terminal_move_cursor(screen_rows - MAX_VISIBLE - 1, 3 + panel%search_pos) |
| 332 | | - end subroutine render_workspace_symbols_panel |
| 525 | + if (last_slash > 0 .and. last_slash < len_trim(path)) then |
| 526 | + basename = path(last_slash+1:len_trim(path)) |
| 527 | + else |
| 528 | + basename = path |
| 529 | + end if |
| 530 | + end function get_basename |
| 333 | 531 | |
| 334 | 532 | end module workspace_symbols_panel_module |