From 83cbef649d941e3a65a89295d0924d2c7f1f9b3e Mon Sep 17 00:00:00 2001 From: sxyazi Date: Mon, 24 Jul 2023 07:25:12 +0800 Subject: [PATCH] up --- Cargo.lock | 24 ++++++------------------ src/config/keymap/exec.rs | 19 +++++++++++++++++++ src/config/keymap/key.rs | 4 +++- src/config/theme/theme.rs | 3 ++- src/core/manager/manager.rs | 4 +++- src/core/which/which.rs | 3 +++ src/misc/fns.rs | 5 +++-- src/ui/app.rs | 4 ++-- src/ui/dispatcher.rs | 9 ++++++++- src/ui/which/layout.rs | 35 +++++++++++++++++++++++++---------- src/ui/which/side.rs | 36 +++++++++++++++++++++++++++++------- 11 files changed, 103 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dced0abc..eb333e10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,9 +382,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "equivalent" @@ -665,15 +665,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" -[[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys 0.48.0", -] - [[package]] name = "http" version = "0.2.9" @@ -1334,9 +1325,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -2358,12 +2349,9 @@ dependencies = [ [[package]] name = "xdg" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688597db5a750e9cad4511cb94729a078e274308099a0382b5b8203bbc767fee" -dependencies = [ - "home", -] +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] name = "yaml-rust" diff --git a/src/config/keymap/exec.rs b/src/config/keymap/exec.rs index e21562c5..e64abd28 100644 --- a/src/config/keymap/exec.rs +++ b/src/config/keymap/exec.rs @@ -28,6 +28,25 @@ impl From<&str> for Exec { } } +impl ToString for Exec { + fn to_string(&self) -> String { + let mut s = self.cmd.clone(); + for arg in &self.args { + s.push(' '); + s.push_str(arg); + } + for (name, value) in &self.named { + s.push_str(" --"); + s.push_str(name); + if !value.is_empty() { + s.push('='); + s.push_str(value); + } + } + s + } +} + impl Exec { pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where diff --git a/src/config/keymap/key.rs b/src/config/keymap/key.rs index 1c86d4e1..a9b59afe 100644 --- a/src/config/keymap/key.rs +++ b/src/config/keymap/key.rs @@ -106,7 +106,8 @@ impl TryFrom for Key { impl ToString for Key { fn to_string(&self) -> String { if let Some(c) = self.plain() { - return if self.shift { c.to_ascii_uppercase() } else { c }.to_string(); + let c = if self.shift { c.to_ascii_uppercase() } else { c }; + return if c == ' ' { "".to_string() } else { c.to_string() }; } let mut s = "<".to_string(); @@ -149,6 +150,7 @@ impl ToString for Key { KeyCode::F(12) => "F12", KeyCode::Esc => "Esc", + KeyCode::Char(c) if c == ' ' => "Space", KeyCode::Char(c) => { s.push(if self.shift { c.to_ascii_uppercase() } else { c }); "" diff --git a/src/config/theme/theme.rs b/src/config/theme/theme.rs index f8da9ed6..952ce5ab 100644 --- a/src/config/theme/theme.rs +++ b/src/config/theme/theme.rs @@ -64,7 +64,8 @@ pub struct Theme { impl Theme { pub fn new() -> Self { let mut theme: Self = toml::from_str(&MERGED_THEME).unwrap(); - theme.preview.syntect_theme = absolute_path(&theme.preview.syntect_theme); + theme.preview.syntect_theme = + futures::executor::block_on(absolute_path(&theme.preview.syntect_theme)); theme } } diff --git a/src/core/manager/manager.rs b/src/core/manager/manager.rs index c362495f..a1e114e6 100644 --- a/src/core/manager/manager.rs +++ b/src/core/manager/manager.rs @@ -1,4 +1,4 @@ -use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, mem, path::PathBuf}; +use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, mem, path::PathBuf}; use tokio::fs; @@ -25,6 +25,8 @@ impl Manager { } pub fn refresh(&mut self) { + env::set_current_dir(&self.current().cwd).ok(); + self.watcher.trigger(&self.current().cwd); if let Some(p) = self.parent() { self.watcher.trigger(&p.cwd); diff --git a/src/core/which/which.rs b/src/core/which/which.rs index e444ab5e..194920c2 100644 --- a/src/core/which/which.rs +++ b/src/core/which/which.rs @@ -41,6 +41,9 @@ impl Which { } else if self.cands.len() == 1 { self.visible = false; emit!(Ctrl(self.cands.remove(0), self.layer)); + } else if let Some(i) = self.cands.iter().position(|c| c.on.len() == self.times + 1) { + emit!(Ctrl(self.cands.remove(i), self.layer)); + self.visible = false; } self.times += 1; diff --git a/src/misc/fns.rs b/src/misc/fns.rs index 86c98d02..81fa6045 100644 --- a/src/misc/fns.rs +++ b/src/misc/fns.rs @@ -2,7 +2,8 @@ use std::{env, path::{Path, PathBuf}}; use tokio::fs; -pub fn absolute_path(p: &Path) -> PathBuf { +pub async fn absolute_path(p: impl AsRef) -> PathBuf { + let p = p.as_ref(); if p.starts_with("~") { if let Ok(home) = env::var("HOME") { let mut expanded = PathBuf::new(); @@ -11,7 +12,7 @@ pub fn absolute_path(p: &Path) -> PathBuf { return expanded; } } - p.to_path_buf() + fs::canonicalize(p).await.unwrap_or_else(|_| p.to_path_buf()) } pub fn readable_path(p: &Path, base: &Path) -> String { diff --git a/src/ui/app.rs b/src/ui/app.rs index 45890ba3..30f564ef 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -3,7 +3,7 @@ use crossterm::event::KeyEvent; use tokio::sync::oneshot::{self}; use super::{root::Root, Ctx, Executor, Logs, Signals, Term}; -use crate::{config::keymap::{Control, Key, KeymapLayer}, core::{files::FilesOp, Event}, emit}; +use crate::{config::keymap::{Control, Key, KeymapLayer}, core::{files::FilesOp, Event}, emit, misc::absolute_path}; pub struct App { cx: Ctx, @@ -84,7 +84,7 @@ impl App { let tasks = &mut self.cx.tasks; match event { Event::Cd(path) => { - manager.active_mut().cd(path).await; + manager.active_mut().cd(absolute_path(path).await).await; } Event::Refresh => { manager.refresh(); diff --git a/src/ui/dispatcher.rs b/src/ui/dispatcher.rs index d8f8447b..2b1af850 100644 --- a/src/ui/dispatcher.rs +++ b/src/ui/dispatcher.rs @@ -1,5 +1,7 @@ +use std::path::PathBuf; + use super::Ctx; -use crate::{config::{keymap::{Control, Exec, Key, KeymapLayer}, KEYMAP}, core::input::InputMode, misc::optional_bool}; +use crate::{config::{keymap::{Control, Exec, Key, KeymapLayer}, KEYMAP}, core::input::InputMode, emit, misc::optional_bool}; pub struct Executor; @@ -60,6 +62,11 @@ impl Executor { "enter" => cx.manager.active_mut().enter(), "back" => cx.manager.active_mut().back(), "forward" => cx.manager.active_mut().forward(), + "cd" => { + let path = exec.args.get(0).map(|s| PathBuf::from(s)).unwrap_or_default(); + emit!(Cd(path)); + false + } // Selection "select" => { diff --git a/src/ui/which/layout.rs b/src/ui/which/layout.rs index ff83ef3a..30335a3a 100644 --- a/src/ui/which/layout.rs +++ b/src/ui/which/layout.rs @@ -1,4 +1,4 @@ -use ratatui::{layout, prelude::{Buffer, Constraint, Direction, Rect}, widgets::Widget}; +use ratatui::{layout, prelude::{Buffer, Constraint, Direction, Rect}, widgets::{Clear, Widget}}; use super::Side; use crate::ui::Ctx; @@ -13,20 +13,35 @@ impl<'a> Which<'a> { impl Widget for Which<'_> { fn render(self, area: Rect, buf: &mut Buffer) { - let chunks = layout::Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) - .split(area); + let which = &self.cx.which; + let mut cands: (Vec<_>, Vec<_>, Vec<_>) = Default::default(); + for (i, c) in which.cands.iter().enumerate() { + match i % 3 { + 0 => cands.0.push(c), + 1 => cands.1.push(c), + 2 => cands.2.push(c), + _ => unreachable!(), + } + } + + let height = cands.0.len() as u16 + 2; + let area = Rect { + x: 1, + y: area.height.saturating_sub(height + 2), + width: area.width.saturating_sub(2), + height, + }; let chunks = layout::Layout::default() .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) - .split(chunks[1]); - - let which = &self.cx.which; - let cands: (Vec<_>, Vec<_>) = which.cands.iter().enumerate().partition(|(i, _)| i % 2 == 0); + .constraints( + [Constraint::Ratio(1, 3), Constraint::Ratio(1, 3), Constraint::Ratio(1, 3)].as_ref(), + ) + .split(area); + Clear.render(area, buf); Side::new(which.times, cands.0).render(chunks[0], buf); Side::new(which.times, cands.1).render(chunks[1], buf); + Side::new(which.times, cands.2).render(chunks[2], buf); } } diff --git a/src/ui/which/side.rs b/src/ui/which/side.rs index 26dfaea7..2e0fe814 100644 --- a/src/ui/which/side.rs +++ b/src/ui/which/side.rs @@ -1,14 +1,14 @@ -use ratatui::{prelude::{Buffer, Rect}, widgets::{List, ListItem, Widget}}; +use ratatui::{prelude::{Buffer, Rect}, style::{Color, Style, Stylize}, text::{Line, Span}, widgets::{Block, List, ListItem, Padding, Widget}}; use crate::config::keymap::Control; pub struct Side<'a> { times: usize, - cands: Vec<(usize, &'a Control)>, + cands: Vec<&'a Control>, } impl<'a> Side<'a> { - pub fn new(times: usize, cands: Vec<(usize, &'a Control)>) -> Self { Self { times, cands } } + pub fn new(times: usize, cands: Vec<&'a Control>) -> Self { Self { times, cands } } } impl Widget for Side<'_> { @@ -16,12 +16,34 @@ impl Widget for Side<'_> { let items = self .cands .into_iter() - .map(|(_, c)| { - let s = c.on[self.times..].into_iter().map(ToString::to_string).collect::(); - ListItem::new(format!("{:?}", s)) + .map(|c| { + let mut spans = vec![]; + + // Keys + let keys = c.on[self.times..].iter().map(ToString::to_string).collect::>(); + spans.push(Span::raw(" ".repeat(10usize.saturating_sub(keys.join("").len())))); + spans.push(Span::styled(keys[0].clone(), Style::default().fg(Color::LightCyan))); + spans.extend( + keys + .iter() + .skip(1) + .map(|k| Span::styled(k.to_string(), Style::default().fg(Color::DarkGray))), + ); + + // Separator + spans.push(Span::styled("  ".to_string(), Style::default().fg(Color::DarkGray))); + + // Exec + let exec = c.exec.iter().map(ToString::to_string).collect::>().join("; "); + spans.push(Span::styled(exec, Style::default().fg(Color::Magenta))); + + ListItem::new(Line::from(spans)) }) .collect::>(); - List::new(items).render(area, buf); + List::new(items) + .block(Block::new().padding(Padding::new(0, 1, 1, 1))) + .bg(Color::Rgb(47, 51, 73)) + .render(area, buf); } }