1
0
mirror of https://github.com/skywind3000/z.lua synced 2026-03-22 07:39:48 +00:00

39 Commits

Author SHA1 Message Date
skywind3000
30220996ca fix typo 2024-02-20 12:40:23 +08:00
skywind3000
d3ba781d4d Refactor the z.lua.plugin.zsh script to ensure proper initialization with or without FZF support 2024-02-20 11:43:00 +08:00
skywind3000
9a24fef334 Refactor logic to initialize fzf in zsh plugin to support a new condition where fzf can be disabled. 2024-02-19 11:29:04 +08:00
skywind3000
a9e034cb5c Update z.lua zsh plugin to allow customization of the fzf command used for fuzzy finding.
- Introduced new environment variable _ZL_ZSH_FZF to specify the fzf command
- Updated the eval statement to use the custom fzf command if provided by the user
2024-02-19 11:24:30 +08:00
Linwei
992134061a Merge pull request #196 from ilyagr/hyphens
Make z.lua try treating `-` as a normal character if there are no results
2023-12-11 01:11:14 +08:00
Ilya Grigoriev
b62784b66d Make z.lua try treating - as a normal character if there are no results
Previously, you needed to set `_ZL_HYPHEN=1` to treat `-` as a normal
character.  Otherwise, it was treated as a Lua regexp special character, see
https://www.lua.org/pil/20.2.html. Note that it is not super-useful to treat
`-` as a special character; it is almost the same as `*` and the difference
is not very useful in the context of fuzzy matching.

Now, if `_ZL_HYPHEN` is not set, z.lua first tries to treat it as a regexp
character. If there are no results (which is likely if the user does not know
it's a special character), z.lua tries again, treating `-` as a normal
character this time.

If `_ZL_HYPHEN=0` or `_ZL_HYPHEN=1`, z.lua will always treat `-` as
either a regex symbol or as a normal character (respectively).

Hopefully, this will make the FAQ at
https://github.com/skywind3000/z.lua/wiki/FAQ#how-to-input-a-hyphen---in-the-keyword-
unnecessary.  It took me weeks to look into the question of why `z
home-manager` refused to work and to find that FAQ. 

I only tested this briefly, but it seems to work.
2023-12-08 22:21:38 -08:00
Linwei
7f2bfcbfc1 Merge pull request #185 from kang8/feature/support-fzf-for-zsh-tab
ZSH: TAB complete using fzf
2023-07-13 11:02:56 +08:00
kang
86cb43af67 ZSH: TAB complete using fzf
Tested in Linux(ArchLinux) and MacOS

Close: #99, #77
2023-07-13 10:29:48 +08:00
skywind3000
71bae7fc0b refine window batch script initializing 2023-05-19 10:51:41 +08:00
Linwei
4d89b55363 Merge pull request #181 from chrisant996/clink_changes
Clink changes
2023-05-18 05:49:33 +08:00
Chris Antos
db1a863d40 Update z completions for Clink.
- Added description strings for the flags.
- Added dir completions for the `-x` flag.
2023-05-17 10:48:42 -07:00
Chris Antos
dff016528c z.lua was missing some lines for z.cmd.
The auto-init for z.cmd was missing a couple of lines.  The HomeDir
line, in particular, is important because it enables Lua to find the
z.lua script.
2023-05-17 10:48:05 -07:00
Linwei
6fe677aae4 Merge pull request #179 from Kosette/master
fix potential compatibilty issue for some fish shell versions and add…
2023-05-04 18:17:06 +08:00
Simsum
ba83bf67b2 fix potential compatibilty issue for some fish shell versions and add autocompletion for cmd options
1. `alias` command not available in some fishshell versions like 3.3.1. use fish-native `function` instead;
2. add autocompletion for cmd options benefitting from magic power of fish. just type `z -` and press tab. enjoy yourself.
2023-05-04 17:49:20 +08:00
skywind3000
0992ebf9f1 update z.lua 2022-09-29 15:48:52 +08:00
Linwei
83dfec0843 Merge pull request #170 from ilyagr/fuzzy-zb
Allow `z -b` to do fuzzy matching
2022-09-06 21:13:00 +08:00
Ilya Grigoriev
3703c5a0ea Put z -b foo bar in command summary, add regex docs 2022-08-27 22:00:52 -07:00
Ilya Grigoriev
3894a6b936 Reduce indentation and add comments 2022-08-27 22:00:52 -07:00
Ilya Grigoriev
0905165889 Allow z -b to do fuzzy matching
If `z -b foo bar` finds no exact match in the path to the current directory,
it tries a "fuzzy" substitution with a frecent directory. For example, if
we are in `~/github/jekyll/test` and run `z -b jek gh`, it will try to
substitute the entire `jekyll` path component with `gh`. The result will
be equivalent to running `z ~/github gh test`.
2022-08-27 22:00:52 -07:00
Linwei
3009e33176 Merge pull request #167 from FlTr/convert-string-to-float
Substitute comma with dot before conversion
2022-08-15 17:17:25 +08:00
FlTr
32786a0592 Substitute comma with dot before conversion 2022-08-15 09:37:36 +02:00
Linwei
47468a8588 Merge pull request #165 from ilyagr/ilya
Fixes and docs for the ranger plugin
2022-08-14 15:52:11 +08:00
Ilya Grigoriev
f347eaf1c8 Slight stylistic edits to ranger_zlua.py 2022-08-13 18:10:20 -07:00
Ilya Grigoriev
e11d2e2017 Fixes and docs for the ranger plugin
- Makes Ranger plugin use the standard `$ZLUA_LUAEXE` and `$ZLUA_SCRIPT`
  environment variables that `z.lua` itself uses.

- Better error handling; errors loading plugin no longer cause
  `ranger` to quit entirely.

- Briefly document the plugin
2022-08-13 16:14:50 -07:00
skywind3000
3ecc14747f prevent loading 2022-08-10 16:58:47 +08:00
skywind3000
632f722ee4 bloat version number 2022-07-21 22:12:50 +08:00
Linwei
9b9c0b82e6 Merge pull request #163 from jpcirrus/patch-1
Update fzf --inline-info option to --info=inline
2022-07-21 22:11:56 +08:00
John Purnell
08510fe6c6 Update fzf --inline-info option to --info=inline
fzf changed the option `--inline-info` to the equivalent `--info=inline` in release 0.19.0 with commit junegunn/fzf@d2fa470165 on 2019-11-14.
2022-07-21 15:30:21 +02:00
Linwei
1ead694395 Merge pull request #157 from wtfzambo/patch-1
docs: added warning for powershell users
2022-06-14 20:35:45 +08:00
wtfzambo
ee6aa2c5ce docs: added warning for powershell users
`.zlua` file doesn't get created for Powershell users that use [Starship Prompt](https://starship.rs/) and place z.lua init command before starship init command in their `profile.ps1`.

Couldn't reproduce the bug in zsh. Didn't test other shells.
2022-06-14 06:16:58 -04:00
skywind3000
a8e92e0216 fix Monterey initialization issues 2022-03-27 21:51:29 +08:00
skywind3000
e2cce39ee4 bloat version to 1.8.14 2022-01-30 21:54:08 +08:00
skywind3000
3c88f8d8fa recognize %_ZL_CD% in cmd.exe 2022-01-30 10:55:40 +08:00
Linwei
786225005c Merge pull request #148 from phanirithvij/imgbot
[ImgBot] Optimize images
2022-01-29 18:37:34 +08:00
ImgBotApp
481c1774ed [ImgBot] Optimize images
*Total -- 161.14kb -> 53.31kb (66.92%)

/images/step1.png -- 27.95kb -> 7.53kb (73.06%)
/images/mru.png -- 38.12kb -> 10.42kb (72.68%)
/images/fzf.png -- 29.02kb -> 8.47kb (70.81%)
/images/complete-2.png -- 28.69kb -> 9.05kb (68.46%)
/images/complete-1.png -- 12.35kb -> 5.12kb (58.53%)
/images/step2.png -- 12.63kb -> 5.66kb (55.16%)
/images/step3.png -- 7.56kb -> 3.63kb (52.03%)
/images/step4.png -- 4.83kb -> 3.44kb (28.77%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
2022-01-29 07:03:13 +00:00
Linwei
35e1199eff Merge pull request #145 from doubleloop/zluaexec
Try luajit in zsh and fish, fix ZLUA_EXEC check
2021-11-14 01:40:55 +08:00
Jakub Łuczyński
99dbe7b677 Mention support for luajit in README 2021-11-13 11:29:00 +01:00
Jakub Łuczyński
c88746629b zsh plugin: fix ZLUA_EXEC check
Previous check required full path (even if value was available in PATH)
2021-11-13 10:33:41 +01:00
Jakub Łuczyński
336e95b05a Try luajit in zsh and fish 2021-11-13 10:32:59 +01:00
16 changed files with 272 additions and 129 deletions

View File

@@ -325,7 +325,13 @@ zsh/fish 的补全系统是比较完善的,使用 `z foo<tab>` 就能触发补
eval "$(lua /path/to/z.lua --init bash enhanced once echo fzf)"
```
然后你在 bash 中,输入部分关键字后按 tab就能把匹配的路径列出来
如果你想在 zsh 中使用 fzf 补全,初始化时在 `--init` 后追加 `fzf` 关键字
```zsh
eval "$(lua /path/to/z.lua --init zsh enhanced once echo fzf)"
```
然后你在 bash/zsh 中,输入部分关键字后按 tab就能把匹配的路径列出来
![](images/complete-2.png)

View File

@@ -35,23 +35,24 @@ From people using z.lua:
- 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 and 5.3+
- 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 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
```
@@ -89,7 +90,7 @@ z -b foo # cd to the parent directory starting with foo
eval "$(lua /path/to/z.lua --init zsh)"
Options like "enhanced" and "once" can be used after `--init` too. It can also be initialized from "skywind3000/z.lua" with your zsh plugin managers (antigen / oh-my-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.
@@ -119,6 +120,8 @@ z -b foo # cd to the parent directory starting with foo
- 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" })
@@ -157,7 +160,12 @@ z -b foo # cd to the parent directory starting with foo
- 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 1 to treat hyphon (-) as a normal character not a lua regexp keyword.
- 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
@@ -174,16 +182,12 @@ To z.lua, a directory that has low ranking but has been accessed recently will q
## 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.
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
- cd to a directory ends with foo:
z foo$
- use multiple arguments:
Assuming the following database:
@@ -193,6 +197,15 @@ By default, z.lua uses default matching algorithm similar to the original z.sh.
`"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:
@@ -317,6 +330,7 @@ New option `"-b"` can quickly go back to a specific parent directory in bash ins
- **(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`:
@@ -336,6 +350,11 @@ Let's start by aliasing `z -b` to `zb`:
# 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` ``).
@@ -366,6 +385,12 @@ Bash is not as powerful as zsh/fish, so we introduced fzf-completion for bash, i
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)
@@ -418,6 +443,14 @@ 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -27,6 +27,8 @@ 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

View File

@@ -2,41 +2,45 @@ import time, sys, os
import ranger.api
import subprocess
old_hook_init = ranger.api.hook_init
# $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')
PATH_LUA = os.environ.get('RANGER_LUA')
PATH_ZLUA = os.environ.get('RANGER_ZLUA')
if not PATH_LUA:
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):
PATH_LUA = test
ZLUA_LUAEXE = test
break
if not PATH_LUA:
sys.stderr.write('Please install lua or set $RANGER_LUA.\n')
sys.exit()
def _report_error(msg):
sys.stderr.write('ranger_zlua: ' + msg)
raise RuntimeError(msg)
if (not PATH_ZLUA) or (not os.path.exists(PATH_ZLUA)):
sys.stderr.write('Not find z.lua, please set $RANGER_ZLUA to absolute path of z.lua.\n')
sys.exit()
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([PATH_LUA, PATH_ZLUA, "--add", signal.new.path])
p = subprocess.Popen([ZLUA_LUAEXE, ZLUA_SCRIPT, "--add", signal.new.path])
p.wait()
if PATH_ZLUA and PATH_LUA and os.path.exists(PATH_ZLUA):
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
@@ -52,13 +56,13 @@ class z(ranger.api.commands.Command):
elif arg[:1] != '-':
break
if mode:
cmd = '"%s" "%s" '%(PATH_LUA, PATH_ZLUA)
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([PATH_LUA, PATH_ZLUA, '--cd'] + args)
path = subprocess.check_output([ZLUA_LUAEXE, ZLUA_SCRIPT, '--cd'] + args)
path = path.decode("utf-8", "ignore")
path = path.rstrip('\n')
self.fm.notify(path)
@@ -76,7 +80,7 @@ class z(ranger.api.commands.Command):
if path and os.path.exists(path):
self.fm.cd(path)
else:
path = subprocess.check_output([PATH_LUA, PATH_ZLUA, '--cd'] + args)
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):

12
z.cmd
View File

@@ -1,10 +1,8 @@
@echo off
setlocal EnableDelayedExpansion
set "HomeDir=%~dp0"
set "PathSave=%PATH%"
set "LuaExe=lua"
set "LuaScript=%HomeDir%z.lua"
set "LuaScript=%~dp0z.lua"
set "MatchType=-n"
set "StrictSub=-n"
set "RunMode=-n"
@@ -120,8 +118,12 @@ rem -- Exploits variable expansion and the pushd stack to set the current
rem -- directory without leaking a pushd.
popd
setlocal
set NewPath=%CD%
endlocal & popd & cd /d "%NewPath%"
set "NewPath=%CD%"
set "CDCmd=cd /d"
if /i not "%_ZL_CD%"=="" (
set "CDCmd=%_ZL_CD%"
)
endlocal & popd & %CDCmd% "%NewPath%"
:end
echo.

257
z.lua
View File

@@ -1,10 +1,10 @@
#! /usr/bin/env lua
--=====================================================================
--
-- z.lua - a cd command that learns, by skywind 2018, 2019, 2020, 2021
-- z.lua - a cd command that learns, by skywind 2018-2022
-- Licensed under MIT license.
--
-- Version 1.8.12, Last Modified: 2021/02/15 00:05
-- Version 1.8.17, Last Modified: 2022/09/29 15:47
--
-- * 10x faster than fasd and autojump, 3x faster than z.sh
-- * available for posix shells: bash, zsh, sh, ash, dash, busybox
@@ -12,17 +12,18 @@
-- * compatible with lua 5.1, 5.2 and 5.3+
--
-- USE:
-- * 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 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 -x path # remove path from history
-- * 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 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 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 -x path # remove path from history
-- * 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
--
-- Bash Install:
-- * put something like this in your .bashrc:
@@ -46,11 +47,11 @@
--
-- Fish Shell Install:
-- * put something like this in your config file:
-- source (lua /path/to/z.lua --init fish | psub)
-- lua /path/to/z.lua --init fish | source
--
-- Power Shell Install:
-- * put something like this in your config file:
-- Invoke-Expression (& {
-- Invoke-Expression (& {
-- (lua /path/to/z.lua --init powershell) -join "`n" })
--
-- Windows Install (with Clink):
@@ -126,7 +127,7 @@ Z_CMD = 'z'
Z_MATCHMODE = 0
Z_MATCHNAME = false
Z_SKIPPWD = false
Z_HYPHEN = false
Z_HYPHEN = "auto"
os.LOG_NAME = os.getenv('_ZL_LOG_NAME')
@@ -405,7 +406,7 @@ if os.native.status then
return hr ~= nil and ffi.string(buffer) or nil
end
end
function os.native.tickcount()
function os.native.tickcount()
if windows then
return os.native.GetTickCount()
else
@@ -527,13 +528,16 @@ function os.path.abspath(path)
return test
end
end
for _, python in pairs({'python', 'python2', 'python3'}) do
for _, python in pairs({'python3', 'python2', 'python'}) do
local s = 'sys.stdout.write(os.path.abspath(sys.argv[1]))'
local s = '-c "import os, sys;' .. s .. '" \'' .. path .. '\''
local s = python .. ' ' .. s
local test = os.path.which(python)
if test ~= nil and test ~= '' then
return os.call(s)
test = os.call(s)
if test ~= nil and test ~= '' then
return test
end
end
end
end
@@ -928,8 +932,8 @@ function os.environ(name, default)
end
elseif type(default) == 'number' then
value = tonumber(value)
if value == nil then
return default
if value == nil then
return default
else
return value
end
@@ -1073,6 +1077,7 @@ function data_load(filename)
local item = {}
if part and part[1] and part[2] and part[3] then
local key = insensitive and part[1]:lower() or part[1]
part[2] = part[2]:gsub(",", ".")
item.name = part[1]
item.rank = tonumber(part[2])
item.time = tonumber(part[3]) + 0
@@ -1287,13 +1292,16 @@ end
-----------------------------------------------------------------------
-- select matched pathnames
-----------------------------------------------------------------------
function data_select(M, patterns, matchlast)
-- z_hyphen must be `true`, `false``, or `"auto"`.
function data_select(M, patterns, matchlast, z_hyphen)
local N = {}
local i = 1
local pats = {}
local hyphens = false
for i = 1, #patterns do
local p = patterns[i]
if Z_HYPHEN then
hyphens = hyphens or string.match(p, "%-")
if z_hyphen == true then
p = p:gsub('-', '%%-')
end
table.insert(pats, case_insensitive_pattern(p))
@@ -1304,6 +1312,9 @@ function data_select(M, patterns, matchlast)
table.insert(N, item)
end
end
if (hyphens and z_hyphen == "auto" and #N == 0) then
N = data_select(M, patterns, matchlast, true)
end
return N
end
@@ -1453,10 +1464,10 @@ function z_match(patterns, method, subdir)
method = method ~= nil and method or 'frecent'
subdir = subdir ~= nil and subdir or false
local M = data_load(DATA_FILE)
M = data_select(M, patterns, false)
M = data_select(M, patterns, false, Z_HYPHEN)
M = data_filter(M)
if Z_MATCHNAME then
local N = data_select(M, patterns, true)
local N = data_select(M, patterns, true, Z_HYPHEN)
N = data_filter(N)
if #N > 0 then
M = N
@@ -1631,7 +1642,7 @@ function z_cd(patterns)
elseif Z_INTERACTIVE == 2 then
local fzf = os.environ('_ZL_FZF', 'fzf')
local tmpname = '/tmp/zlua.txt'
local cmd = '--nth 2.. --reverse --inline-info --tac '
local cmd = '--nth 2.. --reverse --info=inline --tac '
local flag = os.environ('_ZL_FZF_FLAG', '')
flag = (flag == '' or flag == nil) and '+s -e' or flag
cmd = ((fzf == '') and 'fzf' or fzf) .. ' ' .. cmd .. ' ' .. flag
@@ -1715,47 +1726,45 @@ function cd_backward(args, options, pwd)
local pwd = (pwd ~= nil) and pwd or os.pwd()
if nargs == 0 then
return find_vcs_root(pwd)
elseif nargs == 1 then
if args[1]:sub(1, 2) == '..' then
local size = args[1]:len() - 1
if args[1]:match('^%.%.+$') then
size = args[1]:len() - 1
elseif args[1]:match('^%.%.%d+$') then
size = tonumber(args[1]:sub(3))
else
return nil
end
local path = pwd
for index = 1, size do
path = os.path.join(path, '..')
end
return os.path.normpath(path)
elseif nargs == 1 and args[1]:sub(1, 2) == '..' then
local size = args[1]:len() - 1
if args[1]:match('^%.%.+$') then
size = args[1]:len() - 1
elseif args[1]:match('^%.%.%d+$') then
size = tonumber(args[1]:sub(3))
else
pwd = os.path.split(pwd)
local test = windows and pwd:gsub('\\', '/') or pwd
local key = windows and args[1]:lower() or args[1]
if not key:match('%u') then
test = test:lower()
end
local pos, ends = test:rfind('/' .. key)
if pos then
ends = test:find('/', pos + key:len() + 1, true)
ends = ends and ends or test:len()
return os.path.normpath(pwd:sub(1, ends))
elseif windows and test:startswith(key) then
ends = test:find('/', key:len(), true)
ends = ends and ends or test:len()
return os.path.normpath(pwd:sub(1, ends))
end
pos = test:rfind(key)
if pos then
ends = test:find('/', pos + key:len(), true)
ends = ends and ends or test:len()
return os.path.normpath(pwd:sub(1, ends))
end
return nil
end
else
local path = pwd
for index = 1, size do
path = os.path.join(path, '..')
end
return os.path.normpath(path)
elseif nargs == 1 then
pwd = os.path.split(pwd)
local test = windows and pwd:gsub('\\', '/') or pwd
local key = windows and args[1]:lower() or args[1]
if not key:match('%u') then
test = test:lower()
end
local pos, ends = test:rfind('/' .. key)
if pos then
ends = test:find('/', pos + key:len() + 1, true)
ends = ends and ends or test:len()
return os.path.normpath(pwd:sub(1, ends))
elseif windows and test:startswith(key) then
ends = test:find('/', key:len(), true)
ends = ends and ends or test:len()
return os.path.normpath(pwd:sub(1, ends))
end
pos = test:rfind(key)
if pos then
ends = test:find('/', pos + key:len(), true)
ends = ends and ends or test:len()
return os.path.normpath(pwd:sub(1, ends))
end
return nil
elseif nargs == 2 then
local test = windows and pwd:gsub('\\', '/') or pwd
local src = args[1]
local dst = args[2]
@@ -1766,10 +1775,25 @@ function cd_backward(args, options, pwd)
if not start then
return pwd
end
local lhs = pwd:sub(1, start - 1)
local rhs = pwd:sub(ends + 1)
return lhs .. dst .. rhs
local newpath = lhs .. dst .. rhs
if os.path.isdir(newpath) then
return newpath
end
-- Get rid of the entire path component that matched `src`.
lhs = lhs:gsub("[^/]*$", "")
rhs = rhs:gsub("^[^/]*", "")
return z_cd({lhs, dst, rhs})
-- In the future, it would make sense to have `z -b -c from to to2`
-- to z_cd({lhs, dst[1], dst[2]}). Without `-c`, we probably still
-- want to support only 2 argumets.
end
io.stderr:write("Error: " .. Z_CMD .. " -b takes at most 2 arguments.\n")
return nil
end
@@ -1852,7 +1876,7 @@ function cd_breadcrumbs(pwd, interactive)
retval = io.read('*l')
elseif interactive == 2 then
local fzf = os.environ('_ZL_FZF', 'fzf')
local cmd = '--reverse --inline-info --tac '
local cmd = '--reverse --info=inline --tac '
local flag = os.environ('_ZL_FZF_FLAG', '')
flag = (flag == '' or flag == nil) and '+s -e' or flag
cmd = ((fzf == '') and 'fzf' or fzf) .. ' ' .. cmd .. ' ' .. flag
@@ -1918,7 +1942,7 @@ function main(argv)
if options['--cd'] or options['-e'] then
local path = ''
if options['-b'] then
if Z_INTERACTIVE == 0 then
if #args > 0 or Z_INTERACTIVE == 0 then
path = cd_backward(args, options)
else
path = cd_breadcrumbs('', Z_INTERACTIVE)
@@ -2049,10 +2073,13 @@ function z_init()
Z_SKIPPWD = true
end
end
assert(Z_HYPHEN == "auto", "Z_HYPHEN initialized to an unexpected value")
if _zl_hyphen ~= nil then
local m = string.lower(_zl_hyphen)
if (m == '1' or m == 'yes' or m == 'true' or m == 't') then
Z_HYPHEN = true
elseif (m == '0' or m == 'no' or m == 'false' or m == 'f') then
Z_HYPHEN = false
end
end
end
@@ -2083,10 +2110,28 @@ function z_clink_init()
end
return {}
end
local dirmatchfunc = function (word)
clink.matches_are_files(1)
return clink.match_files(word..'*', true, clink.find_dirs)
end
local dirmatchparser = clink.arg.new_parser():set_arguments({ dirmatchfunc })
local z_parser = clink.arg.new_parser()
z_parser:set_arguments({ z_match_completion })
z_parser:set_flags("-c", "-r", "-i", "--cd", "-e", "-b", "--add", "-x", "--purge",
"--init", "-l", "-s", "--complete", "--help", "-h")
z_parser:set_flags("-r", "-i", "-I", "-t", "-l", "-c", "-e", "-b", "-x"..dirmatchparser, "-h")
if z_parser.adddescriptions then
z_parser:adddescriptions({
['-r'] = "cd to highest ranked dir matching",
['-i'] = "cd with interactive selection",
['-I'] = "cd with interactive selection using fzf",
['-t'] = "cd to most recently accessed dir matching",
['-l'] = "list matches instead of cd",
['-c'] = "restrict matches to subdirs of cwd (or %PWD% if set)",
['-e'] = "echo the best match, don't cd",
['-b'] = "jump backwards to given dir or to project root",
['-x'] = { " dir", "remove path from history" },
['-h'] = "show help",
})
end
clink.arg.register_parser("z", z_parser)
end
@@ -2244,6 +2289,31 @@ _zlua_zsh_tab_completion() {
}
if [ "${+functions[compdef]}" -ne 0 ]; then
compdef _zlua_zsh_tab_completion _zlua 2> /dev/null
compdef ${_ZL_CMD:-z}=_zlua
fi
]]
local script_fzf_complete_zsh = [[
if command -v fzf >/dev/null 2>&1; then
# To redraw line after fzf closes (printf '\e[5n')
bindkey '\e[0n' kill-whole-line
_zlua_zsh_fzf_complete() {
local list=$(_zlua -l ${words[2,-1]})
if [ -n "$list" ]; then
local selected=$(print $list | ${=zlua_fzf} | sed 's/^[0-9,.]* *//')
if [ -n "$selected" ]; then
cd ${selected}
printf '\e[5n'
fi
fi
}
if [ "${+functions[compdef]}" -ne 0 ]; then
compdef _zlua_zsh_fzf_complete _zlua > /dev/null 2>&1
compdef ${_ZL_CMD:-z}=_zlua
fi
fi
]]
@@ -2284,7 +2354,7 @@ function z_shell_init(opts)
end
print(script_complete_bash)
if opts.fzf ~= nil then
fzf_cmd = "fzf --nth 2.. --reverse --inline-info --tac "
local fzf_cmd = "fzf --nth 2.. --reverse --info=inline --tac "
local height = os.environ('_ZL_FZF_HEIGHT', '35%')
if height ~= nil and height ~= '' and height ~= '0' then
fzf_cmd = fzf_cmd .. ' --height ' .. height .. ' '
@@ -2300,6 +2370,18 @@ function z_shell_init(opts)
print(once and script_init_zsh_once or script_init_zsh)
end
print(script_complete_zsh)
if opts.fzf ~= nil then
local fzf_cmd = "fzf --nth 2.. --reverse --info=inline --tac "
local height = os.environ('_ZL_FZF_HEIGHT', '35%')
if height ~= nil and height ~= '' and height ~= '0' then
fzf_cmd = fzf_cmd .. ' --height ' .. height .. ' '
end
local flag = os.environ('_ZL_FZF_FLAG', '')
flag = (flag == '' or flag == nil) and '+s -e' or flag
fzf_cmd = fzf_cmd .. ' ' .. flag .. ' '
print('zlua_fzf="' .. fzf_cmd .. '"')
print(script_fzf_complete_zsh)
end
elseif opts.posix ~= nil then
if prompt_hook then
local script = script_init_posix
@@ -2404,7 +2486,9 @@ function _zlua
end
if test -z "$_ZL_CMD"; set -x _ZL_CMD z; end
alias "$_ZL_CMD"=_zlua
function $_ZL_CMD -w _zlua -d "alias $_ZL_CMD=_zlua"
_zlua $argv
end
]]
script_init_fish = [[
@@ -2563,7 +2647,11 @@ goto end
popd
setlocal
set "NewPath=%CD%"
endlocal & popd & cd /d "%NewPath%"
set "CDCmd=cd /d"
if /i not "%_ZL_CD%"=="" (
set "CDCmd=%_ZL_CD%"
)
endlocal & popd & %CDCmd% "%NewPath%"
:end
]]
@@ -2693,17 +2781,18 @@ end
-----------------------------------------------------------------------
function z_help()
local cmd = Z_CMD .. ' '
print(cmd .. 'foo # cd to most frecent dir matching foo')
print(cmd .. 'foo bar # cd to most frecent dir matching foo and bar')
print(cmd .. '-r foo # cd to highest ranked dir matching foo')
print(cmd .. '-t foo # cd to most recently accessed dir matching foo')
print(cmd .. '-l foo # list matches instead of cd')
print(cmd .. '-c foo # restrict matches to subdirs of $PWD')
print(cmd .. '-e foo # echo the best match, don\'t cd')
print(cmd .. '-x path # remove path from history')
print(cmd .. '-i foo # cd with interactive selection')
print(cmd .. '-I foo # cd with interactive selection using fzf')
print(cmd .. '-b foo # cd to the parent directory starting with foo')
print(cmd .. 'foo # cd to most frecent dir matching foo')
print(cmd .. 'foo bar # cd to most frecent dir matching foo and bar')
print(cmd .. '-r foo # cd to highest ranked dir matching foo')
print(cmd .. '-t foo # cd to most recently accessed dir matching foo')
print(cmd .. '-l foo # list matches instead of cd')
print(cmd .. '-c foo # restrict matches to subdirs of $PWD')
print(cmd .. '-e foo # echo the best match, don\'t cd')
print(cmd .. '-x path # remove path from history')
print(cmd .. '-i foo # cd with interactive selection')
print(cmd .. '-I foo # cd with interactive selection using fzf')
print(cmd .. '-b foo # cd to the parent directory starting with foo')
print(cmd .. '-b foo bar # replace foo with bar in cwd and cd there')
end
@@ -2724,7 +2813,7 @@ if os.lfs.enable ~= nil then
end
os.path.isdir = function (name)
local mode = lfs.attributes(name)
if not mode then
if not mode then
return false
end
return (mode.mode == 'directory') and true or false

View File

@@ -2,11 +2,14 @@
ZLUA_SCRIPT="${0:A:h}/z.lua"
[[ -n "$ZLUA_EXEC" ]] && [[ ! -x "$ZLUA_EXEC" ]] && ZLUA_EXEC=""
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 lua5.3 lua5.2 lua5.1; do
for lua in lua luajit lua5.4 lua5.3 lua5.2 lua5.1; do
ZLUA_EXEC="$(command -v "$lua")"
[[ -n "$ZLUA_EXEC" ]] && break
done
@@ -18,7 +21,11 @@ fi
export _ZL_FZF_FLAG=${_ZL_FZF_FLAG:-"-e"}
eval "$($ZLUA_EXEC $ZLUA_SCRIPT --init zsh once enhanced)"
if [[ -z "$_ZL_ZSH_NO_FZF" ]]; then
eval "$($ZLUA_EXEC $ZLUA_SCRIPT --init zsh once enhanced)"
else
eval "$($ZLUA_EXEC $ZLUA_SCRIPT --init zsh once enhanced fzf)"
fi
if [[ -z "$_ZL_NO_ALIASES" ]]; then
alias zz='z -i'