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

31 Commits

Author SHA1 Message Date
Linwei
ef9a49d73d Merge pull request #158 from ibayramli/fig
Add Fig as an installation method to the README
2024-03-20 22:19:26 +08:00
skywind3000
7cd399b30d bloat version 2024-03-20 22:17:58 +08:00
Linwei
9112f0e9cc Merge pull request #189 from Arkaeriit/fix_pipes_in_filenames
Support '|' in path
2024-03-20 22:13:57 +08:00
Maxime Bouillot
cb4c9d3c8f Revert back to the old separator and improve db reading
A smarter reading function lets us support '|' in
filenames whilst still using it as the database
separator.
2024-03-20 14:38:04 +01:00
Maxime Bouillot
924f61a48b Change separator in data file
Using '|' as the data separator caused crashes if
a path with a '|' char in it was in the data file.
Changing that separator to a null byte ensures
that this kind of issue can never happen again as
the null byte can't be in a path.
2024-03-06 14:52:16 +01:00
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
Ilkin Bayramli
4c05e0d911 Add Fig as an installation method to the README 2022-06-15 10:12:16 -07:00
7 changed files with 275 additions and 120 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

@@ -42,21 +42,31 @@ From people using z.lua:
## 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
```
## Install
- Fig (works with all shells)
[Fig](https://fig.io) adds apps, shortcuts, and autocomplete to your existing terminal.
Install `z.lua` in just one click.
<a href="https://fig.io/plugins/other/z.lua" target="_blank"><img src="https://fig.io/badges/install-with-fig.svg" /></a>
- Bash:
put something like this in your `.bashrc`:
@@ -89,7 +99,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.
@@ -159,7 +169,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
@@ -176,16 +191,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:
@@ -195,6 +206,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:
@@ -319,6 +339,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`:
@@ -338,6 +359,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` ``).
@@ -368,6 +394,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)
@@ -420,6 +452,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

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):

4
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"

263
z.lua
View File

@@ -4,7 +4,7 @@
-- z.lua - a cd command that learns, by skywind 2018-2022
-- Licensed under MIT license.
--
-- Version 1.8.16, Last Modified: 2022/07/21 22:12
-- Version 1.8.18, Last Modified: 2024/03/20 22:17
--
-- * 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,8 @@ Z_CMD = 'z'
Z_MATCHMODE = 0
Z_MATCHNAME = false
Z_SKIPPWD = false
Z_HYPHEN = false
Z_HYPHEN = "auto"
Z_DATA_SEPARATOR = "|"
os.LOG_NAME = os.getenv('_ZL_LOG_NAME')
@@ -405,7 +407,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
@@ -931,8 +933,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
@@ -1060,6 +1062,26 @@ function path_case_insensitive()
end
-----------------------------------------------------------------------
-- Read a line of the database and return a list of the 3 fields in it
-----------------------------------------------------------------------
function read_data_line(line)
local part = string.split(line, Z_DATA_SEPARATOR)
if #part <= 3 then
return part
end
-- If the part is made of more than 3 elements, it's probably because the
-- path element contains '|' that have been split. Thus, we want to
-- reconstruct it and keep the 2 last elements of part intact as the end
-- of the returned part.
local path = part[1]
for i=2,#part-2 do
path = path .. Z_DATA_SEPARATOR .. part[i]
end
return {path, part[#part-1], part[#part]}
end
-----------------------------------------------------------------------
-- load and split data
-----------------------------------------------------------------------
@@ -1072,10 +1094,11 @@ function data_load(filename)
return {}
end
for line in fp:lines() do
local part = string.split(line, '|')
local part = read_data_line(line)
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
@@ -1133,7 +1156,7 @@ function data_save(filename, M)
end
for i = 1, #M do
local item = M[i]
local text = item.name .. '|' .. item.rank .. '|' .. item.time
local text = item.name .. Z_DATA_SEPARATOR .. item.rank .. Z_DATA_SEPARATOR .. item.time
fp:write(text .. '\n')
end
fp:close()
@@ -1290,13 +1313,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))
@@ -1307,6 +1333,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
@@ -1456,10 +1485,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
@@ -1718,47 +1747,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]
@@ -1769,10 +1796,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
@@ -1921,7 +1963,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)
@@ -2052,10 +2094,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
@@ -2086,10 +2131,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
@@ -2247,6 +2310,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
]]
@@ -2287,7 +2375,7 @@ function z_shell_init(opts)
end
print(script_complete_bash)
if opts.fzf ~= nil then
fzf_cmd = "fzf --nth 2.. --reverse --info=inline --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 .. ' '
@@ -2303,6 +2391,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
@@ -2407,7 +2507,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 = [[
@@ -2700,17 +2802,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
@@ -2731,7 +2834,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

@@ -21,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'