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 2b226c3e1142001f5f61ce10e97fc97ea26914f8

Fix :yank/:delete not handling optional count arg
A regression in v0.11-beta.

Thanks to CaptainFantastic.
Author: xaizek
Author date (UTC): 2026-03-21 12:59
Committer name: xaizek
Committer date (UTC): 2026-03-21 13:54
Parent(s): b1d2684773f636e2b37b3e231cf72098da6c8f71
Signing key: 99DC5E4DB05F6BE2
Tree: 90adc01197cc1ecfec4accaaac02cd460f714690
File Lines added Lines deleted
ChangeLog 3 0
src/cmd_handlers.c 2 2
src/filelist.c 22 0
src/filelist.h 3 0
src/flist_sel.c 0 22
src/flist_sel.h 0 4
tests/commands/misc_fops.c 35 0
tests/misc/diff.c 12 2
File ChangeLog changed (mode: 100644) (index 0e2b0109a..75ce291d1)
222 222 Fixed :open not entering symbolic links to directories if there is no Fixed :open not entering symbolic links to directories if there is no
223 223 "vifm" executable in $PATH. Thanks to CaptainFantastic. "vifm" executable in $PATH. Thanks to CaptainFantastic.
224 224
225 Fixed :yank and :delete not handling optional count parameter correctly (a
226 regression since v0.11-beta). Thanks to CaptainFantastic.
227
225 228 0.14-beta to 0.14 (2025-02-08) 0.14-beta to 0.14 (2025-02-08)
226 229
227 230 Improved documentation on zh/zl menu keys a bit. Improved documentation on zh/zl menu keys a bit.
File src/cmd_handlers.c changed (mode: 100644) (index aa0a3ff42..fa24cadc2)
... ... get_reg_and_count(const cmd_info_t *cmd_info, int *reg)
5900 5900 ui_sb_err("Count argument can't be zero"); ui_sb_err("Count argument can't be zero");
5901 5901 return CMDS_ERR_CUSTOM; return CMDS_ERR_CUSTOM;
5902 5902 } }
5903 flist_sel_count(curr_view, cmd_info->end, count);
5903 flist_mark_count(curr_view, cmd_info->end, count);
5904 5904 } }
5905 5905 else if(cmd_info->argc == 1) else if(cmd_info->argc == 1)
5906 5906 { {
 
... ... get_reg_and_count(const cmd_info_t *cmd_info, int *reg)
5912 5912 ui_sb_err("Count argument can't be zero"); ui_sb_err("Count argument can't be zero");
5913 5913 return CMDS_ERR_CUSTOM; return CMDS_ERR_CUSTOM;
5914 5914 } }
5915 flist_sel_count(curr_view, cmd_info->end, count);
5915 flist_mark_count(curr_view, cmd_info->end, count);
5916 5916 } }
5917 5917 else else
5918 5918 { {
File src/filelist.c changed (mode: 100644) (index 11b3024ef..2b7c28c06)
... ... flist_set_marking(view_t *view, int prefer_current)
3710 3710 } }
3711 3711 } }
3712 3712
3713 void
3714 flist_mark_count(view_t *view, int at, int count)
3715 {
3716 /* Use current position if none given. */
3717 if(at < 0)
3718 {
3719 at = view->list_pos;
3720 }
3721
3722 clear_marking(view);
3723
3724 while(count-- > 0 && at < view->list_rows)
3725 {
3726 if(fentry_is_valid(&view->dir_entry[at]))
3727 {
3728 view->dir_entry[at].marked = 1;
3729 ++view->selected_files;
3730 }
3731 ++at;
3732 }
3733 }
3734
3713 3735 void void
3714 3736 mark_files_at(view_t *view, int count, const int indexes[]) mark_files_at(view_t *view, int count, const int indexes[])
3715 3737 { {
File src/filelist.h changed (mode: 100644) (index 725d8cafc..b19b1a04b)
... ... void check_marking(view_t *view, int count, const int indexes[]);
229 229 * marked. Non-zero prefer_current parameter makes marking selection contingent * marked. Non-zero prefer_current parameter makes marking selection contingent
230 230 * on current file being selected. */ * on current file being selected. */
231 231 void flist_set_marking(view_t *view, int prefer_current); void flist_set_marking(view_t *view, int prefer_current);
232 /* Marks up to count elements starting at position at (or the current cursor
233 * position, if at is negative). */
234 void flist_mark_count(struct view_t *view, int at, int count);
232 235 /* Unmarks all entries of the view. */ /* Unmarks all entries of the view. */
233 236 void clear_marking(view_t *view); void clear_marking(view_t *view);
234 237 /* Marks files at positions specified in the indexes array of size count. */ /* Marks files at positions specified in the indexes array of size count. */
File src/flist_sel.c changed (mode: 100644) (index 333088a6a..07de2104a)
... ... flist_sel_by_pattern(view_t *view, const char pattern[], int erase_old,
403 403 return 0; return 0;
404 404 } }
405 405
406 void
407 flist_sel_count(view_t *view, int at, int count)
408 {
409 /* Use current position if none given. */
410 if(at < 0)
411 {
412 at = view->list_pos;
413 }
414
415 flist_sel_stash(view);
416
417 while(count-- > 0 && at < view->list_rows)
418 {
419 if(fentry_is_valid(&view->dir_entry[at]))
420 {
421 view->dir_entry[at].selected = 1;
422 ++view->selected_files;
423 }
424 ++at;
425 }
426 }
427
428 406 int int
429 407 flist_sel_range(view_t *view, int begin, int end, int mark_current) flist_sel_range(view_t *view, int begin, int end, int mark_current)
430 408 { {
File src/flist_sel.h changed (mode: 100644) (index f4f1eaaa9..488596dff)
... ... int flist_sel_by_filter(struct view_t *view, const char cmd[], int erase_old,
71 71 int flist_sel_by_pattern(struct view_t *view, const char pattern[], int flist_sel_by_pattern(struct view_t *view, const char pattern[],
72 72 int erase_old, int select); int erase_old, int select);
73 73
74 /* Selects up to count elements starting at position at (or current cursor
75 * position, if at is negative). */
76 void flist_sel_count(struct view_t *view, int at, int count);
77
78 74 /* Marks entries in the range [begin; end]. If begin isn't given (negative), /* Marks entries in the range [begin; end]. If begin isn't given (negative),
79 75 * end is marked. Otherwise, if end is negative and mark_current is non-zero, * end is marked. Otherwise, if end is negative and mark_current is non-zero,
80 76 * current item is marked. Returns non-zero if marking was set up, otherwise * current item is marked. Returns non-zero if marking was set up, otherwise
File tests/commands/misc_fops.c changed (mode: 100644) (index 763f13714..0dc15e04c)
... ... TEST(zero_count_is_rejected)
293 293 assert_string_equal(expected, ui_sb_last()); assert_string_equal(expected, ui_sb_last());
294 294 } }
295 295
296 TEST(non_zero_count_is_handled)
297 {
298 regs_init();
299
300 make_abs_path(lwin.curr_dir, sizeof(lwin.curr_dir), TEST_DATA_PATH,
301 "existing-files", cwd);
302 populate_dir_list(&lwin, /*reload=*/0);
303
304 const reg_t *reg = regs_find('a');
305
306 /* No range, register, count. */
307
308 ui_sb_msg("");
309 assert_failure(cmds_dispatch1("yank a 2", &lwin, CIT_COMMAND));
310 assert_string_equal("2 items yanked", ui_sb_last());
311
312 reg = regs_find('a');
313 assert_int_equal(2, reg->nfiles);
314 assert_string_ends_with("/a", reg->files[0]);
315 assert_string_ends_with("/b", reg->files[1]);
316
317 /* Range, no register, count. */
318
319 ui_sb_msg("");
320 assert_failure(cmds_dispatch1("2yank 2", &lwin, CIT_COMMAND));
321 assert_string_equal("2 items yanked", ui_sb_last());
322
323 reg = regs_find(DEFAULT_REG_NAME);
324 assert_int_equal(2, reg->nfiles);
325 assert_string_ends_with("/b", reg->files[0]);
326 assert_string_ends_with("/c", reg->files[1]);
327
328 regs_reset();
329 }
330
296 331 static OpsResult static OpsResult
297 332 exec_func(OPS op, void *data, const char *src, const char *dst) exec_func(OPS op, void *data, const char *src, const char *dst)
298 333 { {
File tests/misc/diff.c changed (mode: 100644) (index 21b1d3012..cd1e35bc8)
19 19 #include "../../src/utils/fs.h" #include "../../src/utils/fs.h"
20 20 #include "../../src/compare.h" #include "../../src/compare.h"
21 21 #include "../../src/event_loop.h" #include "../../src/event_loop.h"
22 #include "../../src/flist_sel.h"
22 #include "../../src/filelist.h"
23 23 #include "../../src/ops.h" #include "../../src/ops.h"
24 24 #include "../../src/status.h" #include "../../src/status.h"
25 25
 
... ... TEST(can_move_selection)
191 191 strcpy(rwin.curr_dir, SANDBOX_PATH); strcpy(rwin.curr_dir, SANDBOX_PATH);
192 192
193 193 (void)compare_two_panes(CT_CONTENTS, LT_ALL, CF_GROUP_PATHS | CF_SHOW); (void)compare_two_panes(CT_CONTENTS, LT_ALL, CF_GROUP_PATHS | CF_SHOW);
194 flist_sel_count(&lwin, 0, lwin.list_rows);
194
195 int i;
196 for(i = 0; i < lwin.list_rows; ++i)
197 {
198 if(fentry_is_valid(&lwin.dir_entry[i]))
199 {
200 lwin.dir_entry[i].selected = 1;
201 ++lwin.selected_files;
202 }
203 }
204
195 205 (void)compare_move(&lwin, &rwin); (void)compare_move(&lwin, &rwin);
196 206 assert_int_equal(0, lwin.selected_files); assert_int_equal(0, lwin.selected_files);
197 207
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