fix: can't display file name with invalid utf-8 (#529)

This commit is contained in:
三咲雅 · Misaki Masa 2024-01-19 00:49:15 +08:00 committed by GitHub
parent d41cd5684e
commit e987855fca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 86 additions and 73 deletions

View File

@ -33,10 +33,10 @@ impl Manager {
let ext = url.extension();
match by {
"name" => ext.map_or_else(String::new, |s| format!(".{}", s.to_string_lossy().to_string())),
"name" => ext.map_or_else(String::new, |s| format!(".{}", s.to_string_lossy().into_owned())),
"ext" if ext.is_some() => format!("{}.", url.file_stem().unwrap().to_string_lossy()),
"dot_ext" if ext.is_some() => url.file_stem().unwrap().to_string_lossy().to_string(),
_ => url.file_name().map_or_else(String::new, |s| s.to_string_lossy().to_string()),
"dot_ext" if ext.is_some() => url.file_stem().unwrap().to_string_lossy().into_owned(),
_ => url.file_name().map_or_else(String::new, |s| s.to_string_lossy().into_owned()),
}
}

View File

@ -1,5 +1,5 @@
use mlua::{Table, TableExt};
use ratatui::{prelude::Buffer, widgets::Widget};
use ratatui::{buffer::Buffer, widgets::Widget};
use tracing::error;
use yazi_plugin::{bindings::Cast, elements::{render_widgets, Rect}, LUA};

View File

@ -1,5 +1,5 @@
use mlua::{Table, TableExt};
use ratatui::{prelude::Buffer, widgets::Widget};
use ratatui::{buffer::Buffer, widgets::Widget};
use tracing::error;
use yazi_plugin::{bindings::Cast, elements::{render_widgets, Rect}, LUA};

View File

@ -1,4 +1,4 @@
use ratatui::{prelude::Buffer, widgets::Widget};
use ratatui::{buffer::Buffer, widgets::Widget};
use crate::Ctx;

View File

@ -1,4 +1,4 @@
use ratatui::{layout::{self, Constraint}, prelude::{Buffer, Direction, Rect}, widgets::{List, ListItem, Widget}};
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, widgets::{List, ListItem, Widget}};
use yazi_config::THEME;
use crate::Ctx;

View File

@ -1,4 +1,4 @@
use ratatui::{buffer::Buffer, layout::{self, Rect}, prelude::{Constraint, Direction}, widgets::{Paragraph, Widget}};
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, widgets::{Paragraph, Widget}};
use yazi_config::THEME;
use super::Bindings;

View File

@ -19,12 +19,14 @@ impl<'a, 'b> Tabs<'a, 'b> {
lua.register_userdata_type::<yazi_core::tab::Tab>(|reg| {
reg.add_method("name", |lua, me, ()| {
Some(lua.create_string(
me.current.cwd.file_name().map_or_else(
|| me.current.cwd.as_os_str().as_encoded_bytes(),
|n| n.as_encoded_bytes(),
Some(
lua.create_string(
me.current
.cwd
.file_name()
.map_or(me.current.cwd.as_os_str().as_encoded_bytes(), |n| n.as_encoded_bytes()),
),
))
)
.transpose()
});

View File

@ -1,4 +1,4 @@
use ratatui::{layout, prelude::{Buffer, Constraint, Direction, Rect}, widgets::{Block, Widget}};
use ratatui::{buffer::Buffer, layout, layout::{Constraint, Direction, Rect}, widgets::{Block, Widget}};
use yazi_config::THEME;
use super::Side;

View File

@ -1,4 +1,4 @@
use ratatui::{prelude::{Buffer, Rect}, text::{Line, Span}, widgets::{Block, List, ListItem, Padding, Widget}};
use ratatui::{buffer::Buffer, layout::Rect, text::{Line, Span}, widgets::{Block, List, ListItem, Padding, Widget}};
use yazi_config::{keymap::Control, THEME};
pub(super) struct Side<'a> {

View File

@ -1,4 +1,4 @@
use mlua::{prelude::LuaUserDataFields, FromLua, UserData};
use mlua::{FromLua, UserData};
use yazi_shared::term::Term;
#[derive(Debug, Clone, Copy, FromLua)]
@ -17,7 +17,7 @@ impl Default for Window {
}
impl UserData for Window {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("rows", |_, me| Ok(me.rows));
fields.add_field_method_get("cols", |_, me| Ok(me.cols));
fields.add_field_method_get("width", |_, me| Ok(me.width));

View File

@ -1,7 +1,7 @@
use std::collections::HashMap;
use anyhow::bail;
use mlua::{prelude::{Lua, LuaResult}, AnyUserData, IntoLua, Value};
use mlua::{AnyUserData, IntoLua, Lua, Value};
use yazi_shared::OrderedFloat;
use crate::elements::Renderable;
@ -59,7 +59,7 @@ impl<'a> TryFrom<Value<'a>> for ValueSendable {
}
impl<'lua> IntoLua<'lua> for ValueSendable {
fn into_lua(self, lua: &Lua) -> LuaResult<Value> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
match self {
ValueSendable::Nil => Ok(Value::Nil),
ValueSendable::Boolean(b) => Ok(Value::Boolean(b)),
@ -121,7 +121,7 @@ impl TryInto<ValueSendableKey> for ValueSendable {
}
impl<'lua> IntoLua<'lua> for ValueSendableKey {
fn into_lua(self, lua: &Lua) -> LuaResult<Value> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
match self {
ValueSendableKey::Nil => Ok(Value::Nil),
ValueSendableKey::Boolean(b) => Ok(Value::Boolean(b)),

View File

@ -58,7 +58,7 @@ impl ListItem {
return Ok(Self { content, style: None });
}
Value::String(s) => {
return Ok(Self { content: s.to_str()?.to_string().into(), style: None });
return Ok(Self { content: s.to_string_lossy().into_owned().into(), style: None });
}
_ => {}
}

View File

@ -10,7 +10,9 @@ impl Span {
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
ui.set(
"Span",
lua.create_function(|_, content: String| Ok(Self(ratatui::text::Span::raw(content))))?,
lua.create_function(|_, content: mlua::String| {
Ok(Self(ratatui::text::Span::raw(content.to_string_lossy().into_owned())))
})?,
)
}
}

View File

@ -54,7 +54,7 @@ pub fn shell(opt: ShellOpt) -> Result<Child> {
#[cfg(windows)]
{
let args: Vec<String> = opt.args.iter().map(|s| s.to_string_lossy().to_string()).collect();
let args: Vec<String> = opt.args.iter().map(|s| s.to_string_lossy().into_owned()).collect();
let args_: Vec<&str> = args.iter().map(|s| s.as_ref()).collect();
let expanded = parser::parse(opt.cmd.to_string_lossy().as_ref(), &args_);
Ok(

View File

@ -1,6 +1,6 @@
use std::time::Duration;
use mlua::{prelude::LuaUserDataMethods, IntoLua, Table, UserData, Value};
use mlua::{IntoLua, Table, UserData, Value};
use tokio::{io::{AsyncBufReadExt, AsyncReadExt, BufReader}, process::{ChildStderr, ChildStdin, ChildStdout}, select};
use super::Status;
@ -22,14 +22,12 @@ impl Child {
}
impl UserData for Child {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
#[inline]
// TODO: return mlua::String instead of String
async fn read_line(me: &mut Child) -> (String, u8) {
async fn read(t: Option<impl AsyncBufReadExt + Unpin>) -> Option<String> {
let Some(mut r) = t else {
return None;
};
let mut r = t?;
let mut buf = String::new();
match r.read_line(&mut buf).await {
Ok(0) | Err(_) => None,
@ -46,10 +44,7 @@ impl UserData for Child {
methods.add_async_method_mut("read", |_, me, len: usize| async move {
async fn read(t: Option<impl AsyncBufReadExt + Unpin>, len: usize) -> Option<Vec<u8>> {
let Some(mut r) = t else {
return None;
};
let mut r = t?;
let mut buf = vec![0; len];
match r.read(&mut buf).await {
Ok(0) | Err(_) => return None,

View File

@ -1,6 +1,6 @@
use std::process::Stdio;
use mlua::{prelude::LuaUserDataMethods, AnyUserData, IntoLua, Lua, Table, UserData, Value};
use mlua::{AnyUserData, IntoLua, Lua, Table, UserData, Value};
use super::{output::Output, Child};
@ -35,19 +35,29 @@ impl Command {
}
impl UserData for Command {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("arg", |_, (ud, arg): (AnyUserData, String)| {
ud.borrow_mut::<Self>()?.inner.arg(arg);
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("arg", |_, (ud, arg): (AnyUserData, mlua::String)| {
ud.borrow_mut::<Self>()?.inner.arg(arg.to_string_lossy().as_ref());
Ok(ud)
});
methods.add_function("args", |_, (ud, args): (AnyUserData, Vec<String>)| {
ud.borrow_mut::<Self>()?.inner.args(args);
Ok(ud)
});
methods.add_function("env", |_, (ud, key, value): (AnyUserData, String, String)| {
ud.borrow_mut::<Self>()?.inner.env(key, value);
methods.add_function("args", |_, (ud, args): (AnyUserData, Vec<mlua::String>)| {
{
let mut me = ud.borrow_mut::<Self>()?;
for arg in args {
me.inner.arg(arg.to_string_lossy().as_ref());
}
}
Ok(ud)
});
methods.add_function(
"env",
|_, (ud, key, value): (AnyUserData, mlua::String, mlua::String)| {
ud.borrow_mut::<Self>()?
.inner
.env(key.to_string_lossy().as_ref(), value.to_string_lossy().as_ref());
Ok(ud)
},
);
methods.add_function("stdin", |_, (ud, stdio): (AnyUserData, u8)| {
ud.borrow_mut::<Self>()?.inner.stdin(match stdio {
PIPED => Stdio::piped(),

View File

@ -1,4 +1,4 @@
use mlua::{prelude::LuaUserDataFields, UserData};
use mlua::UserData;
use super::Status;
@ -11,7 +11,7 @@ impl Output {
}
impl UserData for Output {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("status", |_, me| Ok(Status::new(me.inner.status)));
fields.add_field_method_get("stdout", |lua, me| lua.create_string(&me.inner.stdout));
fields.add_field_method_get("stderr", |lua, me| lua.create_string(&me.inner.stderr));

View File

@ -9,7 +9,7 @@ impl Status {
}
impl UserData for Status {
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("success", |_, me, ()| Ok(me.inner.success()));
methods.add_method("code", |_, me, ()| Ok(me.inner.code()));
}

View File

@ -17,10 +17,10 @@ impl Utils {
match k {
Value::Integer(_) => {
args.push(v.to_str()?.to_owned());
args.push(v.to_string_lossy().into_owned());
}
Value::String(s) => {
named.insert(s.to_str()?.replace('_', "-"), v.to_str()?.to_owned());
named.insert(s.to_str()?.replace('_', "-"), v.to_string_lossy().into_owned());
}
_ => return Err("invalid key in exec".into_lua_err()),
}

View File

@ -10,17 +10,18 @@ impl Utils {
pub(super) fn text(lua: &Lua, ya: &Table) -> mlua::Result<()> {
ya.set(
"truncate",
lua.create_function(|_, (text, max): (String, usize)| {
lua.create_function(|_, (text, max): (mlua::String, usize)| {
let mut width = 0;
let flow = text.chars().try_fold(String::with_capacity(max), |mut s, c| {
width += c.width().unwrap_or(0);
if s.width() < max {
s.push(c);
ControlFlow::Continue(s)
} else {
ControlFlow::Break(s)
}
});
let flow =
text.to_string_lossy().chars().try_fold(String::with_capacity(max), |mut s, c| {
width += c.width().unwrap_or(0);
if s.width() < max {
s.push(c);
ControlFlow::Continue(s)
} else {
ControlFlow::Break(s)
}
});
Ok(match flow {
ControlFlow::Break(s) => s,
@ -29,7 +30,10 @@ impl Utils {
})?,
)?;
ya.set("mime_valid", lua.create_function(|_, mime: String| Ok(mime_valid(&mime)))?)?;
ya.set(
"mime_valid",
lua.create_function(|_, mime: mlua::String| Ok(mime_valid(mime.as_bytes())))?,
)?;
Ok(())
}

View File

@ -98,7 +98,7 @@ impl AsRef<OsStr> for Url {
impl ToString for Url {
fn to_string(&self) -> String {
if self.scheme == UrlScheme::Regular {
return self.path.to_string_lossy().to_string();
return self.path.to_string_lossy().into_owned();
}
let scheme = match self.scheme {

View File

@ -1,23 +1,23 @@
pub const MIME_DIR: &str = "inode/directory";
pub fn mime_valid(s: &str) -> bool {
let parts = s.split('/').collect::<Vec<_>>();
pub fn mime_valid(b: &[u8]) -> bool {
let parts = b.split(|&b| b == b'/').collect::<Vec<_>>();
if parts.len() != 2 || parts[1].is_empty() {
return false;
}
matches!(
parts[0],
"application"
| "audio"
| "example"
| "font"
| "image"
| "inode"
| "message"
| "model"
| "multipart"
| "text"
| "video"
b"application"
| b"audio"
| b"example"
| b"font"
| b"image"
| b"inode"
| b"message"
| b"model"
| b"multipart"
| b"text"
| b"video"
)
}