Skip to content

Commit

Permalink
Add windows drive view (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
Araxeus authored Jan 6, 2023
1 parent 274bdbc commit b673c6a
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 52 deletions.
62 changes: 33 additions & 29 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ fuzzy-matcher = "0.3.7"
crossterm = "0.25.0"
unicode-segmentation = "1.10.0"
tiny_update_notifier = "2.1.0"

[target.'cfg(windows)'.dependencies]
windows = { version = "0.43.0", features = ["Win32_Storage_FileSystem"] }
68 changes: 53 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use std::{fs, path::Path};
use structs::{Entry, Filetype, Icons};
use utils::{display_choices, err, get_first_arg, pretty_path, resolve_lnk, KeyModifiers};

#[cfg(windows)]
use utils::get_logical_drives;

use tiny_update_notifier::check_github;

fn main() {
Expand All @@ -27,13 +30,17 @@ fn main() {
}

fn main_loop(initial_path: String) {
let mut path = initial_path;
let mut selected_entry = Entry {
path: initial_path,
..Default::default()
};

loop {
let choices = get_choices(&path);
let choices = get_choices(&selected_entry);

let (index, modifier) = display_choices(&choices, &path);
let (index, modifier) = display_choices(&choices, &selected_entry.path);

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

// exec file
if entry.filetype.should_exec() || modifier == KeyModifiers::CONTROL {
Expand All @@ -47,25 +54,45 @@ fn main_loop(initial_path: String) {
)),
}
}
// browse directory by continuing loop with new path
path = if entry.filetype == Filetype::Lnk {
resolve_lnk(&entry.path)
} else {
entry.path.to_string()
};

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

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

if selected_entry.filetype == Filetype::Lnk {
selected_entry.path = resolve_lnk(&selected_entry.path);
}
}
}

fn get_choices(path: &str) -> Vec<Entry> {
fn get_choices(entry: &Entry) -> Vec<Entry> {
let mut result_vector: Vec<Entry> = Vec::new();

#[cfg(windows)]
// Open Drives View on Windows
if entry.filetype == Filetype::DriveView {
match get_logical_drives() {
Ok(drives) => {
for drive in drives {
result_vector.push(Entry {
name: format!("{drive}:\\"),
path: format!("{drive}:\\"),
icon: &Icons::DRIVE,
filetype: Filetype::Directory,
});
}
return result_vector;
}
Err(_) => err("Failed to get drives"),
}
}

// .. Open parent directory
if let Some(parent) = Path::new(path).parent() {
if let Some(parent) = Path::new(&entry.path).parent() {
result_vector.push(Entry {
name: String::from(".."),
path: parent.to_string_lossy().to_string(),
Expand All @@ -74,8 +101,19 @@ fn get_choices(path: &str) -> Vec<Entry> {
});
}

#[cfg(windows)]
if result_vector.is_empty() {
// .. Open Drives View on Windows
result_vector.push(Entry {
name: String::from(".."),
path: env!("COMPUTERNAME").to_string(),
icon: &Icons::PC,
filetype: Filetype::DriveView,
});
}

// Get files in directory
if let Ok(entries) = fs::read_dir(path) {
if let Ok(entries) = fs::read_dir(&entry.path) {
for entry in entries.flatten() {
result_vector.push(Entry::from_dir_entry(&entry));
}
Expand All @@ -85,7 +123,7 @@ fn get_choices(path: &str) -> Vec<Entry> {
if result_vector.len() < 2 {
result_vector.push(Entry {
name: String::from("<Open>"),
path: path.to_string(),
path: entry.path.clone(),
icon: &Icons::EXPLORER,
filetype: Filetype::Executable,
});
Expand Down
12 changes: 12 additions & 0 deletions src/structs/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@ use super::{Filetype, Icon, Icons};

use std::{fmt, fs};

#[derive(Clone)]
pub struct Entry {
pub name: String,
pub path: String,
pub icon: &'static Icon,
pub filetype: Filetype,
}

impl Default for Entry {
fn default() -> Self {
Self {
name: String::new(),
path: String::new(),
icon: Icons::from_filetype(&Filetype::Unknown),
filetype: Filetype::Unknown,
}
}
}

impl fmt::Display for Entry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.icon, self.name)
Expand Down
6 changes: 4 additions & 2 deletions src/structs/filetype.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{fs, path::Path};

#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Clone)]
pub enum Filetype {
Text, // (default)
Executable,
Expand All @@ -17,6 +17,8 @@ pub enum Filetype {
Symlink,
Lnk,
Unknown,
#[allow(dead_code)]
DriveView,
}

impl Filetype {
Expand All @@ -28,7 +30,7 @@ impl Filetype {
pub const fn should_exec(&self) -> bool {
!matches!(
self,
Self::Directory | Self::Symlink | Self::Lnk | Self::Unknown
Self::Directory | Self::Symlink | Self::Lnk | Self::Unknown | Self::DriveView
)
}

Expand Down
13 changes: 12 additions & 1 deletion src/structs/icons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ use std::fmt;

pub struct Icon(&'static str);

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 {
write!(f, "{}", self.0)
Expand All @@ -14,7 +20,7 @@ impl fmt::Display for Icon {
pub struct Icons;

impl Icons {
pub const EXE: Icon = Icon("💿"); // 💽 📀 💾
pub const EXE: Icon = Icon("💿"); // 📀 💾
pub const TXT: Icon = Icon("📄"); // 📰 📝 📖 📜 📒 📓 📑 🧾 📋 📇
pub const PIC: Icon = Icon("🖼️"); // 📷 📸 🎨
pub const VID: Icon = Icon("🎬"); // 🎞️ 📺 📹 📽️ 🎥 📼
Expand All @@ -31,6 +37,10 @@ impl Icons {
pub const JS: Icon = Icon("📒"); // 🇯 🐍 "\x1b[30;43m🇯\x1b[0m" = black on yellow
pub const CSS: Icon = Icon("💄"); // 💅

// Windows Only
pub const PC: Icon = Icon("🖥️");
pub const DRIVE: Icon = Icon("💽");

// TODO
// Packages: 📦 (zip, tar, gz, bz2, xz, 7z, rar)
// Typescript: 📘
Expand Down Expand Up @@ -61,6 +71,7 @@ impl Icons {
Filetype::Rust => &Self::RUST,
Filetype::Javascript => &Self::JS,
Filetype::Css => &Self::CSS,
Filetype::DriveView => &Self::PC,
Filetype::Unknown => &Self::UNKNOWN,
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/structs/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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.
Expand Down Expand Up @@ -169,7 +170,7 @@ impl Prompt<'_> {
if cursor_pos > 0 {
cursor_pos -= 1;
term.flush()?;
} else if search_term.is_empty() {
} else if search_term.is_empty() && self.items[0].ends_with("..") {
if self.clear {
render.clear()?;
}
Expand All @@ -186,7 +187,9 @@ impl Prompt<'_> {
cursor_pos += 1;
term.flush()?;
} else if search_term.is_empty()
&& filtered_list[sel].0.find('📁').is_some()
&& (filtered_list[sel].0.contains(Icons::DIR.str())
|| (cfg!(windows)
&& filtered_list[sel].0.contains(Icons::DRIVE.str())))
{
if self.clear {
render.clear()?;
Expand Down
Loading

0 comments on commit b673c6a

Please sign in to comment.