7 个版本

0.9.14 2024年1月7日
0.9.12 2023年2月27日
0.9.9 2023年1月1日
0.9.8 2022年12月31日

#1081 in 命令行工具

Download history 18/week @ 2024-04-01 3/week @ 2024-04-22 8/week @ 2024-05-20 9/week @ 2024-05-27 9/week @ 2024-06-03 2/week @ 2024-06-10

87 每月下载量
fm-tui 中使用

MIT 许可证

420KB
10K SLoC

Rust 7K SLoC // 0.0% comments Vim Script 1K SLoC // 0.0% comments Python 848 SLoC // 0.1% comments BASH 373 SLoC // 0.1% comments Zsh 333 SLoC // 0.2% comments Shell 100 SLoC // 0.1% comments

Crates.io Build & Test

生命短暂,使用 skim!

我们生命中有一半的时间都在导航:文件、行、命令……你需要 skim!它是一个节省时间的通用模糊查找器。

skim demo

skim 提供一个可执行文件:sk。基本上,你可以在任何想使用 grep 的地方尝试使用 sk

目录

安装

skim 项目包含几个组件

  1. sk 可执行文件 -- 核心。
  2. sk-tmux -- 在 tmux 窗格中启动 sk 的脚本。
  3. Vim/Nvim 插件 -- 在 Vim/Nvim 中调用 sk。有关更多 Vim 支持,请查看 skim.vim

包管理器

分发 包管理器 命令
macOS Homebrew brewinstall sk
macOS MacPorts sudoport install skim
Fedora dnf dnf install skim
Alpine apk apk add skim
Arch pacman pacman -S skim

作为 Vim 插件安装

通过 vim-plug (推荐)

Plug 'lotabout/skim', { 'dir': '~/.skim', 'do': './install' }

硬核

以下任何一项都适用

  • 使用 Git
    $ git clone --depth 1 [email protected]:lotabout/skim.git ~/.skim
    $ ~/.skim/install
    
  • 使用二进制文件:直接 下载 sk 可执行文件
  • crates.io 安装: cargo install skim
  • 手动构建
    $ git clone --depth 1 [email protected]:lotabout/skim.git ~/.skim
    $ cd ~/.skim
    $ cargo install
    $ cargo build --release
    $ # put the resulting `target/release/sk` executable on your PATH.
    

用法

skim 可以用作通用过滤器(如 grep)或作为调用命令的交互式界面。

作为过滤器

尝试以下命令

# directly invoke skim
sk

# or pipe some input to it: (press TAB key select multiple items with -m enabled)
vim $(find . -name "*.rs" | sk -m)

上述命令将允许您选择扩展名为 ".rs" 的文件,并在 Vim 中打开您选择的文件。

作为交互式界面

skim 可以动态调用其他命令。通常,您会希望将其与 grepackagrg 集成,以在项目目录中搜索内容

# works with grep
sk --ansi -i -c 'grep -rI --color=always --line-number "{}" .'
# works with ack
sk --ansi -i -c 'ack --color "{}"'
# works with ag
sk --ansi -i -c 'ag --color "{}"'
# works with rg
sk --ansi -i -c 'rg --color=always --line-number "{}"'

interactive mode demo

快捷键

一些常用的键绑定

操作
Enter 接受(选择当前项并退出)
ESC/Ctrl-G 中止
Ctrl-P/Up 向上移动光标
Ctrl-N/Down 向下移动光标
TAB 切换选择并向下移动(与 -m 一起使用)
Shift-TAB 切换选择并向上移动(与 -m 一起使用)

要查看键绑定列表的完整列表,请查看 手册页面(《man sk》)。

搜索语法

skim 采用了 fzf 的语法来匹配项目

标记 匹配类型 描述
text 模糊匹配 匹配 text 的项目
^music 前缀精确匹配 music 开头的项目
.mp3$ 后缀精确匹配 .mp3 结尾的项目
'wild' 精确匹配(引用) 包含 wild 的项目
!fire 非精确匹配 不包含 fire 的项目
!.mp3$ 非后缀精确匹配 不以 .mp3 结尾的项目

skim 还支持标记的组合。

  • 空白表示 AND。对于 src main 这个词,skim 将搜索同时匹配 srcmain 的项目。
  • | 表示 OR(注意 | 周围有空格)。对于 .md$ | .markdown$ 这个词,skim 将搜索以 .md.markdown 结尾的项目。
  • OR 的优先级更高。因此,readme .md$ | .markdown$ 将分组为 readme AND (.md$ OR .markdown$)

如果您想使用正则表达式,skim 提供了 regex 模式

sk --regex

您可以通过按 Ctrl-R(旋转模式)动态切换到 regex 模式。

退出代码

退出代码 含义
0 正常退出
1 未找到匹配项
130 通过 Ctrl-C/Ctrl-G/ESC 等... 中止

自定义

这里的文档仅是预览,请查看手册页面(《man sk》)以获取完整选项列表。

键映射

使用逗号分隔的配对指定绑定(不允许有空格),例如

sk --bind 'alt-a:select-all,alt-d:deselect-all'

此外,使用 + 来连接操作,例如 execute-silent(echo {} | pbcopy)+abort

请参阅手册页的 键盘绑定 部分以获取详细信息。

排序标准

有五个排序键用于结果: score, index, begin, end, length,您可以通过 sk --tiebreak score, index,-begin 或您想要的任何其他顺序来指定记录的排序方式。

颜色方案

你很可能比我更擅长艺术。幸运的是,你不会困在默认的颜色中,skim 支持自定义颜色方案。

--color=[BASE_SCHEME][,COLOR:ANSI]

颜色配置从基本颜色方案名称开始,后跟自定义颜色映射。例如

sk --color=current_bg:24
sk --color=light,fg:232,bg:255,current_bg:116,info:27

请参阅手册页中的 --color 选项以获取详细信息。

杂项

  • --ansi:解析数据源的 ANSI 颜色代码(例如,\e[32mABC
  • --regex:将查询用作正则表达式来匹配数据源

高级主题

交互模式

通过“交互模式”,您可以动态调用命令。尝试一下

sk --ansi -i -c 'rg --color=always --line-number "{}"'

它是如何工作的?

skim's interactive mode

  • Skim 可以接受两种类型的源:命令输出或管道输入
  • Skim 有两种类型的提示:查询提示用于指定查询模式,命令提示用于指定命令的“参数”
  • -c 用于指定要执行的命令,默认为 SKIM_DEFAULT_COMMAND
  • - 用于在启动时告诉 skim 打开命令提示符,默认显示 c>

如果您想进一步缩小由命令返回的结果,请按 Ctrl-Q 切换到交互模式。

执行外部程序

您可以设置键绑定,以便在不离开 skim 的情况下启动外部进程(executeexecute-silent)。

# Press F1 to open the file with less without leaving skim
# Press CTRL-Y to copy the line to clipboard and aborts skim (requires pbcopy)
sk --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort'

预览窗口

这是 fzf 的一个很棒的功能,Skim 借鉴了它。例如,我们使用 'ag' 来查找匹配的行,一旦我们缩小到目标行,我们最终想要通过检查行周围的上下文来决定选择哪些行。 grepag 有一个选项 --context,Skim 可以通过预览窗口做得更好。例如

sk --ansi -i -c 'ag --color "{}"' --preview "preview.sh {}"

(注意 preview.sh 是一个脚本,用于根据文件名:行:列打印上下文)你会有这样的东西

preview demo

它是如何工作的?

如果预览命令由 --preview 选项提供,Skim 将将 {} 替换为当前高亮显示的行(用单引号包围),调用命令获取输出,并在预览窗口中打印输出。

有时候你不需要整行来调用命令。在这种情况下,你可以使用 {}{1..}{..3}{1..5} 来选择字段。语法在“字段支持”部分中解释。

最后,你可能想配置预览窗口的位置,使用 --preview-window

  • --preview-window up:30% 将窗口置于上方,高度为 skim 总高度的 30%。
  • --preview-window left:10:wrap,指定 wrap 允许预览窗口包裹预览命令的输出。
  • --preview-window wrap:hidden 在启动时隐藏预览窗口,之后可以通过操作 toggle-preview 显示。

字段支持

通常只有插件用户需要理解这一点。

例如,你有以下格式的数据源

<filename>:<line number>:<column number>

然而,你希望在输入查询时仅搜索 <filename>。这意味着当你输入 21 时,你希望找到一个包含 <filename>21,但不匹配行号或列号。

你可以使用 sk --delimiter ':' --nth 1 来实现这一点。

你还可以使用 --with-nth 来重新排列字段的顺序。

范围语法

  • <num> -- 指定第 num 个字段,从 1 开始。
  • start.. -- 从第 start 个字段开始,直到最后一个字段。
  • ..end -- 从第 end 个字段开始,直到第 end 个字段,包括 end
  • start..end -- 从第 start 个字段开始,直到第 end 个字段,包括 end

作为库使用

Skim 可以在 Rust 的 crates 中作为库使用。

首先,将 skim 添加到你的 Cargo.toml

[dependencies]
skim = "*"

然后尝试运行这个简单的示例

extern crate skim;
use skim::prelude::*;
use std::io::Cursor;

pub fn main() {
    let options = SkimOptionsBuilder::default()
        .height(Some("50%"))
        .multi(true)
        .build()
        .unwrap();

    let input = "aaaaa\nbbbb\nccc".to_string();

    // `SkimItemReader` is a helper to turn any `BufRead` into a stream of `SkimItem`
    // `SkimItem` was implemented for `AsRef<str>` by default
    let item_reader = SkimItemReader::default();
    let items = item_reader.of_bufread(Cursor::new(input));

    // `run_with` would read and show items from the stream
    let selected_items = Skim::run_with(&options, Some(items))
        .map(|out| out.selected_items)
        .unwrap_or_else(|| Vec::new());

    for item in selected_items.iter() {
        print!("{}{}", item.output(), "\n");
    }
}

给定一个 Option<SkimItemReceiver>,skim 将相应地读取项目,执行其工作,并带回到用户选择,包括所选项目、查询等。注意

  • SkimItemReceivercrossbeam::channel::Receiver<Arc<dyn SkimItem>>
  • 如果没有,它将调用给定的命令并从命令输出读取项目
  • 否则,它将从(crossbeam)通道中读取项目。

特性 SkimItem 提供了自定义如何显示、比较和预览一行的方式。它默认实现了对 AsRef<str>

此外,SkimItemReader 是一个辅助工具,可以将 BufRead 转换为 SkimItemReceiver(我们可以轻松地将 File 转换为 BufRead)。这样你就可以轻松地处理字符串或文件。

更多示例请参阅 examples/ 目录。

常见问题解答

如何忽略文件?

Skim 使用 find . 命令来获取过滤文件列表。你可以通过设置环境变量 SKIM_DEFAULT_COMMAND 来覆盖它。例如

$ SKIM_DEFAULT_COMMAND="fd --type f || git ls-tree -r --name-only HEAD || rg --files || find ."
$ sk

如果你希望将其设置为默认值,可以将其放入 .bashrc.zshrc

一些文件在 Vim 插件中没有显示

如果你使用 Vim 插件并执行 :SK 命令,你可能会发现一些文件没有显示。

#3 中所述,在 Vim 插件中,SKIM_DEFAULT_COMMAND 默认设置为命令

let $SKIM_DEFAULT_COMMAND = "git ls-tree -r --name-only HEAD || rg --files || ag -l -g \"\" || find ."

这意味着,git 未能识别的文件将不会显示。你可以通过 let $SKIM_DEFAULT_COMMAND = '' 覆盖默认设置,或者自行查找缺失的文件。

与 fzf 的区别

fzf 是一个用 Go 编写的命令行模糊查找器,skim 尝试在 Rust 中实现一个新版本!

此项目从头开始编写。一些实现决策与 fzf 不同。例如

  1. skim 是一个二进制文件以及库,而 fzf 只是一个二进制文件。
  2. skim 有一个交互模式。
  3. skim 支持预选择
  4. 模糊搜索算法不同。
  5. 显示匹配项的 UI。 fzf 只会显示匹配的范围,而 skim 会显示每个匹配的字符。(fzf 现在有这个功能了)
  6. skim 的范围语法是 Git 风格的:现在它与 fzf 相同。

如何贡献

如果你遇到任何错误或有任何想法,请创建新问题。拉取请求热烈欢迎。

qkzk 的注释

这是一个简单的分支,我在其中将一些属性公开,以便在另一个项目中使用 skim 作为内部程序,我在该项目中需要一个模糊查找器。

100% 的工作由原始作者完成,我对此不承担任何责任。

依赖项

~11–20MB
~275K SLoC