mirror of
https://github.com/bobwen-dev/hunter
synced 2025-04-12 00:55:41 +02:00
start stuff in the background
This commit is contained in:
parent
2ca81c123c
commit
e4a2749ee0
@ -273,6 +273,25 @@ impl FileBrowser {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open_bg(&mut self) -> HResult<()> {
|
||||||
|
let cwd = self.cwd()?;
|
||||||
|
let file = self.selected_file()?;
|
||||||
|
|
||||||
|
let cmd = crate::proclist::Cmd {
|
||||||
|
cmd: OsString::from(file.strip_prefix(&cwd)),
|
||||||
|
short_cmd: None,
|
||||||
|
args: None,
|
||||||
|
cwd: cwd.clone(),
|
||||||
|
cwd_files: None,
|
||||||
|
tab_files: None,
|
||||||
|
tab_paths: None
|
||||||
|
};
|
||||||
|
|
||||||
|
self.proc_view.lock()?.run_proc_raw(cmd)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> {
|
pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> {
|
||||||
match dir.is_readable() {
|
match dir.is_readable() {
|
||||||
Ok(true) => {},
|
Ok(true) => {},
|
||||||
@ -665,58 +684,28 @@ impl FileBrowser {
|
|||||||
fn exec_cmd(&mut self,
|
fn exec_cmd(&mut self,
|
||||||
tab_dirs: Vec<File>,
|
tab_dirs: Vec<File>,
|
||||||
tab_files: Vec<Vec<File>>) -> HResult<()> {
|
tab_files: Vec<Vec<File>>) -> HResult<()> {
|
||||||
let cwd = self.cwd()?;
|
|
||||||
let filename = self.selected_file()?.path.quoted_file_name()?;
|
let cwd = self.cwd()?.clone();
|
||||||
|
let selected_file = self.selected_file()?;
|
||||||
let selected_files = self.selected_files()?;
|
let selected_files = self.selected_files()?;
|
||||||
|
|
||||||
let files = selected_files.iter()
|
let cmd = self.minibuffer("exec")?.trim_start().to_string() + " ";
|
||||||
.map(|f| f.path())
|
|
||||||
.collect::<Vec<PathBuf>>();
|
|
||||||
|
|
||||||
let cmd = self.minibuffer("exec")?.trim_start().to_string();
|
let cwd_files = if selected_files.len() == 0 {
|
||||||
|
vec![selected_file]
|
||||||
|
} else { selected_files };
|
||||||
|
|
||||||
let cmd = OsString::from(cmd);
|
let cmd = crate::proclist::Cmd {
|
||||||
let space = OsString::from(" ");
|
cmd: OsString::from(cmd),
|
||||||
|
short_cmd: None,
|
||||||
let mut cmd = if files.len() == 0 {
|
args: None,
|
||||||
cmd.replace(&OsString::from("$s"), &filename)
|
cwd: cwd,
|
||||||
} else {
|
cwd_files: Some(cwd_files),
|
||||||
let args = files.iter()
|
tab_files: Some(tab_files),
|
||||||
.fold(OsString::new(), |mut args, file| {
|
tab_paths: Some(tab_dirs)
|
||||||
if let Some(name) = file.quoted_file_name() {
|
|
||||||
args.push(name);
|
|
||||||
args.push(space.clone());
|
|
||||||
}
|
|
||||||
args
|
|
||||||
});
|
|
||||||
let args = args.trim_last_space();
|
|
||||||
|
|
||||||
cmd.replace(&OsString::from("$s"), &args)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, tab_dir) in tab_dirs.iter().enumerate() {
|
self.proc_view.lock()?.run_proc_subshell(cmd)?;
|
||||||
if let Some(tab_files) = tab_files.get(i) {
|
|
||||||
let tab_file_identifier = OsString::from(format!("${}s", i));
|
|
||||||
|
|
||||||
let args = tab_files.iter()
|
|
||||||
.fold(OsString::new(), |mut args, file| {
|
|
||||||
let file_path = file.strip_prefix(&cwd);
|
|
||||||
let name = file_path.quoted_path();
|
|
||||||
args.push(name);
|
|
||||||
args.push(space.clone());
|
|
||||||
|
|
||||||
args
|
|
||||||
});
|
|
||||||
|
|
||||||
cmd = cmd.replace(&tab_file_identifier, &args);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tab_identifier = OsString::from(format!("${}", i));
|
|
||||||
let tab_path = tab_dir.path().into_os_string();
|
|
||||||
cmd = cmd.replace(&tab_identifier, &tab_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.proc_view.lock()?.run_proc(&cmd)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -856,6 +845,7 @@ impl Widget for FileBrowser {
|
|||||||
Key::Char('/') => { self.turbo_cd()?; },
|
Key::Char('/') => { self.turbo_cd()?; },
|
||||||
Key::Char('Q') => { self.quit_with_dir()?; },
|
Key::Char('Q') => { self.quit_with_dir()?; },
|
||||||
Key::Right | Key::Char('f') => { self.enter_dir()?; },
|
Key::Right | Key::Char('f') => { self.enter_dir()?; },
|
||||||
|
Key::Char('F') => { self.open_bg()?; },
|
||||||
Key::Left | Key::Char('b') => { self.go_back()?; },
|
Key::Left | Key::Char('b') => { self.go_back()?; },
|
||||||
Key::Char('-') => { self.goto_prev_cwd()?; },
|
Key::Char('-') => { self.goto_prev_cwd()?; },
|
||||||
Key::Char('`') => { self.goto_bookmark()?; },
|
Key::Char('`') => { self.goto_bookmark()?; },
|
||||||
|
96
src/files.rs
96
src/files.rs
@ -517,6 +517,10 @@ impl File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn strip_prefix(&self, base: &File) -> PathBuf {
|
pub fn strip_prefix(&self, base: &File) -> PathBuf {
|
||||||
|
if self == base {
|
||||||
|
return PathBuf::from("./");
|
||||||
|
}
|
||||||
|
|
||||||
let base_path = base.path.clone();
|
let base_path = base.path.clone();
|
||||||
match self.path.strip_prefix(base_path) {
|
match self.path.strip_prefix(base_path) {
|
||||||
Ok(path) => PathBuf::from(path),
|
Ok(path) => PathBuf::from(path),
|
||||||
@ -741,13 +745,105 @@ impl PathBufExt for PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait OsStrTools {
|
pub trait OsStrTools {
|
||||||
|
fn split(&self, pat: &OsStr) -> Vec<OsString>;
|
||||||
fn replace(&self, from: &OsStr, to: &OsStr) -> OsString;
|
fn replace(&self, from: &OsStr, to: &OsStr) -> OsString;
|
||||||
fn trim_last_space(&self) -> OsString;
|
fn trim_last_space(&self) -> OsString;
|
||||||
fn contains_osstr(&self, pat: &OsStr) -> bool;
|
fn contains_osstr(&self, pat: &OsStr) -> bool;
|
||||||
fn position(&self, pat: &OsStr) -> Option<usize>;
|
fn position(&self, pat: &OsStr) -> Option<usize>;
|
||||||
|
fn splice_quoted(&self, from: &OsStr, to: Vec<OsString>) -> Vec<OsString>;
|
||||||
|
fn splice_with(&self, from: &OsStr, to: Vec<OsString>) -> Vec<OsString>;
|
||||||
|
fn quote(&self) -> OsString;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OsStrTools for OsStr {
|
impl OsStrTools for OsStr {
|
||||||
|
fn split(&self, pat: &OsStr) -> Vec<OsString> {
|
||||||
|
let orig_string = self.as_bytes().to_vec();
|
||||||
|
let pat = pat.as_bytes().to_vec();
|
||||||
|
let pat_len = pat.len();
|
||||||
|
|
||||||
|
dbg!(&self);
|
||||||
|
|
||||||
|
let split_string = orig_string
|
||||||
|
.windows(pat_len)
|
||||||
|
.enumerate()
|
||||||
|
.fold(Vec::new(), |mut split_pos, (i, chars)| {
|
||||||
|
dbg!(&chars);
|
||||||
|
dbg!(&split_pos);
|
||||||
|
if chars == pat.as_slice() {
|
||||||
|
if split_pos.len() == 0 {
|
||||||
|
split_pos.push((0, i));
|
||||||
|
} else {
|
||||||
|
let len = split_pos.len();
|
||||||
|
let last_split = split_pos[len-1].1;
|
||||||
|
split_pos.push((last_split, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
split_pos
|
||||||
|
}).iter()
|
||||||
|
.map(|(start, end)| {
|
||||||
|
//let orig_string = orig_string.clone();
|
||||||
|
OsString::from_vec(orig_string[*start..*end]
|
||||||
|
.to_vec()).replace(&OsString::from_vec(pat.clone()),
|
||||||
|
&OsString::from(""))
|
||||||
|
}).collect();
|
||||||
|
split_string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn quote(&self) -> OsString {
|
||||||
|
let mut string = self.as_bytes().to_vec();
|
||||||
|
let mut quote = "\"".as_bytes().to_vec();
|
||||||
|
|
||||||
|
let mut quoted = vec![];
|
||||||
|
quoted.append(&mut quote.clone());
|
||||||
|
quoted.append(&mut string);
|
||||||
|
quoted.append(&mut quote);
|
||||||
|
|
||||||
|
OsString::from_vec(quoted)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn splice_quoted(&self, from: &OsStr, to: Vec<OsString>) -> Vec<OsString> {
|
||||||
|
let quoted_to = to.iter()
|
||||||
|
.map(|to| to.quote())
|
||||||
|
.collect();
|
||||||
|
self.splice_with(from, quoted_to)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn splice_with(&self, from: &OsStr, to: Vec<OsString>) -> Vec<OsString> {
|
||||||
|
let pos = self.position(from);
|
||||||
|
|
||||||
|
if pos.is_none() {
|
||||||
|
return vec![OsString::from(self)];
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(&self);
|
||||||
|
|
||||||
|
let pos = pos.unwrap();
|
||||||
|
let string = self.as_bytes().to_vec();
|
||||||
|
let from = from.as_bytes().to_vec();
|
||||||
|
let fromlen = from.len();
|
||||||
|
|
||||||
|
let lpart = OsString::from_vec(string[0..pos].to_vec());
|
||||||
|
let rpart = OsString::from_vec(string[pos+fromlen..].to_vec());
|
||||||
|
|
||||||
|
dbg!(&lpart);
|
||||||
|
dbg!(&rpart);
|
||||||
|
|
||||||
|
let mut result = vec![
|
||||||
|
vec![lpart.trim_last_space()],
|
||||||
|
to,
|
||||||
|
vec![rpart]
|
||||||
|
].into_iter()
|
||||||
|
.flatten()
|
||||||
|
.filter(|part| part.len() != 0)
|
||||||
|
.collect::<Vec<OsString>>();
|
||||||
|
|
||||||
|
if result.last() == Some(&OsString::from("")) {
|
||||||
|
result.pop();
|
||||||
|
result
|
||||||
|
} else { result }
|
||||||
|
}
|
||||||
|
|
||||||
fn replace(&self, from: &OsStr, to: &OsStr) -> OsString {
|
fn replace(&self, from: &OsStr, to: &OsStr) -> OsString {
|
||||||
let orig_string = self.as_bytes().to_vec();
|
let orig_string = self.as_bytes().to_vec();
|
||||||
let from = from.as_bytes();
|
let from = from.as_bytes();
|
||||||
|
12
src/paths.rs
12
src/paths.rs
@ -10,9 +10,15 @@ pub fn home_path() -> HResult<PathBuf> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn hunter_path() -> HResult<PathBuf> {
|
pub fn hunter_path() -> HResult<PathBuf> {
|
||||||
let mut config_dir = dirs_2::config_dir()?;
|
let mut hunter_path = dirs_2::config_dir()?;
|
||||||
config_dir.push("hunter/");
|
hunter_path.push("hunter/");
|
||||||
Ok(config_dir)
|
Ok(hunter_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config_path() -> HResult<PathBuf> {
|
||||||
|
let mut config_path = hunter_path()?;
|
||||||
|
config_path.push("config");
|
||||||
|
Ok(config_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bookmark_path() -> HResult<PathBuf> {
|
pub fn bookmark_path() -> HResult<PathBuf> {
|
||||||
|
165
src/proclist.rs
165
src/proclist.rs
@ -4,6 +4,7 @@ use std::process::Child;
|
|||||||
use std::os::unix::process::{CommandExt, ExitStatusExt};
|
use std::os::unix::process::{CommandExt, ExitStatusExt};
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
use std::os::unix::ffi::{OsStringExt, OsStrExt};
|
||||||
|
|
||||||
use termion::event::Key;
|
use termion::event::Key;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
@ -17,7 +18,7 @@ use crate::hbox::HBox;
|
|||||||
use crate::preview::WillBeWidget;
|
use crate::preview::WillBeWidget;
|
||||||
use crate::fail::{HResult, HError, ErrorLog};
|
use crate::fail::{HResult, HError, ErrorLog};
|
||||||
use crate::term;
|
use crate::term;
|
||||||
use crate::files::OsStrTools;
|
use crate::files::{File, OsStrTools};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Process {
|
struct Process {
|
||||||
@ -30,6 +31,75 @@ struct Process {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Cmd {
|
||||||
|
pub cmd: OsString,
|
||||||
|
pub args: Option<Vec<OsString>>,
|
||||||
|
pub short_cmd: Option<String>,
|
||||||
|
pub cwd: File,
|
||||||
|
pub cwd_files: Option<Vec<File>>,
|
||||||
|
pub tab_files: Option<Vec<Vec<File>>>,
|
||||||
|
pub tab_paths: Option<Vec<File>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cmd {
|
||||||
|
fn process(&mut self) -> Vec<OsString> {
|
||||||
|
let cmd = self.cmd.clone().split(&OsString::from(" "));
|
||||||
|
let cmd = self.substitute_cwd_files(cmd);
|
||||||
|
let cmd = self.substitute_tab_files(cmd);
|
||||||
|
let cmd = self.substitute_tab_paths(cmd);
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
fn substitute_cwd_files(&mut self, cmd: Vec<OsString>) -> Vec<OsString> {
|
||||||
|
let cwd_pat = OsString::from("$s");
|
||||||
|
let cwd_files = self.cwd_files
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|file| file.strip_prefix(&self.cwd).into_os_string())
|
||||||
|
.collect::<Vec<OsString>>();
|
||||||
|
|
||||||
|
cmd.iter()
|
||||||
|
.map(|part| part.splice_quoted(&cwd_pat,
|
||||||
|
cwd_files.clone()))
|
||||||
|
.flatten().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn substitute_tab_files(&mut self, cmd: Vec<OsString>) -> Vec<OsString> {
|
||||||
|
let tab_files = self.tab_files.take().unwrap();
|
||||||
|
|
||||||
|
tab_files.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.fold(cmd, |cmd, (i, tab_files)| {
|
||||||
|
let tab_files_pat = OsString::from(format!("${}s", i));
|
||||||
|
let tab_file_paths = tab_files.iter()
|
||||||
|
.map(|file| file.strip_prefix(&self.cwd).into_os_string())
|
||||||
|
.collect::<Vec<OsString>>();
|
||||||
|
|
||||||
|
cmd.iter().map(|part| {
|
||||||
|
part.splice_quoted(&tab_files_pat,
|
||||||
|
tab_file_paths.clone())
|
||||||
|
}).flatten().collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn substitute_tab_paths(&mut self, cmd: Vec<OsString>) -> Vec<OsString> {
|
||||||
|
let tab_paths = self.tab_paths.take().unwrap();
|
||||||
|
|
||||||
|
tab_paths.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.fold(cmd, |cmd, (i, tab_path)| {
|
||||||
|
let tab_path_pat = OsString::from(format!("${}", i));
|
||||||
|
let tab_path = tab_path.strip_prefix(&self.cwd).into_os_string();
|
||||||
|
|
||||||
|
cmd.iter().map(|part| {
|
||||||
|
part.splice_quoted(&tab_path_pat,
|
||||||
|
vec![tab_path.clone()])
|
||||||
|
}).flatten().collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Process {
|
impl PartialEq for Process {
|
||||||
fn eq(&self, other: &Process) -> bool {
|
fn eq(&self, other: &Process) -> bool {
|
||||||
self.cmd == other.cmd
|
self.cmd == other.cmd
|
||||||
@ -120,17 +190,44 @@ impl Listable for ListView<Vec<Process>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ListView<Vec<Process>> {
|
impl ListView<Vec<Process>> {
|
||||||
fn run_proc(&mut self, cmd: &OsString) -> HResult<()> {
|
fn run_proc_subshell(&mut self, mut cmd: Cmd) -> HResult<()> {
|
||||||
let shell = std::env::var("SHELL").unwrap_or("sh".into());
|
let shell = std::env::var("SHELL").unwrap_or("sh".into());
|
||||||
let home = crate::paths::home_path()?.into_os_string();
|
let home = crate::paths::home_path()?.into_os_string();
|
||||||
|
|
||||||
|
let cmd_args = cmd.process();
|
||||||
|
|
||||||
let short = OsString::from("~");
|
let short = OsString::from("~");
|
||||||
let short_cmd = cmd.replace(&home, &short).to_string_lossy().to_string();
|
let short_cmd = cmd_args
|
||||||
|
.concat()
|
||||||
|
.replace(&home, &short)
|
||||||
|
.replace(&OsString::from("\""), &OsString::from(""))
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
self.show_status(&format!("Running: {}", &short_cmd)).log();
|
self.show_status(&format!("Running: {}", &short_cmd)).log();
|
||||||
|
|
||||||
let handle = std::process::Command::new(shell)
|
let shell_args = cmd_args.concat();
|
||||||
.arg("-c")
|
let shell_args = vec![OsString::from("-c"), shell_args.clone()];
|
||||||
.arg(cmd)
|
|
||||||
|
cmd.cmd = OsString::from(shell.clone());
|
||||||
|
cmd.args = Some(shell_args.clone());
|
||||||
|
cmd.short_cmd = Some(short_cmd);
|
||||||
|
|
||||||
|
self.run_proc_raw(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_proc_raw(&mut self, cmd: Cmd) -> HResult<()> {
|
||||||
|
let real_cmd = cmd.cmd;
|
||||||
|
let short_cmd = cmd.short_cmd
|
||||||
|
.unwrap_or(real_cmd
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string());
|
||||||
|
let args = cmd.args.unwrap_or(vec![]);
|
||||||
|
|
||||||
|
self.show_status(&format!("Running: {}", &short_cmd)).log();
|
||||||
|
|
||||||
|
let handle = std::process::Command::new(real_cmd)
|
||||||
|
.args(args)
|
||||||
.stdin(std::process::Stdio::null())
|
.stdin(std::process::Stdio::null())
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(std::process::Stdio::piped())
|
||||||
.before_exec(|| unsafe { libc::dup2(1, 2); Ok(()) })
|
.before_exec(|| unsafe { libc::dup2(1, 2); Ok(()) })
|
||||||
@ -289,8 +386,13 @@ impl ProcView {
|
|||||||
self.hbox.get_textview()
|
self.hbox.get_textview()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_proc(&mut self, cmd: &OsString) -> HResult<()> {
|
pub fn run_proc_subshell(&mut self, cmd: Cmd) -> HResult<()> {
|
||||||
self.get_listview_mut().run_proc(cmd)?;
|
self.get_listview_mut().run_proc_subshell(cmd)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_proc_raw(&mut self, cmd: Cmd) -> HResult<()> {
|
||||||
|
self.get_listview_mut().run_proc_raw(cmd)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,3 +569,50 @@ impl Widget for ProcView {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
trait ConcatOsString {
|
||||||
|
fn concat(&self) -> OsString;
|
||||||
|
fn concat_quoted(&self) -> OsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConcatOsString for Vec<OsString> {
|
||||||
|
fn concat(&self) -> OsString {
|
||||||
|
let len = self.len();
|
||||||
|
self.iter().enumerate().fold(OsString::new(), |string, (i, part)| {
|
||||||
|
let mut string = string.into_vec();
|
||||||
|
let mut space = " ".as_bytes().to_vec();
|
||||||
|
let mut part = part.clone().into_vec();
|
||||||
|
|
||||||
|
string.append(&mut part);
|
||||||
|
|
||||||
|
if i != len {
|
||||||
|
string.append(&mut space);
|
||||||
|
}
|
||||||
|
|
||||||
|
OsString::from_vec(string)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn concat_quoted(&self) -> OsString {
|
||||||
|
let len = self.len();
|
||||||
|
self.iter().enumerate().fold(OsString::new(), |string, (i, part)| {
|
||||||
|
let mut string = string.into_vec();
|
||||||
|
let mut space = " ".as_bytes().to_vec();
|
||||||
|
let mut quote = "\"".as_bytes().to_vec();
|
||||||
|
let mut part = part.clone().into_vec();
|
||||||
|
|
||||||
|
|
||||||
|
string.append(&mut quote.clone());
|
||||||
|
string.append(&mut part);
|
||||||
|
string.append(&mut quote);
|
||||||
|
|
||||||
|
|
||||||
|
if i+1 != len {
|
||||||
|
string.append(&mut space);
|
||||||
|
}
|
||||||
|
|
||||||
|
OsString::from_vec(string)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user