Skip to content

Commit

Permalink
Make every file/directory a clickable link (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
Araxeus authored Mar 12, 2023
1 parent 17f3f86 commit eebf883
Show file tree
Hide file tree
Showing 8 changed files with 399 additions and 253 deletions.
387 changes: 313 additions & 74 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ keywords = ["ls", "lsi", "cli", "interactive", "explorer", "list", "files", "fol
categories = ["command-line-utilities"]

[dependencies]
console = "=0.15.5" # ANY LATER VERSION BREAKS SCROLLING (0.15.1 - 0.15.3 tested)
open = "3.2.0"
human-panic = "1.0.3"
console = "0.15.5"
open = "4.0.0"
human-panic = "1.1.1"
lnk = "0.5.1"
fuzzy-matcher = "0.3.7"
crossterm = "0.26.0"
crossterm = "0.26.1"
unicode-segmentation = "1.10.1"
tiny_update_notifier = "2.2.0"

Expand Down
10 changes: 5 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ fn main_loop(initial_path: String) {

let entry = choices[index].clone();

if modifier == KeyModifiers::SHIFT || modifier == KeyModifiers::ALT {
print!("{}", pretty_path(&entry.path));
break;
}

// exec file
if entry.filetype.should_exec() || modifier == KeyModifiers::CONTROL {
match open::that(&entry.path) {
Expand All @@ -55,11 +60,6 @@ fn main_loop(initial_path: String) {
}
}

if modifier == KeyModifiers::SHIFT || modifier == KeyModifiers::ALT {
print!("{}", pretty_path(&selected_entry.path));
break;
}

// browse directory by continuing loop with new path
selected_entry = entry;

Expand Down
12 changes: 7 additions & 5 deletions src/structs/icons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ use super::Filetype;

use std::fmt;

#[derive(PartialEq, Eq)]
pub struct Icon(&'static str);

impl Icon {
pub const fn str(&self) -> &'static str {
self.0
}
}
// impl Icon {
// pub const fn str(&self) -> &'static str {
// self.0
// }
// }

impl fmt::Display for Icon {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand Down Expand Up @@ -39,6 +40,7 @@ impl Icons {

// Windows Only
pub const PC: Icon = Icon("🖥️");
#[allow(dead_code)]
pub const DRIVE: Icon = Icon("💽");

// TODO
Expand Down
2 changes: 1 addition & 1 deletion src/structs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ pub use crate::structs::{
filetype::Filetype,
icons::{Icon, Icons},
prompt::Prompt,
prompt_renderer::ColorfulTheme,
prompt_renderer::Theme,
};
64 changes: 28 additions & 36 deletions src/structs/prompt.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,37 @@
use super::prompt_renderer::{SimpleTheme, TermRenderer, Theme};
use super::{
prompt_renderer::{TermRenderer, Theme},
Entry, Filetype,
};
use console::Term;
use crossterm::{
event::{read, Event, KeyCode, KeyEvent, KeyModifiers},
event::{read, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers},
terminal,
};

use fuzzy_matcher::FuzzyMatcher;
use std::io;
use unicode_segmentation::UnicodeSegmentation;

use crate::Icons;
/// Renders a selection menu that user can fuzzy match to reduce set.
///
/// User can use fuzzy search to limit selectable items.
/// Interaction returns index of an item selected in the order they appear in `item` invocation or `items` slice.
pub struct Prompt<'a> {
default: usize,
items: Vec<String>,
items: Vec<Entry>,
title: String,
report: bool,
clear: bool,
highlight_matches: bool,
theme: &'a dyn Theme,
}

impl Default for Prompt<'static> {
fn default() -> Self {
Self::new()
}
}

impl Prompt<'static> {
/// Creates the prompt with a specific text.
pub fn new() -> Self {
Self::with_theme(&SimpleTheme)
}
theme: &'a Theme,
}

impl Prompt<'_> {
/// Adds multiple items to the fuzzy selector.
pub fn items<T: ToString>(&mut self, items: &[T]) -> &mut Self {
for item in items {
self.items.push(item.to_string());
pub fn items(&mut self, items: &[Entry]) -> &mut Self {
let its = items.to_owned();
for item in its {
self.items.push(item);
}
self
}
Expand Down Expand Up @@ -78,9 +67,9 @@ impl Prompt<'_> {
let mut sel = self.default;

let mut size_vec = Vec::new();
for items in self.items.iter().as_slice() {
let size = &items.len();
size_vec.push(*size);
for item in self.items.iter().as_slice() {
let size = &item.name.len() + 2;
size_vec.push(size);
}

// Fuzzy matcher
Expand All @@ -107,7 +96,7 @@ impl Prompt<'_> {
let mut filtered_list = self
.items
.iter()
.map(|item| (item, matcher.fuzzy_match(item, &search_term.concat())))
.map(|item| (item, matcher.fuzzy_match(&item.name, &search_term.concat())))
.filter_map(|(item, score)| score.map(|s| (item, s)))
.collect::<Vec<_>>();

Expand All @@ -133,7 +122,10 @@ impl Prompt<'_> {
terminal::enable_raw_mode()?;

if let Event::Key(KeyEvent {
code, modifiers, ..
code,
modifiers,
kind: KeyEventKind::Press | KeyEventKind::Repeat,
..
}) = read().unwrap()
{
match code {
Expand Down Expand Up @@ -170,7 +162,7 @@ impl Prompt<'_> {
if cursor_pos > 0 {
cursor_pos -= 1;
term.flush()?;
} else if search_term.is_empty() && self.items[0].ends_with("..") {
} else if search_term.is_empty() && self.items[0].name.ends_with("..") {
if self.clear {
render.clear()?;
}
Expand All @@ -187,18 +179,19 @@ impl Prompt<'_> {
cursor_pos += 1;
term.flush()?;
} else if search_term.is_empty()
&& (filtered_list[sel].0.contains(Icons::DIR.str())
&& !filtered_list.is_empty()
&& (filtered_list[sel].0.filetype == Filetype::Directory
|| (cfg!(windows)
&& filtered_list[sel].0.contains(Icons::DRIVE.str())))
&& filtered_list[sel].0.filetype == Filetype::DriveView))
{
if self.clear {
render.clear()?;
}
let sel_string = filtered_list[sel].0;

let sel_string_pos_in_items = self
.items
.iter()
.position(|item| item.eq(sel_string))
.position(|item| item.name.eq(&filtered_list[sel].0.name))
.unwrap();

terminal::disable_raw_mode()?;
Expand All @@ -216,15 +209,14 @@ impl Prompt<'_> {
if self.report {
render.input_prompt_selection(
self.title.as_str(),
filtered_list[sel].0,
&filtered_list[sel].0.name,
)?;
}

let sel_string = filtered_list[sel].0;
let sel_string_pos_in_items = self
.items
.iter()
.position(|item| item.eq(sel_string))
.position(|item| item.name.eq(&filtered_list[sel].0.name))
.unwrap();

terminal::disable_raw_mode()?;
Expand Down Expand Up @@ -260,7 +252,7 @@ impl Prompt<'_> {

impl<'a> Prompt<'a> {
/// Same as `new` but with a specific theme.
pub fn with_theme(theme: &'a dyn Theme) -> Self {
pub const fn with_theme(theme: &'a Theme) -> Self {
Self {
default: 0,
items: vec![],
Expand Down
Loading

0 comments on commit eebf883

Please sign in to comment.