@@ -299,11 +299,11 @@ contains |
| 299 | prev_selected = selected | 299 | prev_selected = selected |
| 300 | prev_viewport = viewport_offset | 300 | prev_viewport = viewport_offset |
| 301 | | 301 | |
| 302 | - ! Check search timeout (1 second) | 302 | + ! Check search timeout (0.5 seconds) |
| 303 | if (search_length > 0) then | 303 | if (search_length > 0) then |
| 304 | call system_clock(current_tick) | 304 | call system_clock(current_tick) |
| 305 | - ! Check if 1 second has elapsed (clock_rate ticks per second) | 305 | + ! Check if 0.5 seconds has elapsed (clock_rate/2 ticks) |
| 306 | - if (current_tick - last_search_tick > clock_rate) then | 306 | + if (current_tick - last_search_tick > clock_rate / 2) then |
| 307 | search_length = 0 | 307 | search_length = 0 |
| 308 | search_buffer = '' | 308 | search_buffer = '' |
| 309 | needs_full_redraw = .true. | 309 | needs_full_redraw = .true. |
@@ -363,6 +363,21 @@ contains |
| 363 | if ((key >= 'a' .and. key <= 'z') .or. & | 363 | if ((key >= 'a' .and. key <= 'z') .or. & |
| 364 | ((key >= 'E' .and. key <= 'Z') .or. (key >= '0' .and. key <= '9')) .or. & | 364 | ((key >= 'E' .and. key <= 'Z') .or. (key >= '0' .and. key <= '9')) .or. & |
| 365 | key == '_' .or. key == '-' .or. key == '.') then | 365 | key == '_' .or. key == '-' .or. key == '.') then |
| | 366 | + |
| | 367 | + ! Check if timeout elapsed since last keypress - if so, start fresh search |
| | 368 | + if (search_length > 0) then |
| | 369 | + call system_clock(current_tick) |
| | 370 | + if (current_tick - last_search_tick > clock_rate / 2) then |
| | 371 | + ! Timeout elapsed (0.5 seconds) - clear buffer and start new search |
| | 372 | + search_length = 0 |
| | 373 | + search_buffer = '' |
| | 374 | + ! DEBUG |
| | 375 | + open(99, file='/tmp/fuss_debug.log', position='append') |
| | 376 | + write(99, '(A)') 'TIMEOUT: Starting fresh search (0.5s elapsed)' |
| | 377 | + close(99) |
| | 378 | + end if |
| | 379 | + end if |
| | 380 | + |
| 366 | ! Add to search buffer | 381 | ! Add to search buffer |
| 367 | if (search_length < 32) then | 382 | if (search_length < 32) then |
| 368 | search_length = search_length + 1 | 383 | search_length = search_length + 1 |
@@ -686,6 +701,8 @@ contains |
| 686 | ! In normal mode: q quits the application | 701 | ! In normal mode: q quits the application |
| 687 | running = .false. | 702 | running = .false. |
| 688 | end if | 703 | end if |
| | 704 | + case (achar(17)) ! Ctrl-Q - force quit from any mode |
| | 705 | + running = .false. |
| 689 | case default | 706 | case default |
| 690 | ! Unhandled keys - do nothing | 707 | ! Unhandled keys - do nothing |
| 691 | continue | 708 | continue |
@@ -1512,6 +1529,7 @@ contains |
| 1512 | | 1529 | |
| 1513 | subroutine fuzzy_jump_to_match(items, n_items, pattern, selected) | 1530 | subroutine fuzzy_jump_to_match(items, n_items, pattern, selected) |
| 1514 | ! Jump to first item that fuzzy matches the pattern | 1531 | ! Jump to first item that fuzzy matches the pattern |
| | 1532 | + ! Prioritizes matching item names (basename) over full paths |
| 1515 | ! Searches from NEXT position (skips current item to allow cycling) | 1533 | ! Searches from NEXT position (skips current item to allow cycling) |
| 1516 | type(selectable_item), intent(in) :: items(:) | 1534 | type(selectable_item), intent(in) :: items(:) |
| 1517 | integer, intent(in) :: n_items | 1535 | integer, intent(in) :: n_items |
@@ -1523,6 +1541,28 @@ contains |
| 1523 | start_pos = selected + 1 | 1541 | start_pos = selected + 1 |
| 1524 | if (start_pos > n_items) start_pos = 1 | 1542 | if (start_pos > n_items) start_pos = 1 |
| 1525 | | 1543 | |
| | 1544 | + ! PASS 1: Try to match item NAME first (e.g., "src" matches "src/" before "src/file.f90") |
| | 1545 | + ! Search from next position forward |
| | 1546 | + do i = start_pos, n_items |
| | 1547 | + if (associated(items(i)%node)) then |
| | 1548 | + if (fuzzy_match(pattern, items(i)%node%name)) then |
| | 1549 | + selected = i |
| | 1550 | + return |
| | 1551 | + end if |
| | 1552 | + end if |
| | 1553 | + end do |
| | 1554 | + |
| | 1555 | + ! Wrap around: search from beginning to current position (inclusive) |
| | 1556 | + do i = 1, selected |
| | 1557 | + if (associated(items(i)%node)) then |
| | 1558 | + if (fuzzy_match(pattern, items(i)%node%name)) then |
| | 1559 | + selected = i |
| | 1560 | + return |
| | 1561 | + end if |
| | 1562 | + end if |
| | 1563 | + end do |
| | 1564 | + |
| | 1565 | + ! PASS 2: If no name match, try matching full path |
| 1526 | ! Search from next position forward | 1566 | ! Search from next position forward |
| 1527 | do i = start_pos, n_items | 1567 | do i = start_pos, n_items |
| 1528 | if (fuzzy_match(pattern, items(i)%path)) then | 1568 | if (fuzzy_match(pattern, items(i)%path)) then |