mirror of
https://github.com/skywind3000/z.lua
synced 2026-03-15 12:19:49 +00:00
Merge pull request #170 from ilyagr/fuzzy-zb
Allow `z -b` to do fuzzy matching
This commit is contained in:
42
README.md
42
README.md
@@ -42,16 +42,17 @@ 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
|
||||
```
|
||||
|
||||
|
||||
@@ -176,16 +177,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 +192,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 +325,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 +345,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` ``).
|
||||
|
||||
141
z.lua
141
z.lua
@@ -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,7 +47,7 @@
|
||||
--
|
||||
-- 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:
|
||||
@@ -1719,47 +1720,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]
|
||||
@@ -1770,10 +1769,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
|
||||
|
||||
|
||||
@@ -1922,7 +1936,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)
|
||||
@@ -2701,17 +2715,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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user