feat: make mimetype matching more robust (#3082)

This commit is contained in:
三咲雅 misaki masa 2025-08-19 15:17:32 +08:00 committed by GitHub
parent fe9ce240b5
commit ae75fc0f7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 95 additions and 97 deletions

5
.luarc.json Normal file
View 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/"]
}

View file

@ -1,2 +0,0 @@
# this file caused some issues with the build system
yazi-plugin/preset/plugins/mime.lua

4
Cargo.lock generated
View file

@ -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",

View file

@ -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"

View file

@ -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({

View file

@ -1,3 +1,4 @@
syntax = "Lua54"
indent_width = 2
call_parentheses = "NoSingleTable"
collapse_simple_statement = "FunctionOnly"

View file

@ -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

View 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 {

View file

@ -110,17 +110,17 @@ keymap = [
# 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 = [ ",", "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", "linemode btime" ], desc = "Sort by birth time (reverse)" },
{ 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", desc = "Sort by extension (reverse)" },
{ 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", desc = "Sort alphabetically (reverse)" },
{ 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", desc = "Sort naturally (reverse)" },
{ 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", "linemode size" ], desc = "Sort by size (reverse)" },
{ 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

View file

@ -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
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

View file

@ -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