-
Notifications
You must be signed in to change notification settings - Fork 6
/
zoxide.lua
171 lines (145 loc) · 4.85 KB
/
zoxide.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
-- =============================================================================
--
-- Settings copied from 'zoxide init'. Run `clink set` to modify these options, e.g. `clink set zoxide.cmd f`
--
settings.add('zoxide.cmd', 'z', 'Changes the prefix of the aliases')
settings.add('zoxide.hook', { 'pwd', 'prompt', 'none' }, 'Changes when directory scores are incremented')
settings.add('zoxide.no_aliases', false, "Don't define aliases")
settings.add('zoxide.usepromptfilter', false, "Use clink promptfilter to hook even if onbeginedit is supported")
settings.add('zoxide.promptfilter_prio', -50, "Changes the priority of the promptfilter hook (only if usepromptfilter is true)")
-- =============================================================================
--
-- Utility functions for zoxide.
--
-- Generate `cd` command
local function __zoxide_cd(dir)
if os.getenv '_ZO_ECHO' == '1' then
print(dir)
end
-- 'cd /d -' doesn't work for clink versions before v1.2.41 (https://github.com/chrisant996/clink/issues/191)
-- lastest cmder release (v1.3.18) uses clink v1.1.45
if dir == '-' and (clink.version_encoded or 0) < 10020042 then
return 'cd -'
end
return 'cd /d ' .. dir
end
-- Run `zoxide query` and generate `cd` command from result
local function __zoxide_query(options, keywords)
options = table.concat(options, ' ')
keywords = table.concat(keywords, ' ')
local file = io.popen('zoxide query ' .. options .. ' -- ' .. keywords)
local result = file:read '*line'
local ok = file:close()
if ok then
return __zoxide_cd(result)
else
return 'call' -- no-op that just sets %ERRORLEVEL% to 1
end
end
-- Add directory to the database.
local function __zoxide_add(dir)
os.execute('zoxide add -- "' .. dir:gsub('^(.-)\\*$', '%1') .. '"')
end
-- =============================================================================
--
-- Hook configuration for zoxide.
--
local __usepromptfilter = settings.get 'zoxide.usepromptfilter'
if not clink.onbeginedit then
__usepromptfilter = true
end
local __zoxide_oldpwd
function __zoxide_hook()
local zoxide_hook = settings.get 'zoxide.hook'
if zoxide_hook == 'none' then
-- do nothing
return
elseif zoxide_hook == 'prompt' then
-- run `zoxide add` on every prompt
__zoxide_add(os.getcwd())
elseif zoxide_hook == 'pwd' then
-- run `zoxide add` when the working directory changes
local cwd = os.getcwd()
if __zoxide_oldpwd and __zoxide_oldpwd ~= cwd then
__zoxide_add(cwd)
end
__zoxide_oldpwd = cwd
end
end
if __usepromptfilter then
local __promptfilter_prio = settings.get 'zoxide.promptfilter_prio'
local __zoxide_prompt = clink.promptfilter(__promptfilter_prio)
function __zoxide_prompt:filter()
__zoxide_hook()
end
else
clink.onbeginedit(__zoxide_hook)
end
-- =============================================================================
--
-- Define aliases.
--
-- 'z' alias
local function __zoxide_z(keywords)
if #keywords == 0 then
-- NOTE: `os.getenv("HOME")` returns HOME or HOMEDRIVE+HOMEPATH
-- or USERPROFILE.
return __zoxide_cd(os.getenv('HOME'))
elseif #keywords == 1 then
local keyword = keywords[1]
if keyword == '-' then
return __zoxide_cd '-'
elseif os.isdir(keyword) then
return __zoxide_cd(keyword)
end
end
local cwd = '"' .. os.getcwd() .. '"'
return __zoxide_query({ '--exclude', cwd }, keywords)
end
-- 'zi' alias
local function __zoxide_zi(keywords)
return __zoxide_query({ '--interactive' }, keywords)
end
-- =============================================================================
--
-- Clink input text filter.
--
local function onfilterinput(text)
args = string.explode(text, ' ', '"')
if #args == 0 then
return
end
-- settings
zoxide_cmd = settings.get 'zoxide.cmd'
zoxide_no_aliases = settings.get 'zoxide.no_aliases'
-- edge case:
-- * zoxide command prefix is 'cd'
-- * clink converted 'cd -' -> 'cd /d "some_directory"'
local cd_regex = '^%s*cd%s+/d%s+"(.-)"%s*$'
if zoxide_cmd == 'cd' and text:match(cd_regex) then
if zoxide_no_aliases then
-- clink handles it
return
else
-- zoxide handles it
return __zoxide_cd(text:gsub(cd_regex, '%1')), false
end
end
local cmd = table.remove(args, 1)
if cmd == '__zoxide_z' or (cmd == zoxide_cmd and not zoxide_no_aliases) then
return __zoxide_z(args), false
elseif cmd == '__zoxide_zi' or (cmd == zoxide_cmd .. 'i' and not zoxide_no_aliases) then
return __zoxide_zi(args), false
else
return
end
end
if clink.onfilterinput then
clink.onfilterinput(onfilterinput)
else
clink.onendedit(onfilterinput)
end
-- =============================================================================
--
-- To initalize zoxide, add this script to one of clink's lua script locations (e.g. zoxide.lua)
-- (see https://chrisant996.github.io/clink/clink.html#location-of-lua-scripts)