mirror of
https://github.com/sxyazi/yazi.git
synced 2026-05-13 08:16:40 +00:00
feat: make mimetype matching more robust (#3082)
This commit is contained in:
parent
fe9ce240b5
commit
ae75fc0f7b
11 changed files with 95 additions and 97 deletions
5
.luarc.json
Normal file
5
.luarc.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||
"runtime.version": "Lua 5.4",
|
||||
"workspace.library": ["~/.config/yazi/plugins/types.yazi/"]
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
# this file caused some issues with the build system
|
||||
yazi-plugin/preset/plugins/mime.lua
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -2327,9 +2327,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.142"
|
||||
version = "1.0.143"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
|
||||
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ ratatui = { version = "0.29.0", features = [ "unstable-rendered-line
|
|||
regex = "1.11.1"
|
||||
scopeguard = "1.2.0"
|
||||
serde = { version = "1.0.219", features = [ "derive" ] }
|
||||
serde_json = "1.0.142"
|
||||
serde_json = "1.0.143"
|
||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
tokio = { version = "1.47.1", features = [ "full" ] }
|
||||
tokio-stream = "0.1.17"
|
||||
|
|
|
|||
|
|
@ -103,12 +103,14 @@ module.exports = async ({ github, context, core }) => {
|
|||
issue_number: id,
|
||||
name : LABEL_NAME,
|
||||
})
|
||||
await hideOldComments(id)
|
||||
} else if (mark && !marked && !await removedLabelManually(id)) {
|
||||
await github.rest.issues.addLabels({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
labels : [LABEL_NAME],
|
||||
})
|
||||
await hideOldComments(id)
|
||||
await github.rest.issues.createComment({
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
|
|
@ -120,6 +122,37 @@ module.exports = async ({ github, context, core }) => {
|
|||
}
|
||||
}
|
||||
|
||||
async function hideOldComments(id) {
|
||||
try {
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
...context.repo,
|
||||
issue_number: id,
|
||||
per_page : 100,
|
||||
})
|
||||
|
||||
for (const c of comments) {
|
||||
const byBot = c.user?.login?.endsWith("[bot]") || c.user?.type === "Bot"
|
||||
const contains = c?.body?.includes("or closed after 2 days of inactivity")
|
||||
if (!byBot || !contains || !c.node_id) continue
|
||||
|
||||
try {
|
||||
await github.graphql(
|
||||
`mutation($subjectId: ID!, $classifier: ReportedContentClassifiers!) {
|
||||
minimizeComment(input: {subjectId: $subjectId, classifier: $classifier}) {
|
||||
minimizedComment { isMinimized }
|
||||
}
|
||||
}`,
|
||||
{ subjectId: c.node_id, classifier: "OUTDATED" },
|
||||
)
|
||||
} catch (e) {
|
||||
core.error(`Error minimizing comment ${c.id}: ${e.message}`)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
core.error(`Error listing comments: ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function closeOldIssues() {
|
||||
try {
|
||||
const { data: issues } = await github.rest.issues.listForRepo({
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
syntax = "Lua54"
|
||||
indent_width = 2
|
||||
call_parentheses = "NoSingleTable"
|
||||
collapse_simple_statement = "FunctionOnly"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use yazi_fs::{File, FilesOp};
|
||||
use yazi_macro::{act, succ};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::mgr::RevealOpt;
|
||||
use yazi_shared::event::Data;
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ impl Actor for Reveal {
|
|||
|
||||
// Try to hover on the child file
|
||||
let tab = cx.tab_mut();
|
||||
tab.current.hover(child.as_urn());
|
||||
render!(tab.current.hover(child.as_urn()));
|
||||
|
||||
// If the child is not hovered, which means it doesn't exist,
|
||||
// create a dummy file
|
||||
|
|
|
|||
|
|
@ -1,44 +1,6 @@
|
|||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{Attribute, Data, DeriveInput, Fields, FnArg, ItemFn, ext::IdentExt, parse_macro_input};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn command(_: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let mut f: ItemFn = syn::parse(item).unwrap();
|
||||
let mut ins = f.sig.inputs.clone();
|
||||
|
||||
// Turn `opt: Opt` into `opt: impl Into<Opt>`
|
||||
ins[1] = {
|
||||
let FnArg::Typed(opt) = &f.sig.inputs[1] else {
|
||||
panic!("Cannot find the `opt` argument in the function signature.");
|
||||
};
|
||||
|
||||
let opt_ty = &opt.ty;
|
||||
syn::parse2(quote! { opt: impl Into<#opt_ty> }).unwrap()
|
||||
};
|
||||
|
||||
// Make the original function private and add a public wrapper
|
||||
assert!(matches!(f.vis, syn::Visibility::Public(_)));
|
||||
f.vis = syn::Visibility::Inherited;
|
||||
|
||||
// Add `__` prefix to the original function name
|
||||
let name_ori = f.sig.ident;
|
||||
f.sig.ident = format_ident!("__{}", name_ori.unraw());
|
||||
let name_new = &f.sig.ident;
|
||||
|
||||
// Collect the rest of the arguments
|
||||
let rest_args = ins.iter().skip(2).map(|arg| match arg {
|
||||
FnArg::Receiver(_) => unreachable!(),
|
||||
FnArg::Typed(t) => &t.pat,
|
||||
});
|
||||
|
||||
quote! {
|
||||
#[inline]
|
||||
pub fn #name_ori(#ins) { self.#name_new(opt.into(), #(#rest_args),*); }
|
||||
#f
|
||||
}
|
||||
.into()
|
||||
}
|
||||
use syn::{Attribute, Data, DeriveInput, Fields, parse_macro_input};
|
||||
|
||||
#[proc_macro_derive(DeserializeOver1)]
|
||||
pub fn deserialize_over1(input: TokenStream) -> TokenStream {
|
||||
|
|
|
|||
|
|
@ -109,19 +109,19 @@ keymap = [
|
|||
{ on = "N", run = "find_arrow --previous", desc = "Previous found" },
|
||||
|
||||
# Sorting
|
||||
{ on = [ ",", "m" ], run = [ "sort mtime --reverse=no", "linemode mtime" ], desc = "Sort by modified time" },
|
||||
{ on = [ ",", "M" ], run = [ "sort mtime --reverse", "linemode mtime" ], desc = "Sort by modified time (reverse)" },
|
||||
{ on = [ ",", "b" ], run = [ "sort btime --reverse=no", "linemode btime" ], desc = "Sort by birth time" },
|
||||
{ on = [ ",", "B" ], run = [ "sort btime --reverse", "linemode btime" ], desc = "Sort by birth time (reverse)" },
|
||||
{ on = [ ",", "e" ], run = "sort extension --reverse=no", desc = "Sort by extension" },
|
||||
{ on = [ ",", "E" ], run = "sort extension --reverse", desc = "Sort by extension (reverse)" },
|
||||
{ on = [ ",", "a" ], run = "sort alphabetical --reverse=no", desc = "Sort alphabetically" },
|
||||
{ on = [ ",", "A" ], run = "sort alphabetical --reverse", desc = "Sort alphabetically (reverse)" },
|
||||
{ on = [ ",", "n" ], run = "sort natural --reverse=no", desc = "Sort naturally" },
|
||||
{ on = [ ",", "N" ], run = "sort natural --reverse", desc = "Sort naturally (reverse)" },
|
||||
{ on = [ ",", "s" ], run = [ "sort size --reverse=no", "linemode size" ], desc = "Sort by size" },
|
||||
{ on = [ ",", "S" ], run = [ "sort size --reverse", "linemode size" ], desc = "Sort by size (reverse)" },
|
||||
{ on = [ ",", "r" ], run = "sort random --reverse=no", desc = "Sort randomly" },
|
||||
{ on = [ ",", "m" ], run = [ "sort mtime --reverse=no", "linemode mtime" ], desc = "Sort by modified time" },
|
||||
{ on = [ ",", "M" ], run = [ "sort mtime --reverse=yes", "linemode mtime" ], desc = "Sort by modified time (reverse)" },
|
||||
{ on = [ ",", "b" ], run = [ "sort btime --reverse=no", "linemode btime" ], desc = "Sort by birth time" },
|
||||
{ on = [ ",", "B" ], run = [ "sort btime --reverse=yes", "linemode btime" ], desc = "Sort by birth time (reverse)" },
|
||||
{ on = [ ",", "e" ], run = "sort extension --reverse=no", desc = "Sort by extension" },
|
||||
{ on = [ ",", "E" ], run = "sort extension --reverse=yes", desc = "Sort by extension (reverse)" },
|
||||
{ on = [ ",", "a" ], run = "sort alphabetical --reverse=no", desc = "Sort alphabetically" },
|
||||
{ on = [ ",", "A" ], run = "sort alphabetical --reverse=yes", desc = "Sort alphabetically (reverse)" },
|
||||
{ on = [ ",", "n" ], run = "sort natural --reverse=no", desc = "Sort naturally" },
|
||||
{ on = [ ",", "N" ], run = "sort natural --reverse=yes", desc = "Sort naturally (reverse)" },
|
||||
{ on = [ ",", "s" ], run = [ "sort size --reverse=no", "linemode size" ], desc = "Sort by size" },
|
||||
{ on = [ ",", "S" ], run = [ "sort size --reverse=yes", "linemode size" ], desc = "Sort by size (reverse)" },
|
||||
{ on = [ ",", "r" ], run = "sort random --reverse=no", desc = "Sort randomly" },
|
||||
|
||||
# Goto
|
||||
{ on = [ "g", "h" ], run = "cd ~", desc = "Go home" },
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ local M = {}
|
|||
|
||||
function M:peek(job)
|
||||
local limit = job.area.h
|
||||
local files, bound, err = self.list_files({ "-p", tostring(job.file.url) }, job.skip, limit)
|
||||
|
||||
local files, bound, code = self.list_files({ "-p", tostring(job.file.url) }, job.skip, limit)
|
||||
if code ~= 0 then
|
||||
return require("empty").msg(
|
||||
job,
|
||||
code == 2 and "File list in this archive is encrypted"
|
||||
or "Failed to start either `7zz` or `7z`. Do you have 7-zip installed?"
|
||||
)
|
||||
if err then
|
||||
return ya.preview_widget(job, err)
|
||||
elseif job.skip > 0 and bound < job.skip + limit then
|
||||
return ya.emit("peek", { math.max(0, bound - limit), only_if = job.file.url, upper_bound = true })
|
||||
elseif #files == 0 then
|
||||
files = { { path = job.file.url.stem, size = 0, attr = "" } }
|
||||
end
|
||||
|
||||
local left, right = {}, {}
|
||||
|
|
@ -40,14 +40,10 @@ function M:peek(job)
|
|||
}
|
||||
end
|
||||
|
||||
if job.skip > 0 and bound < job.skip + limit then
|
||||
ya.emit("peek", { math.max(0, bound - limit), only_if = job.file.url, upper_bound = true })
|
||||
else
|
||||
ya.preview_widget(job, {
|
||||
ui.Text(left):area(job.area),
|
||||
ui.Text(right):area(job.area):align(ui.Align.RIGHT),
|
||||
})
|
||||
end
|
||||
ya.preview_widget(job, {
|
||||
ui.Text(left):area(job.area),
|
||||
ui.Text(right):area(job.area):align(ui.Align.RIGHT),
|
||||
})
|
||||
end
|
||||
|
||||
function M:seek(job) require("code"):seek(job) end
|
||||
|
|
@ -76,26 +72,22 @@ end
|
|||
---@param limit integer
|
||||
---@return table files
|
||||
---@return integer bound
|
||||
---@return integer code
|
||||
--- 0: success
|
||||
--- 1: failed to spawn
|
||||
--- 2: wrong password
|
||||
--- 3: partial success
|
||||
---@return Error? err
|
||||
function M.list_files(args, skip, limit)
|
||||
local child = M.spawn_7z { "l", "-ba", "-slt", "-sccUTF-8", table.unpack(args) }
|
||||
if not child then
|
||||
return {}, 0, 1
|
||||
return {}, 0, Err("Failed to start either `7zz` or `7z`. Do you have 7-zip installed?")
|
||||
end
|
||||
|
||||
local i, files, code = 0, { { path = "", size = 0, attr = "" } }, 0
|
||||
local key, value = "", ""
|
||||
local i, files, err = 0, { { path = "", size = 0, attr = "" } }, nil
|
||||
local key, value, stderr = "", "", {}
|
||||
repeat
|
||||
local next, event = child:read_line()
|
||||
if event == 1 and M.is_encrypted(next) then
|
||||
code = 2
|
||||
err = Err("File list in this archive is encrypted")
|
||||
break
|
||||
elseif event == 1 then
|
||||
code = 3
|
||||
stderr[#stderr + 1] = next
|
||||
goto continue
|
||||
elseif event ~= 0 then
|
||||
break
|
||||
|
|
@ -127,7 +119,10 @@ function M.list_files(args, skip, limit)
|
|||
if files[#files].path == "" then
|
||||
files[#files] = nil
|
||||
end
|
||||
return files, i, code
|
||||
if #stderr ~= 0 then
|
||||
err = Err("7-zip errored out while listing files, stderr: %s", table.concat(stderr, "\n"))
|
||||
end
|
||||
return files, i, err
|
||||
end
|
||||
|
||||
---List metadata of an archive
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
local SUPPORTED_TYPES = "application/audio/biosig/chemical/font/image/inode/message/model/rinex/text/vector/video/x-epoc/"
|
||||
-- stylua: ignore
|
||||
local TYPE_PATS = { "text", "image", "video", "application", "audio", "font", "inode", "message", "model", "vector", "biosig", "chemical", "rinex", "x%-epoc" }
|
||||
|
||||
local M = {}
|
||||
|
||||
local function match_mimetype(s)
|
||||
local type, sub = s:match("^([-a-z]+/)([+-.a-zA-Z0-9]+)%s*$")
|
||||
if type and sub and SUPPORTED_TYPES:find(type, 1, true) then
|
||||
return type:gsub("^x%-", "", 1) .. sub:gsub("^x%-", "", 1):gsub("^vnd%.", "", 1)
|
||||
for _, pat in ipairs(TYPE_PATS) do
|
||||
local typ, sub = s:match(string.format("(%s/)([+-.a-z0-9]+)%%s+$", pat))
|
||||
if not sub then
|
||||
elseif s:find(typ .. sub, 1, true) == 1 then
|
||||
return typ:gsub("^x%-", "", 1) .. sub:gsub("^x%-", "", 1):gsub("^vnd%.", "", 1)
|
||||
else
|
||||
return nil, true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -32,7 +38,7 @@ function M:fetch(job)
|
|||
end
|
||||
end
|
||||
|
||||
local i, valid, state = 1, nil, {}
|
||||
local i, state, match, ignore = 1, {}, nil, nil
|
||||
repeat
|
||||
local line, event = child:read_line_with { timeout = 300 }
|
||||
if event == 3 then
|
||||
|
|
@ -42,15 +48,13 @@ function M:fetch(job)
|
|||
break
|
||||
end
|
||||
|
||||
valid = match_mimetype(line)
|
||||
if valid then
|
||||
updates[urls[i]], state[i] = valid, true
|
||||
match, ignore = match_mimetype(line)
|
||||
if match then
|
||||
updates[urls[i]], state[i], i = match, true, i + 1
|
||||
flush(false)
|
||||
else
|
||||
state[i] = false
|
||||
elseif not ignore then
|
||||
state[i], i = false, i + 1
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
::continue::
|
||||
until i > #urls
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue