Skip to content

Commit

Permalink
feat: find (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
sxyazi authored Sep 11, 2023
1 parent 0acf345 commit 7ec7e36
Show file tree
Hide file tree
Showing 23 changed files with 403 additions and 64 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use core::{emit, files::FilesOp, input::InputMode, Event};
use std::ffi::OsString;

use anyhow::{Ok, Result};
use config::{keymap::{Control, Key, KeymapLayer}, BOOT};
use config::{keymap::{Exec, Key, KeymapLayer}, BOOT};
use crossterm::event::KeyEvent;
use shared::{expand_url, Term};
use tokio::sync::oneshot;
Expand Down Expand Up @@ -34,7 +34,7 @@ impl App {
Event::Render(_) => app.dispatch_render(),
Event::Resize(..) => app.dispatch_resize(),
Event::Stop(state, tx) => app.dispatch_stop(state, tx),
Event::Ctrl(ctrl, layer) => app.dispatch_ctrl(ctrl, layer),
Event::Call(exec, layer) => app.dispatch_call(exec, layer),
event => app.dispatch_module(event),
}
}
Expand Down Expand Up @@ -109,8 +109,8 @@ impl App {
}

#[inline]
fn dispatch_ctrl(&mut self, ctrl: Control, layer: KeymapLayer) {
if Executor::dispatch(&mut self.cx, &ctrl.exec, layer) {
fn dispatch_call(&mut self, exec: Vec<Exec>, layer: KeymapLayer) {
if Executor::dispatch(&mut self.cx, &exec, layer) {
emit!(Render);
}
}
Expand Down
10 changes: 9 additions & 1 deletion app/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl Executor {
}

#[inline]
pub(super) fn dispatch(cx: &mut Ctx, exec: &Vec<Exec>, layer: KeymapLayer) -> bool {
pub(super) fn dispatch(cx: &mut Ctx, exec: &[Exec], layer: KeymapLayer) -> bool {
let mut render = false;
for e in exec {
render |= match layer {
Expand Down Expand Up @@ -138,6 +138,14 @@ impl Executor {
_ => false,
},

// Find
"find" => {
let query = exec.args.get(0).map(|s| s.as_str());
let prev = exec.named.contains_key("previous");
cx.manager.active_mut().find(query, prev)
}
"find_arrow" => cx.manager.active_mut().find_arrow(exec.named.contains_key("previous")),

// Sorting
"sort" => {
let b = cx.manager.active_mut().set_sorter(FilesSorter {
Expand Down
61 changes: 47 additions & 14 deletions app/src/manager/folder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::files::File;

use config::{MANAGER, THEME};
use ratatui::{buffer::Buffer, layout::Rect, style::Style, widgets::{List, ListItem, Widget}};
use ratatui::{buffer::Buffer, layout::Rect, style::{Color, Modifier, Style}, text::{Line, Span}, widgets::{List, ListItem, Widget}};
use shared::short_path;

use crate::Ctx;
Expand All @@ -11,11 +11,12 @@ pub(super) struct Folder<'a> {
folder: &'a core::manager::Folder,
is_preview: bool,
is_selection: bool,
is_find: bool,
}

impl<'a> Folder<'a> {
pub(super) fn new(cx: &'a Ctx, folder: &'a core::manager::Folder) -> Self {
Self { cx, folder, is_preview: false, is_selection: false }
Self { cx, folder, is_preview: false, is_selection: false, is_find: false }
}

#[inline]
Expand All @@ -30,6 +31,24 @@ impl<'a> Folder<'a> {
self
}

#[inline]
pub(super) fn with_find(mut self, state: bool) -> Self {
self.is_find = state;
self
}
}

impl<'a> Folder<'a> {
#[inline]
fn icon(file: &File) -> &'static str {
THEME
.icons
.iter()
.find(|x| x.name.match_path(file.url(), Some(file.is_dir())))
.map(|x| x.display.as_ref())
.unwrap_or("")
}

#[inline]
fn file_style(&self, file: &File) -> Style {
let mimetype = &self.cx.manager.mimetype;
Expand All @@ -53,17 +72,10 @@ impl<'a> Widget for Folder<'a> {
self.folder.window()
};

let items = window
let items: Vec<_> = window
.iter()
.enumerate()
.map(|(i, f)| {
let icon = THEME
.icons
.iter()
.find(|x| x.name.match_path(f.url(), Some(f.is_dir())))
.map(|x| x.display.as_ref())
.unwrap_or("");

let is_selected = self.folder.files.is_selected(f.url());
if (!self.is_selection && is_selected)
|| (self.is_selection && mode.pending(self.folder.offset() + i, is_selected))
Expand All @@ -87,16 +99,37 @@ impl<'a> Widget for Folder<'a> {
self.file_style(f)
};

let mut path = format!(" {icon} {}", short_path(f.url(), &self.folder.cwd));
let mut spans = Vec::with_capacity(10);

spans.push(Span::raw(format!(" {} ", Self::icon(f))));
spans.push(Span::raw(short_path(f.url(), &self.folder.cwd)));

if let Some(link_to) = f.link_to() {
if MANAGER.show_symlink {
path.push_str(&format!(" -> {}", link_to.display()));
spans.push(Span::raw(format!(" -> {}", link_to.display())));
}
}

ListItem::new(path).style(style)
if let Some(idx) = active
.finder()
.filter(|&f| hovered && self.is_find && f.has_matched())
.and_then(|finder| finder.matched_idx(f.url()))
{
let len = active.finder().unwrap().matched().len();
let style = Style::new().fg(Color::Rgb(255, 255, 50)).add_modifier(Modifier::ITALIC);
spans.push(Span::styled(
format!(
" [{}/{}]",
if idx > 99 { ">99".to_string() } else { (idx + 1).to_string() },
if len > 99 { ">99".to_string() } else { len.to_string() }
),
style,
));
}

ListItem::new(Line::from(spans)).style(style)
})
.collect::<Vec<_>>();
.collect();

List::new(items).render(area, buf);
}
Expand Down
1 change: 1 addition & 0 deletions app/src/manager/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ impl<'a> Widget for Layout<'a> {
// Current
Folder::new(self.cx, manager.current())
.with_selection(manager.active().mode().is_visual())
.with_find(manager.active().finder().is_some())
.render(chunks[1], buf);

// Preview
Expand Down
2 changes: 1 addition & 1 deletion app/src/status/left.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl<'a> Widget for Left<'a> {
let separator = &THEME.status.separator;

// Mode
let mut spans = vec![];
let mut spans = Vec::with_capacity(5);
spans.push(Span::styled(&separator.opening, primary.fg()));
spans.push(Span::styled(
format!(" {mode} "),
Expand Down
2 changes: 1 addition & 1 deletion app/src/status/right.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl<'a> Right<'a> {
impl Widget for Right<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
let manager = self.cx.manager.current();
let mut spans = vec![];
let mut spans = Vec::with_capacity(20);

// Permissions
#[cfg(not(target_os = "windows"))]
Expand Down
2 changes: 1 addition & 1 deletion app/src/which/side.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl Widget for Side<'_> {
.cands
.into_iter()
.map(|c| {
let mut spans = vec![];
let mut spans = Vec::with_capacity(10);

// Keys
let keys = c.on[self.times..].iter().map(ToString::to_string).collect::<Vec<_>>();
Expand Down
14 changes: 10 additions & 4 deletions config/preset/keymap.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ keymap = [
{ on = [ "c", "f" ], exec = "copy filename", desc = "Copy the name of the file" },
{ on = [ "c", "n" ], exec = "copy name_without_ext", desc = "Copy the name of the file without the extension" },

# Find
{ on = [ "/" ], exec = "find" },
{ on = [ "?" ], exec = "find --previous" },
{ on = [ "-" ], exec = "find_arrow" },
{ on = [ "=" ], exec = "find_arrow --previous" },

# Sorting
{ on = [ ",", "a" ], exec = "sort alphabetical --dir_first", desc = "Sort alphabetically, directories first" },
{ on = [ ",", "A" ], exec = "sort alphabetical --reverse --dir_first", desc = "Sort alphabetically, directories first (reverse)" },
Expand Down Expand Up @@ -106,7 +112,7 @@ keymap = [
{ on = [ "g", "<Space>" ], exec = "cd --interactive", desc = "Go to a directory interactively" },

# Help
{ on = [ "?" ], exec = "help", desc = "Open help" },
{ on = [ "~" ], exec = "help", desc = "Open help" },
]

[tasks]
Expand All @@ -125,7 +131,7 @@ keymap = [
{ on = [ "<Enter>" ], exec = "inspect", desc = "Inspect the task" },
{ on = [ "x" ], exec = "cancel", desc = "Cancel the task" },

{ on = [ "?" ], exec = "help", desc = "Open help" }
{ on = [ "~" ], exec = "help", desc = "Open help" }
]

[select]
Expand All @@ -144,7 +150,7 @@ keymap = [
{ on = [ "<Up>" ], exec = "arrow -1", desc = "Move cursor up" },
{ on = [ "<Down>" ], exec = "arrow 1", desc = "Move cursor down" },

{ on = [ "?" ], exec = "help", desc = "Open help" }
{ on = [ "~" ], exec = "help", desc = "Open help" }
]

[input]
Expand Down Expand Up @@ -190,7 +196,7 @@ keymap = [
{ on = [ "<C-r>" ], exec = "redo", desc = "Redo the last operation" },

# Help
{ on = [ "?" ], exec = "help", desc = "Open help" }
{ on = [ "~" ], exec = "help", desc = "Open help" }
]

[help]
Expand Down
7 changes: 6 additions & 1 deletion config/src/keymap/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ pub struct Control {
pub desc: Option<String>,
}

impl Control {
#[inline]
pub fn to_call(&self) -> Vec<Exec> { self.exec.clone() }
}

impl Control {
#[inline]
pub fn on(&self) -> String { self.on.iter().map(ToString::to_string).collect() }
Expand All @@ -28,7 +33,7 @@ impl Control {

#[inline]
pub fn contains(&self, s: &str) -> bool {
self.desc.as_ref().map(|d| d.contains(s)).unwrap_or(false)
self.desc.as_ref().map(|d| d.contains(s)) == Some(true)
|| self.exec().contains(s)
|| self.on().contains(s)
}
Expand Down
23 changes: 23 additions & 0 deletions config/src/keymap/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,26 @@ impl Exec {
deserializer.deserialize_any(ExecVisitor)
}
}

impl Exec {
#[inline]
pub fn call(cwd: &str, args: Vec<String>) -> Self {
Exec { cmd: cwd.to_owned(), args, named: Default::default() }
}

#[inline]
pub fn call_named(cwd: &str, named: BTreeMap<String, String>) -> Self {
Exec { cmd: cwd.to_owned(), args: Default::default(), named }
}

#[inline]
pub fn vec(self) -> Vec<Self> { vec![self] }

#[inline]
pub fn with_bool(mut self, name: &str, state: bool) -> Self {
if state {
self.named.insert(name.to_string(), "".to_string());
}
self
}
}
8 changes: 4 additions & 4 deletions core/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{collections::BTreeMap, ffi::OsString};

use anyhow::Result;
use config::{keymap::{Control, KeymapLayer}, open::Opener};
use config::{keymap::{Exec, KeymapLayer}, open::Opener};
use crossterm::event::KeyEvent;
use shared::{InputError, RoCell, Url};
use tokio::sync::{mpsc::{self, UnboundedSender}, oneshot};
Expand All @@ -18,7 +18,7 @@ pub enum Event {
Render(String),
Resize(u16, u16),
Stop(bool, Option<oneshot::Sender<()>>),
Ctrl(Control, KeymapLayer),
Call(Vec<Exec>, KeymapLayer),

// Manager
Cd(Url),
Expand Down Expand Up @@ -67,8 +67,8 @@ macro_rules! emit {
let (tx, rx) = tokio::sync::oneshot::channel();
$crate::Event::Stop($state, Some(tx)).wait(rx)
}};
(Ctrl($exec:expr, $layer:expr)) => {
$crate::Event::Ctrl($exec, $layer).emit();
(Call($exec:expr, $layer:expr)) => {
$crate::Event::Call($exec, $layer).emit();
};

(Cd($url:expr)) => {
Expand Down
Loading

0 comments on commit 7ec7e36

Please sign in to comment.