fixed linebreak bug

This commit is contained in:
Penwing 2024-01-24 16:30:28 +01:00
parent 89f71ddc06
commit b19905ce94
13 changed files with 714 additions and 569 deletions

View file

@ -24,7 +24,7 @@ Added indent recognition (when there is a line break, the indentation level is k
# 1.0.3 :
Added testing
Added Ctrl+T : turn 4 spaces into tab across the whole document
Added Ctrl+T : refresh current tab
Added Time debug
Added Tree toggle for performance
Added Alt+Arrows to move through tabs
@ -32,3 +32,4 @@ Added Zoom
Added cd
Added terminal color

View file

@ -1 +1 @@
{"tabs":["/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/calcifer/code_editor/themes/sonokai.rs"],"theme":4}
{"tabs":["/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/calcifer/code_editor/themes/sonokai.rs"],"theme":6}

View file

@ -1,17 +1,21 @@
use eframe::egui;
use egui::{text::CCursor, text_edit::CCursorRange};
use std::{env, path::Path, path::PathBuf, cmp::max, io, fs, cmp::min};
use std::{env, path::Path, cmp::max};
use crate::tools;
use crate::Calcifer;
use crate::TIME_LABELS;
use crate::PATH_ROOT;
use crate::MAX_TABS;
pub mod code_editor;
use code_editor::CodeEditor;
use code_editor::themes::DEFAULT_THEMES;
mod app_base;
impl super::Calcifer {
impl Calcifer {
pub fn draw_settings(&mut self, ctx: &egui::Context) {
egui::TopBottomPanel::top("settings")
.resizable(false)
@ -19,7 +23,7 @@ impl super::Calcifer {
ui.horizontal(|ui| {
if ui.add(egui::Button::new("open file")).clicked() {
if let Some(path) = rfd::FileDialog::new().set_directory(Path::new(&PATH_ROOT)).pick_file() {
self.selected_tab = self.open_file(&path);
self.open_file(Some(&path));
}
}
ui.separator();
@ -53,6 +57,7 @@ impl super::Calcifer {
});
}
pub fn draw_tree_panel(&mut self, ctx: &egui::Context) {
if !self.tree_display {
return
@ -65,6 +70,7 @@ impl super::Calcifer {
});
}
pub fn draw_terminal_panel(&mut self, ctx: &egui::Context) {
egui::TopBottomPanel::bottom("terminal")
.default_height(super::TERMINAL_HEIGHT.clone())
@ -113,6 +119,7 @@ impl super::Calcifer {
});
}
pub fn draw_tab_panel(&mut self, ctx: &egui::Context) {
egui::TopBottomPanel::top("tabs")
.resizable(false)
@ -137,16 +144,17 @@ impl super::Calcifer {
}
ui.separator();
}
if tools::TabNumber::from_index(self.tabs.len()) != tools::TabNumber::None {
if self.tabs.len() < MAX_TABS {
ui.selectable_value(&mut self.selected_tab, tools::TabNumber::Open, "+");
}
if self.selected_tab == tools::TabNumber::Open {
self.selected_tab = self.new_tab();
self.open_file(None);
}
});
});
}
pub fn draw_content_panel(&mut self, ctx: &egui::Context) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.horizontal(|ui| {
@ -159,16 +167,14 @@ impl super::Calcifer {
ui.label("Picked file:");
ui.monospace(self.tabs[self.selected_tab.to_index()].path.to_string_lossy().to_string());
});
ui.separator();
if self.selected_tab == tools::TabNumber::None {
return
}
ui.separator();
self.draw_code_file(ui);
});
}
fn draw_code_file(&mut self, ui: &mut egui::Ui) {
let current_tab = &mut self.tabs[self.selected_tab.to_index()];
let lines = current_tab.code.chars().filter(|&c| c == '\n').count() + 1;
@ -190,155 +196,4 @@ impl super::Calcifer {
.with_numlines(true)
.show(ui, &mut current_tab.code, &mut current_tab.saved, &mut current_tab.last_cursor, &mut current_tab.scroll_offset, override_cursor);
}
pub fn save_tab(&self) -> Option<PathBuf> {
if self.tabs[self.selected_tab.to_index()].path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string() == "untitled" {
return self.save_tab_as();
} else {
if let Err(err) = fs::write(&self.tabs[self.selected_tab.to_index()].path, &self.tabs[self.selected_tab.to_index()].code) {
eprintln!("Error writing file: {}", err);
return None;
}
return Some(self.tabs[self.selected_tab.to_index()].path.clone())
}
}
pub fn save_tab_as(&self) -> Option<PathBuf> {
if let Some(path) = rfd::FileDialog::new().save_file() {
if let Err(err) = fs::write(&path, &self.tabs[self.selected_tab.to_index()].code) {
eprintln!("Error writing file: {}", err);
return None;
}
return Some(path);
}
return None
}
pub fn handle_save_file(&mut self, path_option : Option<PathBuf>) {
if let Some(path) = path_option {
println!("File saved successfully at: {:?}", path);
self.tabs[self.selected_tab.to_index()].path = path;
self.tabs[self.selected_tab.to_index()].saved = true;
} else {
println!("File save failed.");
}
}
pub fn from_app_state(app_state: tools::AppState) -> Self {
let mut new = Self {
theme: DEFAULT_THEMES[min(app_state.theme, DEFAULT_THEMES.len() - 1)],
tabs: Vec::new(),
..Default::default()
};
for path in app_state.tabs {
if path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string() != "untitled" {
new.open_file(&path);
}
}
if new.tabs == vec![] {
new.new_tab();
}
new
}
pub fn save_state(&self) {
let mut state_theme : usize = 0;
if let Some(theme) = DEFAULT_THEMES.iter().position(|&r| r == self.theme) {
state_theme = theme;
}
let mut state_tabs = vec![];
for tab in &self.tabs {
state_tabs.push(tab.path.clone());
}
let app_state = tools::AppState {
tabs: state_tabs,
theme: state_theme,
};
let _ = tools::save_state(&app_state, super::SAVE_PATH);
}
pub fn indent_with_tabs(&mut self) {
let current_tab = &mut self.tabs[self.selected_tab.to_index()];
current_tab.code = current_tab.code.replace(" ", "\t")
}
pub fn move_through_tabs(&mut self, forward : bool) {
let new_index = if forward {
(self.selected_tab.to_index() + 1) % self.tabs.len()
} else {
self.selected_tab.to_index().checked_sub(1).unwrap_or(self.tabs.len() - 1)
};
self.selected_tab = tools::TabNumber::from_index(new_index);
}
fn list_files(&mut self, ui: &mut egui::Ui, path: &Path) -> io::Result<()> {
if let Some(name) = path.file_name() {
if path.is_dir() {
egui::CollapsingHeader::new(name.to_string_lossy()).show(ui, |ui| {
let mut paths: Vec<_> = fs::read_dir(&path).expect("Failed to read dir").map(|r| r.unwrap()).collect();
// Sort the vector using the custom sorting function
paths.sort_by(|a, b| tools::sort_directories_first(a, b));
for result in paths {
//let result = path_result.expect("Failed to get path");
//let full_path = result.path();
let _ = self.list_files(ui, &result.path());
}
});
} else {
//ui.label(name.to_string_lossy());
if ui.button(name.to_string_lossy()).clicked() {
self.selected_tab = self.open_file(&path);
}
}
}
Ok(())
}
fn open_file(&mut self, path: &Path) -> tools::TabNumber {
if tools::TabNumber::from_index(self.tabs.len()) == tools::TabNumber::None {
return tools::TabNumber::None
}
let new_tab = tools::Tab {
path: path.into(),
code: fs::read_to_string(path).expect("Not able to read the file").replace(" ", "\t"),
language: path.to_str().unwrap().split('.').last().unwrap().into(),
saved: true,
..tools::Tab::default()
};
self.tabs.push(new_tab);
return tools::TabNumber::from_index(self.tabs.len() - 1)
}
fn new_tab(&mut self) -> tools::TabNumber {
self.tabs.push(tools::Tab::default());
return tools::TabNumber::from_index(self.tabs.len() - 1)
}
fn delete_tab(&mut self, index : usize) -> tools::TabNumber {
self.tabs.remove(index);
return tools::TabNumber::from_index(min(index, self.tabs.len() - 1))
}
fn toggle(&self, ui: &mut egui::Ui, display : bool, title : &str) -> bool {
let text = if display.clone() {
format!("hide {}", title)
} else {
format!("show {}", title)
};
if ui.add(egui::Button::new(text)).clicked() {
return !display
}
return display
}
}

152
src/calcifer/app_base.rs Normal file
View file

@ -0,0 +1,152 @@
use std::{path::PathBuf, fs, path::Path, cmp::min, io};
use eframe::egui;
use crate::Calcifer;
use crate::tools;
use crate::PATH_ROOT;
use crate::DEFAULT_THEMES;
use crate::MAX_TABS;
use crate::SAVE_PATH;
impl Calcifer {
pub fn save_tab(&self) -> Option<PathBuf> {
if self.tabs[self.selected_tab.to_index()].path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string() == "untitled" {
return self.save_tab_as();
} else {
if let Err(err) = fs::write(&self.tabs[self.selected_tab.to_index()].path, &self.tabs[self.selected_tab.to_index()].code) {
eprintln!("Error writing file: {}", err);
return None;
}
return Some(self.tabs[self.selected_tab.to_index()].path.clone())
}
}
pub fn save_tab_as(&self) -> Option<PathBuf> {
if let Some(path) = rfd::FileDialog::new().set_directory(Path::new(&PATH_ROOT)).save_file() {
if let Err(err) = fs::write(&path, &self.tabs[self.selected_tab.to_index()].code) {
eprintln!("Error writing file: {}", err);
return None;
}
return Some(path);
}
return None
}
pub fn handle_save_file(&mut self, path_option : Option<PathBuf>) {
if let Some(path) = path_option {
println!("File saved successfully at: {:?}", path);
self.tabs[self.selected_tab.to_index()].path = path;
self.tabs[self.selected_tab.to_index()].saved = true;
} else {
println!("File save failed.");
}
}
pub fn from_app_state(app_state: tools::AppState) -> Self {
let mut new = Self {
theme: DEFAULT_THEMES[min(app_state.theme, DEFAULT_THEMES.len() - 1)],
tabs: Vec::new(),
..Default::default()
};
for path in app_state.tabs {
if path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string() != "untitled" {
new.open_file(Some(&path));
}
}
if new.tabs == vec![] {
new.open_file(None);
}
new
}
pub fn save_state(&self) {
let mut state_theme : usize = 0;
if let Some(theme) = DEFAULT_THEMES.iter().position(|&r| r == self.theme) {
state_theme = theme;
}
let mut state_tabs = vec![];
for tab in &self.tabs {
state_tabs.push(tab.path.clone());
}
let app_state = tools::AppState {
tabs: state_tabs,
theme: state_theme,
};
let _ = tools::save_state(&app_state, SAVE_PATH);
}
pub fn move_through_tabs(&mut self, forward : bool) {
let new_index = if forward {
(self.selected_tab.to_index() + 1) % self.tabs.len()
} else {
self.selected_tab.to_index().checked_sub(1).unwrap_or(self.tabs.len() - 1)
};
self.selected_tab = tools::TabNumber::from_index(new_index);
}
pub fn list_files(&mut self, ui: &mut egui::Ui, path: &Path) -> io::Result<()> {
if let Some(name) = path.file_name() {
if path.is_dir() {
egui::CollapsingHeader::new(name.to_string_lossy()).show(ui, |ui| {
let mut paths: Vec<_> = fs::read_dir(&path).expect("Failed to read dir").map(|r| r.unwrap()).collect();
paths.sort_by(|a, b| tools::sort_directories_first(a, b));
for result in paths {
let _ = self.list_files(ui, &result.path());
}
});
} else {
if ui.button(name.to_string_lossy()).clicked() {
self.open_file(Some(path));
}
}
}
Ok(())
}
pub fn open_file(&mut self, path_option: Option<&Path>) {
if self.tabs.len() < MAX_TABS {
if let Some(path) = path_option {
self.tabs.push(tools::Tab::new(path.to_path_buf()));
} else {
self.tabs.push(tools::Tab::default());
}
self.selected_tab = tools::TabNumber::from_index(self.tabs.len() - 1);
}
}
pub fn delete_tab(&mut self, index : usize) -> tools::TabNumber {
self.tabs.remove(index);
return tools::TabNumber::from_index(min(index, self.tabs.len() - 1))
}
pub fn toggle(&self, ui: &mut egui::Ui, display : bool, title : &str) -> bool {
let text = if display.clone() {
format!("hide {}", title)
} else {
format!("show {}", title)
};
if ui.add(egui::Button::new(text)).clicked() {
return !display
}
return display
}
}

View file

@ -418,7 +418,11 @@ impl CodeEditor {
fn new_line(&self, cursor_range : CCursorRange, text : String) -> (String, isize) {
let cursor = min(cursor_range.primary.index, cursor_range.secondary.index);
let mut last_line_break = max(0, cursor - 1);
if cursor < 2 {
return (text.clone().to_string(), 1 as isize);
}
let mut last_line_break = cursor - 1;
while last_line_break > 0 && text.char_at(last_line_break) != '\n' {
last_line_break -= 1;
@ -431,6 +435,6 @@ impl CodeEditor {
new_text.push_str(&"\t".repeat(new_indent_depth.clone()));
new_text.push_str(text.clone().slice((cursor + 1)..));
(new_text.clone().to_string(), (new_indent_depth + 1) as isize)
return (new_text.clone().to_string(), (new_indent_depth + 1) as isize);
}
}

137
src/calcifer_base.rs Normal file
View file

@ -0,0 +1,137 @@
// Hello there, Master
impl super::Calcifer {
pub fn save_tab(&self) -> Option<PathBuf> {
if self.tabs[self.selected_tab.to_index()].path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string() == "untitled" {
return self.save_tab_as();
} else {
if let Err(err) = fs::write(&self.tabs[self.selected_tab.to_index()].path, &self.tabs[self.selected_tab.to_index()].code) {
eprintln!("Error writing file: {}", err);
return None;
}
return Some(self.tabs[self.selected_tab.to_index()].path.clone())
}
}
pub fn save_tab_as(&self) -> Option<PathBuf> {
if let Some(path) = rfd::FileDialog::new().set_directory(Path::new(&PATH_ROOT)).save_file() {
if let Err(err) = fs::write(&path, &self.tabs[self.selected_tab.to_index()].code) {
eprintln!("Error writing file: {}", err);
return None;
}
return Some(path);
}
return None
}
pub fn handle_save_file(&mut self, path_option : Option<PathBuf>) {
if let Some(path) = path_option {
println!("File saved successfully at: {:?}", path);
self.tabs[self.selected_tab.to_index()].path = path;
self.tabs[self.selected_tab.to_index()].saved = true;
} else {
println!("File save failed.");
}
}
pub fn from_app_state(app_state: tools::AppState) -> Self {
let mut new = Self {
theme: DEFAULT_THEMES[min(app_state.theme, DEFAULT_THEMES.len() - 1)],
tabs: Vec::new(),
..Default::default()
};
for path in app_state.tabs {
if path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string() != "untitled" {
new.open_file(Some(&path));
}
}
if new.tabs == vec![] {
new.open_file(None);
}
new
}
pub fn save_state(&self) {
let mut state_theme : usize = 0;
if let Some(theme) = DEFAULT_THEMES.iter().position(|&r| r == self.theme) {
state_theme = theme;
}
let mut state_tabs = vec![];
for tab in &self.tabs {
state_tabs.push(tab.path.clone());
}
let app_state = tools::AppState {
tabs: state_tabs,
theme: state_theme,
};
let _ = tools::save_state(&app_state, super::SAVE_PATH);
}
pub fn move_through_tabs(&mut self, forward : bool) {
let new_index = if forward {
(self.selected_tab.to_index() + 1) % self.tabs.len()
} else {
self.selected_tab.to_index().checked_sub(1).unwrap_or(self.tabs.len() - 1)
};
self.selected_tab = tools::TabNumber::from_index(new_index);
}
fn list_files(&mut self, ui: &mut egui::Ui, path: &Path) -> io::Result<()> {
if let Some(name) = path.file_name() {
if path.is_dir() {
egui::CollapsingHeader::new(name.to_string_lossy()).show(ui, |ui| {
let mut paths: Vec<_> = fs::read_dir(&path).expect("Failed to read dir").map(|r| r.unwrap()).collect();
// Sort the vector using the custom sorting function
paths.sort_by(|a, b| tools::sort_directories_first(a, b));
for result in paths {
//let result = path_result.expect("Failed to get path");
//let full_path = result.path();
let _ = self.list_files(ui, &result.path());
}
});
} else {
//ui.label(name.to_string_lossy());
if ui.button(name.to_string_lossy()).clicked() {
self.open_file(Some(path));
}
}
}
Ok(())
}
fn open_file(&mut self, path_option: Option<&Path>) {
if self.tabs.len() < MAX_TABS {
if let Some(path) = path_option {
self.tabs.push(tools::Tab::new(path.to_path_buf()));
} else {
self.tabs.push(tools::Tab::default());
}
self.selected_tab = tools::TabNumber::from_index(self.tabs.len() - 1);
}
}
fn delete_tab(&mut self, index : usize) -> tools::TabNumber {
self.tabs.remove(index);
return tools::TabNumber::from_index(min(index, self.tabs.len() - 1))
}
fn toggle(&self, ui: &mut egui::Ui, display : bool, title : &str) -> bool {
let text = if display.clone() {
format!("hide {}", title)
} else {
format!("show {}", title)
};
if ui.add(egui::Button::new(text)).clicked() {
return !display
}
return display
}

View file

@ -1 +1 @@
{"tabs":["/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/calcifer/code_editor/themes/sonokai.rs"],"theme":4}
{"tabs":["/home/penwing/Documents/notes/victory2.txt","/home/penwing/Documents/projects/rust/calcifer/src/calcifer/code_editor/themes/sonokai.rs"],"theme":6}

View file

@ -15,11 +15,10 @@ const TIME_LABELS : [&str; 5] = ["settings", "tree", "terminal", "tabs", "conten
const MAX_FPS : f32 = 30.0;
const PATH_ROOT : &str = "/home/penwing/Documents/";
const DISPLAY_PATH_DEPTH : usize = 3;
const MAX_TABS : usize = 20;
fn main() -> Result<(), eframe::Error> {
tools::loaded();
let icon_data = tools::load_icon();
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
@ -73,7 +72,7 @@ struct Calcifer {
impl Default for Calcifer {
fn default() -> Self {
Self {
selected_tab: tools::TabNumber::Zero,
selected_tab: tools::TabNumber::from_index(0),
tabs: vec![tools::Tab::default()],
command: String::new(),
@ -103,7 +102,7 @@ impl eframe::App for Calcifer {
let mut watch = time::Instant::now();
if ctx.input( |i| i.key_pressed(egui::Key::T) && i.modifiers.ctrl) {
self.indent_with_tabs();
self.tabs[self.selected_tab.to_index()].refresh();
}
if ctx.input( |i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) {

View file

@ -1,13 +1,19 @@
use std::{env, process::Command, cmp::Ordering, path::PathBuf, path::Path, fs::read_to_string, fs::write, path::Component, ffi::OsStr};
use std::{cmp::Ordering, path::PathBuf, path::Path, fs::read_to_string, fs::write, path::Component, ffi::OsStr};
use crate::calcifer::code_editor::Syntax;
use eframe::egui;
use egui::text_edit::CCursorRange;
use serde::{Serialize, Deserialize};
use crate::DISPLAY_PATH_DEPTH;
//pub mod themes;
//my tools;
pub mod search;
pub mod terminal;
pub use terminal::*;
pub mod tabs;
pub use tabs::*;
pub trait View {
fn ui(&mut self, ui: &mut egui::Ui, tabs: &mut Vec<Tab>, selected_tab: &mut TabNumber);
@ -15,124 +21,12 @@ pub trait View {
/// Something to view
pub trait Demo {
/// Is the demo enabled for this integraton?
fn is_enabled(&self, _ctx: &egui::Context) -> bool {
true
}
/// `&'static` so we can also use it as a key to store open/close state.
fn name(&self) -> &str; //'static
/// Show windows, etc
fn show(&mut self, ctx: &egui::Context, open: &mut bool, tabs: &mut Vec<Tab>, selected_tab: &mut TabNumber);
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum TabNumber {
None,
Open,
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
}
impl TabNumber {
pub fn from_index(n : usize) -> TabNumber {
match n {
0 => TabNumber::Zero,
1 => TabNumber::One,
2 => TabNumber::Two,
3 => TabNumber::Three,
4 => TabNumber::Four,
5 => TabNumber::Five,
6 => TabNumber::Six,
7 => TabNumber::Seven,
_ => TabNumber::None,
}
}
pub fn to_index(&self) -> usize {
match self {
TabNumber::Zero => 0,
TabNumber::One => 1,
TabNumber::Two => 2,
TabNumber::Three => 3,
TabNumber::Four => 4,
TabNumber::Five => 5,
TabNumber::Six => 6,
TabNumber::Seven => 7,
_ => 0,
}
}
}
#[derive(Clone, PartialEq)]
pub struct Tab {
pub path : PathBuf,
pub code : String,
pub language : String,
pub saved : bool,
pub scroll_offset : f32,
pub last_cursor : Option<CCursorRange>,
}
impl Default for Tab {
fn default() -> Self {
Self {
path: "untitled".into(),
code: "// Hello there, Master".into(),
language: "rs".into(),
saved: false,
scroll_offset: 0.0,
last_cursor: None,
}
}
}
impl Tab {
pub fn get_name(&self) -> String {
self.path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string()
}
}
#[derive(Clone, PartialEq)]
pub struct CommandEntry {
pub env: String,
pub command: String,
pub output: String,
pub error: String,
}
impl CommandEntry {
pub fn new(command: String) -> Self {
CommandEntry {
env: format_path(&env::current_dir().expect("Could not find Shell Environnment")),
command,
output: String::new(),
error: String::new(),
}
}
pub fn run(&mut self) -> Self {
let output = Command::new("sh")
.arg("-c")
.arg(self.command.clone())
.output()
.expect("failed to execute process");
self.output = (&String::from_utf8_lossy(&output.stdout)).trim_end_matches('\n').to_string();
self.error = (&String::from_utf8_lossy(&output.stderr)).trim_end_matches('\n').to_string();
self.clone()
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
@ -158,10 +52,6 @@ pub fn load_state(file_path: &str) -> Result<AppState, std::io::Error> {
}
pub fn loaded() {
println!("Tools loaded");
}
pub fn load_icon() -> egui::IconData {
let (icon_rgba, icon_width, icon_height) = {
let icon = include_bytes!("../../assets/icon.png");
@ -190,40 +80,6 @@ pub fn to_syntax(language : &str) -> Syntax {
}
pub fn run_command(command: String) -> CommandEntry {
let mut entry = CommandEntry::new(command);
if entry.command.len() < 2 {
return entry.run();
}
if &entry.command[..2] != "cd" {
return entry.run()
}
if entry.command.len() < 4 {
entry.error = "Invalid cd, should provide path".to_string();
return entry
}
let path_append = entry.command[3..].replace("~", "/home/penwing");
let path = Path::new(&path_append);
if format!("{}", path.display()) == "/" {
entry.error = "Root access denied".to_string();
return entry
}
if env::set_current_dir(path).is_ok() {
entry.output = format!("Moved to : {}", path.display());
} else {
entry.error = format!("Could not find path : {}", path.display());
}
return entry
}
pub fn sort_directories_first(a: &std::fs::DirEntry, b: &std::fs::DirEntry) -> Ordering {
let a_is_dir = a.path().is_dir();
let b_is_dir = b.path().is_dir();

View file

@ -1,5 +1,5 @@
use eframe::egui;
use crate::tools::{View, Demo, Tab, TabNumber};
use crate::tools::{View, Demo, tabs::Tab, tabs::TabNumber};
use std::{cmp::min};
use crate::RED;
@ -24,7 +24,7 @@ pub struct Selection {
impl Default for Selection {
fn default() -> Self {
Self {
tab: TabNumber::Zero,
tab: TabNumber::from_index(0),
start: 0,
end: 0,
}

73
src/tools/tabs.rs Normal file
View file

@ -0,0 +1,73 @@
use std::{fs::read_to_string, path::PathBuf};
use eframe::egui::text_edit::CCursorRange;
use crate::MAX_TABS;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum TabNumber {
Open,
Number(u8), // Using a range for numeric values
}
impl TabNumber {
pub fn from_index(n: usize) -> TabNumber {
match n {
0..=MAX_TABS => TabNumber::Number(n as u8),
_ => TabNumber::Number(0),
}
}
pub fn to_index(&self) -> usize {
match self {
TabNumber::Number(n) => *n as usize,
_ => 0,
}
}
}
#[derive(Clone, PartialEq)]
pub struct Tab {
pub path : PathBuf,
pub code : String,
pub language : String,
pub saved : bool,
pub scroll_offset : f32,
pub last_cursor : Option<CCursorRange>,
}
impl Default for Tab {
fn default() -> Self {
Self {
path: "untitled".into(),
code: "// Hello there, Master".into(),
language: "rs".into(),
saved: false,
scroll_offset: 0.0,
last_cursor: None,
}
}
}
impl Tab {
pub fn new(path : PathBuf) -> Self {
Self {
path: path.clone().into(),
code: read_to_string(path.clone()).expect("Not able to read the file").replace(&" ".repeat(4), "\t"),
language: path.to_str().unwrap().split('.').last().unwrap().into(),
saved: true,
scroll_offset: 0.0,
last_cursor: None,
}
}
pub fn get_name(&self) -> String {
self.path.file_name().expect("Could not get Tab Name").to_string_lossy().to_string()
}
pub fn refresh(&mut self) {
self.code = read_to_string(self.path.clone()).expect("Not able to read the file").replace(&" ".repeat(4), "\t");
println!("refreshed {}", self.path.display());
}
}

68
src/tools/terminal.rs Normal file
View file

@ -0,0 +1,68 @@
use crate::tools::format_path;
use std::{process::Command, env, path::Path};
#[derive(Clone, PartialEq)]
pub struct CommandEntry {
pub env: String,
pub command: String,
pub output: String,
pub error: String,
}
impl CommandEntry {
pub fn new(command: String) -> Self {
CommandEntry {
env: format_path(&env::current_dir().expect("Could not find Shell Environnment")),
command,
output: String::new(),
error: String::new(),
}
}
pub fn run(&mut self) -> Self {
let output = Command::new("sh")
.arg("-c")
.arg(self.command.clone())
.output()
.expect("failed to execute process");
self.output = (&String::from_utf8_lossy(&output.stdout)).trim_end_matches('\n').to_string();
self.error = (&String::from_utf8_lossy(&output.stderr)).trim_end_matches('\n').to_string();
self.clone()
}
}
pub fn run_command(command: String) -> CommandEntry {
let mut entry = CommandEntry::new(command);
if entry.command.len() < 2 {
return entry.run();
}
if &entry.command[..2] != "cd" {
return entry.run()
}
if entry.command.len() < 4 {
entry.error = "Invalid cd, should provide path".to_string();
return entry
}
let path_append = entry.command[3..].replace("~", "/home/penwing");
let path = Path::new(&path_append);
if format!("{}", path.display()) == "/" {
entry.error = "Root access denied".to_string();
return entry
}
if env::set_current_dir(path).is_ok() {
entry.output = format!("Moved to : {}", path.display());
} else {
entry.error = format!("Could not find path : {}", path.display());
}
return entry
}