commit
f9699953e7
11 changed files with 4392 additions and 0 deletions
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
{ |
||||
"version": "0.2.0", |
||||
"configurations": [ |
||||
{ |
||||
"type": "lldb", |
||||
"request": "launch", |
||||
"name": "Debug", |
||||
"program": "${workspaceFolder}/target/debug/text_editor", |
||||
"args": [], |
||||
"cwd": "${workspaceFolder}" |
||||
} |
||||
] |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
[package] |
||||
name = "text_editor" |
||||
version = "0.1.0" |
||||
edition = "2024" |
||||
|
||||
[dependencies] |
||||
# GUI框架 |
||||
egui = "0.31.1" # 用于界面 |
||||
eframe = "0.31.1" # 用于应用框架 |
||||
# 文件系统操作 |
||||
walkdir = "2.4" |
||||
# 文本处理 |
||||
regex = "1.10" |
||||
# Windows特定功能 |
||||
windows = { version = "0.61.1", features = [ |
||||
"Win32_Foundation", |
||||
"Win32_UI_WindowsAndMessaging", |
||||
"Win32_UI_Shell", |
||||
"Win32_Storage_FileSystem", |
||||
] } |
||||
|
||||
serde = { version = "1.0", features = ["derive"] } |
||||
serde_json = "1.0" |
Binary file not shown.
@ -0,0 +1,150 @@
@@ -0,0 +1,150 @@
|
||||
use eframe::egui; |
||||
use serde_json::{Value, to_string_pretty}; |
||||
use std::path::{Path, PathBuf}; |
||||
use walkdir::WalkDir; |
||||
|
||||
pub struct TextEditorApp { |
||||
current_dir: String, |
||||
files: Vec<PathBuf>, |
||||
selected_file: Option<PathBuf>, |
||||
file_content: String, |
||||
} |
||||
|
||||
impl Default for TextEditorApp { |
||||
fn default() -> Self { |
||||
Self { |
||||
current_dir: String::from("C:\\"), // 默认目录
|
||||
files: Vec::new(), |
||||
selected_file: None, |
||||
file_content: String::new(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl eframe::App for TextEditorApp { |
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { |
||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { |
||||
ui.heading("轻量文本编辑器"); |
||||
}); |
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| { |
||||
ui.horizontal(|ui| { |
||||
// 左侧资源管理器面板
|
||||
egui::SidePanel::left("explorer_panel") |
||||
.resizable(true) |
||||
.default_width(200.0) |
||||
.show_inside(ui, |ui| { |
||||
ui.heading("资源管理器"); |
||||
|
||||
// 目录输入框
|
||||
ui.horizontal(|ui| { |
||||
ui.label("目录:"); |
||||
ui.text_edit_singleline(&mut self.current_dir); |
||||
if ui.button("加载").clicked() { |
||||
self.load_directory(); |
||||
} |
||||
}); |
||||
|
||||
// 文件列表
|
||||
egui::ScrollArea::vertical().show(ui, |ui| { |
||||
let mut clicked_file = None; |
||||
|
||||
for file in &self.files { |
||||
let display_name = file |
||||
.file_name() |
||||
.and_then(|n| n.to_str()) |
||||
.unwrap_or_default(); |
||||
|
||||
if ui |
||||
.selectable_label( |
||||
self.selected_file.as_ref() == Some(file), |
||||
display_name, |
||||
) |
||||
.clicked() |
||||
{ |
||||
clicked_file = Some(file.clone()); |
||||
} |
||||
} |
||||
|
||||
if let Some(file) = clicked_file { |
||||
self.selected_file = Some(file.clone()); |
||||
self.load_file_content(&file); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
// 右侧文本编辑面板
|
||||
egui::CentralPanel::default().show_inside(ui, |ui| { |
||||
ui.heading("文本编辑器"); |
||||
|
||||
// 文本编辑区域
|
||||
egui::ScrollArea::both().show(ui, |ui| { |
||||
ui.text_edit_multiline(&mut self.file_content); |
||||
}); |
||||
|
||||
// 转换按钮
|
||||
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| { |
||||
ui.horizontal(|ui| { |
||||
if ui.button("转换为大写").clicked() { |
||||
self.convert_to_uppercase(); |
||||
} |
||||
if ui.button("转换为小写").clicked() { |
||||
self.convert_to_lowercase(); |
||||
} |
||||
if ui.button("格式化JSON").clicked() { |
||||
self.format_json(); |
||||
} |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
impl TextEditorApp { |
||||
fn load_directory(&mut self) { |
||||
self.files.clear(); |
||||
self.selected_file = None; |
||||
self.file_content.clear(); |
||||
|
||||
let path = Path::new(&self.current_dir); |
||||
if path.is_dir() { |
||||
for entry in WalkDir::new(path) |
||||
.max_depth(1) |
||||
.into_iter() |
||||
.filter_map(|e| e.ok()) |
||||
{ |
||||
if entry.file_type().is_file() { |
||||
self.files.push(entry.path().to_path_buf()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
fn load_file_content(&mut self, file_path: &Path) { |
||||
self.file_content = std::fs::read_to_string(file_path).unwrap_or_default(); |
||||
} |
||||
|
||||
fn convert_to_uppercase(&mut self) { |
||||
self.file_content = self.file_content.to_uppercase(); |
||||
} |
||||
|
||||
fn convert_to_lowercase(&mut self) { |
||||
self.file_content = self.file_content.to_lowercase(); |
||||
} |
||||
|
||||
fn format_json(&mut self) { |
||||
match serde_json::from_str::<Value>(&self.file_content) { |
||||
Ok(parsed) => { |
||||
if let Ok(formatted) = to_string_pretty(&parsed) { |
||||
self.file_content = formatted; |
||||
} |
||||
} |
||||
Err(e) => { |
||||
// 可以在这里添加错误处理,比如显示错误消息
|
||||
println!("JSON 格式化错误: {}", e); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
use std::path::{Path, PathBuf}; |
||||
use walkdir::WalkDir; |
||||
|
||||
pub fn list_files_in_dir(path: &str) -> Vec<PathBuf> { |
||||
let mut files = Vec::new(); |
||||
let path = Path::new(path); |
||||
|
||||
if path.is_dir() { |
||||
for entry in WalkDir::new(path) |
||||
.max_depth(1) |
||||
.into_iter() |
||||
.filter_map(|e| e.ok()) |
||||
{ |
||||
if entry.file_type().is_file() { |
||||
files.push(entry.path().to_path_buf()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
files |
||||
} |
||||
|
||||
pub fn read_file_content(file_path: &Path) -> Option<String> { |
||||
std::fs::read_to_string(file_path).ok() |
||||
} |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
mod app; |
||||
use app::TextEditorApp; |
||||
use eframe::egui; |
||||
|
||||
fn main() -> eframe::Result<()> { |
||||
let options = eframe::NativeOptions { |
||||
viewport: egui::ViewportBuilder::default() |
||||
.with_inner_size([1000.0, 600.0]) |
||||
.with_min_inner_size([400.0, 300.0]), |
||||
..Default::default() |
||||
}; |
||||
|
||||
eframe::run_native( |
||||
"轻量文本编辑器", |
||||
options, |
||||
Box::new(|cc| { |
||||
// 使用系统字体
|
||||
let mut fonts = egui::FontDefinitions::default(); |
||||
|
||||
// 添加中文字体
|
||||
fonts.font_data.insert( |
||||
"msyh".to_owned(), |
||||
egui::FontData::from_static(include_bytes!("C:\\Windows\\Fonts\\msyh.ttc")), |
||||
); |
||||
|
||||
// 或者使用系统已安装的字体
|
||||
fonts |
||||
.families |
||||
.entry(egui::FontFamily::Proportional) |
||||
.or_default() |
||||
.insert(0, "Microsoft YaHei".to_owned()); |
||||
|
||||
fonts |
||||
.families |
||||
.entry(egui::FontFamily::Monospace) |
||||
.or_default() |
||||
.push("Microsoft YaHei".to_owned()); |
||||
|
||||
cc.egui_ctx.set_fonts(fonts); |
||||
|
||||
Ok(Box::new(TextEditorApp::default())) |
||||
}), |
||||
) |
||||
} |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
use regex::Regex; |
||||
use serde_json::{Value, to_string_pretty}; |
||||
|
||||
pub fn to_uppercase(text: &str) -> String { |
||||
text.to_uppercase() |
||||
} |
||||
|
||||
pub fn to_lowercase(text: &str) -> String { |
||||
text.to_lowercase() |
||||
} |
||||
|
||||
pub fn format_json(text: &str) -> Option<String> { |
||||
match serde_json::from_str::<Value>(text) { |
||||
Ok(parsed) => to_string_pretty(&parsed).ok(), |
||||
Err(_) => None, |
||||
} |
||||
} |
||||
|
||||
pub fn extract_emails(text: &str) -> Vec<String> { |
||||
let re = Regex::new(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b").unwrap(); |
||||
re.find_iter(text).map(|m| m.as_str().to_string()).collect() |
||||
} |
Loading…
Reference in new issue