@@ -24,6 +24,9 @@ program fuss |
| 24 | 24 | call build_and_display_tree(show_all) |
| 25 | 25 | end if |
| 26 | 26 | |
| 27 | + ! Ensure terminal is always restored (safety cleanup) |
| 28 | + call cleanup_terminal() |
| 29 | + |
| 27 | 30 | contains |
| 28 | 31 | |
| 29 | 32 | subroutine parse_arguments(show_all, interactive) |
@@ -154,6 +157,13 @@ contains |
| 154 | 157 | end if |
| 155 | 158 | end subroutine build_and_display_tree |
| 156 | 159 | |
| 160 | + subroutine cleanup_terminal() |
| 161 | + ! Emergency cleanup - restores terminal to normal state |
| 162 | + ! Call this before any exit or when calling external programs |
| 163 | + call disable_raw_mode() |
| 164 | + call exit_alternate_screen() |
| 165 | + end subroutine cleanup_terminal |
| 166 | + |
| 157 | 167 | subroutine interactive_mode(show_all) |
| 158 | 168 | logical, intent(in) :: show_all |
| 159 | 169 | type(file_entry), allocatable :: files(:) |
@@ -190,14 +200,12 @@ contains |
| 190 | 200 | ! Initialize hide_dotfiles before first use |
| 191 | 201 | hide_dotfiles = .false. |
| 192 | 202 | |
| 193 | | - ! Get files |
| 203 | + ! Get files and mark incoming changes |
| 194 | 204 | if (show_all) then |
| 195 | 205 | call get_all_files(files, n_files) |
| 196 | 206 | else |
| 197 | 207 | call get_dirty_files(files, n_files) |
| 198 | 208 | end if |
| 199 | | - |
| 200 | | - ! Mark files with incoming changes |
| 201 | 209 | call mark_incoming_changes(files, n_files) |
| 202 | 210 | |
| 203 | 211 | if (n_files == 0) then |
@@ -227,6 +235,9 @@ contains |
| 227 | 235 | viewport_offset = 1 |
| 228 | 236 | running = .true. |
| 229 | 237 | |
| 238 | + ! Enter alternate screen buffer (preserves terminal content) |
| 239 | + call enter_alternate_screen() |
| 240 | + |
| 230 | 241 | ! Enable raw terminal mode |
| 231 | 242 | call enable_raw_mode() |
| 232 | 243 | |
@@ -273,128 +284,63 @@ contains |
| 273 | 284 | if (.not. items(selected)%is_file) then |
| 274 | 285 | call git_stage_directory(items(selected)%path) |
| 275 | 286 | ! Refresh files after staging directory |
| 276 | | - if (show_all) then |
| 277 | | - call get_all_files(files, n_files) |
| 278 | | - else |
| 279 | | - call get_dirty_files(files, n_files) |
| 280 | | - end if |
| 281 | | - call mark_incoming_changes(files, n_files) |
| 282 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 283 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 284 | | - if (n_items == 0) running = .false. |
| 287 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 288 | + hide_dotfiles, selected, running, exit_if_empty=.true.) |
| 285 | 289 | ! Otherwise it's a file - stage individual file |
| 286 | 290 | else if (items(selected)%is_file .and. (items(selected)%is_unstaged .or. items(selected)%is_untracked)) then |
| 287 | 291 | call git_add_file(items(selected)%path) |
| 288 | 292 | ! Refresh files after git add |
| 289 | | - if (show_all) then |
| 290 | | - call get_all_files(files, n_files) |
| 291 | | - else |
| 292 | | - call get_dirty_files(files, n_files) |
| 293 | | - end if |
| 294 | | - call mark_incoming_changes(files, n_files) |
| 295 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 296 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 297 | | - if (n_items == 0) running = .false. |
| 293 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 294 | + hide_dotfiles, selected, running, exit_if_empty=.true.) |
| 298 | 295 | end if |
| 299 | 296 | case ('u') ! Unstage file (lowercase) |
| 300 | 297 | if (items(selected)%is_file .and. items(selected)%is_staged) then |
| 301 | 298 | call git_unstage_file(items(selected)%path) |
| 302 | 299 | ! Refresh files after git unstage |
| 303 | | - if (show_all) then |
| 304 | | - call get_all_files(files, n_files) |
| 305 | | - else |
| 306 | | - call get_dirty_files(files, n_files) |
| 307 | | - end if |
| 308 | | - call mark_incoming_changes(files, n_files) |
| 309 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 310 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 300 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 301 | + hide_dotfiles, selected, running) |
| 311 | 302 | end if |
| 312 | 303 | case ('S') ! Stage all (Shift+S to avoid conflict with up arrow 'A') |
| 313 | 304 | call git_stage_all() |
| 314 | 305 | ! Refresh files after staging all |
| 315 | | - if (show_all) then |
| 316 | | - call get_all_files(files, n_files) |
| 317 | | - else |
| 318 | | - call get_dirty_files(files, n_files) |
| 319 | | - end if |
| 320 | | - call mark_incoming_changes(files, n_files) |
| 321 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 322 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 323 | | - if (n_items == 0) running = .false. |
| 306 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 307 | + hide_dotfiles, selected, running, exit_if_empty=.true.) |
| 324 | 308 | case ('U') ! Unstage all (Shift+U) |
| 325 | 309 | call git_unstage_all() |
| 326 | 310 | ! Refresh files after unstaging all |
| 327 | | - if (show_all) then |
| 328 | | - call get_all_files(files, n_files) |
| 329 | | - else |
| 330 | | - call get_dirty_files(files, n_files) |
| 331 | | - end if |
| 332 | | - call mark_incoming_changes(files, n_files) |
| 333 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 334 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 311 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 312 | + hide_dotfiles, selected, running) |
| 335 | 313 | case ('m') ! Commit (lowercase) |
| 336 | 314 | call commit_prompt() |
| 337 | 315 | ! Refresh files after commit |
| 338 | | - if (show_all) then |
| 339 | | - call get_all_files(files, n_files) |
| 340 | | - else |
| 341 | | - call get_dirty_files(files, n_files) |
| 342 | | - end if |
| 343 | | - call mark_incoming_changes(files, n_files) |
| 344 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 345 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 316 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 317 | + hide_dotfiles, selected, running) |
| 346 | 318 | case ('M') ! Amend last commit (Shift+m) |
| 347 | 319 | call amend_commit_prompt() |
| 348 | 320 | ! Refresh files after amend commit |
| 349 | | - if (show_all) then |
| 350 | | - call get_all_files(files, n_files) |
| 351 | | - else |
| 352 | | - call get_dirty_files(files, n_files) |
| 353 | | - end if |
| 354 | | - call mark_incoming_changes(files, n_files) |
| 355 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 356 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 321 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 322 | + hide_dotfiles, selected, running) |
| 357 | 323 | case ('s') ! Show git status (lowercase) |
| 358 | 324 | call show_status_view() |
| 359 | 325 | case ('p') ! Push (lowercase) |
| 360 | 326 | call push_prompt() |
| 361 | 327 | ! Refresh files after push |
| 362 | | - if (show_all) then |
| 363 | | - call get_all_files(files, n_files) |
| 364 | | - else |
| 365 | | - call get_dirty_files(files, n_files) |
| 366 | | - end if |
| 367 | | - call mark_incoming_changes(files, n_files) |
| 368 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 369 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 328 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 329 | + hide_dotfiles, selected, running) |
| 370 | 330 | case ('t') ! Tag (lowercase) |
| 371 | 331 | call tag_prompt() |
| 372 | 332 | case ('b') ! Switch branch |
| 373 | 333 | call branch_switch_prompt() |
| 374 | 334 | ! Refresh files after branch switch |
| 375 | | - if (show_all) then |
| 376 | | - call get_all_files(files, n_files) |
| 377 | | - else |
| 378 | | - call get_dirty_files(files, n_files) |
| 379 | | - end if |
| 380 | | - call mark_incoming_changes(files, n_files) |
| 381 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 382 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 383 | | - if (n_items == 0) running = .false. |
| 335 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 336 | + hide_dotfiles, selected, running, exit_if_empty=.true.) |
| 384 | 337 | ! Update branch name display |
| 385 | 338 | call get_repo_info(repo_name, branch_name) |
| 386 | 339 | case ('n') ! Create new branch |
| 387 | 340 | call branch_create_prompt() |
| 388 | 341 | ! Refresh files after branch creation |
| 389 | | - if (show_all) then |
| 390 | | - call get_all_files(files, n_files) |
| 391 | | - else |
| 392 | | - call get_dirty_files(files, n_files) |
| 393 | | - end if |
| 394 | | - call mark_incoming_changes(files, n_files) |
| 395 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 396 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 397 | | - if (n_items == 0) running = .false. |
| 342 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 343 | + hide_dotfiles, selected, running, exit_if_empty=.true.) |
| 398 | 344 | ! Update branch name display |
| 399 | 345 | call get_repo_info(repo_name, branch_name) |
| 400 | 346 | case ('R') ! Delete branch (Shift+r, since 'r' is used for delete file) |
@@ -403,16 +349,8 @@ contains |
| 403 | 349 | case ('f') ! Git fetch |
| 404 | 350 | call git_fetch() |
| 405 | 351 | ! Refresh files after fetch and include files with incoming changes |
| 406 | | - if (show_all) then |
| 407 | | - call get_all_files(files, n_files) |
| 408 | | - call mark_incoming_changes(files, n_files) |
| 409 | | - else |
| 410 | | - ! In non-all mode, add files that only have incoming changes |
| 411 | | - call get_dirty_files(files, n_files) |
| 412 | | - call add_incoming_files(files, n_files) |
| 413 | | - end if |
| 414 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 415 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 352 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 353 | + hide_dotfiles, selected, running, include_incoming=.true.) |
| 416 | 354 | case ('d') ! Git diff with less |
| 417 | 355 | if (items(selected)%is_file) then |
| 418 | 356 | call git_diff_file(items(selected)%path, items(selected)%has_incoming) |
@@ -429,89 +367,43 @@ contains |
| 429 | 367 | if (items(selected)%is_file) then |
| 430 | 368 | call delete_prompt(items(selected)%path, items(selected)%is_untracked) |
| 431 | 369 | ! Refresh files after delete |
| 432 | | - if (show_all) then |
| 433 | | - call get_all_files(files, n_files) |
| 434 | | - else |
| 435 | | - call get_dirty_files(files, n_files) |
| 436 | | - end if |
| 437 | | - call mark_incoming_changes(files, n_files) |
| 438 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 439 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 440 | | - if (n_items == 0) running = .false. |
| 370 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 371 | + hide_dotfiles, selected, running, exit_if_empty=.true.) |
| 441 | 372 | end if |
| 442 | 373 | case ('x', 'X') ! Discard changes |
| 443 | 374 | if (items(selected)%is_file .and. (items(selected)%is_staged .or. items(selected)%is_unstaged .or. items(selected)%is_untracked)) then |
| 444 | 375 | call discard_prompt(items(selected)%path, items(selected)%is_staged, items(selected)%is_untracked) |
| 445 | 376 | ! Refresh files after discard |
| 446 | | - if (show_all) then |
| 447 | | - call get_all_files(files, n_files) |
| 448 | | - else |
| 449 | | - call get_dirty_files(files, n_files) |
| 450 | | - end if |
| 451 | | - call mark_incoming_changes(files, n_files) |
| 452 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 453 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 454 | | - if (n_items == 0) running = .false. |
| 377 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 378 | + hide_dotfiles, selected, running, exit_if_empty=.true.) |
| 455 | 379 | end if |
| 456 | 380 | case ('l') ! Git pull |
| 457 | 381 | call git_pull() |
| 458 | 382 | ! Refresh files after pull (incoming indicators will automatically clear) |
| 459 | | - if (show_all) then |
| 460 | | - call get_all_files(files, n_files) |
| 461 | | - call mark_incoming_changes(files, n_files) |
| 462 | | - else |
| 463 | | - call get_dirty_files(files, n_files) |
| 464 | | - call add_incoming_files(files, n_files) |
| 465 | | - end if |
| 466 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 467 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 383 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 384 | + hide_dotfiles, selected, running, include_incoming=.true.) |
| 468 | 385 | ! Note: After successful pull, git diff will show no upstream differences |
| 469 | 386 | ! so has_incoming will be .false. for all files automatically |
| 470 | 387 | case ('z') ! Stash push (save changes) |
| 471 | 388 | call stash_push_prompt() |
| 472 | 389 | ! Refresh files after stash |
| 473 | | - if (show_all) then |
| 474 | | - call get_all_files(files, n_files) |
| 475 | | - else |
| 476 | | - call get_dirty_files(files, n_files) |
| 477 | | - end if |
| 478 | | - call mark_incoming_changes(files, n_files) |
| 479 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 480 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 481 | | - if (n_items == 0) running = .false. |
| 390 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 391 | + hide_dotfiles, selected, running, exit_if_empty=.true.) |
| 482 | 392 | case ('Z') ! Stash pop/apply (restore changes) |
| 483 | 393 | call stash_pop_apply_prompt() |
| 484 | 394 | ! Refresh files after stash pop/apply |
| 485 | | - if (show_all) then |
| 486 | | - call get_all_files(files, n_files) |
| 487 | | - else |
| 488 | | - call get_dirty_files(files, n_files) |
| 489 | | - end if |
| 490 | | - call mark_incoming_changes(files, n_files) |
| 491 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 492 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 395 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 396 | + hide_dotfiles, selected, running) |
| 493 | 397 | case ('y') ! Cherry-pick (yank commit) |
| 494 | 398 | call cherry_pick_prompt() |
| 495 | 399 | ! Refresh files after cherry-pick |
| 496 | | - if (show_all) then |
| 497 | | - call get_all_files(files, n_files) |
| 498 | | - else |
| 499 | | - call get_dirty_files(files, n_files) |
| 500 | | - end if |
| 501 | | - call mark_incoming_changes(files, n_files) |
| 502 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 503 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 400 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 401 | + hide_dotfiles, selected, running) |
| 504 | 402 | case ('v') ! Revert commit |
| 505 | 403 | call revert_commit_prompt() |
| 506 | 404 | ! Refresh files after revert |
| 507 | | - if (show_all) then |
| 508 | | - call get_all_files(files, n_files) |
| 509 | | - else |
| 510 | | - call get_dirty_files(files, n_files) |
| 511 | | - end if |
| 512 | | - call mark_incoming_changes(files, n_files) |
| 513 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 514 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 405 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 406 | + hide_dotfiles, selected, running) |
| 515 | 407 | case ('h') ! Show commit history |
| 516 | 408 | call history_browser_prompt() |
| 517 | 409 | ! No refresh needed - read-only |
@@ -521,38 +413,20 @@ contains |
| 521 | 413 | case ('G') ! Merge branch (Shift+g) |
| 522 | 414 | call merge_branch_prompt() |
| 523 | 415 | ! Refresh files after merge |
| 524 | | - if (show_all) then |
| 525 | | - call get_all_files(files, n_files) |
| 526 | | - else |
| 527 | | - call get_dirty_files(files, n_files) |
| 528 | | - end if |
| 529 | | - call mark_incoming_changes(files, n_files) |
| 530 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 531 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 416 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 417 | + hide_dotfiles, selected, running) |
| 532 | 418 | ! Update branch name display in case we merged |
| 533 | 419 | call get_repo_info(repo_name, branch_name) |
| 534 | 420 | case ('O') ! Reset (Shift+o - "Oh no, undo!") |
| 535 | 421 | call reset_prompt() |
| 536 | 422 | ! Refresh files after reset |
| 537 | | - if (show_all) then |
| 538 | | - call get_all_files(files, n_files) |
| 539 | | - else |
| 540 | | - call get_dirty_files(files, n_files) |
| 541 | | - end if |
| 542 | | - call mark_incoming_changes(files, n_files) |
| 543 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 544 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 423 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 424 | + hide_dotfiles, selected, running) |
| 545 | 425 | case ('I') ! Interactive rebase (Shift+i) |
| 546 | 426 | call rebase_prompt() |
| 547 | 427 | ! Refresh files after rebase |
| 548 | | - if (show_all) then |
| 549 | | - call get_all_files(files, n_files) |
| 550 | | - else |
| 551 | | - call get_dirty_files(files, n_files) |
| 552 | | - end if |
| 553 | | - call mark_incoming_changes(files, n_files) |
| 554 | | - call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 555 | | - if (selected > n_items .and. n_items > 0) selected = n_items |
| 428 | + call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 429 | + hide_dotfiles, selected, running) |
| 556 | 430 | case ('.') ! Toggle hiding dotfiles and gitignored files |
| 557 | 431 | hide_dotfiles = .not. hide_dotfiles |
| 558 | 432 | ! Rebuild item list with new filter |
@@ -569,15 +443,15 @@ contains |
| 569 | 443 | end select |
| 570 | 444 | end do |
| 571 | 445 | |
| 572 | | - ! Restore terminal |
| 573 | | - call disable_raw_mode() |
| 446 | + ! Restore terminal to normal state |
| 447 | + call cleanup_terminal() |
| 574 | 448 | |
| 575 | 449 | ! Free the tree |
| 576 | 450 | if (associated(tree_root)) then |
| 577 | 451 | call free_tree(tree_root) |
| 578 | 452 | end if |
| 579 | 453 | |
| 580 | | - ! Final display |
| 454 | + ! Final display (now in normal terminal buffer) |
| 581 | 455 | call clear_screen() |
| 582 | 456 | call build_and_display_tree(show_all) |
| 583 | 457 | end subroutine interactive_mode |
@@ -1336,4 +1210,51 @@ contains |
| 1336 | 1210 | call read_key(key) |
| 1337 | 1211 | end subroutine branch_delete_prompt |
| 1338 | 1212 | |
| 1213 | + subroutine refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, & |
| 1214 | + hide_dotfiles, selected, running, exit_if_empty, include_incoming) |
| 1215 | + ! Centralized helper to refresh file list and rebuild tree |
| 1216 | + ! Consolidates the pattern repeated 20+ times in the codebase |
| 1217 | + logical, intent(in) :: show_all, hide_dotfiles |
| 1218 | + type(file_entry), allocatable, intent(inout) :: files(:) |
| 1219 | + integer, intent(inout) :: n_files, n_items, selected |
| 1220 | + type(tree_node), pointer, intent(inout) :: tree_root |
| 1221 | + type(selectable_item), allocatable, intent(inout) :: items(:) |
| 1222 | + logical, intent(inout), optional :: running |
| 1223 | + logical, intent(in), optional :: exit_if_empty, include_incoming |
| 1224 | + |
| 1225 | + logical :: do_exit_if_empty, do_include_incoming |
| 1226 | + |
| 1227 | + ! Handle optional parameters |
| 1228 | + do_exit_if_empty = .false. |
| 1229 | + if (present(exit_if_empty)) do_exit_if_empty = exit_if_empty |
| 1230 | + |
| 1231 | + do_include_incoming = .false. |
| 1232 | + if (present(include_incoming)) do_include_incoming = include_incoming |
| 1233 | + |
| 1234 | + ! Get files based on mode |
| 1235 | + if (show_all) then |
| 1236 | + call get_all_files(files, n_files) |
| 1237 | + call mark_incoming_changes(files, n_files) |
| 1238 | + else |
| 1239 | + call get_dirty_files(files, n_files) |
| 1240 | + if (do_include_incoming) then |
| 1241 | + ! For fetch/pull: also include files with only incoming changes |
| 1242 | + call add_incoming_files(files, n_files) |
| 1243 | + else |
| 1244 | + call mark_incoming_changes(files, n_files) |
| 1245 | + end if |
| 1246 | + end if |
| 1247 | + |
| 1248 | + ! Rebuild tree and flatten to items |
| 1249 | + call build_item_list(files, n_files, items, n_items, tree_root, hide_dotfiles) |
| 1250 | + |
| 1251 | + ! Adjust selection if needed |
| 1252 | + if (selected > n_items .and. n_items > 0) selected = n_items |
| 1253 | + |
| 1254 | + ! Exit if no items and exit_if_empty is set |
| 1255 | + if (do_exit_if_empty .and. n_items == 0) then |
| 1256 | + if (present(running)) running = .false. |
| 1257 | + end if |
| 1258 | + end subroutine refresh_and_rebuild |
| 1259 | + |
| 1339 | 1260 | end program fuss |