-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
328 additions
and
2 deletions.
There are no files selected for viewing
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,10 @@ | ||
[package] | ||
name = "tsh" | ||
version = "0.1.0" | ||
edition = "2024" | ||
|
||
[dependencies] | ||
regex = "1" | ||
termcolor = "1.1" | ||
rustyline = "9.0" | ||
chrono = "0.4" |
Empty file.
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,25 @@ | ||
#!/bin/bash | ||
|
||
set -e | ||
|
||
echo "Installing TSH..." | ||
|
||
REPO_URL="https://github.com/ElisStaaf/tsh" | ||
INSTALL_DIR="/tmp/tsh_install" | ||
|
||
git clone "$REPO_URL" "$INSTALL_DIR" | ||
|
||
cd "$INSTALL_DIR" | ||
|
||
echo "Compiling the project..." | ||
cargo build --release | ||
|
||
BIN_PATH="/usr/bin/tsh" | ||
echo "Installing the executable to $BIN_PATH..." | ||
sudo mv target/release/tsh "$BIN_PATH" | ||
|
||
echo "Removing temporary files..." | ||
rm -rf "$INSTALL_DIR" | ||
|
||
echo "TSH has been installed correctly!" | ||
echo "Execute \"TSH\" to run." |
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,16 @@ | ||
arrows=( | ||
"↪" | ||
"→" | ||
) | ||
|
||
arrow() { | ||
local common_arrow=${arrows[0]} | ||
local flech_arrow=${arrows[1]} | ||
|
||
echo -e "Variable name: common_arrow, Value: \033[33m$common_arrow\033[0m" | ||
echo -e "Variable name: common_arrow, Value: \033[33m$flech_arrow\033[0m" | ||
|
||
|
||
} | ||
|
||
arrow |
Empty file.
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,31 @@ | ||
use std::fs; | ||
use std::path::Path; | ||
|
||
pub fn autocomplete(input: &str, current_dir: &str) -> Vec<String> { | ||
let mut suggestions = Vec::new(); | ||
|
||
let base_path = if input.is_empty() { | ||
Path::new(current_dir).to_path_buf() | ||
} else if input.starts_with('/') { | ||
Path::new(input).to_path_buf() | ||
} else { | ||
Path::new(current_dir).join(input) | ||
}; | ||
|
||
if let Some(parent) = base_path.parent() { | ||
if let Ok(entries) = fs::read_dir(parent) { | ||
for entry in entries { | ||
if let Ok(entry) = entry { | ||
let file_name = entry.file_name(); | ||
let file_name_str = file_name.to_string_lossy(); | ||
|
||
if file_name_str.starts_with(base_path.file_name().unwrap_or_default().to_string_lossy().as_ref()) { | ||
suggestions.push(file_name_str.to_string()); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
suggestions | ||
} |
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,13 @@ | ||
use std::env; | ||
|
||
pub fn change_directory(command: &str) { | ||
let dir: &str = command.trim(); | ||
if dir.is_empty() { | ||
eprintln!("Error: There is no directory of said name."); | ||
return; | ||
} | ||
|
||
if let Err(e) = env::set_current_dir(dir) { | ||
eprintln!("Error: Couldn't enter directory: {}", e); | ||
} | ||
} |
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,10 @@ | ||
use crate::Command; | ||
|
||
pub fn arrows_library() { | ||
let output = Command::new("bash") | ||
.arg("./arrows.sh") | ||
.output() | ||
.expect("Error"); | ||
|
||
println!("\n{}", String::from_utf8_lossy(&output.stdout)); | ||
} |
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,27 @@ | ||
pub struct CommandHistory { | ||
history: Vec<String>, | ||
} | ||
|
||
impl CommandHistory { | ||
pub fn new() -> Self { | ||
CommandHistory { | ||
history: Vec::new(), | ||
} | ||
} | ||
|
||
pub fn add_command(&mut self, command: &str) { | ||
if !command.trim().is_empty() { | ||
self.history.push(command.to_string()); | ||
} | ||
} | ||
|
||
pub fn show_history(&self) { | ||
if self.history.is_empty() { | ||
println!("No commands here! Yet..."); | ||
} else { | ||
for (index, cmd) in self.history.iter().enumerate() { | ||
println!("{}: {}", index + 1, cmd); | ||
} | ||
} | ||
} | ||
} |
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,194 @@ | ||
use std::env; | ||
use std::fs::{self, DirEntry}; | ||
use std::io::{self, Write}; | ||
use std::process::{exit, Command, Output}; | ||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; | ||
use chrono::Local; | ||
use std::path::Path; | ||
|
||
mod commands; | ||
mod history; | ||
use history::CommandHistory; | ||
|
||
fn arrows_library() { | ||
let output = Command::new("bash") | ||
.arg("../lib/arrows.sh") | ||
.output() | ||
.expect("Error"); | ||
|
||
println!("\n{}", String::from_utf8_lossy(&output.stdout)); | ||
} | ||
|
||
fn list_files_with_size() { | ||
let current_dir = env::current_dir().unwrap(); | ||
let dir_str = current_dir.to_str().unwrap_or_default(); | ||
let entries = fs::read_dir(current_dir).unwrap(); | ||
|
||
let mut stdout = StandardStream::stdout(ColorChoice::Always); | ||
|
||
let mut arrow_color = ColorSpec::new(); | ||
arrow_color.set_fg(Some(Color::Red)); | ||
|
||
for entry in entries { | ||
match entry { | ||
Ok(entry) => { | ||
let path = entry.path(); | ||
let file_name = path.file_name().unwrap_or_default().to_str().unwrap_or_default(); | ||
|
||
let file_size = fs::metadata(&path).unwrap().len(); | ||
|
||
let mut color = ColorSpec::new(); | ||
if file_size < 1024 { | ||
color.set_fg(Some(Color::Blue)); | ||
} else if file_size < 1048576 { | ||
color.set_fg(Some(Color::Yellow)); | ||
} else { | ||
color.set_fg(Some(Color::Red)); | ||
} | ||
|
||
stdout.set_color(&arrow_color).unwrap(); | ||
write!(stdout, "↪ ").unwrap(); | ||
stdout.reset().unwrap(); | ||
|
||
stdout.set_color(&color).unwrap(); | ||
write!(stdout, "{:<20} {:>10} bytes", file_name, file_size).unwrap(); | ||
stdout.reset().unwrap(); | ||
println!(); | ||
} | ||
Err(_) => continue, | ||
} | ||
} | ||
} | ||
|
||
fn show_current_time() { | ||
let now = Local::now(); | ||
let formatted_time = now.format("%Y-%m-%d %H:%M:%S").to_string(); | ||
|
||
let mut stdout = StandardStream::stdout(ColorChoice::Always); | ||
let mut arrow_color = ColorSpec::new(); | ||
arrow_color.set_fg(Some(Color::Red)); | ||
|
||
stdout.set_color(&arrow_color).unwrap(); | ||
write!(stdout, "↪ ").unwrap(); | ||
stdout.reset().unwrap(); | ||
|
||
println!("{}", formatted_time); | ||
} | ||
|
||
fn show_hostname() { | ||
let hostname = env::var("COMPUTERNAME"); | ||
|
||
let mut stdout = StandardStream::stdout(ColorChoice::Always); | ||
let mut arrow_color = ColorSpec::new(); | ||
arrow_color.set_fg(Some(Color::Red)); | ||
|
||
stdout.set_color(&arrow_color).unwrap(); | ||
write!(stdout, "↪ ").unwrap(); | ||
stdout.reset().unwrap(); | ||
|
||
let mut text_color_hostname = ColorSpec::new(); | ||
text_color_hostname.set_fg(Some(Color::Cyan)); | ||
|
||
stdout.set_color(&text_color_hostname).unwrap(); | ||
write!(stdout, "Hostname: ").unwrap(); | ||
stdout.reset().unwrap(); | ||
|
||
println!("{}", hostname.unwrap_or("Unknown Hostname".to_string())); | ||
|
||
} | ||
|
||
|
||
|
||
fn main() { | ||
let mut command_history = CommandHistory::new(); | ||
|
||
loop { | ||
let current_dir = env::current_dir().unwrap(); | ||
let dir_str = current_dir.to_str().unwrap_or_default(); | ||
|
||
let mut stdout = StandardStream::stdout(ColorChoice::Always); | ||
|
||
let mut green = ColorSpec::new(); | ||
green.set_fg(Some(Color::Green)).set_bold(true); | ||
stdout.set_color(&green).unwrap(); | ||
|
||
let mut arrow_color = ColorSpec::new(); | ||
arrow_color.set_fg(Some(Color::Red)); | ||
|
||
stdout.set_color(&arrow_color).unwrap(); | ||
write!(stdout, "").unwrap(); | ||
stdout.reset().unwrap(); | ||
|
||
stdout.set_color(&green).unwrap(); | ||
write!(stdout, "{:?} $ ", dir_str).unwrap(); | ||
stdout.reset().unwrap(); | ||
|
||
let mut command_input = String::new(); | ||
io::stdout().flush().unwrap(); | ||
io::stdin().read_line(&mut command_input).unwrap(); | ||
|
||
let command_input = command_input.trim(); | ||
|
||
if command_input.is_empty() { | ||
continue; | ||
} | ||
|
||
command_history.add_command(command_input); | ||
|
||
if command_input == "exit" { | ||
break; | ||
} | ||
|
||
if command_input == "history" { | ||
command_history.show_history(); | ||
continue; | ||
} | ||
|
||
if command_input.starts_with("cd ") { | ||
commands::change_directory(&command_input[3..]); | ||
continue; | ||
} | ||
|
||
if command_input == "ls" { | ||
list_files_with_size(); | ||
continue; | ||
} | ||
|
||
if command_input == "now" { | ||
show_current_time(); | ||
continue; | ||
} | ||
|
||
if command_input == "hostname" { | ||
show_hostname(); | ||
continue; | ||
} | ||
|
||
if command_input == "arrows_library" { | ||
arrows_library(); | ||
continue; | ||
} | ||
|
||
let mut parts = command_input.split_whitespace(); | ||
let command = parts.next().unwrap_or_default(); | ||
|
||
let output = Command::new(command).args(parts).output(); | ||
|
||
match output { | ||
Ok(output) => { | ||
if !output.stdout.is_empty() { | ||
print!("↪ "); | ||
println!("{}", String::from_utf8_lossy(&output.stdout)); | ||
} | ||
if !output.stderr.is_empty() { | ||
eprint!("→ "); | ||
eprintln!("{}", String::from_utf8_lossy(&output.stderr)); | ||
} | ||
} | ||
Err(e) => { | ||
eprintln!("Error: Execution of command \"{}\" failed", e); | ||
exit(1); | ||
} | ||
} | ||
} | ||
} |
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,2 @@ | ||
#!/bin/bash | ||
ls --color=auto "$@" | GREP_COLORS='mt=01;31' grep --color=always '\.txt$' || true |