Inital Commit

This commit is contained in:
2026-01-11 01:15:35 -06:00
commit ade1e41d1b
7 changed files with 18022 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

4198
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

9
Cargo.toml Normal file
View File

@@ -0,0 +1,9 @@
[package]
name = "gcodium"
version = "0.1.0"
edition = "2024"
[dependencies]
eframe = "0.33.3"
rfd = "0.17.1"
ropey = "1.6.1"

13618
file.txt Normal file

File diff suppressed because it is too large Load Diff

37
src/main.rs Normal file
View File

@@ -0,0 +1,37 @@
use eframe::egui;
use rfd::FileDialog;
mod ropeintegration;
mod rope_editor;
fn main() {
let native_options = eframe::NativeOptions::default();
eframe::run_native("gcodium", native_options, Box::new(|cc| Ok(Box::new(GCodium::new(cc)))));
}
#[derive(Default)]
struct GCodium {
text_buffer: ropeintegration::ERopey,
}
impl GCodium {
fn new(cc: &eframe::CreationContext<'_>) -> Self {
Self::default()
}
}
impl eframe::App for GCodium {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Hello, World!");
if ui.button("Open File").clicked() {
let filepath = FileDialog::new().add_filter("text", &["txt"]).set_directory("/").pick_file().expect("File not Selected");
let file = std::fs::File::open(filepath).expect("unable to open file");
self.text_buffer.rope = ropey::Rope::from_reader(file).expect("unable to read file to rope");
}
ui.text_edit_multiline(&mut self.text_buffer);
});
}
}

126
src/rope_editor.rs Normal file
View File

@@ -0,0 +1,126 @@
use std::{sync::Arc, usize};
use eframe::egui::{Align2, Color32, Context, EventFilter, FontSelection, Galley, Id, Key, KeyboardShortcut, Margin, Modifiers, NumExt, Shape, TextBuffer, Ui, Vec2, WidgetWithState, text::LayoutJob, text_edit::{TextEditOutput, TextEditState}};
type LayouterFn<'t> = &'t mut dyn FnMut(&Ui, &dyn TextBuffer, f32) -> Arc<Galley>;
pub struct RopeEdit<'t> {
text: &'t mut dyn TextBuffer,
//hint_text: String,
//hint_text_font: Option<FontSelection>,
id: Option<Id>,
id_salt: Option<Id>,
font_selection: FontSelection,
text_color: Option<Color32>,
layouter: Option<LayouterFn<'t>>,
frame: bool,
margin: Margin,
desired_width: Option<f32>,
desired_height_rows: usize,
event_filter: EventFilter,
cursor_at_end: bool,
min_size: Vec2,
align: Align2,
char_limit: usize,
return_key: Option<KeyboardShortcut>,
background_color: Option<Color32>,
}
impl WidgetWithState for RopeEdit<'_> {
type State = TextEditState;
}
impl RopeEdit<'_> {
pub fn load_state(ctx: &Context, id: Id) -> Option<TextEditState> {
TextEditState::load(ctx, id)
}
pub fn store_state(ctx: &Context, id: Id, state: TextEditState) {
state.store(ctx, id);
}
pub fn show(self, ui: &mut Ui) -> TextEditOutput {
let frame = self.frame;
let where_to_put_background = ui.painter().add(Shape::Noop);
let background_color = ui.visuals().text_edit_bg_color();
let output = self.show_content(ui);
}
pub fn show_content(self, ui: &mut Ui) -> TextEditOutput {
let RopeEdit {
text,
//hint_text,
//hint_text_font,
id,
id_salt,
font_selection,
text_color,
layouter,
frame,
margin,
desired_width,
desired_height_rows,
event_filter,
cursor_at_end,
min_size,
align,
char_limit,
return_key,
background_color
} = self;
let text_color = text_color
.or(ui.visuals().override_text_color)
// .unwrap_or_else(|| ui.style().interact(&response).text_color()); // too bright
.unwrap_or_else(|| ui.visuals().widgets.inactive.text_color());
let font_id = font_selection.resolve(ui.style());
let row_height = ui.fonts_mut(|f| f.row_height(&font_id));
const MIN_WIDTH: f32 = 24.0;
let available_width = (ui.available_width() - margin.sum().x).at_least(MIN_WIDTH);
let desired_width = desired_width.unwrap_or_else(|| ui.spacing().text_edit_width);
let wrap_width = if ui.layout().horizontal_justify() {
available_width
} else {
desired_width.min(available_width)
};
let font_id_clone = font_id.clone();
let mut default_layouter = move |ui: &Ui, text: &dyn TextBuffer, wrap_width: f32,| {
let layout_job = LayoutJob::simple(text, font_id_clone.clone(), text_color, wrap_width)
}
}
}
impl<'t> RopeEdit<'t> {
pub fn new(text: &'t mut dyn TextBuffer) -> Self {
Self {
text,
//hint_text: Default::default(),
//hint_text_font: None,
id: None,
id_salt: None,
font_selection: Default::default(),
text_color: None,
layouter: None,
frame: false,
margin: Margin::symmetric(4, 2),
desired_width: None,
desired_height_rows: 4,
event_filter: EventFilter {
tab: false,
horizontal_arrows: true,
vertical_arrows: true,
..Default::default()
},
cursor_at_end: true,
min_size: Vec2::ZERO,
align: Align2::LEFT_TOP,
char_limit: usize::MAX,
return_key: Some(KeyboardShortcut::new(Modifiers::NONE, Key::Enter)),
background_color: None
}
}
}

33
src/ropeintegration.rs Normal file
View File

@@ -0,0 +1,33 @@
use eframe::egui::{self, scroll_area::State};
use ropey;
#[derive(Default)]
pub struct ERopey {
pub rope: ropey::Rope,
viewbuffer: String,
}
impl egui::widgets::TextBuffer for ERopey {
fn is_mutable(&self) -> bool {
true
}
fn as_str(&self) -> &str {
self.rope.slice(..).as_str().unwrap()
}
fn insert_text(&mut self, text: &str, char_index: usize) -> usize {
let first = self.rope.len_chars();
self.rope.insert(char_index, text);
let second = self.rope.len_chars();
second-first
}
fn delete_char_range(&mut self, char_range: std::ops::Range<usize>) {
self.rope.remove(char_range);
}
fn type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<Self>()
}
}