-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from Araxeus/refactor
v1.2.0 ✨
- Loading branch information
Showing
10 changed files
with
361 additions
and
114 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
[package] | ||
name = "ls-interactive" | ||
description = "Interactive ls command" | ||
version = "1.1.2" | ||
version = "1.2.0" | ||
authors = ["Araxeus <[email protected]>"] | ||
homepage = "https://github.com/Araxeus/ls-interactive" | ||
license = "MIT" | ||
|
@@ -16,6 +16,7 @@ dialoguer = "0.10.0" | |
console = "0.15.0" | ||
open = "2.1.2" | ||
human-panic = "1.0.3" | ||
lnk = "0.3.0" | ||
|
||
[[bin]] | ||
name = "lsi" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,120 +1,78 @@ | ||
mod icons; | ||
mod structs; | ||
mod utils; | ||
|
||
use std::env; | ||
use std::fmt; | ||
use std::fs; | ||
use std::path::Path; | ||
|
||
struct Entry { | ||
name: String, | ||
path: String, | ||
icon: String, | ||
is_dir: bool, | ||
is_link: bool, | ||
} | ||
|
||
impl fmt::Display for Entry { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
write!(f, "{} {}", self.icon, self.name) | ||
} | ||
} | ||
use structs::{Entry, Filetype, Icons}; | ||
use utils::{display_choices, err, resolve_lnk}; | ||
|
||
fn main() { | ||
human_panic::setup_panic!(); | ||
|
||
let args: Vec<String> = env::args().collect(); | ||
let path = if args.len() >= 2 { args[1].trim() } else { "." }; | ||
|
||
let path = fs::canonicalize(path); | ||
let path = if args.len() >= 2 { args[1].trim() } else { "." }; | ||
|
||
match path { | ||
Ok(path) => open_entry(path.to_str().unwrap()), | ||
Err(_) => println!("Invalid path"), | ||
match fs::canonicalize(path) { | ||
Ok(path) => main_loop(path.to_string_lossy().to_string()), | ||
Err(_) => err("Invalid path"), | ||
} | ||
} | ||
|
||
fn open_entry(path: &str) { | ||
let dir = get_dir(path); | ||
|
||
let entry = &dir[select(&dir, path)]; | ||
if entry.is_dir || entry.is_link { | ||
open_entry(&entry.path); | ||
} else { | ||
open::that(&entry.path).unwrap(); | ||
fn main_loop(initial_path: String) { | ||
let mut path = initial_path; | ||
loop { | ||
let choices = get_choices(&path); | ||
// make user select a choice and get the selected Entry | ||
let entry = &choices[display_choices(&choices, &path)]; | ||
|
||
// exec file | ||
if entry.filetype.should_exec() { | ||
match open::that(&entry.path) { | ||
// quit if file was opened | ||
Ok(_) => break, | ||
// else display error and open as directory | ||
Err(_) => err(format!("Failed to open file \"{}\"", &entry.path[4..])), | ||
} | ||
} | ||
// browse directory by continuing loop with new path | ||
path = if entry.filetype == Filetype::Lnk { | ||
resolve_lnk(&entry.path) | ||
} else { | ||
entry.path.to_string() | ||
}; | ||
} | ||
} | ||
|
||
fn get_dir(path: &str) -> Vec<Entry> { | ||
fn get_choices(path: &str) -> Vec<Entry> { | ||
let mut result_vector: Vec<Entry> = Vec::new(); | ||
|
||
// .. Open parent directory | ||
if let Ok(parent) = Path::new(path).parent().ok_or("No parent") { | ||
result_vector.push(Entry { | ||
name: String::from(".."), | ||
path: parent.to_str().unwrap().to_string(), | ||
icon: String::from(icons::DIR), | ||
is_dir: true, | ||
is_link: false, | ||
icon: &Icons::DIR, | ||
filetype: Filetype::Directory, | ||
}); | ||
} | ||
|
||
// Get files in directory | ||
if let Ok(entries) = fs::read_dir(path) { | ||
for entry in entries.flatten() { | ||
if let Ok(file_type) = entry.file_type() { | ||
let ext = entry.path(); | ||
let icon = String::from(if file_type.is_file() { | ||
icons::from_ext( | ||
ext.extension() | ||
.unwrap_or_default() | ||
.to_str() | ||
.unwrap_or_default(), | ||
) | ||
} else if file_type.is_dir() { | ||
icons::DIR | ||
} else if file_type.is_symlink() { | ||
icons::LINK | ||
} else { | ||
icons::UNKNOWN | ||
}); | ||
let entry = Entry { | ||
name: entry.file_name().to_str().unwrap().to_string(), | ||
path: entry.path().to_str().unwrap().to_string(), | ||
is_link: icon == icons::LINK, | ||
is_dir: file_type.is_dir(), | ||
icon, | ||
}; | ||
result_vector.push(entry); | ||
} | ||
result_vector.push(Entry::from_dir_entry(entry)); | ||
} | ||
} | ||
|
||
// Open current directory in explorer | ||
result_vector.push(Entry { | ||
name: String::new(), | ||
path: path.to_string(), | ||
icon: String::from(icons::EXPLORER), | ||
is_dir: false, | ||
is_link: false, | ||
icon: &Icons::EXPLORER, | ||
filetype: Filetype::Executable, | ||
}); | ||
|
||
result_vector | ||
} | ||
|
||
use console::Term; | ||
use dialoguer::{theme::ColorfulTheme, Select}; | ||
|
||
fn select(items: &[Entry], path: &str) -> usize { | ||
let selection = Select::with_theme(&ColorfulTheme::default()) | ||
.with_prompt(&path[4..]) | ||
.report(false) | ||
.items(items) | ||
.default(0) | ||
.interact_on_opt(&Term::stderr()) | ||
.ok() | ||
.unwrap(); | ||
|
||
match selection { | ||
Some(index) => index, | ||
// exit process if none | ||
None => std::process::exit(0), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
use super::{Filetype, Icon, Icons}; | ||
|
||
use std::fmt; | ||
use std::fs; | ||
|
||
pub struct Entry { | ||
pub name: String, | ||
pub path: String, | ||
pub icon: &'static Icon, | ||
pub filetype: Filetype, | ||
} | ||
|
||
impl fmt::Display for Entry { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
write!(f, "{} {}", self.icon, self.name) | ||
} | ||
} | ||
|
||
impl Entry { | ||
// pub fn to_string(self) -> String { | ||
// format!("{} {}", self.icon, self.name) | ||
// } | ||
|
||
#[allow(clippy::needless_pass_by_value)] | ||
pub fn from_dir_entry(entry: fs::DirEntry) -> Self { | ||
let path = entry.path(); | ||
|
||
let native_file_type = entry.file_type().unwrap(); | ||
|
||
let filetype = Filetype::from_native(native_file_type, &path); | ||
|
||
Self { | ||
name: entry.file_name().to_string_lossy().to_string(), | ||
path: path.to_str().unwrap().to_string(), | ||
icon: Icons::from_filetype(&filetype), | ||
filetype, | ||
} | ||
} | ||
} |
Oops, something went wrong.