diff --git a/app/Cargo.toml b/app/Cargo.toml index 099f2ce1..d86d7a26 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -14,9 +14,7 @@ ansi-to-tui = "^3" anyhow = "^1" crossterm = { version = "^0", features = [ "event-stream" ] } futures = "^0" -libc = "^0" ratatui = "^0" -signal-hook-tokio = { version = "^0", features = [ "futures-v0_3" ] } tokio = { version = "^1", features = [ "parking_lot" ] } unicode-width = "^0" @@ -25,6 +23,10 @@ tracing = "^0" tracing-appender = "^0" tracing-subscriber = "^0" +[target.'cfg(not(target_os = "windows"))'.dependencies] +libc = "^0" +signal-hook-tokio = { version = "^0", features = [ "futures-v0_3" ] } + [[bin]] name = "yazi" path = "src/main.rs" diff --git a/app/src/app.rs b/app/src/app.rs index ef308dfa..9cc0fb1d 100644 --- a/app/src/app.rs +++ b/app/src/app.rs @@ -1,5 +1,4 @@ use core::{emit, files::FilesOp, input::InputMode, Event}; -use std::{ffi::OsString, os::unix::prelude::OsStrExt}; use anyhow::{Ok, Result}; use config::{keymap::{Control, Key, KeymapLayer}, BOOT}; @@ -43,6 +42,7 @@ impl App { fn dispatch_quit(&mut self) { if let Some(p) = &BOOT.cwd_file { + use std::os::unix::prelude::OsStrExt; let cwd = self.cx.manager.cwd().as_os_str(); std::fs::write(p, cwd.as_bytes()).ok(); } diff --git a/app/src/signals.rs b/app/src/signals.rs index 94e696ea..4dd921df 100644 --- a/app/src/signals.rs +++ b/app/src/signals.rs @@ -1,9 +1,8 @@ use core::Event; use anyhow::Result; -use crossterm::event::{Event as CrosstermEvent, EventStream}; +use crossterm::event::{Event as CrosstermEvent, EventStream, KeyEvent, KeyEventKind}; use futures::StreamExt; -use libc::{SIGHUP, SIGINT, SIGQUIT, SIGTERM}; use tokio::{select, sync::{mpsc::{self, UnboundedReceiver, UnboundedSender}, oneshot}, task::JoinHandle}; pub(super) struct Signals { @@ -46,7 +45,13 @@ impl Signals { } } + #[cfg(target_os = "windows")] + fn spawn_system_task(&self) -> Result<()> { Ok(()) } + + #[cfg(not(target_os = "windows"))] fn spawn_system_task(&self) -> Result> { + use libc::{SIGHUP, SIGINT, SIGQUIT, SIGTERM}; + let tx = self.tx.clone(); let mut signals = signal_hook_tokio::Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT])?; @@ -76,7 +81,9 @@ impl Signals { _ = &mut stop_rx => break, Some(Ok(event)) = reader.next() => { let event = match event { - CrosstermEvent::Key(key) => Event::Key(key), + // We need to check key event kind; + // otherwise event will be dispatched twice. + CrosstermEvent::Key(key @ KeyEvent { kind: KeyEventKind::Press, .. }) => Event::Key(key), CrosstermEvent::Paste(str) => Event::Paste(str), CrosstermEvent::Resize(cols, rows) => Event::Resize(cols, rows), _ => continue, diff --git a/app/src/status/right.rs b/app/src/status/right.rs index ba7906cb..9b051111 100644 --- a/app/src/status/right.rs +++ b/app/src/status/right.rs @@ -1,8 +1,5 @@ -use std::os::unix::prelude::PermissionsExt; - use config::THEME; use ratatui::{buffer::Buffer, layout::{Alignment, Rect}, text::{Line, Span}, widgets::{Paragraph, Widget}}; -use shared::file_mode; use super::Progress; use crate::Ctx; @@ -70,8 +67,10 @@ impl Widget for Right<'_> { let mut spans = vec![]; // Permissions + #[cfg(not(target_os = "windows"))] if let Some(h) = &manager.hovered { - spans.extend(self.permissions(&file_mode(h.meta.permissions().mode()))) + use std::os::unix::prelude::PermissionsExt; + spans.extend(self.permissions(&shared::file_mode(h.meta.permissions().mode()))) } // Position diff --git a/config/src/dir.rs b/config/src/dir.rs new file mode 100644 index 00000000..475eae17 --- /dev/null +++ b/config/src/dir.rs @@ -0,0 +1,23 @@ +use std::path::PathBuf; + +#[cfg(target_os = "windows")] +pub(crate) fn get_config_file(path: &str) -> PathBuf { dirs::config_dir().unwrap().join(path) } + +#[cfg(not(target_os = "windows"))] +pub(crate) fn get_config_file(path: &str) -> PathBuf { + xdg::BaseDirectories::new().unwrap().get_config_file(path) +} + +#[cfg(target_os = "windows")] +pub(crate) fn get_state_dir() -> Result { + dirs::data_dir() + .map(|dir| dir.join("yazi").join("state")) + .ok_or_else(|| String::from("failed to get state directory")) +} + +#[cfg(not(target_os = "windows"))] +pub(crate) fn get_state_dir() -> Result { + xdg::BaseDirectories::with_prefix("yazi") + .map(|dirs| dirs.get_state_home()) + .map_err(|e| e.to_string()) +} diff --git a/config/src/lib.rs b/config/src/lib.rs index ca467e9e..b49df695 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -3,6 +3,7 @@ use shared::RoCell; mod boot; +mod dir; pub mod keymap; mod log; pub mod manager; diff --git a/core/src/manager/folder.rs b/core/src/manager/folder.rs index 15280969..1a56d60e 100644 --- a/core/src/manager/folder.rs +++ b/core/src/manager/folder.rs @@ -1,8 +1,8 @@ use std::path::{Path, PathBuf}; +use crossterm::terminal::size; use indexmap::map::Slice; use ratatui::layout::Rect; -use shared::tty_size; use super::{ALL_RATIO, CURRENT_RATIO, DIR_PADDING, PARENT_RATIO}; use crate::{emit, files::{File, Files, FilesOp}}; @@ -27,7 +27,7 @@ impl Folder { } #[inline] - pub fn limit() -> usize { tty_size().ws_row.saturating_sub(DIR_PADDING) as usize } + pub fn limit() -> usize { size().unwrap_or_default().1.saturating_sub(DIR_PADDING) as usize } pub fn update(&mut self, op: FilesOp) -> bool { let b = match op { @@ -183,12 +183,12 @@ impl Folder { pub fn rect_current(&self, path: &Path) -> Option { let pos = self.position(path)? - self.offset; - let s = tty_size(); + let s = size().unwrap_or_default(); Some(Rect { - x: (s.ws_col as u32 * PARENT_RATIO / ALL_RATIO) as u16, + x: (s.0 as u32 * PARENT_RATIO / ALL_RATIO) as u16, y: pos as u16, - width: (s.ws_col as u32 * CURRENT_RATIO / ALL_RATIO) as u16, + width: (s.0 as u32 * CURRENT_RATIO / ALL_RATIO) as u16, height: 1, }) } diff --git a/core/src/tasks/workers/file.rs b/core/src/tasks/workers/file.rs index 8f2f98f9..e808fae4 100644 --- a/core/src/tasks/workers/file.rs +++ b/core/src/tasks/workers/file.rs @@ -125,7 +125,16 @@ impl File { match fs::remove_file(&task.to).await { Err(e) if e.kind() != NotFound => Err(e)?, - _ => fs::symlink(src, &task.to).await?, + _ => { + #[cfg(target_os = "windows")] + { + fs::symlink_file(src, &task.to).await? + } + #[cfg(not(target_os = "windows"))] + { + fs::symlink(src, &task.to).await? + } + } } if task.cut { diff --git a/shared/src/fs.rs b/shared/src/fs.rs index 8240e7f0..dec5738d 100644 --- a/shared/src/fs.rs +++ b/shared/src/fs.rs @@ -91,6 +91,10 @@ pub fn copy_with_progress(from: &Path, to: &Path) -> mpsc::Receiver String { String::new() } + +#[cfg(not(target_os = "windows"))] // Convert a file mode to a string representation #[allow(clippy::collapsible_else_if)] pub fn file_mode(mode: u32) -> String { diff --git a/shared/src/tty.rs b/shared/src/tty.rs index 035f09ec..7a70b2f4 100644 --- a/shared/src/tty.rs +++ b/shared/src/tty.rs @@ -1,16 +1,10 @@ -use libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ}; - -#[inline] -pub fn tty_size() -> winsize { - unsafe { - let s: winsize = std::mem::zeroed(); - ioctl(STDOUT_FILENO, TIOCGWINSZ, &s); - s - } -} +use crossterm::terminal::window_size; #[inline] pub fn tty_ratio() -> (f64, f64) { - let s = tty_size(); - (f64::from(s.ws_xpixel) / f64::from(s.ws_col), f64::from(s.ws_ypixel) / f64::from(s.ws_row)) + if let Ok(ws) = window_size() { + (f64::from(ws.width) / f64::from(ws.columns), f64::from(ws.height) / f64::from(ws.rows)) + } else { + (1f64, 1f64) + } }