mirror of
https://github.com/kristoferssolo/solorice.git
synced 2025-10-21 20:10:34 +00:00
Update 2024-01-23
This commit is contained in:
parent
ff0f2da5d2
commit
3e77832510
@ -122,7 +122,7 @@ depends = [ "misc", "local", "eww", "lock" ]
|
|||||||
"config/spotify-tui.yml" = "~/.config/spotify-tui/config.yml"
|
"config/spotify-tui.yml" = "~/.config/spotify-tui/config.yml"
|
||||||
|
|
||||||
[terminal]
|
[terminal]
|
||||||
depends = [ "zsh", "tmux", "yazi" ]
|
depends = [ "zsh", "tmux" ]
|
||||||
|
|
||||||
[terminal.files]
|
[terminal.files]
|
||||||
"config/alacritty/" = "~/.config/alacritty/"
|
"config/alacritty/" = "~/.config/alacritty/"
|
||||||
|
|||||||
0
config/HybridBar/scripts/change-active-workspace
Normal file → Executable file
0
config/HybridBar/scripts/change-active-workspace
Normal file → Executable file
0
config/HybridBar/scripts/get-active-workspace
Normal file → Executable file
0
config/HybridBar/scripts/get-active-workspace
Normal file → Executable file
0
config/HybridBar/scripts/get-window-title
Normal file → Executable file
0
config/HybridBar/scripts/get-window-title
Normal file → Executable file
0
config/HybridBar/scripts/get-workspaces
Normal file → Executable file
0
config/HybridBar/scripts/get-workspaces
Normal file → Executable file
0
config/eww/scripts/change-active-workspace
Normal file → Executable file
0
config/eww/scripts/change-active-workspace
Normal file → Executable file
0
config/eww/scripts/get-active-workspace
Normal file → Executable file
0
config/eww/scripts/get-active-workspace
Normal file → Executable file
0
config/eww/scripts/get-music
Normal file → Executable file
0
config/eww/scripts/get-music
Normal file → Executable file
0
config/eww/scripts/get-network
Normal file → Executable file
0
config/eww/scripts/get-network
Normal file → Executable file
0
config/eww/scripts/get-window-title
Normal file → Executable file
0
config/eww/scripts/get-window-title
Normal file → Executable file
0
config/eww/scripts/get-workspaces
Normal file → Executable file
0
config/eww/scripts/get-workspaces
Normal file → Executable file
0
config/eww/scripts/getvol
Normal file → Executable file
0
config/eww/scripts/getvol
Normal file → Executable file
0
config/eww/scripts/github
Normal file → Executable file
0
config/eww/scripts/github
Normal file → Executable file
0
config/lf/cleaner
Normal file → Executable file
0
config/lf/cleaner
Normal file → Executable file
0
config/lf/lfrc
Normal file → Executable file
0
config/lf/lfrc
Normal file → Executable file
0
config/nsxiv/exec/image-info
Normal file → Executable file
0
config/nsxiv/exec/image-info
Normal file → Executable file
0
config/nsxiv/exec/key-handler
Normal file → Executable file
0
config/nsxiv/exec/key-handler
Normal file → Executable file
0
config/nsxiv/exec/nsxiv-url
Normal file → Executable file
0
config/nsxiv/exec/nsxiv-url
Normal file → Executable file
0
config/nsxiv/exec/thumb-info
Normal file → Executable file
0
config/nsxiv/exec/thumb-info
Normal file → Executable file
0
config/nsxiv/exec/win-title
Normal file → Executable file
0
config/nsxiv/exec/win-title
Normal file → Executable file
@ -114,4 +114,3 @@ export _JAVA_AWT_WM_NONREPARENTING=1 # Fix for Java applications in dwm
|
|||||||
. "$XDG_DATA_HOME/cargo/env"
|
. "$XDG_DATA_HOME/cargo/env"
|
||||||
. "$XDG_DATA_HOME/rye/env"
|
. "$XDG_DATA_HOME/rye/env"
|
||||||
. "$XDG_CACHE_HOME/deno/.deno/env"
|
. "$XDG_CACHE_HOME/deno/.deno/env"
|
||||||
|
|
||||||
|
|||||||
0
config/x11/opt-apps
Normal file → Executable file
0
config/x11/opt-apps
Normal file → Executable file
@ -1,22 +1,82 @@
|
|||||||
[plugin]
|
[[plugin.deps]]
|
||||||
deps = [
|
use = "AnirudhG07/nbpreview"
|
||||||
{use = "AnirudhG07/nbpreview", rev = "1d85745" },
|
rev = "1d85745"
|
||||||
{use = "Reledia/glow", rev = "5ce76dc" },
|
hash = "d378328e5d0a1b9fb9f04ab3aade4575"
|
||||||
{use = "Reledia/hexyl", rev = "39d3d4e" },
|
|
||||||
{use = "Reledia/miller", rev = "40e0265" },
|
[[plugin.deps]]
|
||||||
{use = "Sonico98/exifaudio", rev = "d794614" },
|
use = "Reledia/glow"
|
||||||
{use = "dedukun/relative-motions", rev = "df97039" },
|
rev = "5ce76dc"
|
||||||
{use = "hankertrix/augment-command", rev = "6a367db" },
|
hash = "52e5f5c602962e7cbf874da28f52ba45"
|
||||||
{use = "imsi32/yatline", rev = "600ed1f" },
|
|
||||||
{use = "kirasok/torrent-preview", rev = "c9e67df" },
|
[[plugin.deps]]
|
||||||
{use = "ndtoan96/ouch", rev = "b869886" },
|
use = "Reledia/hexyl"
|
||||||
{use = "pirafrank/what-size", rev = "b23e3a4" },
|
rev = "39d3d4e"
|
||||||
{use = "yazi-rs/plugins:chmod", rev = "71c4fc2" },
|
hash = "dd624cbaff94af65f39fd86bc57b340"
|
||||||
{use = "yazi-rs/plugins:full-border", rev = "71c4fc2" },
|
|
||||||
{use = "yazi-rs/plugins:git", rev = "71c4fc2" },
|
[[plugin.deps]]
|
||||||
{use = "yazi-rs/plugins:hide-preview", rev = "71c4fc2" },
|
use = "Reledia/miller"
|
||||||
{use = "yazi-rs/plugins:max-preview", rev = "71c4fc2" },
|
rev = "40e0265"
|
||||||
]
|
hash = "2d6d77583162aaf0a599e7a3091b5878"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "Sonico98/exifaudio"
|
||||||
|
rev = "d794614"
|
||||||
|
hash = "a8e15d3c21c02a5af41d46ed04778a02"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "dedukun/relative-motions"
|
||||||
|
rev = "df97039"
|
||||||
|
hash = "395940d2b22941e0acb1232579c9d4cf"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "hankertrix/augment-command"
|
||||||
|
rev = "c0fd61f"
|
||||||
|
hash = "3e56e8b9ee07aabc0d08743c05835929"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "imsi32/yatline"
|
||||||
|
rev = "9328205"
|
||||||
|
hash = "3e51d1fd8a2e481fcfa8eab1251d1c5f"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "kirasok/torrent-preview"
|
||||||
|
rev = "c9e67df"
|
||||||
|
hash = "f0d9a684da8e4ab9ccbcd255a97cf42b"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "ndtoan96/ouch"
|
||||||
|
rev = "083d564"
|
||||||
|
hash = "1e4c0ac1fca31a23412324710193358a"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "pirafrank/what-size"
|
||||||
|
rev = "b23e3a4"
|
||||||
|
hash = "98e5f5af3efd3ba8bc2db0720187cc83"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:chmod"
|
||||||
|
rev = "6418698"
|
||||||
|
hash = "4c7e8fd0266eedee7b619d966bd2d025"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:full-border"
|
||||||
|
rev = "6418698"
|
||||||
|
hash = "882ed23839778f82dc137248979c8681"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:git"
|
||||||
|
rev = "6418698"
|
||||||
|
hash = "e9cf1bfc03de7fee0f1d4260da0d1dfd"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:hide-preview"
|
||||||
|
rev = "6418698"
|
||||||
|
hash = "5be5885898ca9df783bdec0d402bf4b0"
|
||||||
|
|
||||||
|
[[plugin.deps]]
|
||||||
|
use = "yazi-rs/plugins:max-preview"
|
||||||
|
rev = "6418698"
|
||||||
|
hash = "9bc26d10d2f6e2aa93b10905b1b76979"
|
||||||
|
|
||||||
[flavor]
|
[flavor]
|
||||||
deps = [ ]
|
deps = []
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2024 Ciarán O'Brien
|
|
||||||
|
|
||||||
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.
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
# ~~archive.yazi~~ compress.yazi
|
|
||||||
|
|
||||||
A Yazi plugin that compresses selected files to an archive. Supporting yazi versions 0.2.5 and up.
|
|
||||||
|
|
||||||
## Supported file types
|
|
||||||
|
|
||||||
| Extention | Unix Command | Windows Command |
|
|
||||||
| ------------- | ------------- | --------------- |
|
|
||||||
| .zip | zip -r | 7z a -tzip |
|
|
||||||
| .7z | 7z a | 7z a |
|
|
||||||
| .tar | tar rpf | tar rpf |
|
|
||||||
| .tar.gz | gzip | 7z a -tgzip |
|
|
||||||
| .tar.xz | xz | 7z a -txz |
|
|
||||||
| .tar.bz2 | bzip2 | 7z a -tbzip2 |
|
|
||||||
| .tar.zst | zstd | zstd |
|
|
||||||
|
|
||||||
|
|
||||||
**NOTE:** Windows users are required to install 7-Zip and add 7z.exe to the `path` environment variable, only tar archives will be available otherwise.
|
|
||||||
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# For Unix platforms
|
|
||||||
git clone https://github.com/KKV9/compress.yazi.git ~/.config/yazi/plugins/compress.yazi
|
|
||||||
|
|
||||||
## For Windows
|
|
||||||
git clone https://github.com/KKV9/compress.yazi.git %AppData%\yazi\config\plugins\compress.yazi
|
|
||||||
|
|
||||||
# Or with yazi plugin manager
|
|
||||||
ya pack -a KKV9/compress
|
|
||||||
```
|
|
||||||
|
|
||||||
- Add this to your `keymap.toml`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[[manager.prepend_keymap]]
|
|
||||||
on = [ "c", "a" ]
|
|
||||||
run = "plugin compress"
|
|
||||||
desc = "Archive selected files"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
- Select files or folders to add, then press `c` `a` to create a new archive.
|
|
||||||
- Type a name for the new file.
|
|
||||||
- The file extention must match one of the supported filetype extentions.
|
|
||||||
- The desired archive/compression command must be installed on your system.
|
|
||||||
@ -1,228 +0,0 @@
|
|||||||
-- Send error notification
|
|
||||||
local function notify_error(message, urgency)
|
|
||||||
ya.notify({
|
|
||||||
title = "Archive",
|
|
||||||
content = message,
|
|
||||||
level = urgency,
|
|
||||||
timeout = 5,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check for windows
|
|
||||||
local is_windows = ya.target_family() == "windows"
|
|
||||||
|
|
||||||
-- Make table of selected or hovered: path = filenames
|
|
||||||
local selected_or_hovered = ya.sync(function()
|
|
||||||
local tab, paths, names, path_fnames = cx.active, {}, {}, {}
|
|
||||||
for _, u in pairs(tab.selected) do
|
|
||||||
paths[#paths + 1] = tostring(u:parent())
|
|
||||||
names[#names + 1] = tostring(u:name())
|
|
||||||
end
|
|
||||||
if #paths == 0 and tab.current.hovered then
|
|
||||||
paths[1] = tostring(tab.current.hovered.url:parent())
|
|
||||||
names[1] = tostring(tab.current.hovered.name)
|
|
||||||
end
|
|
||||||
for idx, name in ipairs(names) do
|
|
||||||
if not path_fnames[paths[idx]] then
|
|
||||||
path_fnames[paths[idx]] = {}
|
|
||||||
end
|
|
||||||
table.insert(path_fnames[paths[idx]], name)
|
|
||||||
end
|
|
||||||
return path_fnames, tostring(tab.current.cwd)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Check if archive command is available
|
|
||||||
local function is_command_available(cmd)
|
|
||||||
local stat_cmd
|
|
||||||
|
|
||||||
if is_windows then
|
|
||||||
stat_cmd = string.format("where %s > nul 2>&1", cmd)
|
|
||||||
else
|
|
||||||
stat_cmd = string.format("command -v %s >/dev/null 2>&1", cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
local cmd_exists = os.execute(stat_cmd)
|
|
||||||
if cmd_exists then
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Archive command list --> string
|
|
||||||
local function find_binary(cmd_list)
|
|
||||||
for _, cmd in ipairs(cmd_list) do
|
|
||||||
if is_command_available(cmd) then
|
|
||||||
return cmd
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return cmd_list[1] -- Return first command as fallback
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if file exists
|
|
||||||
local function file_exists(name)
|
|
||||||
local f = io.open(name, "r")
|
|
||||||
if f ~= nil then
|
|
||||||
io.close(f)
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Append filename to it's parent directory
|
|
||||||
local function combine_url(path, file)
|
|
||||||
path, file = Url(path), Url(file)
|
|
||||||
return tostring(path:join(file))
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
entry = function()
|
|
||||||
-- Exit visual mode
|
|
||||||
ya.manager_emit("escape", { visual = true })
|
|
||||||
|
|
||||||
-- Define file table and output_dir (pwd)
|
|
||||||
local path_fnames, output_dir = selected_or_hovered()
|
|
||||||
|
|
||||||
-- Get input
|
|
||||||
local output_name, event = ya.input({
|
|
||||||
title = "Create archive:",
|
|
||||||
position = { "top-center", y = 3, w = 40 },
|
|
||||||
})
|
|
||||||
if event ~= 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use appropriate archive command
|
|
||||||
local archive_commands = {
|
|
||||||
["%.zip$"] = { command = "zip", args = { "-r" } },
|
|
||||||
["%.7z$"] = { command = { "7z", "7zz" }, args = { "a" } },
|
|
||||||
["%.tar.gz$"] = { command = "tar", args = { "rpf" }, compress = "gzip" },
|
|
||||||
["%.tar.xz$"] = { command = "tar", args = { "rpf" }, compress = "xz" },
|
|
||||||
["%.tar.bz2$"] = { command = "tar", args = { "rpf" }, compress = "bzip2" },
|
|
||||||
["%.tar.zst$"] = { command = "tar", args = { "rpf" }, compress = "zstd", compress_args = { "--rm" } },
|
|
||||||
["%.tar$"] = { command = "tar", args = { "rpf" } },
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_windows then
|
|
||||||
archive_commands = {
|
|
||||||
["%.zip$"] = { command = "7z", args = { "a", "-tzip" } },
|
|
||||||
["%.7z$"] = { command = "7z", args = { "a" } },
|
|
||||||
["%.tar.gz$"] = {
|
|
||||||
command = "tar",
|
|
||||||
args = { "rpf" },
|
|
||||||
compress = "7z",
|
|
||||||
compress_args = { "a", "-tgzip", "-sdel", output_name },
|
|
||||||
},
|
|
||||||
["%.tar.xz$"] = {
|
|
||||||
command = "tar",
|
|
||||||
args = { "rpf" },
|
|
||||||
compress = "7z",
|
|
||||||
compress_args = { "a", "-txz", "-sdel", output_name },
|
|
||||||
},
|
|
||||||
["%.tar.bz2$"] = {
|
|
||||||
command = "tar",
|
|
||||||
args = { "rpf" },
|
|
||||||
compress = "7z",
|
|
||||||
compress_args = { "a", "-tbzip2", "-sdel", output_name },
|
|
||||||
},
|
|
||||||
["%.tar.zst$"] = { command = "tar", args = { "rpf" }, compress = "zstd", compress_args = { "--rm" } },
|
|
||||||
["%.tar$"] = { command = "tar", args = { "rpf" } },
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Match user input to archive command
|
|
||||||
local archive_cmd, archive_args, archive_compress, archive_compress_args
|
|
||||||
for pattern, cmd_pair in pairs(archive_commands) do
|
|
||||||
if output_name:match(pattern) then
|
|
||||||
archive_cmd = cmd_pair.command
|
|
||||||
archive_args = cmd_pair.args
|
|
||||||
archive_compress = cmd_pair.compress
|
|
||||||
archive_compress_args = cmd_pair.compress_args or {}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if archive command has multiple names
|
|
||||||
if type(archive_cmd) == "table" then
|
|
||||||
archive_cmd = find_binary(archive_cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if no archive command is available for the extention
|
|
||||||
if not archive_cmd then
|
|
||||||
notify_error("Unsupported file extention", "error")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Exit if archive command is not available
|
|
||||||
if not is_command_available(archive_cmd) then
|
|
||||||
notify_error(string.format("%s not available", archive_cmd), "error")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Exit if compress command is not available
|
|
||||||
if archive_compress and not is_command_available(archive_compress) then
|
|
||||||
notify_error(string.format("%s compression not available", archive_compress), "error")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If file exists show overwrite prompt
|
|
||||||
local output_url = combine_url(output_dir, output_name)
|
|
||||||
while true do
|
|
||||||
if file_exists(output_url) then
|
|
||||||
local overwrite_answer = ya.input({
|
|
||||||
title = "Overwrite " .. output_name .. "? y/N:",
|
|
||||||
position = { "top-center", y = 3, w = 40 },
|
|
||||||
})
|
|
||||||
if overwrite_answer:lower() ~= "y" then
|
|
||||||
notify_error("Operation canceled", "warn")
|
|
||||||
return -- If no overwrite selected, exit
|
|
||||||
else
|
|
||||||
local rm_status, rm_err = os.remove(output_url)
|
|
||||||
if not rm_status then
|
|
||||||
notify_error(string.format("Failed to remove %s, exit code %s", output_name, rm_err), "error")
|
|
||||||
return
|
|
||||||
end -- If overwrite fails, exit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if archive_compress and not output_name:match("%.tar$") then
|
|
||||||
output_name = output_name:match("(.*%.tar)") -- Test for .tar and .tar.*
|
|
||||||
output_url = combine_url(output_dir, output_name) -- Update output_url
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add to output archive in each path, their respective files
|
|
||||||
for path, names in pairs(path_fnames) do
|
|
||||||
local archive_status, archive_err =
|
|
||||||
Command(archive_cmd):args(archive_args):arg(output_url):args(names):cwd(path):spawn():wait()
|
|
||||||
if not archive_status or not archive_status.success then
|
|
||||||
notify_error(
|
|
||||||
string.format(
|
|
||||||
"%s with selected files failed, exit code %s",
|
|
||||||
archive_args,
|
|
||||||
archive_status and archive_status.code or archive_err
|
|
||||||
),
|
|
||||||
"error"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use compress command if needed
|
|
||||||
if archive_compress then
|
|
||||||
local compress_status, compress_err =
|
|
||||||
Command(archive_compress):args(archive_compress_args):arg(output_name):cwd(output_dir):spawn():wait()
|
|
||||||
if not compress_status or not compress_status.success then
|
|
||||||
notify_error(
|
|
||||||
string.format(
|
|
||||||
"%s with %s failed, exit code %s",
|
|
||||||
archive_compress,
|
|
||||||
output_name,
|
|
||||||
compress_status and compress_status.code or compress_err
|
|
||||||
),
|
|
||||||
"error"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -76,6 +76,7 @@
|
|||||||
---@field archive_path string|nil The path to the archive
|
---@field archive_path string|nil The path to the archive
|
||||||
---@field destination_path string|nil The path to the destination
|
---@field destination_path string|nil The path to the destination
|
||||||
---@field extracted_items_path string|nil The path to the extracted items
|
---@field extracted_items_path string|nil The path to the extracted items
|
||||||
|
---@field extractor_name string|nil The name of the extractor
|
||||||
|
|
||||||
-- The name of the plugin
|
-- The name of the plugin
|
||||||
---@type string
|
---@type string
|
||||||
@ -2137,16 +2138,6 @@ local function recursively_extract_archive(
|
|||||||
local get_extractor_result, extractor =
|
local get_extractor_result, extractor =
|
||||||
get_extractor(archive_path, tostring(temporary_directory_url), config)
|
get_extractor(archive_path, tostring(temporary_directory_url), config)
|
||||||
|
|
||||||
-- Function to add the archive and destination path to the result
|
|
||||||
---@param result ExtractionResult The result to add the paths to
|
|
||||||
---@return ExtractionResult modified_result The result with the paths added
|
|
||||||
local function add_paths_to_result(result)
|
|
||||||
return merge_tables(result, {
|
|
||||||
archive_path = archive_path,
|
|
||||||
destination_path = destination_path,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If there is no extractor, return the result
|
-- If there is no extractor, return the result
|
||||||
if not extractor then
|
if not extractor then
|
||||||
return merge_tables(get_extractor_result, {
|
return merge_tables(get_extractor_result, {
|
||||||
@ -2155,6 +2146,21 @@ local function recursively_extract_archive(
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Function to add additional information to the extraction result
|
||||||
|
-- The additional information are:
|
||||||
|
-- - The archive path
|
||||||
|
-- - The destination path
|
||||||
|
-- - The name of the extractor
|
||||||
|
---@param result ExtractionResult The result to add the paths to
|
||||||
|
---@return ExtractionResult modified_result The result with the paths added
|
||||||
|
local function add_additional_info(result)
|
||||||
|
return merge_tables(result, {
|
||||||
|
archive_path = archive_path,
|
||||||
|
destination_path = destination_path,
|
||||||
|
extractor_name = extractor.name,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
-- Get the list of archive files and directories,
|
-- Get the list of archive files and directories,
|
||||||
-- the error message and the password
|
-- the error message and the password
|
||||||
local archive_files, archive_directories, error = extractor:get_items()
|
local archive_files, archive_directories, error = extractor:get_items()
|
||||||
@ -2171,7 +2177,7 @@ local function recursively_extract_archive(
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- Return the extraction result
|
-- Return the extraction result
|
||||||
return add_paths_to_result(extraction_result)
|
return add_additional_info(extraction_result)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get if the archive has only one file
|
-- Get if the archive has only one file
|
||||||
@ -2183,7 +2189,7 @@ local function recursively_extract_archive(
|
|||||||
|
|
||||||
-- If the extraction result is not successful, return it
|
-- If the extraction result is not successful, return it
|
||||||
if not extraction_result.successful then
|
if not extraction_result.successful then
|
||||||
return add_paths_to_result(extraction_result)
|
return add_additional_info(extraction_result)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get the result of moving the extracted items
|
-- Get the result of moving the extracted items
|
||||||
@ -2202,7 +2208,7 @@ local function recursively_extract_archive(
|
|||||||
or not extracted_items_path
|
or not extracted_items_path
|
||||||
or not config.recursively_extract_archives
|
or not config.recursively_extract_archives
|
||||||
then
|
then
|
||||||
return add_paths_to_result(move_result)
|
return add_additional_info(move_result)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Get the url of the extracted items path
|
-- Get the url of the extracted items path
|
||||||
@ -2272,20 +2278,38 @@ local function recursively_extract_archive(
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Return the move result
|
-- Return the move result
|
||||||
return add_paths_to_result(move_result)
|
return add_additional_info(move_result)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Function to show an extraction error
|
-- Function to show an extraction error
|
||||||
---@param extraction_result ExtractionResult The extraction result
|
---@param extraction_result ExtractionResult The extraction result
|
||||||
---@return nil
|
---@return nil
|
||||||
local function show_extraction_error(extraction_result)
|
local function show_extraction_error(extraction_result)
|
||||||
|
--
|
||||||
|
|
||||||
|
-- The line for the error
|
||||||
|
local error_line = string.format("Error: %s", extraction_result.error)
|
||||||
|
|
||||||
|
-- If the extractor name exists
|
||||||
|
if extraction_result.extractor_name then
|
||||||
|
--
|
||||||
|
|
||||||
|
-- Add the extractor's name to the error
|
||||||
|
error_line = string.format(
|
||||||
|
"%s error: %s",
|
||||||
|
extraction_result.extractor_name,
|
||||||
|
extraction_result.error
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show the extraction error
|
||||||
return show_error(table.concat({
|
return show_error(table.concat({
|
||||||
string.format(
|
string.format(
|
||||||
"Failed to extract archive at: %s",
|
"Failed to extract archive at: %s",
|
||||||
extraction_result.archive_path
|
extraction_result.archive_path
|
||||||
),
|
),
|
||||||
string.format("Destination: %s", extraction_result.destination_path),
|
string.format("Destination: %s", extraction_result.destination_path),
|
||||||
string.format("Error: %s", extraction_result.error),
|
error_line,
|
||||||
}, "\n"))
|
}, "\n"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
local selected_or_hovered = ya.sync(function()
|
|
||||||
local tab, paths = cx.active, {}
|
|
||||||
for _, u in pairs(tab.selected) do
|
|
||||||
paths[#paths + 1] = tostring(u)
|
|
||||||
end
|
|
||||||
if #paths == 0 and tab.current.hovered then
|
|
||||||
paths[1] = tostring(tab.current.hovered.url)
|
|
||||||
end
|
|
||||||
return paths
|
|
||||||
end)
|
|
||||||
|
|
||||||
return {
|
|
||||||
entry = function()
|
|
||||||
ya.manager_emit("escape", { visual = true })
|
|
||||||
|
|
||||||
local urls = selected_or_hovered()
|
|
||||||
if #urls == 0 then
|
|
||||||
return ya.notify { title = "Chmod", content = "No file selected", level = "warn", timeout = 5 }
|
|
||||||
end
|
|
||||||
|
|
||||||
local value, event = ya.input {
|
|
||||||
title = "Chmod:",
|
|
||||||
position = { "top-center", y = 3, w = 40 },
|
|
||||||
}
|
|
||||||
if event ~= 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local status, err = Command("chmod"):arg(value):args(urls):spawn():wait()
|
|
||||||
if not status or not status.success then
|
|
||||||
ya.notify {
|
|
||||||
title = "Chmod",
|
|
||||||
content = string.format("Chmod on selected files failed, error: %s", status and status.code or err),
|
|
||||||
level = "error",
|
|
||||||
timeout = 5,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
@ -1,231 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function GetPath(str)
|
|
||||||
local sep = '/'
|
|
||||||
if ya.target_family() == "windows" then
|
|
||||||
sep = '\\'
|
|
||||||
end
|
|
||||||
return str:match("(.*"..sep..")")
|
|
||||||
end
|
|
||||||
|
|
||||||
function Exiftool(...)
|
|
||||||
local child = Command("exiftool")
|
|
||||||
:args({
|
|
||||||
"-q", "-q", "-S", "-Title", "-SortName",
|
|
||||||
"-TitleSort", "-TitleSortOrder", "-Artist",
|
|
||||||
"-SortArtist", "-ArtistSort", "-PerformerSortOrder",
|
|
||||||
"-Album", "-SortAlbum", "-AlbumSort", "-AlbumSortOrder",
|
|
||||||
"-AlbumArtist", "-SortAlbumArtist", "-AlbumArtistSort",
|
|
||||||
"-AlbumArtistSortOrder", "-Genre", "-TrackNumber",
|
|
||||||
"-Year", "-Duration", "-SampleRate",
|
|
||||||
"-AudioSampleRate", "-AudioBitrate", "-AvgBitrate",
|
|
||||||
"-Channels", "-AudioChannels", tostring(...),
|
|
||||||
})
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.NULL)
|
|
||||||
:spawn()
|
|
||||||
return child
|
|
||||||
end
|
|
||||||
|
|
||||||
function Mediainfo(...)
|
|
||||||
local file, cache_dir = ...
|
|
||||||
local template = cache_dir.."mediainfo.txt"
|
|
||||||
local child = Command("mediainfo")
|
|
||||||
:args({
|
|
||||||
"--Output=file://"..template, tostring(file)
|
|
||||||
})
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.NULL)
|
|
||||||
:spawn()
|
|
||||||
return child
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:peek(job)
|
|
||||||
local cache = ya.file_cache(job)
|
|
||||||
if not cache then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get cache dir to find the mediainfo template file
|
|
||||||
local cache_dir = GetPath(tostring(cache))
|
|
||||||
|
|
||||||
-- Try mediainfo, otherwise use exiftool
|
|
||||||
local status, child = pcall(Mediainfo, job.file.url, cache_dir)
|
|
||||||
if not status or child == nil then
|
|
||||||
status, child = pcall(Exiftool, job.file.url)
|
|
||||||
if not status or child == nil then
|
|
||||||
local error = ui.Line { ui.Span("Make sure exiftool is installed and in your PATH") }
|
|
||||||
-- TODO)) Remove legacy method when v0.4 gets released
|
|
||||||
local function display_error_legacy()
|
|
||||||
local p = ui.Paragraph(job.area, { error }):wrap(ui.Paragraph.WRAP)
|
|
||||||
ya.preview_widgets(job, { p })
|
|
||||||
end
|
|
||||||
local function display_error()
|
|
||||||
local p = ui.Text(error):area(job.area):wrap(ui.Text.WRAP)
|
|
||||||
ya.preview_widgets(job, { p })
|
|
||||||
end
|
|
||||||
if pcall(display_error) then else pcall(display_error_legacy) end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local limit = job.area.h
|
|
||||||
local i, metadata = 0, {}
|
|
||||||
repeat
|
|
||||||
local next, event = child:read_line()
|
|
||||||
if event == 1 then
|
|
||||||
return self:fallback_to_builtin()
|
|
||||||
elseif event ~= 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
if i > job.skip then
|
|
||||||
local m_title, m_tag = Prettify(next)
|
|
||||||
if m_title ~= "" and m_tag ~= "" then
|
|
||||||
local ti = ui.Span(m_title):bold()
|
|
||||||
local ta = ui.Span(m_tag)
|
|
||||||
table.insert(metadata, ui.Line{ti, ta})
|
|
||||||
table.insert(metadata, ui.Line{})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
until i >= job.skip + limit
|
|
||||||
|
|
||||||
-- TODO)) Remove legacy method when v0.4 gets released
|
|
||||||
local function display_metadata_legacy()
|
|
||||||
local p = ui.Paragraph(job.area, metadata):wrap(ui.Paragraph.WRAP)
|
|
||||||
ya.preview_widgets(job, { p })
|
|
||||||
end
|
|
||||||
local function display_metadata()
|
|
||||||
local p = ui.Text(metadata):area(job.area):wrap(ui.Text.WRAP)
|
|
||||||
ya.preview_widgets(job, { p })
|
|
||||||
end
|
|
||||||
if pcall(display_metadata) then else pcall(display_metadata_legacy) end
|
|
||||||
|
|
||||||
local cover_width = job.area.w / 2 - 5
|
|
||||||
local cover_height = (job.area.h / 4) + 3
|
|
||||||
|
|
||||||
local bottom_right = ui.Rect {
|
|
||||||
x = job.area.right - cover_width,
|
|
||||||
y = job.area.bottom - cover_height,
|
|
||||||
w = cover_width,
|
|
||||||
h = cover_height,
|
|
||||||
}
|
|
||||||
|
|
||||||
if self:preload(job) == 1 then
|
|
||||||
ya.image_show(cache, bottom_right)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Prettify(metadata)
|
|
||||||
local substitutions = {
|
|
||||||
Sortname = "Sort Title:",
|
|
||||||
SortName = "Sort Title:",
|
|
||||||
TitleSort = "Sort Title:",
|
|
||||||
TitleSortOrder = "Sort Title:",
|
|
||||||
ArtistSort = "Sort Artist:",
|
|
||||||
SortArtist = "Sort Artist:",
|
|
||||||
Artist = "Artist:",
|
|
||||||
ARTIST = "Artist:",
|
|
||||||
PerformerSortOrder = "Sort Artist:",
|
|
||||||
SortAlbumArtist = "Sort Album Artist:",
|
|
||||||
AlbumArtistSortOrder = "Sort Album Artist:",
|
|
||||||
AlbumArtistSort = "Sort Album Artist:",
|
|
||||||
AlbumSortOrder = "Sort Album:",
|
|
||||||
AlbumSort = "Sort Album:",
|
|
||||||
SortAlbum = "Sort Album:",
|
|
||||||
Album = "Album:",
|
|
||||||
ALBUM = "Album:",
|
|
||||||
AlbumArtist = "Album Artist:",
|
|
||||||
Genre = "Genre:",
|
|
||||||
GENRE = "Genre:",
|
|
||||||
TrackNumber = "Track Number:",
|
|
||||||
Year = "Year:",
|
|
||||||
Duration = "Duration:",
|
|
||||||
AudioBitrate = "Bitrate:",
|
|
||||||
AvgBitrate = "Average Bitrate:",
|
|
||||||
AudioSampleRate = "Sample Rate:",
|
|
||||||
SampleRate = "Sample Rate:",
|
|
||||||
AudioChannels = "Channels:"
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v in pairs(substitutions) do
|
|
||||||
metadata = metadata:gsub(tostring(k)..":", v, 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Separate the tag title from the tag data
|
|
||||||
local t={}
|
|
||||||
for str in string.gmatch(metadata , "([^"..":".."]+)") do
|
|
||||||
if str ~= "\n" then
|
|
||||||
table.insert(t, str)
|
|
||||||
else
|
|
||||||
table.insert(t, nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add back semicolon to title, rejoin tag data if it happened to contain a semicolon
|
|
||||||
local title, tag_data = "", ""
|
|
||||||
if t[1] ~= nil then
|
|
||||||
title, tag_data = t[1]..":", table.concat(t, ":", 2)
|
|
||||||
end
|
|
||||||
return title, tag_data
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:seek(job)
|
|
||||||
local h = cx.active.current.hovered
|
|
||||||
if h and h.url == job.file.url then
|
|
||||||
ya.manager_emit("peek", {
|
|
||||||
tostring(math.max(0, cx.active.preview.skip + job.units)),
|
|
||||||
only_if = tostring(job.file.url),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:preload(job)
|
|
||||||
local cache = ya.file_cache(job)
|
|
||||||
if not cache or fs.cha(cache) then
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local mediainfo_template = 'General;"\
|
|
||||||
$if(%Track%,Title: %Track%,)\
|
|
||||||
$if(%Track/Sort%,Sort Title: %Track/Sort%,)\
|
|
||||||
$if(%Title/Sort%,Sort Title: %Title/Sort%,)\
|
|
||||||
$if(%TITLESORT%,Sort Title: %TITLESORT%,)\
|
|
||||||
$if(%Performer%,Artist: %Performer%,)\
|
|
||||||
$if(%Performer/Sort%,Sort Artist: %Performer/Sort%,)\
|
|
||||||
$if(%ARTISTSORT%,Sort Artist: %ARTISTSORT%,)\
|
|
||||||
$if(%Album%,Album: %Album%,)\
|
|
||||||
$if(%Album/Sort%,Sort Album: %Album/Sort%)\
|
|
||||||
$if(%ALBUMSORT%,Sort Album: %ALBUMSORT%)\
|
|
||||||
$if(%Album/Performer%,Album Artist: %Album/Performer%)\
|
|
||||||
$if(%Album/Performer/Sort%,Sort Album Artist: %Album/Performer/Sort%)\
|
|
||||||
$if(%Genre%,Genre: %Genre%)\
|
|
||||||
$if(%Track/Position%,Track Number: %Track/Position%)\
|
|
||||||
$if(%Recorded_Date%,Year: %Recorded_Date%)\
|
|
||||||
$if(%Duration/String%,Duration: %Duration/String%)\
|
|
||||||
$if(%BitRate/String%,Bitrate: %BitRate/String%)\
|
|
||||||
"\
|
|
||||||
Audio;"Sample Rate: %SamplingRate%\
|
|
||||||
Channels: %Channel(s)%"\
|
|
||||||
'
|
|
||||||
|
|
||||||
-- Write the mediainfo template file into yazi's cache dir
|
|
||||||
local cache_dir = GetPath(tostring(cache))
|
|
||||||
fs.write(Url(cache_dir.."mediainfo.txt"), mediainfo_template)
|
|
||||||
|
|
||||||
local output = Command("exiftool")
|
|
||||||
:args({ "-b", "-CoverArt", "-Picture", tostring(job.file.url) })
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:output()
|
|
||||||
|
|
||||||
if not output then
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
return fs.write(cache, output.stdout) and 1 or 2
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
local function setup(_, opts)
|
|
||||||
local type = opts and opts.type or ui.Border.ROUNDED
|
|
||||||
local old_build = Tab.build
|
|
||||||
|
|
||||||
Tab.build = function(self, ...)
|
|
||||||
local bar = function(c, x, y)
|
|
||||||
if x <= 0 or x == self._area.w - 1 then
|
|
||||||
return ui.Bar(ui.Bar.TOP)
|
|
||||||
end
|
|
||||||
|
|
||||||
return ui.Bar(ui.Bar.TOP)
|
|
||||||
:area(
|
|
||||||
ui.Rect { x = x, y = math.max(0, y), w = ya.clamp(0, self._area.w - x, 1), h = math.min(1, self._area.h) }
|
|
||||||
)
|
|
||||||
:symbol(c)
|
|
||||||
end
|
|
||||||
|
|
||||||
local c = self._chunks
|
|
||||||
self._chunks = {
|
|
||||||
c[1]:padding(ui.Padding.y(1)),
|
|
||||||
c[2]:padding(ui.Padding(c[1].w > 0 and 0 or 1, c[3].w > 0 and 0 or 1, 1, 1)),
|
|
||||||
c[3]:padding(ui.Padding.y(1)),
|
|
||||||
}
|
|
||||||
|
|
||||||
local style = THEME.manager.border_style
|
|
||||||
self._base = ya.list_merge(self._base or {}, {
|
|
||||||
ui.Border(ui.Border.ALL):area(self._area):type(type):style(style),
|
|
||||||
ui.Bar(ui.Bar.RIGHT):area(self._chunks[1]):style(style),
|
|
||||||
ui.Bar(ui.Bar.LEFT):area(self._chunks[3]):style(style),
|
|
||||||
|
|
||||||
bar("┬", c[1].right - 1, c[1].y),
|
|
||||||
bar("┴", c[1].right - 1, c[1].bottom - 1),
|
|
||||||
bar("┬", c[2].right, c[2].y),
|
|
||||||
bar("┴", c[2].right, c[2].bottom - 1),
|
|
||||||
})
|
|
||||||
|
|
||||||
old_build(self, ...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return { setup = setup }
|
|
||||||
@ -1,208 +0,0 @@
|
|||||||
local WIN = ya.target_family() == "windows"
|
|
||||||
local PATS = {
|
|
||||||
{ "[MT]", 6 }, -- Modified
|
|
||||||
{ "[AC]", 5 }, -- Added
|
|
||||||
{ "?$", 4 }, -- Untracked
|
|
||||||
{ "!$", 3 }, -- Ignored
|
|
||||||
{ "D", 2 }, -- Deleted
|
|
||||||
{ "U", 1 }, -- Updated
|
|
||||||
{ "[AD][AD]", 1 }, -- Updated
|
|
||||||
}
|
|
||||||
|
|
||||||
local function match(line)
|
|
||||||
local signs = line:sub(1, 2)
|
|
||||||
for _, p in ipairs(PATS) do
|
|
||||||
local path
|
|
||||||
if signs:find(p[1]) then
|
|
||||||
path = line:sub(4, 4) == '"' and line:sub(5, -2) or line:sub(4)
|
|
||||||
path = WIN and path:gsub("/", "\\") or path
|
|
||||||
end
|
|
||||||
if not path then
|
|
||||||
elseif path:find("[/\\]$") then
|
|
||||||
return p[2] == 3 and 30 or p[2], path:sub(1, -2)
|
|
||||||
else
|
|
||||||
return p[2], path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function root(cwd)
|
|
||||||
local is_worktree = function(url)
|
|
||||||
local file, head = io.open(tostring(url)), nil
|
|
||||||
if file then
|
|
||||||
head = file:read(8)
|
|
||||||
file:close()
|
|
||||||
end
|
|
||||||
return head == "gitdir: "
|
|
||||||
end
|
|
||||||
|
|
||||||
repeat
|
|
||||||
local next = cwd:join(".git")
|
|
||||||
local cha = fs.cha(next)
|
|
||||||
if cha and (cha.is_dir or is_worktree(next)) then
|
|
||||||
return tostring(cwd)
|
|
||||||
end
|
|
||||||
cwd = cwd:parent()
|
|
||||||
until not cwd
|
|
||||||
end
|
|
||||||
|
|
||||||
local function bubble_up(changed)
|
|
||||||
local new, empty = {}, Url("")
|
|
||||||
for k, v in pairs(changed) do
|
|
||||||
if v ~= 3 and v ~= 30 then
|
|
||||||
local url = Url(k):parent()
|
|
||||||
while url and url ~= empty do
|
|
||||||
local s = tostring(url)
|
|
||||||
new[s] = (new[s] or 0) > v and new[s] or v
|
|
||||||
url = url:parent()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return new
|
|
||||||
end
|
|
||||||
|
|
||||||
local function propagate_down(ignored, cwd, repo)
|
|
||||||
local new, rel = {}, cwd:strip_prefix(repo)
|
|
||||||
for k, v in pairs(ignored) do
|
|
||||||
if v == 30 then
|
|
||||||
if rel:starts_with(k) then
|
|
||||||
new[tostring(repo:join(rel))] = 30
|
|
||||||
elseif cwd == repo:join(k):parent() then
|
|
||||||
new[k] = 3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return new
|
|
||||||
end
|
|
||||||
|
|
||||||
local add = ya.sync(function(st, cwd, repo, changed)
|
|
||||||
st.dirs[cwd] = repo
|
|
||||||
st.repos[repo] = st.repos[repo] or {}
|
|
||||||
for k, v in pairs(changed) do
|
|
||||||
if v == 0 then
|
|
||||||
st.repos[repo][k] = nil
|
|
||||||
elseif v == 30 then
|
|
||||||
st.dirs[k] = ""
|
|
||||||
else
|
|
||||||
st.repos[repo][k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
ya.render()
|
|
||||||
end)
|
|
||||||
|
|
||||||
local remove = ya.sync(function(st, cwd)
|
|
||||||
local dir = st.dirs[cwd]
|
|
||||||
if not dir then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
ya.render()
|
|
||||||
st.dirs[cwd] = nil
|
|
||||||
if not st.repos[dir] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, r in pairs(st.dirs) do
|
|
||||||
if r == dir then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
st.repos[dir] = nil
|
|
||||||
end)
|
|
||||||
|
|
||||||
local function setup(st, opts)
|
|
||||||
st.dirs = {}
|
|
||||||
st.repos = {}
|
|
||||||
|
|
||||||
opts = opts or {}
|
|
||||||
opts.order = opts.order or 1500
|
|
||||||
|
|
||||||
-- Chosen by ChatGPT fairly, PRs are welcome to adjust them
|
|
||||||
local t = THEME.git or {}
|
|
||||||
local styles = {
|
|
||||||
[6] = t.modified and ui.Style(t.modified) or ui.Style():fg("#ffa500"),
|
|
||||||
[5] = t.added and ui.Style(t.added) or ui.Style():fg("#32cd32"),
|
|
||||||
[4] = t.untracked and ui.Style(t.untracked) or ui.Style():fg("#a9a9a9"),
|
|
||||||
[3] = t.ignored and ui.Style(t.ignored) or ui.Style():fg("#696969"),
|
|
||||||
[2] = t.deleted and ui.Style(t.deleted) or ui.Style():fg("#ff4500"),
|
|
||||||
[1] = t.updated and ui.Style(t.updated) or ui.Style():fg("#1e90ff"),
|
|
||||||
}
|
|
||||||
local signs = {
|
|
||||||
[6] = t.modified_sign and t.modified_sign or "",
|
|
||||||
[5] = t.added_sign and t.added_sign or "",
|
|
||||||
[4] = t.untracked_sign and t.untracked_sign or "",
|
|
||||||
[3] = t.ignored_sign and t.ignored_sign or "",
|
|
||||||
[2] = t.deleted_sign and t.deleted_sign or "",
|
|
||||||
[1] = t.updated_sign and t.updated_sign or "U",
|
|
||||||
}
|
|
||||||
|
|
||||||
Linemode:children_add(function(self)
|
|
||||||
local url = self._file.url
|
|
||||||
local dir = st.dirs[tostring(url:parent())]
|
|
||||||
local change
|
|
||||||
if dir then
|
|
||||||
change = dir == "" and 3 or st.repos[dir][tostring(url):sub(#dir + 2)]
|
|
||||||
end
|
|
||||||
|
|
||||||
if not change or signs[change] == "" then
|
|
||||||
return ui.Line("")
|
|
||||||
elseif self._file:is_hovered() then
|
|
||||||
return ui.Line { ui.Span(" "), ui.Span(signs[change]) }
|
|
||||||
else
|
|
||||||
return ui.Line { ui.Span(" "), ui.Span(signs[change]):style(styles[change]) }
|
|
||||||
end
|
|
||||||
end, opts.order)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fetch(_, job)
|
|
||||||
local cwd = job.files[1].url:parent()
|
|
||||||
local repo = root(cwd)
|
|
||||||
if not repo then
|
|
||||||
remove(tostring(cwd))
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local paths = {}
|
|
||||||
for _, f in ipairs(job.files) do
|
|
||||||
paths[#paths + 1] = tostring(f.url)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- stylua: ignore
|
|
||||||
local output, err = Command("git")
|
|
||||||
:cwd(tostring(cwd))
|
|
||||||
:args({ "--no-optional-locks", "-c", "core.quotePath=", "status", "--porcelain", "-unormal", "--no-renames", "--ignored=matching" })
|
|
||||||
:args(paths)
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:output()
|
|
||||||
if not output then
|
|
||||||
ya.err("Cannot spawn git command, error: " .. err)
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local changed, ignored = {}, {}
|
|
||||||
for line in output.stdout:gmatch("[^\r\n]+") do
|
|
||||||
local sign, path = match(line)
|
|
||||||
if sign == 30 then
|
|
||||||
ignored[path] = sign
|
|
||||||
else
|
|
||||||
changed[path] = sign
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if job.files[1].cha.is_dir then
|
|
||||||
ya.dict_merge(changed, bubble_up(changed))
|
|
||||||
ya.dict_merge(changed, propagate_down(ignored, cwd, Url(repo)))
|
|
||||||
else
|
|
||||||
ya.dict_merge(changed, propagate_down(ignored, cwd, Url(repo)))
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, p in ipairs(paths) do
|
|
||||||
local s = p:sub(#repo + 2)
|
|
||||||
changed[s] = changed[s] or 0
|
|
||||||
end
|
|
||||||
add(tostring(cwd), repo, changed)
|
|
||||||
|
|
||||||
return 3
|
|
||||||
end
|
|
||||||
|
|
||||||
return { setup = setup, fetch = fetch }
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M:peek(job)
|
|
||||||
-- Set a fixed width of 55 characters for the preview
|
|
||||||
local preview_width = 55
|
|
||||||
|
|
||||||
local child = Command("glow")
|
|
||||||
:args({
|
|
||||||
"--style",
|
|
||||||
"dark",
|
|
||||||
"--width",
|
|
||||||
tostring(preview_width), -- Use fixed width instead of job.area.w
|
|
||||||
tostring(job.file.url),
|
|
||||||
})
|
|
||||||
:env("CLICOLOR_FORCE", "1")
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:spawn()
|
|
||||||
|
|
||||||
if not child then
|
|
||||||
return require("code").peek(job)
|
|
||||||
end
|
|
||||||
|
|
||||||
local limit = job.area.h
|
|
||||||
local i, lines = 0, ""
|
|
||||||
repeat
|
|
||||||
local next, event = child:read_line()
|
|
||||||
if event == 1 then
|
|
||||||
return require("code").peek(job)
|
|
||||||
elseif event ~= 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
if i > job.skip then
|
|
||||||
lines = lines .. next
|
|
||||||
end
|
|
||||||
until i >= job.skip + limit
|
|
||||||
|
|
||||||
child:start_kill()
|
|
||||||
if job.skip > 0 and i < job.skip + limit then
|
|
||||||
ya.manager_emit("peek", {
|
|
||||||
tostring(math.max(0, i - limit)),
|
|
||||||
only_if = job.file.url,
|
|
||||||
upper_bound = true
|
|
||||||
})
|
|
||||||
else
|
|
||||||
lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
|
|
||||||
ya.preview_widgets(job, { ui.Text.parse(lines):area(job.area) })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:seek(job)
|
|
||||||
local h = cx.active.current.hovered
|
|
||||||
if not h or h.url ~= job.file.url then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local scroll_amount = 1
|
|
||||||
local scroll_offset = job.units
|
|
||||||
|
|
||||||
if job.key == "ctrl-e" then
|
|
||||||
scroll_offset = scroll_amount
|
|
||||||
elseif job.key == "ctrl-y" then
|
|
||||||
scroll_offset = -scroll_amount
|
|
||||||
else
|
|
||||||
scroll_offset = job.units
|
|
||||||
end
|
|
||||||
|
|
||||||
ya.manager_emit('peek', {
|
|
||||||
math.max(0, cx.active.preview.skip + scroll_offset),
|
|
||||||
only_if = job.file.url,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M:peek(job)
|
|
||||||
local child
|
|
||||||
local l = self.file.cha.len
|
|
||||||
if l == 0 then
|
|
||||||
child = Command("hexyl")
|
|
||||||
:args({
|
|
||||||
tostring(job.file.url),
|
|
||||||
})
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:spawn()
|
|
||||||
else
|
|
||||||
child = Command("hexyl")
|
|
||||||
:args({
|
|
||||||
"--border",
|
|
||||||
"none",
|
|
||||||
"--terminal-width",
|
|
||||||
tostring(job.area.w),
|
|
||||||
tostring(job.file.url),
|
|
||||||
})
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:spawn()
|
|
||||||
end
|
|
||||||
|
|
||||||
local limit = job.area.h
|
|
||||||
local i, lines = 0, ""
|
|
||||||
repeat
|
|
||||||
local next, event = child:read_line()
|
|
||||||
if event == 1 then
|
|
||||||
ya.err(tostring(event))
|
|
||||||
elseif event ~= 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
if i > job.skip then
|
|
||||||
lines = lines .. next
|
|
||||||
end
|
|
||||||
until i >= job.skip + limit
|
|
||||||
|
|
||||||
child:start_kill()
|
|
||||||
if job.skip > 0 and i < job.skip + limit then
|
|
||||||
ya.manager_emit("peek", { math.max(0, i - limit), only_if = job.file.url, upper_bound = true })
|
|
||||||
else
|
|
||||||
lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
|
|
||||||
ya.preview_widgets(job, { ui.Text.parse(lines):area(job.area) })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:seek(units)
|
|
||||||
require("code").seek(job, units)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
--- @sync entry
|
|
||||||
|
|
||||||
local function entry(st)
|
|
||||||
if st.old then
|
|
||||||
Tab.layout, st.old = st.old, nil
|
|
||||||
else
|
|
||||||
st.old = Tab.layout
|
|
||||||
Tab.layout = function(self)
|
|
||||||
local all = MANAGER.ratio.parent + MANAGER.ratio.current
|
|
||||||
self._chunks = ui.Layout()
|
|
||||||
:direction(ui.Layout.HORIZONTAL)
|
|
||||||
:constraints({
|
|
||||||
ui.Constraint.Ratio(MANAGER.ratio.parent, all),
|
|
||||||
ui.Constraint.Ratio(MANAGER.ratio.current, all),
|
|
||||||
ui.Constraint.Length(1),
|
|
||||||
})
|
|
||||||
:split(self._area)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
ya.app_emit("resize", {})
|
|
||||||
end
|
|
||||||
|
|
||||||
local function enabled(st) return st.old ~= nil end
|
|
||||||
|
|
||||||
return { entry = entry, enabled = enabled }
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
--- @sync entry
|
|
||||||
|
|
||||||
local function entry(st)
|
|
||||||
if st.old then
|
|
||||||
Tab.layout, st.old = st.old, nil
|
|
||||||
else
|
|
||||||
st.old = Tab.layout
|
|
||||||
Tab.layout = function(self)
|
|
||||||
self._chunks = ui.Layout()
|
|
||||||
:direction(ui.Layout.HORIZONTAL)
|
|
||||||
:constraints({
|
|
||||||
ui.Constraint.Percentage(0),
|
|
||||||
ui.Constraint.Percentage(0),
|
|
||||||
ui.Constraint.Percentage(100),
|
|
||||||
})
|
|
||||||
:split(self._area)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
ya.app_emit("resize", {})
|
|
||||||
end
|
|
||||||
|
|
||||||
local function enabled(st) return st.old ~= nil end
|
|
||||||
|
|
||||||
return { entry = entry, enabled = enabled }
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2024 Lauri Niskanen
|
|
||||||
|
|
||||||
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.
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
# mediainfo.yazi
|
|
||||||
|
|
||||||
This is a Yazi plugin for previewing media files. The preview shows thumbnail
|
|
||||||
using `ffmpegthumbnailer` if available and media metadata using `mediainfo`.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Install the plugin:
|
|
||||||
|
|
||||||
```
|
|
||||||
ya pack -a Ape/mediainfo
|
|
||||||
```
|
|
||||||
|
|
||||||
Create `~/.config/yazi/yazi.toml` and add:
|
|
||||||
|
|
||||||
```
|
|
||||||
[plugin]
|
|
||||||
prepend_previewers = [
|
|
||||||
{ mime = "{image,audio,video}/*", run = "mediainfo"},
|
|
||||||
{ mime = "application/x-subrip", run = "mediainfo"},
|
|
||||||
]
|
|
||||||
```
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
local skip_labels = {
|
|
||||||
["Complete name"] = true,
|
|
||||||
["CompleteName_Last"] = true,
|
|
||||||
["Unique ID"] = true,
|
|
||||||
["File size"] = true,
|
|
||||||
["Format/Info"] = true,
|
|
||||||
["Codec ID/Info"] = true,
|
|
||||||
["MD5 of the unencoded content"] = true,
|
|
||||||
}
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M:peek()
|
|
||||||
local image_height = 0
|
|
||||||
|
|
||||||
if self:preload() == 1 then
|
|
||||||
local cache = ya.file_cache(self)
|
|
||||||
if cache and fs.cha(cache).length > 0 then
|
|
||||||
image_height = ya.image_show(cache, self.area).h
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local cmd = "mediainfo"
|
|
||||||
local output, code = Command(cmd)
|
|
||||||
:args({ tostring(self.file.url) })
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:output()
|
|
||||||
|
|
||||||
local lines = {}
|
|
||||||
|
|
||||||
if output then
|
|
||||||
local i = 0
|
|
||||||
for str in output.stdout:gmatch("[^\n]*") do
|
|
||||||
local label, value = str:match("(.*[^ ]) +: (.*)")
|
|
||||||
local line
|
|
||||||
|
|
||||||
if label then
|
|
||||||
if not skip_labels[label] then
|
|
||||||
line = ui.Line({
|
|
||||||
ui.Span(label .. ": "):bold(),
|
|
||||||
ui.Span(value),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
elseif str ~= "General" then
|
|
||||||
line = ui.Line({ ui.Span(str):underline() })
|
|
||||||
end
|
|
||||||
|
|
||||||
if line then
|
|
||||||
if i >= self.skip then
|
|
||||||
table.insert(lines, line)
|
|
||||||
end
|
|
||||||
|
|
||||||
local max_width = math.max(1, self.area.w - 3)
|
|
||||||
i = i + math.max(1, math.ceil(line:width() / max_width))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local error = string.format("Spawn `%s` command returns %s", cmd, code)
|
|
||||||
table.insert(lines, ui.Line(error))
|
|
||||||
end
|
|
||||||
|
|
||||||
ya.preview_widgets(self, {
|
|
||||||
ui.Paragraph(
|
|
||||||
ui.Rect({
|
|
||||||
x = self.area.x,
|
|
||||||
y = self.area.y + image_height,
|
|
||||||
w = self.area.w,
|
|
||||||
h = self.area.h - image_height,
|
|
||||||
}),
|
|
||||||
lines
|
|
||||||
):wrap(ui.Paragraph.WRAP),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:seek(units)
|
|
||||||
local h = cx.active.current.hovered
|
|
||||||
if h and h.url == self.file.url then
|
|
||||||
local step = math.floor(units * self.area.h / 10)
|
|
||||||
ya.manager_emit("peek", {
|
|
||||||
math.max(0, cx.active.preview.skip + step),
|
|
||||||
only_if = self.file.url,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:preload()
|
|
||||||
local cache = ya.file_cache(self)
|
|
||||||
if not cache or fs.cha(cache) then
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local cmd = "ffmpegthumbnailer"
|
|
||||||
local child, code = Command(cmd):args({
|
|
||||||
"-q", "6",
|
|
||||||
"-c", "jpeg",
|
|
||||||
"-i", tostring(self.file.url),
|
|
||||||
"-o", tostring(cache),
|
|
||||||
"-t", "5",
|
|
||||||
"-s", tostring(PREVIEW.max_width),
|
|
||||||
}):spawn()
|
|
||||||
|
|
||||||
if not child then
|
|
||||||
ya.err(string.format("spawn `%s` command returns %s", cmd, code))
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local status = child:wait()
|
|
||||||
return status and status.success and 1 or 2
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M:peek()
|
|
||||||
local child = Command("mlr")
|
|
||||||
:args({
|
|
||||||
"--icsv",
|
|
||||||
"--opprint",
|
|
||||||
"-C",
|
|
||||||
"--key-color",
|
|
||||||
"darkcyan",
|
|
||||||
"--value-color",
|
|
||||||
"grey70",
|
|
||||||
"cat",
|
|
||||||
tostring(self.file.url),
|
|
||||||
})
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:spawn()
|
|
||||||
|
|
||||||
local limit = self.area.h
|
|
||||||
local i, lines = 0, ""
|
|
||||||
repeat
|
|
||||||
local next, event = child:read_line()
|
|
||||||
if event == 1 then
|
|
||||||
ya.err(tostring(event))
|
|
||||||
elseif event ~= 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
if i > self.skip then
|
|
||||||
lines = lines .. next
|
|
||||||
end
|
|
||||||
until i >= self.skip + limit
|
|
||||||
|
|
||||||
child:start_kill()
|
|
||||||
if self.skip > 0 and i < self.skip + limit then
|
|
||||||
ya.manager_emit(
|
|
||||||
"peek",
|
|
||||||
{ tostring(math.max(0, i - limit)), only_if = tostring(self.file.url), upper_bound = "" }
|
|
||||||
)
|
|
||||||
else
|
|
||||||
lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
|
|
||||||
ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:seek(units)
|
|
||||||
local h = cx.active.current.hovered
|
|
||||||
if h and h.url == self.file.url then
|
|
||||||
local step = math.floor(units * self.area.h / 10)
|
|
||||||
ya.manager_emit("peek", {
|
|
||||||
tostring(math.max(0, cx.active.preview.skip + step)),
|
|
||||||
only_if = tostring(self.file.url),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M:peek(job)
|
|
||||||
local child = Command("nbpreview")
|
|
||||||
:args({
|
|
||||||
-- DO NOT CHANGE --
|
|
||||||
"--no-paging",
|
|
||||||
"--nerd-font",
|
|
||||||
"--decorated",
|
|
||||||
|
|
||||||
-- OPTIONAL CHANGES --
|
|
||||||
"--no-files",
|
|
||||||
"--unicode",
|
|
||||||
"--color",
|
|
||||||
"--images",
|
|
||||||
|
|
||||||
-- SPECIAL CUSTOMIZATIONS --
|
|
||||||
"--color-system=standard",
|
|
||||||
"--theme=ansi_dark",
|
|
||||||
tostring(job.file.url),
|
|
||||||
})
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:spawn()
|
|
||||||
if not child then
|
|
||||||
return require("code"):peek(job)
|
|
||||||
end
|
|
||||||
|
|
||||||
local limit = job.area.h
|
|
||||||
local i, lines = 0, ""
|
|
||||||
repeat
|
|
||||||
local next, event = child:read_line()
|
|
||||||
if event == 1 then
|
|
||||||
return require("code"):peek(job)
|
|
||||||
elseif event ~= 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
if i > job.skip then
|
|
||||||
lines = lines .. next
|
|
||||||
end
|
|
||||||
until i >= job.skip + limit
|
|
||||||
|
|
||||||
child:start_kill()
|
|
||||||
if job.skip > 0 and i < job.skip + limit then
|
|
||||||
ya.manager_emit("peek", { math.max(0, i - limit), only_if = job.file.url, upper_bound = true })
|
|
||||||
else
|
|
||||||
lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
|
|
||||||
ya.preview_widgets(job, { ui.Text.parse(lines):area(job.area) })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:seek(job)
|
|
||||||
require("code"):seek(job)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M:peek(job)
|
|
||||||
local child = Command("ouch")
|
|
||||||
:args({ "l", "-t", "-y", tostring(job.file.url) })
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:spawn()
|
|
||||||
local limit = job.area.h
|
|
||||||
local file_name = string.match(tostring(job.file.url), ".*[/\\](.*)")
|
|
||||||
local lines = string.format("📁 \x1b[2m%s\x1b[0m\n", file_name)
|
|
||||||
local num_lines = 1
|
|
||||||
local num_skip = 0
|
|
||||||
repeat
|
|
||||||
local line, event = child:read_line()
|
|
||||||
if event == 1 then
|
|
||||||
ya.err(tostring(event))
|
|
||||||
elseif event ~= 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
if line:find('Archive', 1, true) ~= 1 and line:find('[INFO]', 1, true) ~= 1 then
|
|
||||||
if num_skip >= job.skip then
|
|
||||||
lines = lines .. line
|
|
||||||
num_lines = num_lines + 1
|
|
||||||
else
|
|
||||||
num_skip = num_skip + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
until num_lines >= limit
|
|
||||||
|
|
||||||
child:start_kill()
|
|
||||||
if job.skip > 0 and num_lines < limit then
|
|
||||||
ya.manager_emit(
|
|
||||||
"peek",
|
|
||||||
{ tostring(math.max(0, job.skip - (limit - num_lines))), only_if = tostring(job.file.url), upper_bound = "" }
|
|
||||||
)
|
|
||||||
else
|
|
||||||
ya.preview_widgets(job, { ui.Text(lines):area(job.area) })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:seek(job)
|
|
||||||
local h = cx.active.current.hovered
|
|
||||||
if h and h.url == job.file.url then
|
|
||||||
local step = math.floor(job.units * job.area.h / 10)
|
|
||||||
ya.manager_emit("peek", {
|
|
||||||
math.max(0, cx.active.preview.skip + step),
|
|
||||||
only_if = tostring(job.file.url),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if file exists
|
|
||||||
local function file_exists(name)
|
|
||||||
local f = io.open(name, "r")
|
|
||||||
if f ~= nil then
|
|
||||||
io.close(f)
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get the files that need to be compressed and infer a default archive name
|
|
||||||
local get_compression_target = ya.sync(function()
|
|
||||||
local tab = cx.active
|
|
||||||
local default_name
|
|
||||||
local paths = {}
|
|
||||||
if #tab.selected == 0 then
|
|
||||||
if tab.current.hovered then
|
|
||||||
local name = tab.current.hovered.name
|
|
||||||
default_name = name
|
|
||||||
table.insert(paths, name)
|
|
||||||
else
|
|
||||||
return
|
|
||||||
end
|
|
||||||
else
|
|
||||||
default_name = tab.current.cwd:name()
|
|
||||||
for _, url in pairs(tab.selected) do
|
|
||||||
table.insert(paths, tostring(url))
|
|
||||||
end
|
|
||||||
-- The compression targets are aquired, now unselect them
|
|
||||||
ya.manager_emit("escape", {})
|
|
||||||
end
|
|
||||||
return paths, default_name
|
|
||||||
end)
|
|
||||||
|
|
||||||
local function invoke_compress_command(paths, name)
|
|
||||||
local cmd_output, err_code = Command("ouch")
|
|
||||||
:args({ "c", "-y" })
|
|
||||||
:args(paths)
|
|
||||||
:arg(name)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:output()
|
|
||||||
if err_code ~= nil then
|
|
||||||
ya.notify({
|
|
||||||
title = "Failed to run ouch command",
|
|
||||||
content = "Status: " .. err_code,
|
|
||||||
timeout = 5.0,
|
|
||||||
level = "error",
|
|
||||||
})
|
|
||||||
elseif not cmd_output.status.success then
|
|
||||||
ya.notify({
|
|
||||||
title = "Compression failed: status code " .. cmd_output.status.code,
|
|
||||||
content = cmd_output.stderr,
|
|
||||||
timeout = 5.0,
|
|
||||||
level = "error",
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:entry(job)
|
|
||||||
local default_fmt = job.args[1]
|
|
||||||
|
|
||||||
ya.manager_emit("escape", { visual = true })
|
|
||||||
|
|
||||||
-- Get the files that need to be compressed and infer a default archive name
|
|
||||||
local paths, default_name = get_compression_target()
|
|
||||||
|
|
||||||
-- Get archive name from user
|
|
||||||
local output_name, name_event = ya.input({
|
|
||||||
title = "Create archive:",
|
|
||||||
value = default_name .. "." .. default_fmt,
|
|
||||||
position = { "top-center", y = 3, w = 40 },
|
|
||||||
})
|
|
||||||
if name_event ~= 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get confirmation if file exists
|
|
||||||
if file_exists(output_name) then
|
|
||||||
local confirm, confirm_event = ya.input({
|
|
||||||
title = "Overwrite " .. output_name .. "? (y/N)",
|
|
||||||
position = { "top-center", y = 3, w = 40 },
|
|
||||||
})
|
|
||||||
if not (confirm_event == 1 and confirm:lower() == "y") then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
invoke_compress_command(paths, output_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,326 +0,0 @@
|
|||||||
-- stylua: ignore
|
|
||||||
local MOTIONS_AND_OP_KEYS = {
|
|
||||||
{ on = "0" }, { on = "1" }, { on = "2" }, { on = "3" }, { on = "4" },
|
|
||||||
{ on = "5" }, { on = "6" }, { on = "7" }, { on = "8" }, { on = "9" },
|
|
||||||
-- commands
|
|
||||||
{ on = "d" }, { on = "v" }, { on = "y" }, { on = "x" },
|
|
||||||
-- tab commands
|
|
||||||
{ on = "t" }, { on = "L" }, { on = "H" }, { on = "w" },
|
|
||||||
{ on = "W" }, { on = "<" }, { on = ">" }, { on = "~" },
|
|
||||||
-- movement
|
|
||||||
{ on = "g" }, { on = "j" }, { on = "k" }, { on = "<Down>" }, { on = "<Up>" }
|
|
||||||
}
|
|
||||||
|
|
||||||
-- stylua: ignore
|
|
||||||
local MOTION_KEYS = {
|
|
||||||
{ on = "0" }, { on = "1" }, { on = "2" }, { on = "3" }, { on = "4" },
|
|
||||||
{ on = "5" }, { on = "6" }, { on = "7" }, { on = "8" }, { on = "9" },
|
|
||||||
-- movement
|
|
||||||
{ on = "g" }, { on = "j" }, { on = "k" }
|
|
||||||
}
|
|
||||||
|
|
||||||
-- stylua: ignore
|
|
||||||
local DIRECTION_KEYS = {
|
|
||||||
{ on = "j" }, { on = "k" }, { on = "<Down>" }, { on = "<Up>" },
|
|
||||||
-- tab movement
|
|
||||||
{ on = "t" }
|
|
||||||
}
|
|
||||||
|
|
||||||
local SHOW_NUMBERS_ABSOLUTE = 0
|
|
||||||
local SHOW_NUMBERS_RELATIVE = 1
|
|
||||||
local SHOW_NUMBERS_RELATIVE_ABSOLUTE = 2
|
|
||||||
|
|
||||||
-----------------------------------------------
|
|
||||||
----------------- R E N D E R -----------------
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
local render_motion_setup = ya.sync(function(_)
|
|
||||||
ya.render()
|
|
||||||
|
|
||||||
Status.motion = function() return ui.Span("") end
|
|
||||||
|
|
||||||
Status.children_redraw = function(self, side)
|
|
||||||
local lines = {}
|
|
||||||
if side == self.RIGHT then
|
|
||||||
lines[1] = self:motion(self)
|
|
||||||
end
|
|
||||||
for _, c in ipairs(side == self.RIGHT and self._right or self._left) do
|
|
||||||
lines[#lines + 1] = (type(c[1]) == "string" and self[c[1]] or c[1])(self)
|
|
||||||
end
|
|
||||||
return ui.Line(lines)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- TODO: check why it doesn't work line this
|
|
||||||
-- Status:children_add(function() return ui.Span("") end, 1000, Status.RIGHT)
|
|
||||||
end)
|
|
||||||
|
|
||||||
local render_motion = ya.sync(function(_, motion_num, motion_cmd)
|
|
||||||
ya.render()
|
|
||||||
|
|
||||||
Status.motion = function(self)
|
|
||||||
if not motion_num then
|
|
||||||
return ui.Span("")
|
|
||||||
end
|
|
||||||
|
|
||||||
local style = self:style()
|
|
||||||
|
|
||||||
local motion_span
|
|
||||||
if not motion_cmd then
|
|
||||||
motion_span = ui.Span(string.format(" %3d ", motion_num))
|
|
||||||
else
|
|
||||||
motion_span = ui.Span(string.format(" %3d%s ", motion_num, motion_cmd))
|
|
||||||
end
|
|
||||||
|
|
||||||
return ui.Line {
|
|
||||||
ui.Span(THEME.status.separator_open):fg(style.main.bg),
|
|
||||||
motion_span:style(style.main),
|
|
||||||
ui.Span(THEME.status.separator_close):fg(style.main.bg),
|
|
||||||
ui.Span(" "),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
local render_numbers = ya.sync(function(_, mode)
|
|
||||||
ya.render()
|
|
||||||
|
|
||||||
Entity.number = function(_, index, file, hovered)
|
|
||||||
local idx
|
|
||||||
if mode == SHOW_NUMBERS_RELATIVE then
|
|
||||||
idx = math.abs(hovered - index)
|
|
||||||
elseif mode == SHOW_NUMBERS_ABSOLUTE then
|
|
||||||
idx = file.idx
|
|
||||||
else -- SHOW_NUMBERS_RELATIVE_ABSOLUTE
|
|
||||||
if hovered == index then
|
|
||||||
idx = file.idx
|
|
||||||
else
|
|
||||||
idx = math.abs(hovered - index)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- emulate vim's hovered offset
|
|
||||||
if idx >= 100 then
|
|
||||||
return ui.Span(string.format("%4d ", idx))
|
|
||||||
elseif hovered == index then
|
|
||||||
return ui.Span(string.format("%3d ", idx))
|
|
||||||
else
|
|
||||||
return ui.Span(string.format(" %3d ", idx))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Current.redraw = function(self)
|
|
||||||
local files = self._folder.window
|
|
||||||
if #files == 0 then
|
|
||||||
return self:empty()
|
|
||||||
end
|
|
||||||
|
|
||||||
local hovered_index
|
|
||||||
for i, f in ipairs(files) do
|
|
||||||
if f:is_hovered() then
|
|
||||||
hovered_index = i
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local entities, linemodes = {}, {}
|
|
||||||
for i, f in ipairs(files) do
|
|
||||||
linemodes[#linemodes + 1] = Linemode:new(f):redraw()
|
|
||||||
|
|
||||||
local entity = Entity:new(f)
|
|
||||||
entities[#entities + 1] = ui.Line({ Entity:number(i, f, hovered_index), entity:redraw() }):style(entity:style())
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
ui.List(entities):area(self._area),
|
|
||||||
ui.Text(linemodes):area(self._area):align(ui.Text.RIGHT),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
local function render_clear() render_motion() end
|
|
||||||
|
|
||||||
-----------------------------------------------
|
|
||||||
--------- C O M M A N D P A R S E R ---------
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
local get_keys = ya.sync(function(state) return state._only_motions and MOTION_KEYS or MOTIONS_AND_OP_KEYS end)
|
|
||||||
|
|
||||||
local function normal_direction(dir)
|
|
||||||
if dir == "<Down>" then
|
|
||||||
return "j"
|
|
||||||
elseif dir == "<Up>" then
|
|
||||||
return "k"
|
|
||||||
end
|
|
||||||
return dir
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_cmd(first_char, keys)
|
|
||||||
local last_key
|
|
||||||
local lines = first_char or ""
|
|
||||||
|
|
||||||
while true do
|
|
||||||
render_motion(tonumber(lines))
|
|
||||||
local key = ya.which { cands = keys, silent = true }
|
|
||||||
if not key then
|
|
||||||
return nil, nil, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
last_key = keys[key].on
|
|
||||||
if not tonumber(last_key) then
|
|
||||||
last_key = normal_direction(last_key)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
lines = lines .. last_key
|
|
||||||
end
|
|
||||||
|
|
||||||
render_motion(tonumber(lines), last_key)
|
|
||||||
|
|
||||||
-- command direction
|
|
||||||
local direction
|
|
||||||
if last_key == "g" or last_key == "v" or last_key == "d" or last_key == "y" or last_key == "x" then
|
|
||||||
DIRECTION_KEYS[#DIRECTION_KEYS + 1] = {
|
|
||||||
on = last_key,
|
|
||||||
}
|
|
||||||
local direction_key = ya.which { cands = DIRECTION_KEYS, silent = true }
|
|
||||||
if not direction_key then
|
|
||||||
return nil, nil, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
direction = DIRECTION_KEYS[direction_key].on
|
|
||||||
direction = normal_direction(direction)
|
|
||||||
end
|
|
||||||
|
|
||||||
return tonumber(lines), last_key, direction
|
|
||||||
end
|
|
||||||
|
|
||||||
local function is_tab_command(command)
|
|
||||||
local tab_commands = { "t", "L", "H", "w", "W", "<", ">", "~" }
|
|
||||||
for _, cmd in ipairs(tab_commands) do
|
|
||||||
if command == cmd then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local get_active_tab = ya.sync(function(_) return cx.tabs.idx end)
|
|
||||||
|
|
||||||
-----------------------------------------------
|
|
||||||
---------- E N T R Y / S E T U P ----------
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
return {
|
|
||||||
entry = function(_, job)
|
|
||||||
local initial_value
|
|
||||||
|
|
||||||
local args = job.args
|
|
||||||
-- this is checking if the argument is a valid number
|
|
||||||
if #args > 0 then
|
|
||||||
initial_value = tostring(tonumber(args[1]))
|
|
||||||
if initial_value == "nil" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local lines, cmd, direction = get_cmd(initial_value, get_keys())
|
|
||||||
if not lines or not cmd then
|
|
||||||
-- command was cancelled
|
|
||||||
render_clear()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if cmd == "g" then
|
|
||||||
if direction == "g" then
|
|
||||||
ya.manager_emit("arrow", { -99999999 })
|
|
||||||
ya.manager_emit("arrow", { lines - 1 })
|
|
||||||
render_clear()
|
|
||||||
return
|
|
||||||
elseif direction == "j" then
|
|
||||||
cmd = "j"
|
|
||||||
elseif direction == "k" then
|
|
||||||
cmd = "k"
|
|
||||||
elseif direction == "t" then
|
|
||||||
ya.manager_emit("tab_switch", { lines - 1 })
|
|
||||||
render_clear()
|
|
||||||
return
|
|
||||||
else
|
|
||||||
-- no valid direction
|
|
||||||
render_clear()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if cmd == "j" then
|
|
||||||
ya.manager_emit("arrow", { lines })
|
|
||||||
elseif cmd == "k" then
|
|
||||||
ya.manager_emit("arrow", { -lines })
|
|
||||||
elseif is_tab_command(cmd) then
|
|
||||||
if cmd == "t" then
|
|
||||||
for _ = 1, lines do
|
|
||||||
ya.manager_emit("tab_create", {})
|
|
||||||
end
|
|
||||||
elseif cmd == "H" then
|
|
||||||
ya.manager_emit("tab_switch", { -lines, relative = true })
|
|
||||||
elseif cmd == "L" then
|
|
||||||
ya.manager_emit("tab_switch", { lines, relative = true })
|
|
||||||
elseif cmd == "w" then
|
|
||||||
ya.manager_emit("tab_close", { lines - 1 })
|
|
||||||
elseif cmd == "W" then
|
|
||||||
local curr_tab = get_active_tab()
|
|
||||||
local del_tab = curr_tab + lines - 1
|
|
||||||
for _ = curr_tab, del_tab do
|
|
||||||
ya.manager_emit("tab_close", { curr_tab - 1 })
|
|
||||||
end
|
|
||||||
ya.manager_emit("tab_switch", { curr_tab - 1 })
|
|
||||||
elseif cmd == "<" then
|
|
||||||
ya.manager_emit("tab_swap", { -lines })
|
|
||||||
elseif cmd == ">" then
|
|
||||||
ya.manager_emit("tab_swap", { lines })
|
|
||||||
elseif cmd == "~" then
|
|
||||||
local jump = lines - get_active_tab()
|
|
||||||
ya.manager_emit("tab_swap", { jump })
|
|
||||||
end
|
|
||||||
else
|
|
||||||
ya.manager_emit("visual_mode", {})
|
|
||||||
-- invert direction when user specifies it
|
|
||||||
if direction == "k" then
|
|
||||||
ya.manager_emit("arrow", { -lines })
|
|
||||||
elseif direction == "j" then
|
|
||||||
ya.manager_emit("arrow", { lines })
|
|
||||||
else
|
|
||||||
ya.manager_emit("arrow", { lines - 1 })
|
|
||||||
end
|
|
||||||
ya.manager_emit("escape", {})
|
|
||||||
|
|
||||||
if cmd == "d" then
|
|
||||||
ya.manager_emit("remove", {})
|
|
||||||
elseif cmd == "y" then
|
|
||||||
ya.manager_emit("yank", {})
|
|
||||||
elseif cmd == "x" then
|
|
||||||
ya.manager_emit("yank", { cut = true })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
render_clear()
|
|
||||||
end,
|
|
||||||
setup = function(state, args)
|
|
||||||
if not args then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- initialize state variables
|
|
||||||
state._only_motions = args["only_motions"] or false
|
|
||||||
|
|
||||||
if args["show_motion"] then
|
|
||||||
render_motion_setup()
|
|
||||||
end
|
|
||||||
|
|
||||||
if args["show_numbers"] == "absolute" then
|
|
||||||
render_numbers(SHOW_NUMBERS_ABSOLUTE)
|
|
||||||
elseif args["show_numbers"] == "relative" then
|
|
||||||
render_numbers(SHOW_NUMBERS_RELATIVE)
|
|
||||||
elseif args["show_numbers"] == "relative_absolute" then
|
|
||||||
render_numbers(SHOW_NUMBERS_RELATIVE_ABSOLUTE)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2024 Rolv Apneseth
|
|
||||||
|
|
||||||
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.
|
|
||||||
@ -1,101 +0,0 @@
|
|||||||
# starship.yazi
|
|
||||||
|
|
||||||
Starship prompt plugin for [Yazi](https://github.com/sxyazi/yazi)
|
|
||||||
|
|
||||||
<https://github.com/Rolv-Apneseth/starship.yazi/assets/69486699/f7314687-5cb1-4d66-8d9d-cca960ba6716>
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- [Yazi](https://github.com/sxyazi/yazi)
|
|
||||||
- [starship](https://github.com/starship/starship)
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ya pack -a Rolv-Apneseth/starship
|
|
||||||
```
|
|
||||||
|
|
||||||
### Manual
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# Linux / MacOS
|
|
||||||
git clone https://github.com/Rolv-Apneseth/starship.yazi.git ~/.config/yazi/plugins/starship.yazi
|
|
||||||
# Windows
|
|
||||||
git clone https://github.com/Rolv-Apneseth/starship.yazi.git %AppData%\yazi\config\plugins\starship.yazi
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Add this to `~/.config/yazi/init.lua`:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
require("starship"):setup()
|
|
||||||
```
|
|
||||||
|
|
||||||
If you wish to define a custom config file for `starship` to use, you can pass in a path
|
|
||||||
to the setup function like this:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
starship:setup({ config_file = "/home/rolv/.config/starship_secondary.toml" })
|
|
||||||
```
|
|
||||||
|
|
||||||
Make sure you have [starship](https://github.com/starship/starship) installed and in your `PATH`.
|
|
||||||
|
|
||||||
## Extra
|
|
||||||
|
|
||||||
If you use a `starship` theme with a background colour, it might look a bit to cramped on just the one line `Yazi` gives the header by default. To fix this, you can add this to your `init.lua`:
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Click to expand</summary>
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local old_build = Tab.build
|
|
||||||
Tab.build = function(self, ...)
|
|
||||||
local bar = function(c, x, y)
|
|
||||||
if x <= 0 or x == self._area.w - 1 then
|
|
||||||
return ui.Bar(ui.Rect.default, ui.Bar.TOP)
|
|
||||||
end
|
|
||||||
|
|
||||||
return ui.Bar(
|
|
||||||
ui.Rect({
|
|
||||||
x = x,
|
|
||||||
y = math.max(0, y),
|
|
||||||
w = ya.clamp(0, self._area.w - x, 1),
|
|
||||||
h = math.min(1, self._area.h),
|
|
||||||
}),
|
|
||||||
ui.Bar.TOP
|
|
||||||
):symbol(c)
|
|
||||||
end
|
|
||||||
|
|
||||||
local c = self._chunks
|
|
||||||
self._chunks = {
|
|
||||||
c[1]:padding(ui.Padding.y(1)),
|
|
||||||
c[2]:padding(ui.Padding(c[1].w > 0 and 0 or 1, c[3].w > 0 and 0 or 1, 1, 1)),
|
|
||||||
c[3]:padding(ui.Padding.y(1)),
|
|
||||||
}
|
|
||||||
|
|
||||||
local style = THEME.manager.border_style
|
|
||||||
self._base = ya.list_merge(self._base or {}, {
|
|
||||||
-- Enable for full border
|
|
||||||
--[[ ui.Border(self._area, ui.Border.ALL):type(ui.Border.ROUNDED):style(style), ]]
|
|
||||||
ui.Bar(self._chunks[1], ui.Bar.RIGHT):style(style),
|
|
||||||
ui.Bar(self._chunks[3], ui.Bar.LEFT):style(style),
|
|
||||||
|
|
||||||
bar("┬", c[1].right - 1, c[1].y),
|
|
||||||
bar("┴", c[1].right - 1, c[1].bottom - 1),
|
|
||||||
bar("┬", c[2].right, c[2].y),
|
|
||||||
bar("┴", c[2].right, c[1].bottom - 1),
|
|
||||||
})
|
|
||||||
|
|
||||||
old_build(self, ...)
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> This works by overriding your `Tab.build` function so make sure this is the only place you're doing that in your config. For example, this would be incompatible with the [full-border plugin](https://github.com/yazi-rs/plugins/tree/main/full-border.yazi)
|
|
||||||
|
|
||||||
## Thanks
|
|
||||||
|
|
||||||
- [sxyazi](https://github.com/sxyazi) for providing the code for this plugin and the demo video [in this comment](https://github.com/sxyazi/yazi/issues/767#issuecomment-1977082834)
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
local save = ya.sync(function(st, cwd, output)
|
|
||||||
if cx.active.current.cwd == Url(cwd) then
|
|
||||||
st.output = output
|
|
||||||
ya.render()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Helper function for accessing the `config_file` state variable
|
|
||||||
---@return string
|
|
||||||
local get_config_file = ya.sync(function(st)
|
|
||||||
return st.config_file
|
|
||||||
end)
|
|
||||||
|
|
||||||
return {
|
|
||||||
---User arguments for setup method
|
|
||||||
---@class SetupArgs
|
|
||||||
---@field config_file string Absolute path to a starship config file
|
|
||||||
|
|
||||||
--- Setup plugin
|
|
||||||
--- @param st table State
|
|
||||||
--- @param args SetupArgs|nil
|
|
||||||
setup = function(st, args)
|
|
||||||
-- Replace default header widget
|
|
||||||
Header:children_remove(1, Header.LEFT)
|
|
||||||
Header:children_add(function()
|
|
||||||
return ui.Line.parse(st.output or "")
|
|
||||||
end, 1000, Header.LEFT)
|
|
||||||
|
|
||||||
-- Check for custom starship config file
|
|
||||||
if args ~= nil and args.config_file ~= nil then
|
|
||||||
local url = Url(args.config_file)
|
|
||||||
if url.is_regular then
|
|
||||||
local config_file = args.config_file
|
|
||||||
|
|
||||||
-- Manually replace '~' and '$HOME' at the start of the path with the OS environment variable
|
|
||||||
local home = os.getenv("HOME")
|
|
||||||
if home then
|
|
||||||
home = tostring(home)
|
|
||||||
config_file = config_file:gsub("^~", home):gsub("^$HOME", home)
|
|
||||||
end
|
|
||||||
|
|
||||||
st.config_file = config_file
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Pass current working directory and custom config path (if specified) to the plugin's entry point
|
|
||||||
---Callback for subscribers to update the prompt
|
|
||||||
local callback = function()
|
|
||||||
local cwd = cx.active.current.cwd
|
|
||||||
if st.cwd ~= cwd then
|
|
||||||
st.cwd = cwd
|
|
||||||
ya.manager_emit("plugin", {
|
|
||||||
st._id,
|
|
||||||
args = ya.quote(tostring(cwd), true),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Subscribe to events
|
|
||||||
ps.sub("cd", callback)
|
|
||||||
ps.sub("tab", callback)
|
|
||||||
end,
|
|
||||||
|
|
||||||
entry = function(_, args)
|
|
||||||
local command = Command("starship"):arg("prompt"):cwd(args[1]):env("STARSHIP_SHELL", "")
|
|
||||||
|
|
||||||
-- Point to custom starship config
|
|
||||||
local config_file = get_config_file()
|
|
||||||
if config_file then
|
|
||||||
command = command:env("STARSHIP_CONFIG", config_file)
|
|
||||||
end
|
|
||||||
|
|
||||||
local output = command:output()
|
|
||||||
if output then
|
|
||||||
save(args[1], output.stdout:gsub("^%s+", ""))
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M:peek(job)
|
|
||||||
local child = Command("transmission-show")
|
|
||||||
:args({
|
|
||||||
tostring(job.file.url),
|
|
||||||
})
|
|
||||||
:stdout(Command.PIPED)
|
|
||||||
:stderr(Command.PIPED)
|
|
||||||
:spawn()
|
|
||||||
|
|
||||||
if not child then
|
|
||||||
return require("code"):peek(job)
|
|
||||||
end
|
|
||||||
|
|
||||||
local limit = job.area.h
|
|
||||||
local i, lines = 0, ""
|
|
||||||
repeat
|
|
||||||
local next, event = child:read_line()
|
|
||||||
if event == 1 then
|
|
||||||
return require("code"):peek(job)
|
|
||||||
elseif event ~= 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
if i > job.skip then
|
|
||||||
lines = lines .. next
|
|
||||||
end
|
|
||||||
until i >= job.skip + limit
|
|
||||||
|
|
||||||
child:start_kill()
|
|
||||||
if job.skip > 0 and i < job.skip + limit then
|
|
||||||
ya.manager_emit("peek", { math.max(0, i - limit), only_if = job.file.url, upper_bound = true })
|
|
||||||
else
|
|
||||||
lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size))
|
|
||||||
ya.preview_widgets(job, { ui.Text.parse(lines):area(job.area) })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:seek(job)
|
|
||||||
require("code"):seek(job)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
|
|
||||||
-- function to get paths of selected elements or current directory
|
|
||||||
-- of no elements are selected
|
|
||||||
local get_paths = ya.sync(function()
|
|
||||||
local paths = {}
|
|
||||||
-- get selected files
|
|
||||||
for _, u in pairs(cx.active.selected) do
|
|
||||||
paths[#paths + 1] = tostring(u)
|
|
||||||
end
|
|
||||||
-- if no files are selected, get current directory
|
|
||||||
if #paths == 0 then
|
|
||||||
if cx.active.current.cwd then
|
|
||||||
paths[1] = tostring(cx.active.current.cwd)
|
|
||||||
else
|
|
||||||
ya.err("what-size would return nil paths")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return paths
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Function to get total size from du output
|
|
||||||
local get_total_size = function(s)
|
|
||||||
local lines = {}
|
|
||||||
for line in s:gmatch("[^\n]+") do lines[#lines + 1] = line end
|
|
||||||
local last_line = lines[#lines]
|
|
||||||
local last_line_parts = {}
|
|
||||||
for part in last_line:gmatch("%S+") do last_line_parts[#last_line_parts + 1] = part end
|
|
||||||
local total_size = last_line_parts[1]
|
|
||||||
return total_size
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Function to format file size
|
|
||||||
local function format_size(size)
|
|
||||||
local units = { "B", "KB", "MB", "GB", "TB" }
|
|
||||||
local unit_index = 1
|
|
||||||
|
|
||||||
while size > 1024 and unit_index < #units do
|
|
||||||
size = size / 1024
|
|
||||||
unit_index = unit_index + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
return string.format("%.2f %s", size, units[unit_index])
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
entry = function(self, job)
|
|
||||||
-- defaults not to use clipboard, use it only if required by the user
|
|
||||||
local clipboard = job.args.clipboard or job.args[1] == '-c'
|
|
||||||
local items = get_paths()
|
|
||||||
|
|
||||||
local cmd = "du"
|
|
||||||
local output, err = Command(cmd):arg("-scb"):args(items):output()
|
|
||||||
if not output then
|
|
||||||
ya.err("Failed to run diff, error: " .. err)
|
|
||||||
else
|
|
||||||
local total_size = get_total_size(output.stdout)
|
|
||||||
local formatted_size = format_size(tonumber(total_size))
|
|
||||||
|
|
||||||
local notification_content = "Total size: " .. formatted_size
|
|
||||||
if clipboard then
|
|
||||||
ya.clipboard(formatted_size)
|
|
||||||
notification_content = notification_content .. "\nCopied to clipboard."
|
|
||||||
end
|
|
||||||
|
|
||||||
ya.notify {
|
|
||||||
title = "What size",
|
|
||||||
content = notification_content,
|
|
||||||
timeout = 5,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -143,6 +143,8 @@ bindkey -s '^f' '^utmux neww tmux-sessionizer\n'
|
|||||||
|
|
||||||
eval "$(starship init zsh)"
|
eval "$(starship init zsh)"
|
||||||
eval "$(fzf --zsh)"
|
eval "$(fzf --zsh)"
|
||||||
|
eval "$(uv generate-shell-completion zsh)"
|
||||||
|
eval "$(uvx --generate-shell-completion zsh)"
|
||||||
|
|
||||||
[[ -r ~/.local/share/zsh/plugins/znap/znap.zsh ]] ||
|
[[ -r ~/.local/share/zsh/plugins/znap/znap.zsh ]] ||
|
||||||
git clone --depth 1 -- \
|
git clone --depth 1 -- \
|
||||||
|
|||||||
0
dotter.arm
Normal file → Executable file
0
dotter.arm
Normal file → Executable file
0
dotter.exe
Normal file → Executable file
0
dotter.exe
Normal file → Executable file
Loading…
Reference in New Issue
Block a user