Update to 0.0.4 #1
@ -143,7 +143,7 @@ fn get_shortcuts() -> Vec<ShortcutDefinition> {
|
||||
]
|
||||
}
|
||||
|
||||
fn execute_action(action: ShortcutAction, editor: &mut TextEditor, ctx: &egui::Context) -> bool {
|
||||
fn execute_action(action: ShortcutAction, editor: &mut TextEditor, _ctx: &egui::Context) -> bool {
|
||||
match action {
|
||||
ShortcutAction::NewFile => {
|
||||
io::new_file(editor);
|
||||
@ -171,7 +171,9 @@ fn execute_action(action: ShortcutAction, editor: &mut TextEditor, ctx: &egui::C
|
||||
if let Some(current_tab) = editor.get_active_tab() {
|
||||
if current_tab.is_modified {
|
||||
// Show dialog for unsaved changes
|
||||
editor.pending_unsaved_action = Some(super::state::UnsavedAction::CloseTab(editor.active_tab_index));
|
||||
editor.pending_unsaved_action = Some(
|
||||
super::state::UnsavedAction::CloseTab(editor.active_tab_index),
|
||||
);
|
||||
} else {
|
||||
// Close tab directly if no unsaved changes
|
||||
editor.close_tab(editor.active_tab_index);
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use crate::ui::central_panel::central_panel;
|
||||
use crate::ui::menu_bar::menu_bar;
|
||||
use crate::ui::tab_bar::tab_bar;
|
||||
use crate::ui::about_window::about_window;
|
||||
use crate::ui::shortcuts_window::shortcuts_window;
|
||||
use crate::ui::preferences_window::preferences_window;
|
||||
use crate::ui::find_window::find_window;
|
||||
use crate::app::shortcuts;
|
||||
use super::editor::TextEditor;
|
||||
use crate::app::shortcuts;
|
||||
use crate::ui::about_window::about_window;
|
||||
use crate::ui::central_panel::central_panel;
|
||||
use crate::ui::find_window::find_window;
|
||||
use crate::ui::menu_bar::menu_bar;
|
||||
use crate::ui::preferences_window::preferences_window;
|
||||
use crate::ui::shortcuts_window::shortcuts_window;
|
||||
use crate::ui::tab_bar::tab_bar;
|
||||
|
||||
impl eframe::App for TextEditor {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
|
||||
@ -30,7 +30,7 @@ impl TextEditor {
|
||||
tab_bar_rect: None,
|
||||
menu_bar_stable_until: None,
|
||||
text_processing_result: std::sync::Arc::new(std::sync::Mutex::new(Default::default())),
|
||||
processing_thread_handle: None,
|
||||
_processing_thread_handle: None,
|
||||
find_query: String::new(),
|
||||
find_matches: Vec::new(),
|
||||
current_match_index: None,
|
||||
|
||||
@ -30,17 +30,17 @@ impl Default for TextEditor {
|
||||
tab_bar_rect: None,
|
||||
menu_bar_stable_until: None,
|
||||
text_processing_result: Arc::new(Mutex::new(TextProcessingResult::default())),
|
||||
processing_thread_handle: None,
|
||||
_processing_thread_handle: None,
|
||||
// Find functionality
|
||||
find_query: String::new(),
|
||||
find_matches: Vec::new(),
|
||||
current_match_index: None,
|
||||
case_sensitive_search: false,
|
||||
prev_show_find: false,
|
||||
|
||||
|
||||
// Cursor tracking for smart scrolling
|
||||
previous_cursor_position: None,
|
||||
|
||||
|
||||
// Track previous content for incremental processing
|
||||
previous_content: String::new(),
|
||||
previous_cursor_char_index: None,
|
||||
|
||||
@ -13,8 +13,8 @@ pub enum UnsavedAction {
|
||||
#[derive(Clone)]
|
||||
pub struct TextProcessingResult {
|
||||
pub line_count: usize,
|
||||
pub longest_line_index: usize, // Which line is the longest (0-based)
|
||||
pub longest_line_length: usize, // Character count of the longest line
|
||||
pub longest_line_index: usize, // Which line is the longest (0-based)
|
||||
pub longest_line_length: usize, // Character count of the longest line
|
||||
pub longest_line_pixel_width: f32, // Actual pixel width of the longest line
|
||||
}
|
||||
|
||||
@ -55,20 +55,20 @@ pub struct TextEditor {
|
||||
pub(crate) tab_bar_rect: Option<egui::Rect>,
|
||||
pub(crate) menu_bar_stable_until: Option<std::time::Instant>,
|
||||
pub(crate) text_processing_result: Arc<Mutex<TextProcessingResult>>,
|
||||
pub(crate) processing_thread_handle: Option<thread::JoinHandle<()>>,
|
||||
pub(crate) _processing_thread_handle: Option<thread::JoinHandle<()>>,
|
||||
pub(crate) find_query: String,
|
||||
pub(crate) find_matches: Vec<(usize, usize)>, // (start_pos, end_pos) byte positions
|
||||
pub(crate) current_match_index: Option<usize>,
|
||||
pub(crate) case_sensitive_search: bool,
|
||||
pub(crate) prev_show_find: bool, // Track previous state to detect transitions
|
||||
|
||||
|
||||
// Cursor tracking for smart scrolling
|
||||
pub(crate) previous_cursor_position: Option<usize>,
|
||||
|
||||
|
||||
// Track previous content for incremental processing
|
||||
pub(crate) previous_content: String,
|
||||
pub(crate) previous_cursor_char_index: Option<usize>,
|
||||
pub(crate) current_cursor_line: usize, // Track current line number incrementally
|
||||
pub(crate) previous_cursor_line: usize, // Track previous line for comparison
|
||||
pub(crate) font_settings_changed: bool, // Flag to trigger text reprocessing when font changes
|
||||
pub(crate) current_cursor_line: usize, // Track current line number incrementally
|
||||
pub(crate) previous_cursor_line: usize, // Track previous line for comparison
|
||||
pub(crate) font_settings_changed: bool, // Flag to trigger text reprocessing when font changes
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ impl TextEditor {
|
||||
pub fn process_text_for_rendering(&mut self, content: &str, ui: &egui::Ui) {
|
||||
let lines: Vec<&str> = content.lines().collect();
|
||||
let line_count = lines.len().max(1);
|
||||
|
||||
|
||||
if lines.is_empty() {
|
||||
self.update_processing_result(TextProcessingResult {
|
||||
line_count: 1,
|
||||
@ -17,10 +17,9 @@ impl TextEditor {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the longest line by character count first (fast)
|
||||
let mut longest_line_index = 0;
|
||||
let mut longest_line_length = 0;
|
||||
|
||||
|
||||
for (index, line) in lines.iter().enumerate() {
|
||||
let char_count = line.chars().count();
|
||||
if char_count > longest_line_length {
|
||||
@ -29,17 +28,19 @@ impl TextEditor {
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate pixel width for the longest line
|
||||
let font_id = self.get_font_id();
|
||||
let longest_line_pixel_width = if longest_line_length > 0 {
|
||||
let longest_line_text = lines[longest_line_index];
|
||||
ui.fonts(|fonts| {
|
||||
fonts.layout(
|
||||
longest_line_text.to_string(),
|
||||
font_id,
|
||||
egui::Color32::WHITE,
|
||||
f32::INFINITY,
|
||||
).size().x
|
||||
fonts
|
||||
.layout(
|
||||
longest_line_text.to_string(),
|
||||
font_id,
|
||||
egui::Color32::WHITE,
|
||||
f32::INFINITY,
|
||||
)
|
||||
.size()
|
||||
.x
|
||||
})
|
||||
} else {
|
||||
0.0
|
||||
@ -56,65 +57,106 @@ impl TextEditor {
|
||||
}
|
||||
|
||||
/// Efficiently detect and process line changes without full content iteration
|
||||
pub fn process_incremental_change(&mut self, old_content: &str, new_content: &str,
|
||||
old_cursor_pos: usize, new_cursor_pos: usize, ui: &egui::Ui) {
|
||||
// Calculate cursor line change incrementally
|
||||
let line_change = self.calculate_cursor_line_change(old_content, new_content, old_cursor_pos, new_cursor_pos);
|
||||
|
||||
// Update current cursor line
|
||||
pub fn process_incremental_change(
|
||||
&mut self,
|
||||
old_content: &str,
|
||||
new_content: &str,
|
||||
old_cursor_pos: usize,
|
||||
new_cursor_pos: usize,
|
||||
ui: &egui::Ui,
|
||||
) {
|
||||
let line_change = self.calculate_cursor_line_change(
|
||||
old_content,
|
||||
new_content,
|
||||
old_cursor_pos,
|
||||
new_cursor_pos,
|
||||
);
|
||||
|
||||
self.current_cursor_line = (self.current_cursor_line as isize + line_change) as usize;
|
||||
|
||||
// Detect the type of change and handle appropriately
|
||||
|
||||
if old_content.len() == new_content.len() {
|
||||
// Same length - likely a character replacement
|
||||
self.handle_character_replacement(old_content, new_content, old_cursor_pos, new_cursor_pos, ui);
|
||||
self.handle_character_replacement(
|
||||
old_content,
|
||||
new_content,
|
||||
old_cursor_pos,
|
||||
new_cursor_pos,
|
||||
ui,
|
||||
);
|
||||
} else if new_content.len() > old_content.len() {
|
||||
// Content added
|
||||
self.handle_content_addition(old_content, new_content, old_cursor_pos, new_cursor_pos, ui);
|
||||
self.handle_content_addition(
|
||||
old_content,
|
||||
new_content,
|
||||
old_cursor_pos,
|
||||
new_cursor_pos,
|
||||
ui,
|
||||
);
|
||||
} else {
|
||||
// Content removed
|
||||
self.handle_content_removal(old_content, new_content, old_cursor_pos, new_cursor_pos, ui);
|
||||
self.handle_content_removal(
|
||||
old_content,
|
||||
new_content,
|
||||
old_cursor_pos,
|
||||
new_cursor_pos,
|
||||
ui,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
self.previous_cursor_line = self.current_cursor_line;
|
||||
}
|
||||
|
||||
/// Calculate the change in cursor line without full iteration
|
||||
fn calculate_cursor_line_change(&self, old_content: &str, new_content: &str,
|
||||
old_cursor_pos: usize, new_cursor_pos: usize) -> isize {
|
||||
// Count newlines up to the cursor position in both contents
|
||||
fn calculate_cursor_line_change(
|
||||
&self,
|
||||
old_content: &str,
|
||||
new_content: &str,
|
||||
old_cursor_pos: usize,
|
||||
new_cursor_pos: usize,
|
||||
) -> isize {
|
||||
let old_newlines = old_content[..old_cursor_pos.min(old_content.len())]
|
||||
.bytes()
|
||||
.filter(|&b| b == b'\n')
|
||||
.count();
|
||||
|
||||
|
||||
let new_newlines = new_content[..new_cursor_pos.min(new_content.len())]
|
||||
.bytes()
|
||||
.filter(|&b| b == b'\n')
|
||||
.count();
|
||||
|
||||
|
||||
new_newlines as isize - old_newlines as isize
|
||||
}
|
||||
|
||||
/// Handle character replacement (same length change)
|
||||
fn handle_character_replacement(&mut self, old_content: &str, new_content: &str,
|
||||
old_cursor_pos: usize, new_cursor_pos: usize, ui: &egui::Ui) {
|
||||
// Extract the current line from new content
|
||||
fn handle_character_replacement(
|
||||
&mut self,
|
||||
_old_content: &str,
|
||||
new_content: &str,
|
||||
_old_cursor_pos: usize,
|
||||
new_cursor_pos: usize,
|
||||
ui: &egui::Ui,
|
||||
) {
|
||||
let current_line = self.extract_current_line(new_content, new_cursor_pos);
|
||||
let current_line_length = current_line.chars().count();
|
||||
|
||||
self.update_line_if_longer(self.current_cursor_line, ¤t_line, current_line_length, ui);
|
||||
|
||||
self.update_line_if_longer(
|
||||
self.current_cursor_line,
|
||||
¤t_line,
|
||||
current_line_length,
|
||||
ui,
|
||||
);
|
||||
}
|
||||
|
||||
/// Handle content addition
|
||||
fn handle_content_addition(&mut self, old_content: &str, new_content: &str,
|
||||
old_cursor_pos: usize, new_cursor_pos: usize, ui: &egui::Ui) {
|
||||
// Find the common prefix and suffix to identify the added text
|
||||
fn handle_content_addition(
|
||||
&mut self,
|
||||
old_content: &str,
|
||||
new_content: &str,
|
||||
_old_cursor_pos: usize,
|
||||
new_cursor_pos: usize,
|
||||
ui: &egui::Ui,
|
||||
) {
|
||||
let min_len = old_content.len().min(new_content.len());
|
||||
let mut common_prefix = 0;
|
||||
let mut common_suffix = 0;
|
||||
|
||||
// Find common prefix
|
||||
|
||||
for i in 0..min_len {
|
||||
if old_content.as_bytes()[i] == new_content.as_bytes()[i] {
|
||||
common_prefix += 1;
|
||||
@ -122,8 +164,7 @@ impl TextEditor {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find common suffix
|
||||
|
||||
for i in 0..min_len - common_prefix {
|
||||
let old_idx = old_content.len() - 1 - i;
|
||||
let new_idx = new_content.len() - 1 - i;
|
||||
@ -133,36 +174,42 @@ impl TextEditor {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the added text
|
||||
|
||||
let added_start = common_prefix;
|
||||
let added_end = new_content.len() - common_suffix;
|
||||
let added_text = &new_content[added_start..added_end];
|
||||
let newlines_added = added_text.bytes().filter(|&b| b == b'\n').count();
|
||||
|
||||
|
||||
if newlines_added > 0 {
|
||||
// Lines were added, update line count
|
||||
let mut current_result = self.get_text_processing_result();
|
||||
current_result.line_count += newlines_added;
|
||||
self.update_processing_result(current_result);
|
||||
}
|
||||
|
||||
// Check if the current line is now longer
|
||||
|
||||
let current_line = self.extract_current_line(new_content, new_cursor_pos);
|
||||
let current_line_length = current_line.chars().count();
|
||||
|
||||
self.update_line_if_longer(self.current_cursor_line, ¤t_line, current_line_length, ui);
|
||||
|
||||
self.update_line_if_longer(
|
||||
self.current_cursor_line,
|
||||
¤t_line,
|
||||
current_line_length,
|
||||
ui,
|
||||
);
|
||||
}
|
||||
|
||||
/// Handle content removal
|
||||
fn handle_content_removal(&mut self, old_content: &str, new_content: &str,
|
||||
old_cursor_pos: usize, new_cursor_pos: usize, ui: &egui::Ui) {
|
||||
// Find the common prefix and suffix to identify the removed text
|
||||
fn handle_content_removal(
|
||||
&mut self,
|
||||
old_content: &str,
|
||||
new_content: &str,
|
||||
_old_cursor_pos: usize,
|
||||
new_cursor_pos: usize,
|
||||
ui: &egui::Ui,
|
||||
) {
|
||||
let min_len = old_content.len().min(new_content.len());
|
||||
let mut common_prefix = 0;
|
||||
let mut common_suffix = 0;
|
||||
|
||||
// Find common prefix
|
||||
|
||||
for i in 0..min_len {
|
||||
if old_content.as_bytes()[i] == new_content.as_bytes()[i] {
|
||||
common_prefix += 1;
|
||||
@ -170,8 +217,7 @@ impl TextEditor {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find common suffix
|
||||
|
||||
for i in 0..min_len - common_prefix {
|
||||
let old_idx = old_content.len() - 1 - i;
|
||||
let new_idx = new_content.len() - 1 - i;
|
||||
@ -181,77 +227,80 @@ impl TextEditor {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the removed text
|
||||
|
||||
let removed_start = common_prefix;
|
||||
let removed_end = old_content.len() - common_suffix;
|
||||
let removed_text = &old_content[removed_start..removed_end];
|
||||
let newlines_removed = removed_text.bytes().filter(|&b| b == b'\n').count();
|
||||
|
||||
|
||||
if newlines_removed > 0 {
|
||||
// Lines were removed, update line count
|
||||
let mut current_result = self.get_text_processing_result();
|
||||
current_result.line_count = current_result.line_count.saturating_sub(newlines_removed);
|
||||
|
||||
// If we removed the longest line, we need to rescan (but only if necessary)
|
||||
|
||||
if self.current_cursor_line <= current_result.longest_line_index {
|
||||
// The longest line might have been affected, but let's be conservative
|
||||
// and only rescan if we're sure it was the longest line
|
||||
if self.current_cursor_line == current_result.longest_line_index {
|
||||
self.process_text_for_rendering(new_content, ui);
|
||||
return;
|
||||
}
|
||||
self.process_text_for_rendering(new_content, ui);
|
||||
}
|
||||
|
||||
|
||||
self.update_processing_result(current_result);
|
||||
}
|
||||
|
||||
// Check if the current line changed
|
||||
|
||||
let current_line = self.extract_current_line(new_content, new_cursor_pos);
|
||||
let current_line_length = current_line.chars().count();
|
||||
|
||||
// If this was the longest line and it got shorter, we might need to rescan
|
||||
|
||||
let current_result = self.get_text_processing_result();
|
||||
if self.current_cursor_line == current_result.longest_line_index &&
|
||||
current_line_length < current_result.longest_line_length {
|
||||
if self.current_cursor_line == current_result.longest_line_index
|
||||
&& current_line_length < current_result.longest_line_length
|
||||
{
|
||||
self.process_text_for_rendering(new_content, ui);
|
||||
} else {
|
||||
self.update_line_if_longer(self.current_cursor_line, ¤t_line, current_line_length, ui);
|
||||
self.update_line_if_longer(
|
||||
self.current_cursor_line,
|
||||
¤t_line,
|
||||
current_line_length,
|
||||
ui,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the current line efficiently without full content scan
|
||||
fn extract_current_line(&self, content: &str, cursor_pos: usize) -> String {
|
||||
let bytes = content.as_bytes();
|
||||
|
||||
// Find line start (search backwards from cursor)
|
||||
|
||||
let mut line_start = cursor_pos;
|
||||
while line_start > 0 && bytes[line_start - 1] != b'\n' {
|
||||
line_start -= 1;
|
||||
}
|
||||
|
||||
// Find line end (search forwards from cursor)
|
||||
|
||||
let mut line_end = cursor_pos;
|
||||
while line_end < bytes.len() && bytes[line_end] != b'\n' {
|
||||
line_end += 1;
|
||||
}
|
||||
|
||||
|
||||
content[line_start..line_end].to_string()
|
||||
}
|
||||
|
||||
/// Update longest line info if the current line is longer
|
||||
fn update_line_if_longer(&mut self, line_index: usize, line_content: &str, line_length: usize, ui: &egui::Ui) {
|
||||
fn update_line_if_longer(
|
||||
&mut self,
|
||||
line_index: usize,
|
||||
line_content: &str,
|
||||
line_length: usize,
|
||||
ui: &egui::Ui,
|
||||
) {
|
||||
let current_result = self.get_text_processing_result();
|
||||
|
||||
|
||||
if line_length > current_result.longest_line_length {
|
||||
let font_id = self.get_font_id();
|
||||
let pixel_width = ui.fonts(|fonts| {
|
||||
fonts.layout(
|
||||
line_content.to_string(),
|
||||
font_id,
|
||||
egui::Color32::WHITE,
|
||||
f32::INFINITY,
|
||||
).size().x
|
||||
fonts
|
||||
.layout(
|
||||
line_content.to_string(),
|
||||
font_id,
|
||||
egui::Color32::WHITE,
|
||||
f32::INFINITY,
|
||||
)
|
||||
.size()
|
||||
.x
|
||||
});
|
||||
|
||||
let result = TextProcessingResult {
|
||||
@ -260,7 +309,7 @@ impl TextEditor {
|
||||
longest_line_length: line_length,
|
||||
longest_line_pixel_width: pixel_width,
|
||||
};
|
||||
|
||||
|
||||
self.update_processing_result(result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ fn get_pywal_colors() -> Option<egui::Visuals> {
|
||||
let fg = parse_color(colors.get(7).unwrap_or(&colors[0]))?;
|
||||
let bg_alt = parse_color(colors.get(8).unwrap_or(&colors[0]))?;
|
||||
let accent = parse_color(colors.get(1).unwrap_or(&colors[0]))?;
|
||||
let secondary = parse_color(colors.get(2).unwrap_or(&colors[0]))?;
|
||||
let _secondary = parse_color(colors.get(2).unwrap_or(&colors[0]))?;
|
||||
|
||||
let mut visuals = if is_dark_color(bg) {
|
||||
egui::Visuals::dark()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::app::TextEditor;
|
||||
use crate::app::tab::Tab;
|
||||
use crate::app::TextEditor;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ use eframe::egui;
|
||||
mod app;
|
||||
mod io;
|
||||
mod ui;
|
||||
use app::{TextEditor, config::Config};
|
||||
use app::{config::Config, TextEditor};
|
||||
|
||||
fn main() -> eframe::Result {
|
||||
let options = eframe::NativeOptions {
|
||||
|
||||
@ -14,7 +14,7 @@ pub(crate) fn central_panel(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
let line_side = app.line_side;
|
||||
let font_size = app.font_size;
|
||||
|
||||
let output = egui::CentralPanel::default()
|
||||
let _output = egui::CentralPanel::default()
|
||||
.frame(egui::Frame::NONE)
|
||||
.show(ctx, |ui| {
|
||||
let bg_color = ui.visuals().extreme_bg_color;
|
||||
@ -23,20 +23,20 @@ pub(crate) fn central_panel(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
let editor_height = panel_rect.height();
|
||||
|
||||
if !show_line_numbers || app.get_active_tab().is_none() {
|
||||
let scroll_response = egui::ScrollArea::vertical()
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
// Create an invisible interaction area for context menu that covers the whole area
|
||||
let full_rect = ui.available_rect_before_wrap();
|
||||
let context_response = ui.allocate_response(full_rect.size(), egui::Sense::click());
|
||||
|
||||
// Reset cursor to render editor at the top
|
||||
ui.allocate_ui_at_rect(full_rect, |ui| {
|
||||
editor_view_ui(ui, app);
|
||||
let _scroll_response =
|
||||
egui::ScrollArea::vertical()
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
let full_rect = ui.available_rect_before_wrap();
|
||||
let context_response =
|
||||
ui.allocate_response(full_rect.size(), egui::Sense::click());
|
||||
|
||||
ui.scope_builder(egui::UiBuilder::new().max_rect(full_rect), |ui| {
|
||||
editor_view_ui(ui, app);
|
||||
});
|
||||
|
||||
show_context_menu(ui, app, &context_response);
|
||||
});
|
||||
|
||||
show_context_menu(ui, app, &context_response);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -86,7 +86,8 @@ pub(crate) fn central_panel(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
.show(ui, |ui| {
|
||||
if line_side {
|
||||
// Line numbers on the right
|
||||
let text_editor_width = editor_dimensions.text_width + editor_dimensions.total_reserved_width;
|
||||
let text_editor_width =
|
||||
editor_dimensions.text_width + editor_dimensions.total_reserved_width;
|
||||
ui.allocate_ui_with_layout(
|
||||
egui::vec2(text_editor_width, editor_height),
|
||||
egui::Layout::left_to_right(egui::Align::TOP),
|
||||
@ -98,13 +99,19 @@ pub(crate) fn central_panel(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
|ui| {
|
||||
// Create an invisible interaction area for context menu
|
||||
let full_rect = ui.available_rect_before_wrap();
|
||||
let context_response = ui.allocate_response(full_rect.size(), egui::Sense::click());
|
||||
|
||||
let context_response = ui.allocate_response(
|
||||
full_rect.size(),
|
||||
egui::Sense::click(),
|
||||
);
|
||||
|
||||
// Reset cursor to render editor at the top
|
||||
ui.allocate_ui_at_rect(full_rect, |ui| {
|
||||
editor_view_ui(ui, app);
|
||||
});
|
||||
|
||||
ui.scope_builder(
|
||||
egui::UiBuilder::new().max_rect(full_rect),
|
||||
|ui| {
|
||||
editor_view_ui(ui, app);
|
||||
},
|
||||
);
|
||||
|
||||
show_context_menu(ui, app, &context_response);
|
||||
},
|
||||
);
|
||||
@ -114,23 +121,28 @@ pub(crate) fn central_panel(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
);
|
||||
} else {
|
||||
// Line numbers on the left
|
||||
let text_editor_width = editor_dimensions.text_width + editor_dimensions.total_reserved_width;
|
||||
let text_editor_width =
|
||||
editor_dimensions.text_width + editor_dimensions.total_reserved_width;
|
||||
ui.allocate_ui_with_layout(
|
||||
egui::vec2(text_editor_width, editor_height),
|
||||
egui::Layout::left_to_right(egui::Align::TOP),
|
||||
|ui| {
|
||||
line_numbers_widget(ui);
|
||||
separator_widget(ui);
|
||||
|
||||
|
||||
// Create an invisible interaction area for context menu
|
||||
let editor_area = ui.available_rect_before_wrap();
|
||||
let context_response = ui.allocate_response(editor_area.size(), egui::Sense::click());
|
||||
|
||||
let context_response =
|
||||
ui.allocate_response(editor_area.size(), egui::Sense::click());
|
||||
|
||||
// Reset cursor to render editor at the current position
|
||||
ui.allocate_ui_at_rect(editor_area, |ui| {
|
||||
editor_view_ui(ui, app);
|
||||
});
|
||||
|
||||
ui.scope_builder(
|
||||
egui::UiBuilder::new().max_rect(editor_area),
|
||||
|ui| {
|
||||
editor_view_ui(ui, app);
|
||||
},
|
||||
);
|
||||
|
||||
show_context_menu(ui, app, &context_response);
|
||||
},
|
||||
);
|
||||
@ -139,17 +151,19 @@ pub(crate) fn central_panel(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
});
|
||||
}
|
||||
|
||||
fn show_context_menu(ui: &mut egui::Ui, app: &mut TextEditor, context_response: &egui::Response) {
|
||||
fn show_context_menu(_ui: &mut egui::Ui, app: &mut TextEditor, context_response: &egui::Response) {
|
||||
context_response.context_menu(|ui| {
|
||||
let text_len = app.get_active_tab().unwrap().content.len();
|
||||
let reset_zoom_key = egui::Id::new("editor_reset_zoom");
|
||||
|
||||
if ui.button("Cut").clicked() {
|
||||
ui.ctx().send_viewport_cmd(egui::ViewportCommand::RequestCut);
|
||||
ui.ctx()
|
||||
.send_viewport_cmd(egui::ViewportCommand::RequestCut);
|
||||
ui.close_menu();
|
||||
}
|
||||
if ui.button("Copy").clicked() {
|
||||
ui.ctx().send_viewport_cmd(egui::ViewportCommand::RequestCopy);
|
||||
ui.ctx()
|
||||
.send_viewport_cmd(egui::ViewportCommand::RequestCopy);
|
||||
ui.close_menu();
|
||||
}
|
||||
if ui.button("Paste").clicked() {
|
||||
|
||||
@ -84,7 +84,6 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
|
||||
.char_range()
|
||||
.map(|range| range.primary.index);
|
||||
|
||||
|
||||
if let Some(content) = content_for_processing {
|
||||
let previous_content = app.previous_content.clone();
|
||||
let previous_cursor_pos = app.previous_cursor_char_index;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use eframe::egui;
|
||||
|
||||
pub(super) fn draw_find_highlight(
|
||||
pub(super) fn _draw_find_highlight(
|
||||
ui: &mut egui::Ui,
|
||||
content: &str,
|
||||
start_pos: usize,
|
||||
@ -74,10 +74,7 @@ pub(super) fn draw_find_highlight(
|
||||
egui::vec2(match_width, line_height),
|
||||
);
|
||||
|
||||
ui.painter().rect_filled(
|
||||
highlight_rect,
|
||||
0.0,
|
||||
ui.visuals().selection.bg_fill,
|
||||
);
|
||||
ui.painter()
|
||||
.rect_filled(highlight_rect, 0.0, ui.visuals().selection.bg_fill);
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,8 +86,7 @@ pub(super) fn render_line_numbers(
|
||||
let bg_color = ui.visuals().extreme_bg_color;
|
||||
|
||||
let line_numbers_rect = ui.available_rect_before_wrap();
|
||||
ui.painter()
|
||||
.rect_filled(line_numbers_rect, 0.0, bg_color);
|
||||
ui.painter().rect_filled(line_numbers_rect, 0.0, bg_color);
|
||||
|
||||
let font_id = egui::FontId::monospace(font_size);
|
||||
let line_count_width = line_count.to_string().len();
|
||||
|
||||
@ -178,10 +178,7 @@ pub(crate) fn menu_bar(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
app.save_config();
|
||||
ui.close_menu();
|
||||
}
|
||||
if ui
|
||||
.checkbox(&mut app.word_wrap, "Word Wrap")
|
||||
.clicked()
|
||||
{
|
||||
if ui.checkbox(&mut app.word_wrap, "Word Wrap").clicked() {
|
||||
app.save_config();
|
||||
ui.close_menu();
|
||||
}
|
||||
|
||||
@ -72,7 +72,11 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
app.font_size_input = Some(app.font_size.to_string());
|
||||
}
|
||||
|
||||
let mut font_size_text = app.font_size_input.as_ref().unwrap_or(&"14".to_string()).clone();
|
||||
let mut font_size_text = app
|
||||
.font_size_input
|
||||
.as_ref()
|
||||
.unwrap_or(&"14".to_string())
|
||||
.clone();
|
||||
let response = ui.add(
|
||||
egui::TextEdit::singleline(&mut font_size_text)
|
||||
.desired_width(50.0)
|
||||
@ -123,8 +127,10 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
},
|
||||
);
|
||||
ui.label(
|
||||
egui::RichText::new("The quick brown fox jumps over the lazy dog.")
|
||||
.font(preview_font.clone()),
|
||||
egui::RichText::new(
|
||||
"The quick brown fox jumps over the lazy dog.",
|
||||
)
|
||||
.font(preview_font.clone()),
|
||||
);
|
||||
ui.label(
|
||||
egui::RichText::new("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
@ -134,7 +140,9 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
|
||||
egui::RichText::new("abcdefghijklmnopqrstuvwxyz")
|
||||
.font(preview_font.clone()),
|
||||
);
|
||||
ui.label(egui::RichText::new("1234567890 !@#$%^&*()").font(preview_font));
|
||||
ui.label(
|
||||
egui::RichText::new("1234567890 !@#$%^&*()").font(preview_font),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user