xaizek / vifm (License: GPLv2+) (since 2018-12-07)
Vifm is a file manager with curses interface, which provides Vi[m]-like environment for managing objects within file systems, extended with some useful ideas from mutt.
Commit 31bcd6aa384a15465f86d5c86c348d3fa2c0b136

Fixed non-stop refresh of directory preview
Happened when 'previewoptions' listed non-default values for builtin
directory preview.

Initial fix was just caching option values unconditionally in
update_cache_entry() but later thought that having a flag indicating
builtin directory preview reads better and also avoids is_dir()
invocation in is_cache_valid().

Thanks to Chris at Vifm Q2A site.

See
https://q2a.vifm.info/2482/sometimes-quickview-directory-very-working-under-vsplit-mode
Author: xaizek
Author date (UTC): 2026-08-05 09:07
Committer name: xaizek
Committer date (UTC): 2026-08-05 09:10
Parent(s): 6083f5297eb525e8d397701a898c02c236c1896d
Signing key: 99DC5E4DB05F6BE2
Tree: 19677f49f2f3428c2b4da8ba2ac91d70855d42a6
File Lines added Lines deleted
ChangeLog 4 0
src/vcache.c 9 2
tests/misc/vcache.c 38 0
File ChangeLog changed (mode: 100644) (index b17938667..6c30ee582)
287 287
288 288 Fixed Alt-. command-line mode key not working on Windows. Fixed Alt-. command-line mode key not working on Windows.
289 289
290 Fixed external preview of directories being indefinitely refreshed when
291 'previewoptions' lists non-default values for builtin directory preview.
292 Thanks to Chris at Vifm Q2A site.
293
290 294 0.14-beta to 0.14 (2025-02-08) 0.14-beta to 0.14 (2025-02-08)
291 295
292 296 Improved documentation on zh/zl menu keys a bit. Improved documentation on zh/zl menu keys a bit.
File src/vcache.c changed (mode: 100644) (index 9880b96b1..3b4ebe586)
... ... typedef struct vcache_entry_t
67 67 int max_tree_depth; int max_tree_depth;
68 68 /* Whether cache contains complete output of the viewer. */ /* Whether cache contains complete output of the viewer. */
69 69 unsigned int complete : 1; unsigned int complete : 1;
70 /* Whether builtin directory preview is used. */
71 unsigned int builtin_dir : 1;
70 72 /* Whether last line is truncated. */ /* Whether last line is truncated. */
71 73 unsigned int truncated : 1; unsigned int truncated : 1;
72 74 /* Value of toptreestats for this entry. */ /* Value of toptreestats for this entry. */
 
... ... is_cache_valid(const vcache_entry_t *centry, const char path[],
426 428 } }
427 429 } }
428 430
429 if((centry->top_tree_stats != cfg.top_tree_stats ||
430 centry->max_tree_depth != cfg.max_tree_depth) && is_dir(path))
431 if(centry->builtin_dir && (centry->top_tree_stats != cfg.top_tree_stats ||
432 centry->max_tree_depth != cfg.max_tree_depth))
431 433 { {
432 434 return 0; return 0;
433 435 } }
 
... ... update_cache_entry(vcache_entry_t *centry, const char path[],
450 452
451 453 if(centry->job == NULL) if(centry->job == NULL)
452 454 { {
455 /* Old and new cache isn't necessarily of the same kind. */
456 centry->builtin_dir = 0;
457
453 458 free_string_array(centry->lines.items, centry->lines.nitems); free_string_array(centry->lines.items, centry->lines.nitems);
454 459 centry->lines = view_entry(centry, flags, error); centry->lines = view_entry(centry, flags, error);
455 460
 
... ... view_builtin(vcache_entry_t *centry, const char **error)
673 678 FILE *fp = NULL; FILE *fp = NULL;
674 679 if(dir) if(dir)
675 680 { {
681 centry->builtin_dir = 1;
676 682 centry->top_tree_stats = cfg.top_tree_stats; centry->top_tree_stats = cfg.top_tree_stats;
677 683 centry->max_tree_depth = cfg.max_tree_depth; centry->max_tree_depth = cfg.max_tree_depth;
684
678 685 fp = qv_view_dir(centry->path, centry->max_lines); fp = qv_view_dir(centry->path, centry->max_lines);
679 686 } }
680 687 else else
File tests/misc/vcache.c changed (mode: 100644) (index 51b68b5cd..fc681d841)
7 7
8 8 #include <test-utils.h> #include <test-utils.h>
9 9
10 #include "../../src/cfg/config.h"
11 #include "../../src/engine/var.h"
12 #include "../../src/engine/variables.h"
10 13 #include "../../src/lua/vlua.h" #include "../../src/lua/vlua.h"
11 14 #include "../../src/ui/quickview.h" #include "../../src/ui/quickview.h"
12 15 #include "../../src/ui/ui.h" #include "../../src/ui/ui.h"
 
... ... TEST(vcache_check_reports_correct_status)
390 393 assert_false(vcache_check(&is_previewed)); assert_false(vcache_check(&is_previewed));
391 394 } }
392 395
396 TEST(dir_preview_options_do_not_break_caching)
397 {
398 init_variables();
399 var_t var = var_from_int(0);
400 setvar("v:jobcount", var);
401 var_free(var);
402
403 cfg.top_tree_stats = 1;
404 cfg.max_tree_depth = 3;
405
406 strlist_t lines = vcache_lookup(TEST_DATA_PATH "/read/", "echo dir", MF_NONE,
407 VK_TEXTUAL, /*max_lines=*/10, VC_ASYNC, &error);
408 assert_string_equal(NULL, error);
409 assert_int_equal(1, lines.nitems);
410 assert_string_equal("[...]", lines.items[0]);
411
412 assert_true(wait_for_cache());
413 if(bg_jobs != NULL)
414 {
415 wait_for_job(bg_jobs);
416 }
417 (void)vcache_check(&is_previewed);
418
419 lines = vcache_lookup(TEST_DATA_PATH "/read/", "echo dir", MF_NONE,
420 VK_TEXTUAL, /*max_lines=*/10, VC_ASYNC, &error);
421 assert_string_equal(NULL, error);
422 assert_int_equal(1, lines.nitems);
423 assert_string_starts_with("dir", lines.items[0]);
424
425 vcache_finish();
426 cfg.top_tree_stats = 0;
427 cfg.max_tree_depth = 0;
428 clear_variables();
429 }
430
393 431 TEST(kill_all_async_previews_on_exit, IF(not_windows)) TEST(kill_all_async_previews_on_exit, IF(not_windows))
394 432 { {
395 433 strlist_t lines = vcache_lookup(TEST_DATA_PATH "/read/two-lines", "sleep 100", strlist_t lines = vcache_lookup(TEST_DATA_PATH "/read/two-lines", "sleep 100",
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vifm

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vifm

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master