backup: 2025-06-0

This commit is contained in:
Marsway 2025-06-09 17:41:55 +08:00
parent 43a7867f58
commit 396488e38c
23 changed files with 4649 additions and 4 deletions

42
.bin/z.lua/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
# Compiled Lua sources
luac.out
# luarocks build files
*.src.rock
*.zip
*.tar.gz
# Object files
*.o
*.os
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
*.def
*.exp
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
/.vscode/*

21
.bin/z.lua/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Linwei
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

470
.bin/z.lua/README.cn.md Normal file
View File

@ -0,0 +1,470 @@
# z.lua
快速路径切换工具(类似 z.sh / autojump / fasd兼容 Windows 和所有 Posix Shell 以及 Fish Shell同时包含了众多改进。
## Description
z.lua 是一个快速路径切换工具,它会跟踪你在 shell 下访问过的路径,通过一套称为 Frecent 的机制(源自 FireFox经过一段简短的学习之后z.lua 会帮你跳转到所有匹配正则关键字的路径里 Frecent 值最高的那条路径去。
正则将按顺序进行匹配,"z foo bar" 可以匹配到 /foo/bar ,但是不能匹配 /bar/foo。
## Features
- 性能比 **z.sh** 快三倍,比 **fasd** / **autojump** 快十倍以上。
- 支持 Posix Shellbash, zsh, dash, sh, ash, busybox 等等。
- 支持 Fish ShellPower Shell 和 Windows cmd。
- 使用增强匹配算法,更准确的带你去到你想去的地方。
- 低占用,能够仅在当前路径改变时才更新数据库(将 `$_ZL_ADD_ONCE` 设成 1
- 交互选择模式,如果有多个匹配结果的话,跳转前允许你进行选择。
- 集成 fzf (可选),可以用来做可视化选择或者参数补全。
- 快速跳转到父目录,或者项目根目录,代替反复 “cd ../../.." 。
- 兼容 lua 5.1, 5.2 和 5.3 以上版本。
- 自包含且无额外依赖,单个 `z.lua` 文件完成所有工作。
## Examples
```bash
z foo # 跳转到包含 foo 并且权重Frecent最高的路径
z foo bar # 跳转到同时包含 foo 和 bar 并且权重最高的路径
z -r foo # 跳转到包含 foo 并且访问次数最高的路径
z -t foo # 跳转到包含 foo 并且最近访问过的路径
z -l foo # 不跳转,只是列出所有匹配 foo 的路径
z -c foo # 跳转到包含 foo 并且是当前路径的子路径的权重最高的路径
z -e foo # 不跳转,只是打印出匹配 foo 并且权重最高的路径
z -i foo # 进入交互式选择模式,让你自己挑选去哪里(多个结果的话)
z -I foo # 进入交互式选择模式,但是使用 fzf 来选择
z -b foo # 跳转到父目录中名称以 foo 开头的那一级
```
## Install
- Posix ShellsBash、zsh、dash、sh 或 BusyBox 等):
在你的 `.bashrc`, `.zshrc` 或者 `.profile` 文件中按 shell 类型添加对应语句:
eval "$(lua /path/to/z.lua --init bash)" # BASH 初始化
eval "$(lua /path/to/z.lua --init zsh)" # ZSH 初始化
eval "$(lua /path/to/z.lua --init posix)" # Posix shell 初始化
用下面参数初始化会进入“增强匹配模式”:
eval "$(lua /path/to/z.lua --init bash once enhanced)" # BASH 初始化
eval "$(lua /path/to/z.lua --init zsh once enhanced)" # ZSH 初始化
eval "$(lua /path/to/z.lua --init posix once enhanced)" # Posix shell 初始化
同时 zsh 支持 antigen/oh-my-zsh 等包管理器,可以用下面路径:
skywind3000/z.lua
进行安装,比如 antigen 的话,在 `.zshrc` 中加入:
antigen bundle skywind3000/z.lua
就可以了(主要要放在 antigen apply 语句之前)。
**注意**:使用 WSL-1 的用户,需要安装 `lua-filesystem` 包:
sudo apt-get install lua-filesystem
这是由于 wsl-1 的 [bug](https://github.com/microsoft/WSL/issues/5505) 引起的,使用 lua-filesystem 可以避免该问题。
- Fish Shell:
新建 `~/.config/fish/conf.d/z.fish` 文件,并包含如下代码:
source (lua /path/to/z.lua --init fish | psub)
Fish version `2.4.0` 或者以上版本都支持,还有一种初始化方法:
lua /path/to/z.lua --init fish > ~/.config/fish/conf.d/z.fish
但是第二种方法需要记得在 z.lua 位置改变或者 lua 版本升级后需要重新生成。
- Nushell:
`env.nu` 中加入如下代码:
lua /path/to/z.lua --init nushell | save -f ~/.cache/zlua.nu
然后在 `config.nu` 中加入如下代码:
source ~/.cache/zlua.nu
alias z = _zlua
- Power Shell:
在你 Power Shell 的配置文件 `profile.ps1` 中放入下面语句:
Invoke-Expression (& { (lua /path/to/z.lua --init powershell) -join "`n" })
- Windows cmd (with clink):
- 将 z.lua 和 z.cmd 拷贝到 clink 的安装目录。
- 将 clink 的安装目录添加到 `%PATH%` (z.cmd 可以被任意位置调用到)。
- 保证 lua 命令在你的 `%PATH%` 环境变量中。
- Windows cmder:
- 将 z.lua 和 z.cmd 拷贝到 cmder/vendor 目录中。
- 将 cmder/vendor 添加到环境变量 `%PATH%` 里面。
- 保证 lua 命令在你的 `%PATH%` 环境变量中。
## Options
- 设置 `$_ZL_CMD` 来改变命令名称 (默认为 z)。
- 设置 `$_ZL_DATA` 来改变数据文件 (default ~/.zlua)。
- 设置 `$_ZL_NO_PROMPT_COMMAND` 为 1 来跳过钩子函数初始化(方便自己处理)。
- 设置 `$_ZL_EXCLUDE_DIRS` 逗号分隔的路径列表,列表内的路径不会被收集。
- 设置 `$_ZL_ADD_ONCE` 为 '1' 时,仅在当前路径 `$PWD` 改变时才更新数据库。
- 设置 `$_ZL_MAXAGE` 来确定一个数据老化的阈值 (默认为 5000)。
- 设置 `$_ZL_CD` 用来指定你想用的 cd 命令,比如有人用 cd_func 。
- 设置 `$_ZL_ECHO` 为 1 可以在跳转后显示目标路径名称。
- 设置 `$_ZL_MATCH_MODE` 为 1 可以打开 “增强匹配模式”。
- 设置 `$_ZL_HYPHEN` 为 1 可以允许关键字中包含横线 (横线默认是 lua 正则关键字,要转写成 `%-`)。
## Aging
`z.lua` 在数据库中为每条路径维护着一个称为 rank 的字段,用于记录每条历史路径的访问次数,每次访问某路径,该路径对应 rank 字段的值就会增加 1。随着被添加的路径越来越多`z.lua` 使用一种称为 “数据老化” 的方式来控制数据的总量。即,每次更新数据库后,会将所有路径的 rank 值加起来,如果这个值大于 5000 `$_ZL_MAXAGE`),所有路径的 rank 值都会乘以 0.9,然后剔除所有 rank 小于 1 的记录。
## Frecency
Frecency 是一个由 'recent' 和 'frequency' 组成的合成词,这个术语由 Mozilla 发明,用于同时兼顾访问的频率和上一次访问到现在的时间差(是否最近访问)两种情况。
对于 z.lua一条路径如果访问次数过低它的 rank 值就会比较低但是如果它最近被访问过那么它将迅速获得一个比其他曾经频繁访问但是最近没有访问过的路径更高的权重。Frecent 并不记录在数据库中,是运行的时候即时计算出来的。
## 默认匹配算法
默认情况下 z.lua 使用和 z.sh 类似的匹配算法,成为默认匹配法。给定路径会按顺序匹配各个正则表达式。
- cd 到一个包含 foo 的路径:
z foo
- cd 到一个以 foo 结尾的路径:
z foo$
- 使用多个参数进行跳转:
假设路径历史数据库(~/.zlua中有两条记录
10 /home/user/work/inbox
30 /home/user/mail/inbox
`"z in"`将会跳转到 `/home/user/mail/inbox` 因为它有更高的权重,同时你可以传递更多参数给 z.lua 来更加精确的指明,如 `"z w in"` 则会让你跳到 `/home/user/work/inbox`
## 增强匹配算法
你可以通过设置环境变量来启用增强匹配模式:
export _ZL_MATCH_MODE=1
或者使用下面语句:
eval "$(lua /path/to/z.lua --init bash enhanced)"
进行初始化,他们是等效的,记得把上面的 bash 可以根据你的 shell 改为 `zsh` 或者 `posix`
对于一个给定的正则关键字序列(即 z 命令后面的参数),只有同时满足两个条件才算匹配成功:
1. 正则关键字将按顺序进行匹配(这条和默认匹配法相同)。
2. 最后一个关键字可以和路径名的最后一段相匹配。
如果两条规则同时启用找不到任何结果,那么将会退回到只用规则 1 进行筛选,这两条规则是参考 fasd 引入的。
- 匹配路径名的最后一段:
假设数据库内容为:
10 /home/user/workspace
20 /home/user/workspace/project1
30 /home/user/workspace/project2
40 /home/user/workspace/project3
在增强模式下使用 `"z wo"` 的话,只有 `/home/user/workspace` 满足匹配,因为按照第二条规则,这是唯一一条最有一段名称匹配 `wo` 的路径。
因为最后一级目录名称总是最容易记住的,所以给到它比较高的优先级。在默认匹配算法中,你同样可以用 `"z space$"` 来达到相同的目的,但是 `"z wo"` 可以打更少的字。
小技巧:
- 如果你在增强匹配算法下,想让最后一个关键字不当匹配最后一段路径名,还可以像默认匹配算法中一样匹配路径的其他部分的话,你可以在最后加一个独立的 '$' 参数,比如:`"z wo $"`
- 如果你在增强匹配算法下,想让最后一个关键字匹配最后一段路径名以前的部分,那么可以增加一个斜杆参数,比如:`"z wo /"`。
- 如果没法匹配,同时又存在一条路径名和关键字相同,那么 cd 过去:
有时候如果你输入:
z foo
但是数据库里又没有任何匹配 foo 的记录,然后却存在一个可以在当前位置访问的目录,刚好名字是 "foo",那么 "`z foo`" 的效果将会和下面的命令效果相同:
cd foo
因此,在增强匹配算法中,你总可以像 cd 命令一样使用 z 命令,而不必当心目标路径是否被记录过。
- 忽略当前路径:
如果你使用 `z xxx` 但是当前路径恰好是最佳匹配结果,那么 z.lua 会使用次优结果进行跳转。假设有如下数据:
10 /Users/Great_Wall/.rbenv/versions/2.4.1/lib/ruby/gems
20 /Library/Ruby/Gems/2.0.0/gems
默认情况下,当我使用 `z gems` 时,我会被带到 `/Library/Ruby/Gems/2.0.0/gems`,因为它有更高权重,但是可能并不是我想要去的地方,这时我按一下方向键上键,再次执行 `z gems`,那么我就能被带到 `/Users/Great_Wall/.rbenv/versions/2.4.1/lib/ruby/gems` 目录中,而这正是我想去的地方。
我当然可以每次使用`z env gems` 来精确指明,但是每当我输入 `z xxx` 我必然是想进行路径跳转的,而不是呆在原地,所以使用增强匹配模式,即便当前目录是最佳匹配,它也能懂得你想跳转的心思。
在我最初实现 z.lua 时,只有一个和 z.sh 类似的默认匹配算法,在网友的建议下,我陆续学习了来自 fasd / autojump 中的优秀理念,并加以完善改进,成为如今集三家之长的 “增强匹配算法” ,给它取个昵称,叫做 “更懂你的匹配算法”。
## Add once
何时更新数据呢默认情况下z.lua 会在每次显示命令提示符时记录当前路径(和 z.sh 一致),但是还提供了一个 $_ZL_ADD_ONCE 的环境变量选项,设置成 1 的话,只有当前路径改变,才会将新路径添加到数据库。
除了设置环境变量外,不同的 shell 下还可以在初始化时增加 "once" 参数来达到相同目的,比如:
````bash
eval "$(lua /path/to/z.lua --init bash once enhanced)"
eval "$(lua /path/to/z.lua --init zsh once enhanced)"
source (lua /path/to/z.lua --init fish once enhanced | psub)
````
将会同时启用增强匹配算法和 once 机制在一些比较慢的硬件下路由器cygwinmsys使用该机制将有效的提升性能。其实 autojump 在 zsh 下会使用类似 once 的机制,而 bash 下则和 z.sh 类似。
从效果上来讲z.sh 的模式(关闭 once强调的是 “在某路径下工作的时间长短”,而 autojump 的模式(启用 once则强调 “进入某路径的次数多少”。
## 交互式选择模式
使用 -i 参数进行跳转时, 如果有多个匹配结果,那么 z.lua 会给你显示一个列表:
```bash
$ z -i soft
3: 0.25 /home/data/software
2: 3.75 /home/skywind/tmp/comma/software
1: 21 /home/skywind/software
> {光标位置}
```
然后你按照最前面的序号输入你想要去的地方,比如输入 3 就会进入 `/home/data/software`。如果你不输入任何东西直接按回车,那么将会直接退出而不进行任何跳转。
PS如果你使用 Fish shell需要 2.7.0 以上才支持该功能。
## FZF supports
版本 1.1.0 引入了新的 `"-I"` 参数,让你可以使用 fzf 在多项结果进行快速选择:
![](images/fzf.png)
当你使用 `"z -I vim"`12 条路径被筛选出来,并按照 frecent 排序,他们都包含 "vim" 关键字,在实际 cd 改变路径前z.lua 会调用 fzf 来让你更方便的选择你想去的地方,每条记录包含左边的 frecent 权重和右边的路径名,权重越高的排在越前面。
你可以在 fzf 里输入一些**空格分隔**的关键字(不需要先后顺序),或者按 `CTRL+J` / `CTRL+K` (方向键的上下也可以)进行选择,`ESC` 或者 `CTRL`+`D`/`G` 放弃。
你仍然可以用老方法,通过在 `z` 命令后面添加更多关键词来精确的匹配你想去的地方,这个特性给了你一个可视化的方式来做这件事情。为了方便起见,通常把 `z -I` alias 成 `zf` (z + fuzzy finder)。如果搜索结果只有一项,那么 z.lua 会直接跳转过去,不需要启动 fzf 再选择一遍,只有多项结果要选择时,才会启动 fzf。
`"z -I ."` 或者 `"zf ."` 可以让 fzf 来对整个数据库中的路径进行选择。
PS你可以使用 `$_ZL_FZF` 环境变量来精确指明 fzf 的可执行路径,默认的话就是 fzf。如果你使用 Fish shell需要 2.7.0 以上才支持该功能。
## 快速回到父目录
`"-b"` 选项可以快速回到某一级父目录,避免重复的输入 "cd ../../.."。
- **(没有参数)**`cd` 到项目根目录,即跳转到最近的包含 (.git/.svn/.hg) 的父目录。
- **(单个参数)**`cd` 到离当前目录最近的以关键字开头的父目录,如果找不到就尝试跳到包含关键字的父目录。
- **(两个参数)**:将当前路径中的第一个关键词替换为第二个关键词。
先将 `z -b` 别名成 `zb`
```bash
# 一直向上退到项目根目录(就是里面有一个 .git 目录的地方)
~/github/lorem/src/public$ zb
=> cd ~/github/lorem
# cd 到第一个以 g 开头的父目录
~/github/vimium/src/public$ zb g
=> cd ~/github
# 快速回到 site 目录
~/github/demo/src/org/main/site/utils/file/reader/whatever$ zb si
=> cd ~/github/demo/src/org/main/site
# 将 jekyll 替换为 ghost
~/github/jekyll/test$ zb jekyll ghost
=> cd ~/github/ghost/test
```
向后跳转同样也支持环境变量 `$_ZL_ECHO`(用来显示跳转结果),这样可以搭配其他工具,在目标目录内执行命令,而并不需要改变当前工作目录(比如:``ls `zb git` ``)。
环境变量 `$_ZL_ROOT_MARKERS` 是一个逗号分隔的列表,用来识别项目根目录,可以重定义成:
```bash
export _ZL_ROOT_MARKERS=".git,.svn,.hg,.root,package.json"
```
这样在用 `zb` 时,可以回到包含 `.root`文件,或者 `package.json` 文件的父目录。
**Bonus**`zb ..` 相当于 `cd ..``zb ...` 相当于 `cd ../..`,而 `zb ....` 相当于 `cd ../../..` 等等。 最后 `zb ..20` 等同于调用 `cd ..` 二十次。
**Bonus**: 试试 `z -b -i` 以及 `z -b -I`,推荐把他们取个别名成 `zbi``zbf`
## 补全功能
zsh/fish 的补全系统是比较完善的,使用 `z foo<tab>` 就能触发补全,显示一个列表:
![](images/complete-1.png)
再次按 `<tab>` 键,就可以用可视化的方式对列表进行选择。
在 bash 下面补全系统没有那么强大,所以 z.lua 引入了 fzf 补全,初始化时在 `--init` 后追加 `fzf` 关键字:
```bash
eval "$(lua /path/to/z.lua --init bash enhanced once echo fzf)"
```
如果你想在 zsh 中使用 fzf 补全,初始化时在 `--init` 后追加 `fzf` 关键字:
```zsh
eval "$(lua /path/to/z.lua --init zsh enhanced once echo fzf)"
```
然后你在 bash/zsh 中,输入部分关键字后按 tab就能把匹配的路径列出来
![](images/complete-2.png)
有了 fzf 的帮助bash 下补全也非常方便了。注意看左边的权重fzf 搜索过滤的顺序是有讲究的Frecent 权重越高的越靠前,不是乱排序的,更不是简单的按字符串字母排序。这里完全保证权重越高的路径越靠前。
`z.lua` 可以同 [fz](https://github.com/changyuheng/fz) 协作以提供**更好的补全结果**,详细见 [FAQ](https://github.com/skywind3000/z.lua/wiki/FAQ#fzsh-for-better-completion)。
注意:该功能在初始化 z.lua 之前,会检测 $PATH 中是否有 fzf 这个程序,有的话才启用。
## MRU
`z.lua` 提供 `dirstack` 让你更便捷的访问最近刚刚去过的目录,而不需要输入任何关键字。这个方法叫做 `dirstack`,它记录着最近你刚刚去过的 10 条最新路径,然后是用 `z -``z --` 和 `z -{num}` 来操作:
```bash
# 显示当前的 dir stack
$ z --
0 /home/skywind/work/match/memory-match
1 /home/skywind/.local/etc
2 /home/skywind/software/vifm-0.9.1
3 /home/skywind/work
4 /home/skywind/work/match
# cd 到栈里 2 号路径
$ z -2
=> cd /home/skywind/software/vifm-0.9.1
# 弹出栈顶 (cd 到上一次的老路径),和 "z -0" 相同
$ z -
=> cd -
```
这个 `dirstack` 是根据 z.lua 的路径历史数据库计算的出来的,和具体的 shell 或者操作系统无关。你退出再登陆不会丢失这些记录,不同的 shell 之间也可以共享同一份记录。
此外,还能通过前面提到的 `-I``-t` 参数组和,使用 fzf 选择最近去过的目录:
```bash
alias zh='z -I -t .'
```
方便起见,定义个新的别名 `zh`(回到历史路径的意思),我们用 `-t` 参数来告诉 `z.lua` 按时间戳为权重排序,同时 `-I` 启用 fzf 搜索,最后句号代表任意路径。
那么当我们在命令行敲入 zh 时,就可以用 fzf 进行历史路径操作了:
![](images/mru.png)
第一列上次访问距今多少秒,第二列是目录名。你可以试着敲几个字母,用 fzf 的字符串模糊匹配进行定位或者用光标键的上和下CTRL+J/K 也可以)来上下移动,最后按回车 cd 过去,或者 ESC 放弃。
## Tips
推荐一些常用的命令别名:
```bash
alias zc='z -c' # 严格匹配当前路径的子路径
alias zz='z -i' # 使用交互式选择模式
alias zf='z -I' # 使用 fzf 对多个结果进行选择
alias zb='z -b' # 快速回到父目录
```
导入 z.sh 的数据:
```bash
cat ~/.z >> ~/.zlua
```
导入 autojump 的数据:
```bash
FN="$HOME/.local/share/autojump/autojump.txt"
awk -F '\t' '{print $2 "|" $1 "|" 0}' $FN >> ~/.zlua
```
要更好的使用 `z.lua`,别忘记阅读:[Frequently Asked Questions](https://github.com/skywind3000/z.lua/wiki/FAQ)。
## Benchmark
最慢的部分当然是添加当前路径到数据库。该操作会在每次你按回车时执行,所以我在我的 Nas 上做了个对比:
```bash
$ time autojump --add /tmp
real 0m0.352s
user 0m0.077s
sys 0m0.185s
$ time fasd -A /tmp
real 0m0.618s
user 0m0.076s
sys 0m0.242s
$ time _z --add /tmp
real 0m0.194s
user 0m0.046s
sys 0m0.154s
$ time _zlua --add /tmp
real 0m0.052s
user 0m0.015s
sys 0m0.030s
```
可以看出z.lua 是消耗资源最少,并且最快的,可以更流畅的在性能不好的环境中使用。
## Why Lua ?
更好的兼容性,最开始我想要在我的路由器和 Nas 系统上使用 z.sh但是它依赖的 awk 版本比较高,这两个系统上的 awk 都是一个 busybox 的经过裁剪的 awk z.sh 完全无法正常工作。使用 shell 开发还有一个问题是严重依赖 shell 的版本,很多逻辑既要在 zsh 下可以运行,又要在 dash 下能跑,用 lua 开发的话,核心逻辑全部写成 lua 不用考虑太多琐碎的兼容性,可以为各种 shell 提供完全一致的体验。
描述力强,可以更好的实现核心功能,同时速度更快,纯 shell 开发的话,太多语句是通过子进程 shell 的模式运行,所以性能很差,而 Python 开发的话启动速度又太慢,我在 Cygwin/msys 下用 z.sh 都觉得很卡autojump/fasd 卡到不能用。
最关键的一点Lua 速度很快 200 KB 的可执行程序,启动速度是 python 的 3 倍perl 的 2 倍,很多命令行工具 go/rust 写成,动不动就 2MB / 3MB他们都还没有完成加载lua 脚本可能都运行完了。
## Credit
我的推特https://x.com/skywind3000
个人博客: https://skywind.me/blog
## License
Licensed under MIT license.

610
.bin/z.lua/README.md Normal file
View File

@ -0,0 +1,610 @@
# z.lua
A command line tool which helps you navigate faster by learning your habits :zap:
An alternative to [z.sh](https://github.com/rupa/z) with windows and posix shells support and various improvements.
【[README in Chinese | 中文文档](README.cn.md)】
## Description
z.lua is a faster way to navigate your filesystem. It tracks your most used directories, based on 'frecency'. After a short learning phase, z will take you to the most 'frecent' directory that matches ALL of the regexes given on the command line, in order.
For example, `z foo bar` would match `/foo/bar` but not `/bar/foo`.
## Reputation
From people using z.lua:
- I like this in principal. Im pretty damn predictable at the command line and far too lazy to make shortcuts
- It feels far more intuitive and it's so incredibly convenient to be able to jump between folders I'm working in without having to traverse an entire tree. The shell used to feel so constraining for me, but tools like this are making me enjoy it so much more.
- I can finally have autojump-like functionality on my Raspberry Pi 1 without waiting 30 seconds every time I open a new shell. Thanks z.lua devs.
- Anyway, z.lua is a promising project. If you only need directory jumping, it may be the best choice.
## Features
- **10x** times faster than **fasd** and **autojump**, **3x** times faster than **z.sh**.
- Gain the ultimate speed with an optional [native module](https://github.com/skywind3000/czmod) written in C.
- Available for **posix shells**: bash, zsh, dash, sh, ash, ksh, busybox and etc.
- Available for Fish Shell, Power Shell and Windows cmd.
- [Enhanced matching algorithm](#enhanced-matching) takes you to where ever you want precisely.
- Allow updating database only if `$PWD` changed with "$_ZL_ADD_ONCE" set to 1.
- Interactive selection enables you to choose where to go before cd.
- Integrated with FZF (optional) for interactive selection and completion.
- Quickly go back to a parent directory instead of typing "cd ../../..".
- Corresponding experience in different shells and operating systems.
- Compatible with Lua (5.1, 5.2, 5.3+) and luajit.
- Self contained, distributed as a single `z.lua` script, no other dependence.
## Examples
```bash
z foo # cd to most frecent dir matching foo
z foo bar # cd to most frecent dir matching foo and bar
z -r foo # cd to the highest ranked dir matching foo
z -t foo # cd to most recently accessed dir matching foo
z -l foo # list matches instead of cd
z -c foo # restrict matches to subdirs of $PWD
z -e foo # echo the best match, don't cd
z -i foo # cd with interactive selection
z -I foo # cd with interactive selection using fzf
z -b foo # cd to the parent directory starting with foo
z -b foo bar # replace foo with bar in cwd and cd there
```
## Install
- Bash:
put something like this in your `.bashrc`:
eval "$(lua /path/to/z.lua --init bash)"
the default matching algorithm is similar to z.sh to keep compatible, you may like the enhanced matching algorithm for productivity:
eval "$(lua /path/to/z.lua --init bash enhanced once)"
and perhaps this:
eval "$(lua /path/to/z.lua --init bash enhanced once echo)"
if you want `z.lua` print the new directory after cd.
For `fzf` tab completion use:
eval "$(lua /path/to/z.lua --init bash enhanced once fzf)"
**NOTE**: For wsl-1 users, `lua-filesystem` must be installed:
sudo apt-get install lua-filesystem
To avoid a wsl-1 [defect](https://github.com/microsoft/WSL/issues/5505).
- Zsh:
put something like this in your `.zshrc`:
eval "$(lua /path/to/z.lua --init zsh)"
Options like "enhanced", "once" and "fzf" can be used after `--init` too. It can also be initialized from "skywind3000/z.lua" with your zsh plugin managers (antigen / oh-my-zsh).
**NOTE**: for wsl-1 users, `lua-filesystem` must be installed.
- Posix Shells:
put something like this in your `.profile`:
eval "$(lua /path/to/z.lua --init posix)"
For old shells like ksh (Korn Shell), some features are missing, you can try:
eval "$(lua /path/to/z.lua --init posix legacy)"
To generate old posix compatible script.
- Fish Shell (version `2.4.0` or above):
Create `~/.config/fish/conf.d/z.fish` with following code
lua /path/to/z.lua --init fish | source
If you'd like `z.lua` to cooperate with fish's own [directory history](https://fishshell.com/docs/3.2/index.html#id34), you can put
set -gx _ZL_CD cd
into the same file.
- Nushell
Put something like this in your `env.nu`:
lua /path/to/z.lua --init nushell | save -f ~/.cache/zlua.nu
Then put something like this in your `config.nu`:
source ~/.cache/zlua.nu
alias z = _zlua
- Power Shell:
> ⚠️ **WARNING**: users of [Starship Prompt](https://starship.rs/) should add the following command *after* `starship init`.
put something like this in your `profile.ps1`:
Invoke-Expression (& { (lua /path/to/z.lua --init powershell) -join "`n" })
- Windows cmd (with clink):
- Copy z.lua and z.cmd to clink's home directory
- Add clink's home to `%PATH%` (z.cmd can be called anywhere)
- Ensure that "lua" can be called in `%PATH%`
- Windows cmder:
- Copy z.lua and z.cmd to cmder/vendor
- Add cmder/vendor to `%PATH%`
- Ensure that "lua" can be called in `%PATH%`
- Windows WSL-1:
Install `lua-filesystem` module before init z.lua:
sudo apt-get install lua-filesystem
This module is required due to a wsl-1 [defect](https://github.com/microsoft/WSL/issues/5505).
## Options
- set `$_ZL_CMD` in .bashrc/.zshrc to change the command (default z).
- set `$_ZL_DATA` in .bashrc/.zshrc to change the datafile (default ~/.zlua).
- set `$_ZL_NO_PROMPT_COMMAND` if you're handling PROMPT_COMMAND yourself.
- set `$_ZL_EXCLUDE_DIRS` to a comma separated list of dirs to exclude.
- set `$_ZL_ADD_ONCE` to '1' to update database only if `$PWD` changed.
- set `$_ZL_MAXAGE` to define a aging threshold (default is 5000).
- set `$_ZL_CD` to specify your own cd command (default is `builtin cd` in Unix shells).
- set `$_ZL_ECHO` to 1 to display new directory name after cd.
- set `$_ZL_MATCH_MODE` to 1 to enable enhanced matching.
- set `$_ZL_NO_CHECK` to 1 to disable path validation, use `z --purge` to clean
- set `$_ZL_HYPHEN` to 0 to treat a hyphen (`-`) as a
[lua regexp special character](https://www.lua.org/pil/20.2.html),
set `$_ZL_HYPHEN` to 1 to treat a hyphen as a normal character.
If `$_ZL_HYPHEN` is not set or if it is set to `auto`, z.lua tries to treat `-`
as a lua regexp special character first. If there are no matches, z.lua tries
again, this time treating `-` as a normal character.
- set `$_ZL_CLINK_PROMPT_PRIORITY` change clink prompt register priority (default 99).
## Aging
The rank of directories maintained by z.lua undergoes aging based on a simple formula. The rank of each entry is incremented every time it is accessed. When the sum of ranks is over 5000 (`$_ZL_MAXAGE`), all ranks are multiplied by 0.9. Entries with a rank lower than 1 are forgotten.
## Frecency
Frecency is a portmanteau of 'recent' and 'frequency'. It is a weighted rank that depends on how often and how recently something occurred. As far as I know, Mozilla came up with the term.
To z.lua, a directory that has low ranking but has been accessed recently will quickly have higher rank than a directory accessed frequently a long time ago. Frecency is determined at runtime.
## Default Matching
By default, `z.lua` uses default matching algorithm similar to the original `z.sh`. Paths must be match all of the regexes in order.
- cd to a directory contains foo:
z foo
- use multiple arguments:
Assuming the following database:
10 /home/user/work/inbox
30 /home/user/mail/inbox
`"z in"` would cd into `/home/user/mail/inbox` as the higher weighted entry. However you can pass multiple arguments to z.lua to prefer a different entry. In the above example, `"z w in"` would then change directory to `/home/user/work/inbox`.
- use regexes:
```bash
z foo$ # cd to a directory ends with foo
z %d # cd to a directory that contains a digit
```
Unlike `z.sh`, `z.lua` uses the [Lua regular expression syntax](https://www.lua.org/pil/20.2.html).
## Enhanced Matching
Enhanced matching can be enabled by exporting the environment:
```bash
export _ZL_MATCH_MODE=1
```
Or, append a `enhanced` after `--init xxx`:
```bash
eval "$(lua /path/to/z.lua --init bash enhanced)"
```
For a given set of queries (the set of command-line arguments passed to z.lua), a path is a match if and only if:
1. Queries match the path in order (same as default method).
2. The last query matches the last segment of the path.
If no match is found, it will fall back to default matching method.
- match the last segment of the path:
Assuming the following database:
10 /home/user/workspace
20 /home/user/workspace/project1
30 /home/user/workspace/project2
40 /home/user/workspace/project3
If you use `"z wo"` in enhanced matching mode, only the `/home/user/workspace` will be matched, because according to rule No.2 it is the only path whose last segment matches `"wo"`.
Since the last segment of a path is always easier to be recalled, it is sane to give it higher priority. You can also achieve this by typing `"z space$"` in both methods, but `"z wo"` is easier to type.
Tips for rule No.2:
- If you want your last query **not only** to match the last segment of the path, append '$' as the last query. eg. `"z wo $"`.
- If you want your last query **not** to match the last segment of the path, append '/' as the last query. eg. `"z wo /"`.
- cd to the existent path if there is no match:
Sometimes if you use:
z foo
And there is no matching result in the database, but there is an existent directory which can be accessed with the name "foo" from current directory, "`z foo`" will just work as:
cd foo
So, in the enhanced matching method, you can always use `z` like `cd` to change directory even if the new directory is untracked (hasn't been accessed).
- Skip the current directory:
When you are calling `z xxx` but the best match is the current directory, z.lua will choose the 2nd best match result for you. Assuming the database:
10 /Users/Great_Wall/.rbenv/versions/2.4.1/lib/ruby/gems
20 /Library/Ruby/Gems/2.0.0/gems
When I use `z gems` by default, it will take me to `/Library/Ruby/Gems/2.0.0/gems`, but it's not what I want, so I press up arrow and execute `z gems` again, it will take me to `/Users/Great_Wall/.rbenv/versions/2.4.1/lib/ruby/gems` and this what I want.
Of course, I can always use `z env gems` to indicate what I want precisely. Skip the current directory means when you use `z xxx` you always want to change directory instead of stay in the same directory and do nothing if current directory is the best match.
The default matching method is designed to be compatible with original z.sh, but the enhanced matching method is much more handy and exclusive to z.lua.
## Add Once
By default, z.lua will add current directory to database each time before display command prompt (correspond with z.sh). But there is an option to allow z.lua add path only if current working directory changed.
To enable this, you can set `$_ZL_ADD_ONCE` to `1` before init z.lua. Or you can initialize z.lua on linux like this:
````bash
eval "$(lua /path/to/z.lua --init bash once)"
eval "$(lua /path/to/z.lua --init zsh once)"
lua /path/to/z.lua --init fish once | source
````
With `add once` mode off (default), z.lua will consider the time you spent in the directory (like z.sh). When this mode is on, consider the times you accessed the directory (like autojump), and that could be much faster on slow hardware.
## Interactive Selection
When there are multiple matches found, using `z -i` will display a list:
```bash
$ z -i soft
3: 0.25 /home/data/software
2: 3.75 /home/skywind/tmp/comma/software
1: 21 /home/skywind/software
> {CURSOR}
```
And then you can input the number and choose where to go before actual cd. eg. input 3 to cd to `/home/data/software`. And if you just press ENTER and input nothing, it will just quit and stay where you were.
NOTE: for fish shell, this feature requires fish 2.7.0 or above.
## FZF Supports
From version 1.1.0, a new option `"-I"` will allow you to use fzf to select when there are multiple matches.
![](images/fzf.png)
When we use `"z -I vim"`12 paths contains keyword "vim" has been matched and ordered by their frecent value, the higher frecent comes with the higher rank. Then without cd to the highest ranked path, z.lua passes all the candidates to fzf.
Now you can input some space separated keywords (no order required) or use `CTRL+J`/`CTRL+K` (same as `UP`/`DOWN`) to select where you want to go, or `ESC` / `CTRL`+`D`/`G` to give up.
Of course, you can always give more keywords to `z` command to match your destination precisely. `"z -I"` is similar to `"z -i"`, but use fzf. Both `"-i"` and `"-I"` provide you another way for path navigation.
Usually, `z -I` can be aliased to `zf` (z + fuzzy finder) for convenience. If there are only one path matched, `z -I` will jump to it directly, fzf will only be invoked for multiple matches. `"z -I ."` or `"zf ."` can be used to use fzf select from entire database.
For more information about this, please visit [wiki - effective with fzf](https://github.com/skywind3000/z.lua/wiki/Effective-with-fzf).
NOTE: For fish shell, this feature requires fish 2.7.0 or above. You can specify fzf executable in `$_ZL_FZF` environment variable, `"fzf"` will be called by default.
## Jump Backwards
New option `"-b"` can quickly go back to a specific parent directory in bash instead of typing "cd ../../.." redundantly.
- **(No argument)**: `cd` into the project root, the project root the nearest parent directory with `.git`/`.hg`/`.svn` in it.
- **(One argument)**: `cd` into the closest parent starting with keyword, if not find, go to the parent containing keyword.
- **(Two arguments)**: replace the first value with the second one (in the current path).
If simple substitution does not work, falls back to fuzzily replacing path components.
Let's start by aliasing `z -b` to `zb`:
```bash
# go all the way up to the project root (in this case, the one that has .git in it)
~/github/lorem/src/public$ zb
=> cd ~/github/lorem
# cd into to the first parent directory named g*
~/github/vimium/src/public$ zb g
=> cd ~/github
# goto the site directory quickly
~/github/demo/src/org/main/site/utils/file/reader/whatever$ zb si
=> cd ~/github/demo/src/org/main/site
# substitute jekyll with ghost
~/github/jekyll/test$ zb jekyll ghost
=> cd ~/github/ghost/test
# same as above, but fuzzy
~/github/jekyll/test$ zb jek gh
=> z ~/github/ gh /test
=> cd ~/github/ghost/test # Assuming that's the most frecent match
```
Backward jumping can also be used with `$_ZL_ECHO` option (echo $PWD after cd), which makes it possible to combine them with other tools without actually changing the working directory (eg. ``ls `zb git` ``).
Environment variable `$_ZL_ROOT_MARKERS` is a comma separated list for project root locating, and can be redefined as:
```bash
export _ZL_ROOT_MARKERS=".git,.svn,.hg,.root,package.json"
```
If you want `zb` jump back to a parent directory contains a `.root` or `package.json` in it.
**Bonus**: `zb ..` equals to `cd ..`, `zb ...` equals to `cd ../..` and `zb ....` equals to `cd ../../..`, and so on. Finally, `zb ..20` equals to `cd (..)x20`.
**Bonus**: try `z -b -i` and `z -b -I` and you can alias them to `zbi` and `zbf`.
## Completion
For zsh/fish, completion can be triggered by `z foo<tab>`. and a list of candidates will display in zsh / fish:
![](images/complete-1.png)
Press `<tab>` again, you can select your destination in a visualized way.
Bash is not as powerful as zsh/fish, so we introduced fzf-completion for bash, initialize your z.lua and append `fzf` keyword after `--init`:
```bash
eval "$(lua /path/to/z.lua --init bash enhanced once echo fzf)"
```
If you want use fzf completion in zsh, initalize your z.lua and append `fzf` keyword after `--init`:
```zsh
eval "$(lua /path/to/z.lua --init zsh enhanced once echo fzf)"
```
Then press `<tab>` after `z xxx`:
![](images/complete-2.png)
With the help of fzf, completion in bash is much easier now.
`z.lua` can cooperate with [fz](https://github.com/changyuheng/fz) for **better completion** result in both bash and zsh, for more information see [FAQ](https://github.com/skywind3000/z.lua/wiki/FAQ#fzsh-for-better-completion).
NOTE: To enable this, command `fzf` must be found in `$PATH` before initialization.
## Most Recently Accessed Path
`z.lua` provides a fast way to visit MRU directories without typing any keyword. That is `dirstack`, which records recently visited paths and can be manipulated by `z -`, `z --` and `z -{num}`:
```bash
# display current dir stack
$ z --
0 /home/skywind/work/match/memory-match
1 /home/skywind/.local/etc
2 /home/skywind/software/vifm-0.9.1
3 /home/skywind/work
4 /home/skywind/work/match
# cd to the 2nd directory in the stack
$ z -2
=> cd /home/skywind/software/vifm-0.9.1
# popup stacktop (cd to previous directory), same as "z -0"
$ z -
=> cd -
```
The `dirstack` is calculated from z.lua's database, and has no dependency on shells or systems. You will not lost records after re-login, and history can be shared across shells and sessions.
There is another way to access MRU directories interactively by utilizing parameter `-I` (fzf) and `-t` (sort by time):
```bash
alias zh='z -I -t .'
```
The new alias `zh` (jump to history) is very easy to input:
![](images/mru.png)
The first column indicates how many seconds ago you have visited, and the second column is the path name. With `zh`, you can type some character to use string matching in fzf, or use `<Up>`/`<Down>` (as well as `CTRL+j/k`) to move the selector (red `>`) up and down.
At last, press `<enter>` to accept or `<ESC>` to give up.
Remember to enable the [enhanced matching](#enhanced-matching) algorithm, the current working directory can be skipped with it.
## Ranger integration
To add a `:z` command to the [`ranger` file manager], copy the `ranger_zlua.py` file to `~/.config/ranger/plugins/`.
You can then use `:z foo`, `:z -b foo`, etc. from ranger. Use `:z -h` for help.
[`ranger` file manager]: https://github.com/ranger/ranger
To define additional commands (`:zb` for example) in ranger, you can put `alias zb z -b` into `~/.config/ranger/rc.conf`.
## Tips
Recommended aliases you may find useful:
```bash
alias zz='z -c' # restrict matches to subdirs of $PWD
alias zi='z -i' # cd with interactive selection
alias zf='z -I' # use fzf to select in multiple matches
alias zb='z -b' # quickly cd to the parent directory
```
Import data from z.sh
```bash
cat ~/.z >> ~/.zlua
```
Import data from autojump
```bash
FN="$HOME/.local/share/autojump/autojump.txt"
awk -F '\t' '{print $2 "|" $1 "|" 0}' $FN >> ~/.zlua
```
Don't forget to read the [Frequently Asked Questions](https://github.com/skywind3000/z.lua/wiki/FAQ).
## Benchmark
The slowest part is adding path to history data file. It will run every time when you press enter (installed in $PROMPT_COMMAND). So I profile it on my NAS:
```bash
$ time autojump --add /tmp
real 0m0.352s
user 0m0.077s
sys 0m0.185s
$ time fasd -A /tmp
real 0m0.618s
user 0m0.076s
sys 0m0.242s
$ time _z --add /tmp
real 0m0.194s
user 0m0.046s
sys 0m0.154s
$ time _zlua --add /tmp
real 0m0.052s
user 0m0.015s
sys 0m0.030s
```
As you see, z.lua is the fastest one and requires less resource.
## Native Module
z.lua is fast enough for most case, the path tracking action will be triggered each time when you change your current directory.
So I still recommend the pure lua script for portability and flexibility, but for someone who really care about `10ms` or `1ms` things, this module can help them to gain the ultimate speed.
- [czmod](https://github.com/skywind3000/czmod): native module to boost `z.lua`.
Average performance:
| Name | czmod | z.lua |
|-|-|-|
| **Update Time** | 1.6ms | 13.2ms |
| **Query Time** | 1.5ms | 9.8ms |
## History
- 1.8.7 (2020-06-29): use lfs or luajit's cffi if possible.
- 1.8.4 (2020-02-10): fish shell: set `$_ZL_ECHO` to global scope.
- 1.8.3 (2020-02-09): new: `z -b -i` and `z -b -I` to jump backwards in interactive mode.
- 1.7.4 (2019-12-29): new: `$_ZL_HYPHEN` to treat hyphen as a normal character, see [here](https://github.com/skywind3000/z.lua/wiki/FAQ#how-to-input-a-hyphen---in-the-keyword-).
- 1.7.3 (2019-09-07): use [lua-filesystem](http://keplerproject.github.io/luafilesystem/) package if possible when `$_ZL_USE_LFS` is `1`.
- 1.7.2 (2019-08-01): Improve bash/zsh shell compatibility by [@barlik](https://github.com/barlik).
- 1.7.1 (2019-06-07): Fixed: `$_ZL_DATA` failure on Linux sometimes.
- 1.7.0 (2019-03-09): Support [ranger](https://github.com/skywind3000/z.lua/wiki/FAQ#how-to-integrate-zlua-to-ranger-), fix ReplaceFile issue in luajit (windows).
- 1.6.0 (2019-03-04): optimize with ffi module (luajit builtin module).
- 1.5.11 (2019-03-02): fixed: os.path.isdir doesn't work for symbol link folders.
- 1.5.10 (2019-03-01): Prevent writing file racing.
- 1.5.9 (2019-02-25): `z -b` should not match current directory (close #56).
- 1.5.8 (2019-02-21): new `$_ZL_FZF_HEIGHT` to control `--height` parameter in fzf.
- 1.5.7 (2019-02-21): rename `$_ZL_FZF_SORT` to `$_ZL_INT_SORT` it will affect both `-i` and `-I`.
- 1.5.6 (2019-02-20): set `$_ZL_FZF_SORT` to 1 to sort directories by alphabet in fzf.
- 1.5.5 (2019-02-20): `$_ZL_FZF_FLAG` can be used to override fzf flags, default to "+s -e".
- 1.5.4 (2019-02-19): fixed: file/path existence detection fails on read-only fs (closed [#49](https://github.com/skywind3000/z.lua/issues/49) by [@contrun](https://github.com/contrun)).
- 1.5.3 (2019-02-17): new `$_ZL_FZF_FLAG` for passing additional flags to fzf, add `-e` argument to fzf.
- 1.5.2 (2019-02-16): be aware of all arguments in fzf completion.
- 1.5.1 (2019-02-15): new: simulated dir stack by `z -`, `z --` and `z -{num}`.
- 1.5.0 (2019-02-14): fixed minor issues in backward jumping.
- 1.4.7 (2019-02-13): Don't use regex in backward jumping (use plain text instead).
- 1.4.6 (2019-02-12): change: `_ZL_EXCLUDE_DIRS` to a comma separated list of dirs to exclude.
- 1.4.5 (2019-02-10): improve bash fzf completion and posix compatibility.
- 1.4.4 (2019-02-10): supports legacy posix shells like ksh, init with `z.lua --init posix legacy`.
- 1.4.3 (2019-02-08): fixed minor issues.
- 1.4.2 (2019-02-06): you can disabled path validation by `$_ZL_NO_CHECK`, and use `z --purge` to clear bad paths manually.
- 1.4.1 (2019-02-06): fzf tab-completion in bash ([@BarbUk](https://github.com/BarbUk)), fixed hang in fish shell (close [#29](https://github.com/skywind3000/z.lua/issues/29)).
- 1.4.0 (2019-02-04): Ported to Power Shell ([@manhong2112](https://github.com/manhong2112))
- 1.3.0 (2019-02-04): Backward jumping, prevent "cd ../../.." repeatly.
- 1.2.0 (2019-02-03): Upgrade string lib and path lib.
- 1.1.0 (2019-02-02): New option '-I' to use fzf to select from multiple matches.
- 1.0.0 (2019-02-01): Fixed minor issues and make it stable.
- 0.5.0 (2019-01-21): Ported to Fish Shell ([@TeddyDD](https://github.com/TeddyDD)).
- 0.4.1 (2019-01-20): Don't return failed exit code when $_ZL_ECHO is unbind (Mario Rodas).
- 0.4.0 (2019-01-17): new enhanced matching algorithmcan be enabled by appending `enhanced` keyword after `--init`.
- 0.3.0 (2018-12-26): new option `-i` to enable interactive selection.
- 0.2.0 (2018-11-25): new option `$_ZL_ADD_ONCE` to enable updating datafile only if `$PWD` changed.
- 0.1.0 (2018-04-30): supports windows cmd, cmder and conemu.
- 0.0.0 (2018-03-21): initial commit, compatible with original z.sh.
## Help
This project needs help for the tasks below:
- [ ] Support csh/tcsh.
- [ ] Completion: Actually I got little knowledge in completion, and need help to improve it.
- [ ] Completion: Implement completion for Power Shell.
- [ ] Completion: Implement completion for different arguments.
- [ ] Packaging: make it possible to be installed easily in different systems or popular plugin managers.
## Thanks
- Thanks to [@rupa](https://github.com/rupa) for inspiring me to start this project.
- Thanks to [@vigneshwaranr](https://github.com/vigneshwaranr) and [@shyiko](https://github.com/shyiko) for inspiring me the backward jumping.
- Thanks to [@TeddyDD](https://github.com/TeddyDD) for Fish Shell porting.
- Thanks to [@manhong2112](https://github.com/manhong2112) for Power Shell porting.
- Thanks to [@BarbUk](https://github.com/BarbUk) for fzf completion in Bash.
- Thanks to [@barlik](https://github.com/barlik) for many improvements.
- Thanks to [@brglng](https://github.com/brglng) for nushell porting.
And many others.
## License
Licensed under MIT license.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
.bin/z.lua/images/fzf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
.bin/z.lua/images/mru.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
.bin/z.lua/images/step1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
.bin/z.lua/images/step2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
.bin/z.lua/images/step3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
.bin/z.lua/images/step4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

52
.bin/z.lua/init.fish Normal file
View File

@ -0,0 +1,52 @@
#! /usr/bin/env fish
if test -z "$XDG_DATA_HOME"
set -U _ZL_DATA_DIR "$HOME/.local/share/zlua"
else
set -U _ZL_DATA_DIR "$XDG_DATA_HOME/zlua"
end
set -x _ZL_DATA "$_ZL_DATA_DIR/zlua.txt" 2> /dev/null
set -U _ZL_DATA "$_ZL_DATA_DIR/zlua.txt" 2> /dev/null
if test ! -e "$_ZL_DATA"
if test ! -e "$_ZL_DATA_DIR"
mkdir -p -m 700 "$_ZL_DATA_DIR" 2> /dev/null
end
end
set -x _ZL_DATA "$_ZL_DATA"
set -q XDG_DATA_HOME; or set XDG_DATA_HOME ~/.local/share
if functions -q fisher
set _zlua_dir $XDG_DATA_HOME/fisher/github.com/skywind3000/z.lua
else
set _zlua_dir (dirname (status --current-filename))
end
if test -e $_zlua_dir/z.lua
if type -q lua
lua $_zlua_dir/z.lua --init fish enhanced once echo | source
else if type -q luajit
luajit $_zlua_dir/z.lua --init fish enhanced once echo | source
else if type -q lua5.3
lua5.3 $_zlua_dir/z.lua --init fish enhanced once echo | source
else if type -q lua5.2
lua5.2 $_zlua_dir/z.lua --init fish enhanced once echo | source
else if type -q lua5.1
lua5.1 $_zlua_dir/z.lua --init fish enhanced once echo | source
else
echo "init z.lua failed, not find lua in your system"
end
alias zc='z -c' # restrict matches to subdirs of $PWD
alias zz='z -i' # cd with interactive selection
alias zf='z -I' # use fzf to select in multiple matches
alias zb='z -b' # quickly cd to the parent directory
alias zbi='z -b -i' # interactive jump backward
alias zbf='z -b -I' # interactive jump backward with fzf
set -U ZLUA_SCRIPT "$ZLUA_SCRIPT" 2> /dev/null
set -U ZLUA_LUAEXE "$ZLUA_LUAEXE" 2> /dev/null
end

91
.bin/z.lua/ranger_zlua.py Normal file
View File

@ -0,0 +1,91 @@
import time, sys, os
import ranger.api
import subprocess
# $RANGER_LUA and $RANGER_ZLUA variables are deprecated, do not use them.
ZLUA_LUAEXE = os.environ.get('RANGER_LUA') or os.environ.get('ZLUA_LUAEXE')
ZLUA_SCRIPT = os.environ.get('RANGER_ZLUA') or os.environ.get('ZLUA_SCRIPT')
if not ZLUA_LUAEXE:
for path in os.environ.get('PATH', '').split(os.path.pathsep):
for name in ('lua', 'luajit', 'lua5.3', 'lua5.2', 'lua5.1'):
test = os.path.join(path, name)
test = test + (sys.platform[:3] == 'win' and ".exe" or "")
if os.path.exists(test):
ZLUA_LUAEXE = test
break
def _report_error(msg):
sys.stderr.write('ranger_zlua: ' + msg)
raise RuntimeError(msg)
if not ZLUA_LUAEXE:
_report_error('Please install lua in $PATH or make sure $ZLUA_LUAEXE points to a lua executable.\n')
if (not ZLUA_SCRIPT) or (not os.path.exists(ZLUA_SCRIPT)):
_report_error('Could not find z.lua, please make sure $ZLUA_SCRIPT is set to absolute path of z.lua.\n')
# Inform z.lua about directories the user browses to inside ranger
old_hook_init = ranger.api.hook_init
def hook_init(fm):
def update_zlua(signal):
import os, random
os.environ['_ZL_RANDOM'] = str(random.randint(0, 0x7fffffff))
p = subprocess.Popen([ZLUA_LUAEXE, ZLUA_SCRIPT, "--add", signal.new.path])
p.wait()
if ZLUA_SCRIPT and ZLUA_LUAEXE and os.path.exists(ZLUA_SCRIPT):
fm.signal_bind('cd', update_zlua)
return old_hook_init(fm)
ranger.api.hook_init = hook_init
class z(ranger.api.commands.Command):
def execute (self):
import sys, os, time
args = self.args[1:]
if args:
mode = ''
for arg in args:
if arg in ('-l', '-e', '-x', '-h', '--help', '--'):
mode = arg
break
elif arg in ('-I', '-i'):
mode = arg
elif arg[:1] != '-':
break
if mode:
cmd = '"%s" "%s" '%(ZLUA_LUAEXE, ZLUA_SCRIPT)
if mode in ('-I', '-i', '--'):
cmd += ' --cd'
for arg in args:
cmd += ' "%s"'%arg
if mode in ('-e', '-x'):
path = subprocess.check_output([ZLUA_LUAEXE, ZLUA_SCRIPT, '--cd'] + args)
path = path.decode("utf-8", "ignore")
path = path.rstrip('\n')
self.fm.notify(path)
elif mode in ('-h', '-l', '--help'):
p = self.fm.execute_command(cmd + '| less +G', universal_newlines=True)
stdout, stderr = p.communicate()
elif mode == '--':
p = self.fm.execute_command(cmd + ' 2>&1 | less +G', universal_newlines=True)
stdout, stderr = p.communicate()
else:
p = self.fm.execute_command(cmd, universal_newlines=True, stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
path = stdout.rstrip('\n')
self.fm.execute_console('redraw_window')
if path and os.path.exists(path):
self.fm.cd(path)
else:
path = subprocess.check_output([ZLUA_LUAEXE, ZLUA_SCRIPT, '--cd'] + args)
path = path.decode("utf-8", "ignore")
path = path.rstrip('\n')
if path and os.path.exists(path):
self.fm.cd(path)
else:
self.fm.notify('No matching found', bad = True)
return True

View File

@ -0,0 +1,193 @@
local zmod = require('z')
local windows = os.path.sep == '\\'
-----------------------------------------------------------------------
-- logo
-----------------------------------------------------------------------
function print_title(text)
print(string.rep('-', 72))
print('-- '.. text)
print(string.rep('-', 72))
end
-----------------------------------------------------------------------
-- os.path.normpath
-----------------------------------------------------------------------
print_title('os.path.normpath')
function assert_posix(path, result)
local x = os.path.normpath(path)
print('[test] normpath: ('..path..') -> (' .. result .. ')')
if x:gsub('\\', '/') ~= result then
print('failed: "' .. x .. '" != "'..result.. '"')
os.exit()
else
print('passed')
print()
end
end
function assert_windows(path, result)
local x = os.path.normpath(path)
print('[test] normpath: ('..path..') -> (' .. result .. ')')
if x ~= result then
print('failed: "' .. x .. '" != "'..result.. '"')
os.exit()
else
print('passed')
print()
end
end
assert_posix("", ".")
assert_posix("/", "/")
assert_posix("///", "/")
assert_posix("///foo/.//bar//", "/foo/bar")
assert_posix("///foo/.//bar//.//..//.//baz", "/foo/baz")
assert_posix("///..//./foo/.//bar", "/foo/bar")
if windows then
assert_windows('A//////././//.//B', 'A\\B')
assert_windows('A/./B', 'A\\B')
assert_windows('A/foo/../B', 'A\\B')
assert_windows('C:A//B', 'C:A\\B')
assert_windows('D:A/./B', 'D:A\\B')
assert_windows('e:A/foo/../B', 'e:A\\B')
assert_windows('C:///A//B', 'C:\\A\\B')
assert_windows('D:///A/./B', 'D:\\A\\B')
assert_windows('e:///A/foo/../B', 'e:\\A\\B')
assert_windows('..', '..')
assert_windows('.', '.')
assert_windows('', '.')
assert_windows('/', '\\')
assert_windows('c:/', 'c:\\')
assert_windows('/../.././..', '\\')
assert_windows('c:/../../..', 'c:\\')
assert_windows('../.././..', '..\\..\\..')
assert_windows('K:../.././..', 'K:..\\..\\..')
assert_windows('C:////a/b', 'C:\\a\\b')
end
print()
-----------------------------------------------------------------------
-- os.path.join
-----------------------------------------------------------------------
print_title('os.path.join')
function assert_join_posix(segments, result, isnt)
print('[test] join: '..zmod.dump(segments)..' -> (' .. result .. ')')
local path = ''
for _, item in ipairs(segments) do
path = os.path.join(path, item)
end
if windows and (not isnt) then
path = path:gsub('\\', '/')
end
if path ~= result then
print('failed: "' .. path .. '"')
os.exit()
else
print('passed')
end
end
function assert_join_windows(segments, result)
assert_join_posix(segments, result, 1)
end
assert_join_posix({"/foo", "bar", "/bar", "baz"}, "/bar/baz")
assert_join_posix({"/foo", "bar", "baz"}, "/foo/bar/baz")
assert_join_posix({"/foo/", "bar/", "baz/"}, "/foo/bar/baz/")
if windows then
assert_join_windows({""}, '')
assert_join_windows({"", "", ""}, '')
assert_join_windows({"a"}, 'a')
assert_join_windows({"/a"}, '/a')
assert_join_windows({"\\a"}, '\\a')
assert_join_windows({"a:"}, 'a:')
assert_join_windows({"a:", "\\b"}, 'a:\\b')
assert_join_windows({"a", "\\b"}, '\\b')
assert_join_windows({"a", "b", "c"}, 'a\\b\\c')
assert_join_windows({"a\\", "b", "c"}, 'a\\b\\c')
assert_join_windows({"a", "b\\", "c"}, 'a\\b\\c')
assert_join_windows({"a", "b", "\\c"}, '\\c')
assert_join_windows({"d:\\", "\\pleep"}, 'd:\\pleep')
assert_join_windows({"d:\\", "a", "b"}, 'd:\\a\\b')
assert_join_windows({'', 'a'}, 'a')
assert_join_windows({'', '', '', '', 'a'}, 'a')
assert_join_windows({'a', ''}, 'a\\')
assert_join_windows({'a', '', '', '', ''}, 'a\\')
assert_join_windows({'a\\', ''}, 'a\\')
assert_join_windows({'a\\', '', '', '', ''}, 'a\\')
assert_join_windows({'a/', ''}, 'a/')
assert_join_windows({'a/b', 'x/y'}, 'a/b\\x/y')
assert_join_windows({'/a/b', 'x/y'}, '/a/b\\x/y')
assert_join_windows({'/a/b/', 'x/y'}, '/a/b/x/y')
assert_join_windows({'c:', 'x/y'}, 'c:x/y')
assert_join_windows({'c:a/b', 'x/y'}, 'c:a/b\\x/y')
assert_join_windows({'c:a/b/', 'x/y'}, 'c:a/b/x/y')
assert_join_windows({'c:/', 'x/y'}, 'c:/x/y')
assert_join_windows({'c:/a/b', 'x/y'}, 'c:/a/b\\x/y')
assert_join_windows({'c:/a/b/', 'x/y'}, 'c:/a/b/x/y')
assert_join_windows({'a/b', '/x/y'}, '/x/y')
assert_join_windows({'/a/b', '/x/y'}, '/x/y')
assert_join_windows({'c:', '/x/y'}, 'c:/x/y')
assert_join_windows({'c:a/b', '/x/y'}, 'c:/x/y')
assert_join_windows({'c:/', '/x/y'}, 'c:/x/y')
assert_join_windows({'c:/a/b', '/x/y'}, 'c:/x/y')
assert_join_windows({'c:', 'C:x/y'}, 'C:x/y')
assert_join_windows({'c:a/b', 'C:x/y'}, 'C:a/b\\x/y')
assert_join_windows({'c:/', 'C:x/y'}, 'C:/x/y')
assert_join_windows({'c:/a/b', 'C:x/y'}, 'C:/a/b\\x/y')
for _, x in ipairs({'', 'a/b', '/a/b', 'c:', 'c:a/b', 'c:/', 'c:/a/b'}) do
for _, y in ipairs({'d:', 'd:x/y', 'd:/', 'd:/x/y'}) do
assert_join_windows({x, y}, y)
end
end
end
print()
-----------------------------------------------------------------------
-- os.path.split
-----------------------------------------------------------------------
print_title('os.path.split')
function assert_split(path, sep1, sep2)
print('[test] split: "' .. path ..'" -> ("' .. sep1 .. '", "' .. sep2 .. '")')
local x, y = os.path.split(path)
if x ~= sep1 or y ~= sep2 then
print('failed: ("'..x..'", "'..y..'")')
os.exit()
else
print('passed')
end
end
assert_split("", "", "")
assert_split(".", "", ".")
assert_split("/foo/bar", "/foo", "bar")
assert_split("/", "/", "")
assert_split("foo", "", "foo")
assert_split("////foo", "////", "foo")
assert_split("//foo//bar", "//foo", "bar")
if windows then
assert_split("c:\\foo\\bar", 'c:\\foo', 'bar')
assert_split("\\\\conky\\mountpoint\\foo\\bar", '\\\\conky\\mountpoint\\foo', 'bar')
assert_split("c:\\", "c:\\", '')
assert_split("c:/", "c:/", '')
assert_split("c:test", "c:", 'test')
assert_split("c:", "c:", '')
-- assert_split("\\\\conky\\mountpoint\\", "\\\\conky\\mountpoint\\", '')
end

130
.bin/z.lua/z.cmd Normal file
View File

@ -0,0 +1,130 @@
@echo off
setlocal EnableDelayedExpansion
set "LuaExe=lua"
set "LuaScript=%~dp0z.lua"
set "MatchType=-n"
set "StrictSub=-n"
set "RunMode=-n"
set "StripMode="
set "InterMode="
if /i not "%_ZL_LUA_EXE%"=="" (
set "LuaExe=%_ZL_LUA_EXE%"
)
:parse
if /i "%1"=="-r" (
set "MatchType=-r"
shift /1
goto parse
)
if /i "%1"=="-t" (
set "MatchType=-t"
shift /1
goto parse
)
if /i "%1"=="-c" (
set "StrictSub=-c"
shift /1
goto parse
)
if /i "%1"=="-l" (
set "RunMode=-l"
shift /1
goto parse
)
if /i "%1"=="-e" (
set "RunMode=-e"
shift /1
goto parse
)
if /i "%1"=="-x" (
set "RunMode=-x"
shift /1
goto parse
)
if /i "%1"=="--add" (
set "RunMode=--add"
shift /1
goto parse
)
if "%1"=="-i" (
set "InterMode=-i"
shift /1
goto parse
)
if "%1"=="-I" (
set "InterMode=-I"
shift /1
goto parse
)
if /i "%1"=="-s" (
set "StripMode=-s"
shift /1
goto parse
)
if /i "%1"=="-h" (
call "%LuaExe%" "%LuaScript%" -h
goto end
)
if /i "%1"=="--purge" (
call "%LuaExe%" "%LuaScript%" --purge
goto end
)
:check
if /i "%1"=="" (
set "RunMode=-l"
)
for /f "delims=" %%i in ('cd') do set "PWD=%%i"
if /i "%RunMode%"=="-n" (
for /f "delims=" %%i in ('call "%LuaExe%" "%LuaScript%" --cd %MatchType% %StrictSub% %InterMode% %*') do set "NewPath=%%i"
if not "!NewPath!"=="" (
if exist !NewPath!\nul (
if /i not "%_ZL_ECHO%"=="" (
echo !NewPath!
)
pushd !NewPath!
pushd !NewPath!
endlocal
goto popdir
)
)
) else (
call "%LuaExe%" "%LuaScript%" "%RunMode%" %MatchType% %StrictSub% %InterMode% %StripMode% %*
)
goto end
:popdir
rem -- Exploits variable expansion and the pushd stack to set the current
rem -- directory without leaking a pushd.
popd
setlocal
set "NewPath=%CD%"
set "CDCmd=cd /d"
if /i not "%_ZL_CD%"=="" (
set "CDCmd=%_ZL_CD%"
)
endlocal & popd & %CDCmd% "%NewPath%"
:end
echo.

2990
.bin/z.lua/z.lua Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
#! /usr/bin/env zsh
ZLUA_SCRIPT="${0:A:h}/z.lua"
if [[ -n "$ZLUA_EXEC" ]] && ! which "$ZLUA_EXEC" &>/dev/null; then
echo "$ZLUA_EXEC not found"
ZLUA_EXEC=""
fi
# search lua executable
if [[ -z "$ZLUA_EXEC" ]]; then
for lua in lua luajit lua5.4 lua5.3 lua5.2 lua5.1; do
ZLUA_EXEC="$(command -v "$lua")"
[[ -n "$ZLUA_EXEC" ]] && break
done
if [[ -z "$ZLUA_EXEC" ]]; then
echo "Not find lua in your $PATH, please install it."
return
fi
fi
export _ZL_FZF_FLAG=${_ZL_FZF_FLAG:-"-e"}
if [[ -z "$_ZL_ZSH_NO_FZF" ]]; then
eval "$($ZLUA_EXEC $ZLUA_SCRIPT --init zsh once enhanced fzf)"
else
eval "$($ZLUA_EXEC $ZLUA_SCRIPT --init zsh once enhanced)"
fi
if [[ -z "$_ZL_NO_ALIASES" ]]; then
alias zz='z -i'
alias zc='z -c'
alias zf='z -I'
alias zb='z -b'
alias zbi='z -b -i'
alias zbf='z -b -I'
alias zh='z -I -t .'
alias zzc='zz -c'
fi

View File

@ -36,6 +36,7 @@ brew "wget"
brew "xdotool" brew "xdotool"
brew "xprop" brew "xprop"
brew "xwininfo" brew "xwininfo"
cask "affine"
cask "agent-tars" cask "agent-tars"
cask "alacritty" cask "alacritty"
cask "alcove" cask "alcove"
@ -43,7 +44,6 @@ cask "android-studio"
cask "appcleaner" cask "appcleaner"
cask "bettertouchtool" cask "bettertouchtool"
cask "cap" cask "cap"
cask "capacities"
cask "cherry-studio" cask "cherry-studio"
cask "clash-verge-rev" cask "clash-verge-rev"
cask "coteditor" cask "coteditor"
@ -51,6 +51,8 @@ cask "cursor"
cask "daisydisk" cask "daisydisk"
cask "dockdoor" cask "dockdoor"
cask "flutter" cask "flutter"
cask "font-fira-code"
cask "font-fira-code-nerd-font"
cask "font-jetbrains-mono" cask "font-jetbrains-mono"
cask "font-jetbrains-mono-nerd-font" cask "font-jetbrains-mono-nerd-font"
cask "font-maple-mono-nf-cn" cask "font-maple-mono-nf-cn"
@ -72,6 +74,7 @@ cask "maccy"
cask "masscode" cask "masscode"
cask "mihomo-party" cask "mihomo-party"
cask "miniconda" cask "miniconda"
cask "mos"
cask "musescore" cask "musescore"
cask "navicat-premium-lite" cask "navicat-premium-lite"
cask "notion" cask "notion"
@ -92,6 +95,7 @@ cask "snipaste"
cask "spotify" cask "spotify"
cask "steam" cask "steam"
cask "tagspaces" cask "tagspaces"
cask "tailscale"
cask "thor" cask "thor"
cask "trae" cask "trae"
cask "trae-cn" cask "trae-cn"
@ -99,6 +103,7 @@ cask "ultimate-vocal-remover"
cask "visual-studio-code" cask "visual-studio-code"
cask "wechatwebdevtools" cask "wechatwebdevtools"
cask "windsurf" cask "windsurf"
cask "wolai"
cask "wpsoffice-cn" cask "wpsoffice-cn"
cask "zed" cask "zed"
mas "Aspect Ratio", id: 1156930257 mas "Aspect Ratio", id: 1156930257

View File

@ -1,12 +1,12 @@
[gd] [gd]
type = drive type = drive
scope = drive scope = drive
token = {"access_token":"ya29.a0AZYkNZgxL9qXDm9KpfJxpFfd3gGXErk22oHQ6D9Bn0uSbS8H871-j7Jq_YuTBkUktOruShQ0XbDH3tPdZjspsiX4ze75x-2Z73npwlCYYFZA76tls5eYtcAaY2eMg5Hzdd1xVbgMS6pqDpSaW52cj_UOQdsZ74UPCkieTmzVAwaCgYKAUMSARQSFQHGX2MiW1oX_j-MtlFk2MLWdt5vhg0177","token_type":"Bearer","refresh_token":"1//06TiWE1qRgHJbCgYIARAAGAYSNwF-L9Ir03ZLbQ5mqZN2Cmx3UVDneqzkfxI2dqn9uHe5zJk9VZo9OCVd9XjYG1i84gMW7aXwSTY","expiry":"2025-04-21T21:27:08.43310467+08:00"} token = {"access_token":"ya29.a0AW4XtxghIGG7lrwLfmb7QHNpsMz2QsPy8DHhP1VxkTTTO7xFuW6hCj5Iwe3cyrierTd97y4zDorgP4_hJDsBIg_w1D9zhlZ6KubcXkLmeDGuFhM_J4Q0CA5DWd0Qz3-8wst-bTjxqEpXQ0D7cfl7CvAyb02ENY-vTcOHsB3Q2toaCgYKAcYSARQSFQHGX2MiIVF3f4wLB-1kcH9e-ks_tg0178","token_type":"Bearer","refresh_token":"1//06TiWE1qRgHJbCgYIARAAGAYSNwF-L9Ir03ZLbQ5mqZN2Cmx3UVDneqzkfxI2dqn9uHe5zJk9VZo9OCVd9XjYG1i84gMW7aXwSTY","expiry":"2025-05-29T18:15:36.994872+08:00"}
team_drive = team_drive =
[od] [od]
type = onedrive type = onedrive
token = {"access_token":"EwA4BMl6BAAUBKgm8k1UswUNwklmy2v7U/S+1fEAAZZ0PYIXlfgLSKs7rJjREEMzA/rYLkdjQvqU1yv9O2mN3vcvVE46WjO+3bIPqkH/uJwu8uB2f7ga9rj4OxJComucKid3g1n4bX6Pi4mpCpiW9zsLCxITfjU86c8hCqMXkCQKzemNnwgM27RvgngrH7QMpk2LGswAPbYVNJ5r3eYsEPk9CeHxHqQFqrhOkzE3pbNklytKPI3Kv3k9uPu4LXsVq3jrWLCZWkyXsaJi2pxwtBKxyHD3hQttHkzy4FEkRXPKarfok6bB0q4w9YJmmCk58RqLrXrLPy7X0+Vtv9CpaTz0uvmXXKSDEzkMKn5MnrH/2SyZ31jZ1Uu5YklpkmwQZgAAEFZUbqokNY61TKKECX9mt/UAA7Hl4zZQwBEqWE7VhTyzEPcU8jBv6X9XcFqU6JyEFiRc5TKcPg0Y1PHtMED+iL0RekDLy0Wth6gci1vgmEvE/EdNRbrHersucs4bpzlOasnCW3gJEOFFrnZC2DdVGpLjr40pnJJ0Pm0ohLprxE4uJh1crM6LbzhvslbAabr+i8nMU2yQ19SM2Yy8zQZSGEoXYYA9KM3i6gWF5qBsvFQ7RYQZUCtyMvpfBgKeTuVqSBsHO/gdi2boPvmNc5ZdfGOPjnU8AgtUhgGDDHKTE+iM/r51OCL8nXPMR5jmrdOF3yCGR+8VHm1KuZ1si4Gm3IXyZzEQLZL5zqZIa6OueJZVI4L1QiaVsirIsmN/hm0qHsG1yx+W6prKFQWXihYz0Y4pxdKrD+DUa3/ZI7S/84rsRmbz2z2AfR2ciLRaWdsIRXxiggPEwz6AllsQ2x3nbTTJDNDXq2ytYxh3Jrlp101bnMEI7DLF8vpaY0cBVacMOqFLscibvaERhwiT/yGScmiVS0tykYSCuLvJMlTVqVgJW7pFh5MezUnQ8fEHRjxuqGEXLwp/CYrVFO0oqTFoB6a/h31MKR8eYA3zRnlO61tCkfVfpbbfrmUkQWWeh5aC2exopTazzW67qjX4g7s+hW8Lap9YhiVbsY4M9fWWSXzmrnuc9BIzCdGsedoM2eEbLzEirRNrxElV2dULN6AACuW5+bDKIgJQ1xuW4P2kB09lPpBc/6jz4UDHgeiro5VXWEYdeqXJ409ES/VC286gmvl9JCyJdiCb+LREUBM4LH3VGRrT45c6UEyorW8/7jq7S3mcH2KG+yBuAjmIbnUSygeMpb1Ti27lR6MZeJ/Crj6Tw9WfaNOXUu2w5eYmw9kgrX/59IWhi0TW1Mfz5dHp9fAv/8UncorkZDtfoNsOQZsI2VsmLalGzvyaVZVu2Y7b/cRh7Jd/D5+ukO6y1bqH06LVZue5Wx54S5AZxHqpyCu1lYaz0PKd9lplcqXLeFkcTxDlegLdghnKQ2Qct7v9ZLb+2TkD","token_type":"Bearer","refresh_token":"M.C534_SN1.0.U.-CsNFZmVINToEW8*HVLD7xHaaV6GHyk0wnL!ETnyhqUMAFP!IvjPAV*eFuj45ftz7nGQuLR6EB2urd5JK*ln!9Rw9cK!1ezDZw8zWIQm3l4zGdCes!cPGpqlZvB4WDfNi69K1nlNS!uA!qn91PtmdDhPmKwFwvbgz9HDub!BoKdeK83pcAYqLTv!odEI*UzDgAjZv37Ki2YIbhH38xRmIaqmq8dZ3dISZSHCgZHmEGluaU2IPtYVKLp9rCu77fb7LVZu!PGG5lvu4J!pVlAL0d1RDdwh672WIFX*6sePFRdOWm4IR9tI8YbAl2Z7IproxDBA*3dI!JG0A*9QAWdCCE!YYZnWMjPGaZ!ASavda9ycF","expiry":"2025-05-12T03:28:14.136561914+08:00"} token = {"access_token":"EwA4BMl6BAAUBKgm8k1UswUNwklmy2v7U/S+1fEAAdUGB8PTLMhDOiwG7uLu9QgSf67kcBVFbUZZT1ZnvB9yQibUe2/ok4+/I6pZrpexuKMZGcl+ffaaMhpZTS6nrIkj2dLbb9jq75KnQAP81lS9xqdVcV7QvKt6FTDZsHMQ2bFm0C6Eq6Z6U2YJEV2vWjjZY1Tb/jdZl5mGFzFbR90RsHq15tDmcudetde2U1tenlgslnjxhHkABZRxkiQitEVCX4aCaXhafwBo23FgOrUibdLXTxfuLrjRJUYFZj/fqqlD7ptWxA7mx2Xj1RJNmF34EuO5fd16q8+1QfsSolcSDguZS6QFKR7O0U/jxi8bB2C8B2d+PsrTNpsducu2wBEQZgAAEAKOWXq/X2g5vPVCvbJVMecAA7Z0nutP3cW2Kp3LfrqHUli+OwdKsucaCyBuuU2xF+SlvrdRrl0RdSIzGQveyLoKhrIgWzkEcLJm+58vj2oZ5fdguLUnJoJF4rF5mDARxHzbEEzHrrYBUBcrj/7HLl3PdkaIrHuQk2ScHNga4oarfLRgPZMlw8mOAL+HUZpI4hhowJYfpfEy0UWVeI45KYmWhhpnNzNxzyR/zLi5XaY2fsvTeG3AIzpdkKWkeuk3NBJk08sbOmGaKtRQfOtWTuZqwUULUAKkURt0mA2y+tIttfy78TNzSkoMnvUm6XoT1VeWr2o0knwXEfASHQ68hBUl34ImmFN+BynZNspe7mLQl86c0aYS9lEp37bfHIhVAV/08uJ3Q2AbFdgwx8SmyvO4dYFT/wOgZGa6rjXL8Z/guE0xJlFhAFROSzccUWmmXBjmjw7UllyaKlbn3pQxb/JyRHSOdeK4olBNxg29y5loPUznFxb7VEP+/uQCjPZBRaQrjwZrJzqChG+9o0dTeprVbaVvzp+wWgO7+Q6AJczhXAEjEF30HMNof1yQOiYhzJa6fi9hi5jwA92OQ5Uxfwaj+S4Ch7RIcQwFn6jpsolwhLPd+K4H8zD7Ut0MV41P+2d10njtgtBjoAtuKG7oGu0ITTJ8/pD/7P9fK+iknJ0wT3zl+LPHswPRIpOBPBK9BTLhEc/NaIGu/uLUmF8PAAs49FgoKd8J7YAdlZuXlJ2Z4E4Z/NnNzO6jfk3cVOFlJESOYw3jY9O0dKemDt65gi5vyTan8uF+doM8Rw321EKX1BlSaYVUdX16HV1VhWkBhqEVTs35vkHifHNPBIpmgzS4p9sxcosqnxJaLc/KdEE8QeLYCio9Zj1Hp+gpI0yLSGWNEOo6IN+lGGJD0MaYYXxiYSQWKaStSxM/TJgm/vyBwtuTBroM5JXIQldZZqd76B9kAm+XmUH13knd0ttufSCN0jnHnr5TObQGOoLm2UlquXF1ptrBNlOrTugFhfgoIwKKYzFuijvn+1w/8n5iknfEITkD","token_type":"Bearer","refresh_token":"M.C534_BAY.0.U.-Ck5DTsGaJoOnE0OwmKqR6nuWZvRX*tOhEBpK04yGFDzL1F**ZV7EsGseoZZfjgLm3LXbEa9kmXeGe1Qkfc3lz3pWTUhWzANJ2d!G4xNc22RNn7P2IIweANb6*t51MLAta0khsw*tla0vY4lraZdGGGIBwHVmrqzTokmmsP7yecQIn8WRMIyyTwygwFfhcBohpq7e1hIRh*Bpt8*Vi9OcChjdSCKoO7mZoOccw6*UaySgwB62NL7ByC2hZicfrh6eBTgiTbr54Ip78LmFVw4hivBpO3NAp9sr!j!G6mscR*fXgcHgBD*c*UwxdhuuXWwo5kbki3FDS9GESjMq7sv*!rMx*YxvId*defxL2OWgVpWg","expiry":"2025-05-30T02:53:16.186871+08:00"}
drive_id = DA445CD50DBE653E drive_id = DA445CD50DBE653E
drive_type = personal drive_type = personal

0
.gitmodules vendored
View File

@ -1 +0,0 @@
Subproject commit 1af6bace7b05a4d25fceb9006cd37f68d17141c8

View File

@ -13,3 +13,6 @@ autops.eagle.local ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICXyXL24LLKF0GAsVOAWqwkjz
portal.eagle.local ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMYLIIUHcfd2hWVI2VQr1wDzHRgS8F5aRYE87uSn5fAV portal.eagle.local ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMYLIIUHcfd2hWVI2VQr1wDzHRgS8F5aRYE87uSn5fAV
portal.eagle.local ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPv25Fr8/XHoRp8cS4p8gvt4xPjwJWT62MhCBvBCP/yfP3h3lbWCAJL8GZqrVxzXnnOqsW9Ggz+OvStmTEv0+v8= portal.eagle.local ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPv25Fr8/XHoRp8cS4p8gvt4xPjwJWT62MhCBvBCP/yfP3h3lbWCAJL8GZqrVxzXnnOqsW9Ggz+OvStmTEv0+v8=
suzgitex.eagle.local ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMYLIIUHcfd2hWVI2VQr1wDzHRgS8F5aRYE87uSn5fAV suzgitex.eagle.local ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMYLIIUHcfd2hWVI2VQr1wDzHRgS8F5aRYE87uSn5fAV
nas.local ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGrw1W1hB6yQ1VMbUthNH4b3yfNISDzHHiemAU3S3KlB
nas ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGrw1W1hB6yQ1VMbUthNH4b3yfNISDzHHiemAU3S3KlB
xxl.marsway.red ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKPK7TJzKpzuwH39jLPIRWjA6FehyG4x3cQAZjyUm2hz