求助:ivy 标记多个 candidate 后调用 action

使用 counsel-file-jump 可以遍历搜索文件夹下的文件,例如:


/home/scriptdevil/test/
|-- doc
|   |-- boo
|   |-- build-instructions.md
|   `-- running-tests.md
|-- include
|   |-- bar.h
|   `-- foo.h
|-- README
`-- src
    |-- bar.c
    `-- foo.c

在 test 调用 counsel-file-jump 会遍历所有子文件夹 doc、include、src 下的文件。

为 counsel-file-jump 添加 action:dired-do-copy


(ivy-add-actions
     'counsel-file-jump
     '(("C" dired-do-copy "@ Copy to")))

使用需要

在遍历出来的文件候选项,调用 ivy-mark 标记多个 candidate 后,调用 ivy-action:dired-do-copy。

我的期待

希望就像在 dired-mode 下在 dired-mark 多个 candidate 后,使用 dired-do-copy ,这个函数会询问需要复制到的目的文件夹,选定目的文件夹并确认后,就会完成复制。

实际情况

ivy-action:dired-do-copy 会多次被调用,依次传入 ivy-mark candidate 为参数到 action,导致需要多次为 dired-do-copy 函数选定目的文件夹。使用起来失去了 action 的便利宗旨。

问题

如何解决 ivy-action 这样使用情景,使得使用习惯保持和 dired-mode 一致?

你直接打开 dired 标记不好吗? 为什么要在 ivy 里面选?

1 个赞

因为 dired 只能 mark 一个文件夹下的文件,如果需要整理的文件散落在多个,有深度的子文件夹,需要频繁切换到各个子文件夹进行操作,比较麻烦。

dired 可以显示子文件夹的,C-u C-x d 可以给 dired 传参数,加个 R 就好,或者在 dired 里面也可以用 C-u s 来设置参数

https://www.gnu.org/software/emacs/manual/html_node/emacs/Subdirectories-in-Dired.html#:~:text=The%20simplest%20way,at%20all%20levels.

:grinning:

谢谢,为命令 ls 添加参数 R 后,可以一定程度满足需求。

稍微看了一下 ivy,它的 :action 是一个一个 candidate 调用的。:multi-action 是所有 candidates 一起调用的:

(ivy-read "select: " '("a" "b" "c" "d" "e")
            :action
            ;; 直接回车不标记
            (lambda (x)
              (message "==> x: %S" x))
            :multi-action
            ;; 标记了任意项
            (lambda (xs)
              (message "==> xs: %S" xs)))

不知 ivy-add-actions 添加的 action 是哪一种,如果是 :action,其实也可以通过变量 ivy-marked-candidates 取得所有标记的项:

(ivy-read "select: " '("a" "b" "c" "d" "e")
            :action
            (lambda (x)
              (when (equal (concat ivy-mark-prefix x)
                           (car ivy-marked-candidates))
                (message "==> marked candidates: %S" ivy-marked-candidates))
              (message "==> x: %S" x)))

解决这个问题无非是要把目录「拉直」。 要么用 subtree 展开,要么用 fd 。楼上提供的 ls -R 也可以实现,不过 dired 会用 subdir 的形式展示,多余要素很多。

但不管怎么讲,用 minibuffer 来选无疑最慢也最累。

如果是 Git项目,目录下还有 .git 文件夹,加R参数,会把 .git 文件夹下的子目录也展开。 这个有办法过滤掉吗?

我是用 dired-omit-mode,需要 (require 'dired-x) , 可以通过设置变量 dired-omit-files 来用正则过滤文件

(setq dired-omit-files "\\`[.]?#\\|\\`[.][.]?\\'\\|^.git$")
1 个赞