first commit
This commit is contained in:
21
yazi/plugins/yamb.yazi/LICENSE
Normal file
21
yazi/plugins/yamb.yazi/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Hunter Hwang
|
||||
|
||||
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.
|
||||
112
yazi/plugins/yamb.yazi/README.md
Normal file
112
yazi/plugins/yamb.yazi/README.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Yet another bookmarks
|
||||
|
||||
A [Yazi](https://github.com/sxyazi/yazi) plugin for bookmark management, supporting the following features
|
||||
|
||||
- Persistent bookmarks. No bookmarks are lost after you close yazi.
|
||||
- Quickly jump, delete, and rename a bookmark by keymap.
|
||||
- Support fuzzy search through [fzf](https://github.com/junegunn/fzf).
|
||||
- Configure your bookmarks using Lua language.
|
||||
|
||||
## Installation
|
||||
|
||||
> [!NOTE]
|
||||
> Yazi >= 0.25.
|
||||
|
||||
```sh
|
||||
# Linux/macOS
|
||||
git clone https://github.com/h-hg/yamb.yazi.git ~/.config/yazi/plugins/yamb.yazi
|
||||
|
||||
# Windows
|
||||
git clone https://github.com/h-hg/yamb.yazi.git $env:APPDATA\yazi\config\plugins\yamb.yazi
|
||||
|
||||
# if you are using Yazi version >= 3.0
|
||||
ya pack -a h-hg/yamb
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `init.lua`
|
||||
|
||||
```lua
|
||||
-- You can configure your bookmarks by lua language
|
||||
local bookmarks = {}
|
||||
|
||||
local path_sep = package.config:sub(1, 1)
|
||||
local home_path = ya.target_family() == "windows" and os.getenv("USERPROFILE") or os.getenv("HOME")
|
||||
if ya.target_family() == "windows" then
|
||||
table.insert(bookmarks, {
|
||||
tag = "Scoop Local",
|
||||
|
||||
path = (os.getenv("SCOOP") or home_path .. "\\scoop") .. "\\",
|
||||
key = "p"
|
||||
})
|
||||
table.insert(bookmarks, {
|
||||
tag = "Scoop Global",
|
||||
path = (os.getenv("SCOOP_GLOBAL") or "C:\\ProgramData\\scoop") .. "\\",
|
||||
key = "P"
|
||||
})
|
||||
end
|
||||
table.insert(bookmarks, {
|
||||
tag = "Desktop",
|
||||
path = home_path .. path_sep .. "Desktop" .. path_sep,
|
||||
key = "d"
|
||||
})
|
||||
|
||||
require("yamb"):setup {
|
||||
-- Optional, the path ending with path seperator represents folder.
|
||||
bookmarks = bookmarks,
|
||||
-- Optional, recieve notification everytime you jump.
|
||||
jump_notify = true,
|
||||
-- Optional, the cli of fzf.
|
||||
cli = "fzf",
|
||||
-- Optional, a string used for randomly generating keys, where the preceding characters have higher priority.
|
||||
keys = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
-- Optional, the path of bookmarks
|
||||
path = (ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") or
|
||||
(os.getenv("HOME") .. "/.config/yazi/bookmark"),
|
||||
}
|
||||
```
|
||||
|
||||
Add this to your `keymap.toml`:
|
||||
|
||||
```toml
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "u", "a" ]
|
||||
run = "plugin yamb save"
|
||||
desc = "Add bookmark"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "u", "g" ]
|
||||
run = "plugin yamb jump_by_key"
|
||||
desc = "Jump bookmark by key"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "u", "G" ]
|
||||
run = "plugin yamb jump_by_fzf"
|
||||
desc = "Jump bookmark by fzf"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "u", "d" ]
|
||||
run = "plugin yamb delete_by_key"
|
||||
desc = "Delete bookmark by key"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "u", "D" ]
|
||||
run = "plugin yamb delete_by_fzf"
|
||||
desc = "Delete bookmark by fzf"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "u", "A" ]
|
||||
run = "plugin yamb delete_all"
|
||||
desc = "Delete all bookmarks"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "u", "r" ]
|
||||
run = "plugin yamb rename_by_key"
|
||||
desc = "Rename bookmark by key"
|
||||
|
||||
[[manager.prepend_keymap]]
|
||||
on = [ "u", "R" ]
|
||||
run = "plugin yamb rename_by_fzf"
|
||||
desc = "Rename bookmark by fzf"
|
||||
```
|
||||
355
yazi/plugins/yamb.yazi/main.lua
Normal file
355
yazi/plugins/yamb.yazi/main.lua
Normal file
@@ -0,0 +1,355 @@
|
||||
local path_sep = package.config:sub(1, 1)
|
||||
|
||||
local get_hovered_path = ya.sync(function(state)
|
||||
local h = cx.active.current.hovered
|
||||
if h then
|
||||
local path = tostring(h.url)
|
||||
if h.cha.is_dir then
|
||||
return path .. path_sep
|
||||
end
|
||||
return path
|
||||
else
|
||||
return ''
|
||||
end
|
||||
end)
|
||||
|
||||
local get_state_attr = ya.sync(function(state, attr)
|
||||
return state[attr]
|
||||
end)
|
||||
|
||||
local set_state_attr = ya.sync(function(state, attr, value)
|
||||
state[attr] = value
|
||||
end)
|
||||
|
||||
local set_bookmarks = ya.sync(function(state, path, value)
|
||||
state.bookmarks[path] = value
|
||||
end)
|
||||
|
||||
local sort_bookmarks = function(bookmarks, key1, key2, reverse)
|
||||
reverse = reverse or false
|
||||
table.sort(bookmarks, function(x, y)
|
||||
if x[key1] == nil and y[key1] == nil then
|
||||
return x[key2] < y[key2]
|
||||
elseif x[key1] == nil then
|
||||
return false
|
||||
elseif y[key1] == nil then
|
||||
return true
|
||||
else
|
||||
return x[key1] < y[key1]
|
||||
end
|
||||
end)
|
||||
if reverse then
|
||||
local n = #bookmarks
|
||||
for i = 1, math.floor(n / 2) do
|
||||
bookmarks[i], bookmarks[n - i + 1] = bookmarks[n - i + 1], bookmarks[i]
|
||||
end
|
||||
end
|
||||
return bookmarks
|
||||
end
|
||||
|
||||
local save_to_file = function(mb_path, bookmarks)
|
||||
local file = io.open(mb_path, "w")
|
||||
if file == nil then
|
||||
return
|
||||
end
|
||||
local array = {}
|
||||
for _, item in pairs(bookmarks) do
|
||||
table.insert(array, item)
|
||||
end
|
||||
sort_bookmarks(array, "tag", "key", true)
|
||||
for _, item in ipairs(array) do
|
||||
file:write(string.format("%s\t%s\t%s\n", item.tag, item.path, item.key))
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
local fzf_find = function(cli, mb_path)
|
||||
local permit = ya.hide()
|
||||
local cmd = string.format("%s < \"%s\"", cli, mb_path)
|
||||
local handle = io.popen(cmd, "r")
|
||||
local result = ""
|
||||
if handle then
|
||||
-- strip
|
||||
result = string.gsub(handle:read("*all") or "", "^%s*(.-)%s*$", "%1")
|
||||
handle:close()
|
||||
end
|
||||
permit:drop()
|
||||
local tag, path, key = string.match(result or "", "(.-)\t(.-)\t(.*)")
|
||||
return path
|
||||
end
|
||||
|
||||
local which_find = function(bookmarks)
|
||||
local cands = {}
|
||||
for path, item in pairs(bookmarks) do
|
||||
if #item.tag ~= 0 then
|
||||
table.insert(cands, { desc = item.tag, on = item.key, path = item.path })
|
||||
end
|
||||
end
|
||||
sort_bookmarks(cands, "on", "desc", false)
|
||||
if #cands == 0 then
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Empty bookmarks",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
return nil
|
||||
end
|
||||
local idx = ya.which { cands = cands }
|
||||
if idx == nil then
|
||||
return nil
|
||||
end
|
||||
return cands[idx].path
|
||||
end
|
||||
|
||||
local action_jump = function(bookmarks, path, jump_notify)
|
||||
if path == nil then
|
||||
return
|
||||
end
|
||||
local tag = bookmarks[path].tag
|
||||
if string.sub(path, -1) == path_sep then
|
||||
ya.manager_emit("cd", { path })
|
||||
else
|
||||
ya.manager_emit("reveal", { path })
|
||||
end
|
||||
if jump_notify then
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = 'Jump to "' .. tag .. '"',
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local generate_key = function(bookmarks)
|
||||
local keys = get_state_attr("keys")
|
||||
local key2rank = get_state_attr("key2rank")
|
||||
local mb = {}
|
||||
for _, item in pairs(bookmarks) do
|
||||
if #item.key == 1 then
|
||||
table.insert(mb, item.key)
|
||||
end
|
||||
end
|
||||
if #mb == 0 then
|
||||
return keys[1]
|
||||
end
|
||||
table.sort(mb, function(a, b)
|
||||
return key2rank[a] < key2rank[b]
|
||||
end)
|
||||
local idx = 1
|
||||
for _, key in ipairs(keys) do
|
||||
if idx > #mb or key2rank[key] < key2rank[mb[idx]] then
|
||||
return key
|
||||
end
|
||||
idx = idx + 1
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local action_save = function(mb_path, bookmarks, path)
|
||||
if path == nil or #path == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local path_obj = bookmarks[path]
|
||||
-- check tag
|
||||
local tag = path_obj and path_obj.tag or path:match(".*[\\/]([^\\/]+)[\\/]?$")
|
||||
while true do
|
||||
local value, event = ya.input({
|
||||
title = "Tag (alias name)",
|
||||
value = tag,
|
||||
position = { "top-center", y = 3, w = 40 },
|
||||
})
|
||||
if event ~= 1 then
|
||||
return
|
||||
end
|
||||
tag = value or ''
|
||||
if #tag == 0 then
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Empty tag",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
else
|
||||
-- check the tag
|
||||
local tag_obj = nil
|
||||
for _, item in pairs(bookmarks) do
|
||||
if item.tag == tag then
|
||||
tag_obj = item
|
||||
break
|
||||
end
|
||||
end
|
||||
if tag_obj == nil or tag_obj.path == path then
|
||||
break
|
||||
end
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Duplicated tag",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
end
|
||||
-- check key
|
||||
local key = path_obj and path_obj.key or generate_key(bookmarks)
|
||||
while true do
|
||||
local value, event = ya.input({
|
||||
title = "Key (1 character, optional)",
|
||||
value = key,
|
||||
position = { "top-center", y = 3, w = 40 },
|
||||
})
|
||||
if event ~= 1 then
|
||||
return
|
||||
end
|
||||
key = value or ""
|
||||
if key == "" then
|
||||
key = ""
|
||||
break
|
||||
elseif #key == 1 then
|
||||
-- check the key
|
||||
local key_obj = nil
|
||||
for _, item in pairs(bookmarks) do
|
||||
if item.key == key then
|
||||
key_obj = item
|
||||
break
|
||||
end
|
||||
end
|
||||
if key_obj == nil or key_obj.path == path then
|
||||
break
|
||||
else
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Duplicated key",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
else
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "The length of key shoule be 1",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
end
|
||||
-- save
|
||||
set_bookmarks(path, { tag = tag, path = path, key = key })
|
||||
bookmarks = get_state_attr("bookmarks")
|
||||
save_to_file(mb_path, bookmarks)
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = '"' .. tag .. '" saved"',
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
|
||||
local action_delete = function(mb_path, bookmarks, path)
|
||||
if path == nil then
|
||||
return
|
||||
end
|
||||
local tag = bookmarks[path].tag
|
||||
set_bookmarks(path, nil)
|
||||
bookmarks = get_state_attr("bookmarks")
|
||||
save_to_file(mb_path, bookmarks)
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = '"' .. tag .. '" deleted',
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
|
||||
local action_delete_all = function(mb_path)
|
||||
local value, event = ya.input({
|
||||
title = "Delete all bookmarks? (y/n)",
|
||||
position = { "top-center", y = 3, w = 40 },
|
||||
})
|
||||
if event ~= 1 then
|
||||
return
|
||||
end
|
||||
if string.lower(value) == "y" then
|
||||
set_state_attr("bookmarks", {})
|
||||
save_to_file(mb_path, {})
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "All bookmarks deleted",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
else
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Cancel delete",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
setup = function(state, options)
|
||||
state.path = options.path or
|
||||
(ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") or
|
||||
(os.getenv("HOME") .. "/.config/yazi/bookmark")
|
||||
state.cli = options.cli or "fzf"
|
||||
state.jump_notify = options.jump_notify and true
|
||||
-- init the keys
|
||||
local keys = options.keys or "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
state.keys = {}
|
||||
state.key2rank = {}
|
||||
for i = 1, #keys do
|
||||
local char = keys:sub(i, i)
|
||||
table.insert(state.keys, char)
|
||||
state.key2rank[char] = i
|
||||
end
|
||||
|
||||
-- init the bookmarks
|
||||
local bookmarks = {}
|
||||
for _, item in pairs(options.bookmarks or {}) do
|
||||
bookmarks[item.path] = { tag = item.tag, path = item.path, key = item.key }
|
||||
end
|
||||
-- load the config
|
||||
local file = io.open(state.path, "r")
|
||||
if file ~= nil then
|
||||
for line in file:lines() do
|
||||
local tag, path, key = string.match(line, "(.-)\t(.-)\t(.*)")
|
||||
if tag and path then
|
||||
key = key or ""
|
||||
bookmarks[path] = { tag = tag, path = path, key = key }
|
||||
end
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
-- create bookmarks file to enable fzf
|
||||
save_to_file(state.path, bookmarks)
|
||||
state.bookmarks = bookmarks
|
||||
end,
|
||||
entry = function(self, jobs)
|
||||
local action = jobs.args[1]
|
||||
if not action then
|
||||
return
|
||||
end
|
||||
local mb_path, cli, bookmarks, jump_notify = get_state_attr("path"), get_state_attr("cli"), get_state_attr("bookmarks"), get_state_attr("jump_notify")
|
||||
if action == "save" then
|
||||
action_save(mb_path, bookmarks, get_hovered_path())
|
||||
elseif action == "delete_by_key" then
|
||||
action_delete(mb_path, bookmarks, which_find(bookmarks))
|
||||
elseif action == "delete_by_fzf" then
|
||||
action_delete(mb_path, bookmarks, fzf_find(cli, mb_path))
|
||||
elseif action == "delete_all" then
|
||||
action_delete_all(mb_path)
|
||||
elseif action == "jump_by_key" then
|
||||
action_jump(bookmarks, which_find(bookmarks), jump_notify)
|
||||
elseif action == "jump_by_fzf" then
|
||||
action_jump(bookmarks, fzf_find(cli, mb_path), jump_notify)
|
||||
elseif action == "rename_by_key" then
|
||||
action_save(mb_path, bookmarks, which_find(bookmarks))
|
||||
elseif action == "rename_by_fzf" then
|
||||
action_save(mb_path, bookmarks, fzf_find(cli, mb_path))
|
||||
end
|
||||
end,
|
||||
}
|
||||
355
yazi/plugins/yamb.yazi/main.lua.bak
Executable file
355
yazi/plugins/yamb.yazi/main.lua.bak
Executable file
@@ -0,0 +1,355 @@
|
||||
local path_sep = package.config:sub(1, 1)
|
||||
|
||||
local get_hovered_path = ya.sync(function(state)
|
||||
local h = cx.active.current.hovered
|
||||
if h then
|
||||
local path = tostring(h.url)
|
||||
if h.cha.is_dir then
|
||||
return path .. path_sep
|
||||
end
|
||||
return path
|
||||
else
|
||||
return ''
|
||||
end
|
||||
end)
|
||||
|
||||
local get_state_attr = ya.sync(function(state, attr)
|
||||
return state[attr]
|
||||
end)
|
||||
|
||||
local set_state_attr = ya.sync(function(state, attr, value)
|
||||
state[attr] = value
|
||||
end)
|
||||
|
||||
local set_bookmarks = ya.sync(function(state, path, value)
|
||||
state.bookmarks[path] = value
|
||||
end)
|
||||
|
||||
local sort_bookmarks = function(bookmarks, key1, key2, reverse)
|
||||
reverse = reverse or false
|
||||
table.sort(bookmarks, function(x, y)
|
||||
if x[key1] == nil and y[key1] == nil then
|
||||
return x[key2] < y[key2]
|
||||
elseif x[key1] == nil then
|
||||
return false
|
||||
elseif y[key1] == nil then
|
||||
return true
|
||||
else
|
||||
return x[key1] < y[key1]
|
||||
end
|
||||
end)
|
||||
if reverse then
|
||||
local n = #bookmarks
|
||||
for i = 1, math.floor(n / 2) do
|
||||
bookmarks[i], bookmarks[n - i + 1] = bookmarks[n - i + 1], bookmarks[i]
|
||||
end
|
||||
end
|
||||
return bookmarks
|
||||
end
|
||||
|
||||
local save_to_file = function(mb_path, bookmarks)
|
||||
local file = io.open(mb_path, "w")
|
||||
if file == nil then
|
||||
return
|
||||
end
|
||||
local array = {}
|
||||
for _, item in pairs(bookmarks) do
|
||||
table.insert(array, item)
|
||||
end
|
||||
sort_bookmarks(array, "tag", "key", true)
|
||||
for _, item in ipairs(array) do
|
||||
file:write(string.format("%s\t%s\t%s\n", item.tag, item.path, item.key))
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
local fzf_find = function(cli, mb_path)
|
||||
local permit = ya.hide()
|
||||
local cmd = string.format("%s < \"%s\"", cli, mb_path)
|
||||
local handle = io.popen(cmd, "r")
|
||||
local result = ""
|
||||
if handle then
|
||||
-- strip
|
||||
result = string.gsub(handle:read("*all") or "", "^%s*(.-)%s*$", "%1")
|
||||
handle:close()
|
||||
end
|
||||
permit:drop()
|
||||
local tag, path, key = string.match(result or "", "(.-)\t(.-)\t(.*)")
|
||||
return path
|
||||
end
|
||||
|
||||
local which_find = function(bookmarks)
|
||||
local cands = {}
|
||||
for path, item in pairs(bookmarks) do
|
||||
if #item.tag ~= 0 then
|
||||
table.insert(cands, { desc = item.tag, on = item.key, path = item.path })
|
||||
end
|
||||
end
|
||||
sort_bookmarks(cands, "on", "desc", false)
|
||||
if #cands == 0 then
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Empty bookmarks",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
return nil
|
||||
end
|
||||
local idx = ya.which { cands = cands }
|
||||
if idx == nil then
|
||||
return nil
|
||||
end
|
||||
return cands[idx].path
|
||||
end
|
||||
|
||||
local action_jump = function(bookmarks, path, jump_notify)
|
||||
if path == nil then
|
||||
return
|
||||
end
|
||||
local tag = bookmarks[path].tag
|
||||
if string.sub(path, -1) == path_sep then
|
||||
ya.manager_emit("cd", { path })
|
||||
else
|
||||
ya.manager_emit("reveal", { path })
|
||||
end
|
||||
if jump_notify then
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = 'Jump to "' .. tag .. '"',
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local generate_key = function(bookmarks)
|
||||
local keys = get_state_attr("keys")
|
||||
local key2rank = get_state_attr("key2rank")
|
||||
local mb = {}
|
||||
for _, item in pairs(bookmarks) do
|
||||
if #item.key == 1 then
|
||||
table.insert(mb, item.key)
|
||||
end
|
||||
end
|
||||
if #mb == 0 then
|
||||
return keys[1]
|
||||
end
|
||||
table.sort(mb, function(a, b)
|
||||
return key2rank[a] < key2rank[b]
|
||||
end)
|
||||
local idx = 1
|
||||
for _, key in ipairs(keys) do
|
||||
if key2rank[key] < key2rank[mb[idx]] then
|
||||
return key
|
||||
end
|
||||
idx = idx + 1
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local action_save = function(mb_path, bookmarks, path)
|
||||
if path == nil or #path == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local path_obj = bookmarks[path]
|
||||
-- check tag
|
||||
local tag = path_obj and path_obj.tag or path:match(".*[\\/]([^\\/]+)[\\/]?$")
|
||||
while true do
|
||||
local value, event = ya.input({
|
||||
title = "Tag (alias name)",
|
||||
value = tag,
|
||||
position = { "top-center", y = 3, w = 40 },
|
||||
})
|
||||
if event ~= 1 then
|
||||
return
|
||||
end
|
||||
tag = value or ''
|
||||
if #tag == 0 then
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Empty tag",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
else
|
||||
-- check the tag
|
||||
local tag_obj = nil
|
||||
for _, item in pairs(bookmarks) do
|
||||
if item.tag == tag then
|
||||
tag_obj = item
|
||||
break
|
||||
end
|
||||
end
|
||||
if tag_obj == nil or tag_obj.path == path then
|
||||
break
|
||||
end
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Duplicated tag",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
end
|
||||
-- check key
|
||||
local key = path_obj and path_obj.key or generate_key(bookmarks)
|
||||
while true do
|
||||
local value, event = ya.input({
|
||||
title = "Key (1 character, optional)",
|
||||
value = key,
|
||||
position = { "top-center", y = 3, w = 40 },
|
||||
})
|
||||
if event ~= 1 then
|
||||
return
|
||||
end
|
||||
key = value or ""
|
||||
if key == "" then
|
||||
key = ""
|
||||
break
|
||||
elseif #key == 1 then
|
||||
-- check the key
|
||||
local key_obj = nil
|
||||
for _, item in pairs(bookmarks) do
|
||||
if item.key == key then
|
||||
key_obj = item
|
||||
break
|
||||
end
|
||||
end
|
||||
if key_obj == nil or key_obj.path == path then
|
||||
break
|
||||
else
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Duplicated key",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
else
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "The length of key shoule be 1",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
end
|
||||
-- save
|
||||
set_bookmarks(path, { tag = tag, path = path, key = key })
|
||||
bookmarks = get_state_attr("bookmarks")
|
||||
save_to_file(mb_path, bookmarks)
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = '"' .. tag .. '" saved"',
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
|
||||
local action_delete = function(mb_path, bookmarks, path)
|
||||
if path == nil then
|
||||
return
|
||||
end
|
||||
local tag = bookmarks[path].tag
|
||||
set_bookmarks(path, nil)
|
||||
bookmarks = get_state_attr("bookmarks")
|
||||
save_to_file(mb_path, bookmarks)
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = '"' .. tag .. '" deleted',
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
|
||||
local action_delete_all = function(mb_path)
|
||||
local value, event = ya.input({
|
||||
title = "Delete all bookmarks? (y/n)",
|
||||
position = { "top-center", y = 3, w = 40 },
|
||||
})
|
||||
if event ~= 1 then
|
||||
return
|
||||
end
|
||||
if string.lower(value) == "y" then
|
||||
set_state_attr("bookmarks", {})
|
||||
save_to_file(mb_path, {})
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "All bookmarks deleted",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
else
|
||||
ya.notify {
|
||||
title = "Bookmarks",
|
||||
content = "Cancel delete",
|
||||
timeout = 2,
|
||||
level = "info",
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
setup = function(state, options)
|
||||
state.path = options.path or
|
||||
(ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") or
|
||||
(os.getenv("HOME") .. "/.config/yazi/bookmark")
|
||||
state.cli = options.cli or "fzf"
|
||||
state.jump_notify = options.jump_notify and true
|
||||
-- init the keys
|
||||
local keys = options.keys or "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
state.keys = {}
|
||||
state.key2rank = {}
|
||||
for i = 1, #keys do
|
||||
local char = keys:sub(i, i)
|
||||
table.insert(state.keys, char)
|
||||
state.key2rank[char] = i
|
||||
end
|
||||
|
||||
-- init the bookmarks
|
||||
local bookmarks = {}
|
||||
for _, item in pairs(options.bookmarks or {}) do
|
||||
bookmarks[item.path] = { tag = item.tag, path = item.path, key = item.key }
|
||||
end
|
||||
-- load the config
|
||||
local file = io.open(state.path, "r")
|
||||
if file ~= nil then
|
||||
for line in file:lines() do
|
||||
local tag, path, key = string.match(line, "(.-)\t(.-)\t(.*)")
|
||||
if tag and path then
|
||||
key = key or ""
|
||||
bookmarks[path] = { tag = tag, path = path, key = key }
|
||||
end
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
-- create bookmarks file to enable fzf
|
||||
save_to_file(state.path, bookmarks)
|
||||
state.bookmarks = bookmarks
|
||||
end,
|
||||
entry = function(self, jobs)
|
||||
local action = jobs.args[1]
|
||||
if not action then
|
||||
return
|
||||
end
|
||||
local mb_path, cli, bookmarks, jump_notify = get_state_attr("path"), get_state_attr("cli"), get_state_attr("bookmarks"), get_state_attr("jump_notify")
|
||||
if action == "save" then
|
||||
action_save(mb_path, bookmarks, get_hovered_path())
|
||||
elseif action == "delete_by_key" then
|
||||
action_delete(mb_path, bookmarks, which_find(bookmarks))
|
||||
elseif action == "delete_by_fzf" then
|
||||
action_delete(mb_path, bookmarks, fzf_find(cli, mb_path))
|
||||
elseif action == "delete_all" then
|
||||
action_delete_all(mb_path)
|
||||
elseif action == "jump_by_key" then
|
||||
action_jump(bookmarks, which_find(bookmarks), jump_notify)
|
||||
elseif action == "jump_by_fzf" then
|
||||
action_jump(bookmarks, fzf_find(cli, mb_path), jump_notify)
|
||||
elseif action == "rename_by_key" then
|
||||
action_save(mb_path, bookmarks, which_find(bookmarks))
|
||||
elseif action == "rename_by_fzf" then
|
||||
action_save(mb_path, bookmarks, fzf_find(cli, mb_path))
|
||||
end
|
||||
end,
|
||||
}
|
||||
Reference in New Issue
Block a user