Browse Source

初始工程创建

master
hejl 2 months ago
commit
f9699953e7
  1. 1
      .gitignore
  2. 1
      .vscode/settings.json
  3. 13
      text_editor/.vscode/lauch.json
  4. 1
      text_editor/.vscode/settings.json
  5. 4112
      text_editor/Cargo.lock
  6. 23
      text_editor/Cargo.toml
  7. BIN
      text_editor/assets/fronts/msyh.ttf
  8. 150
      text_editor/src/app.rs
  9. 25
      text_editor/src/file_utils.rs
  10. 44
      text_editor/src/main.rs
  11. 22
      text_editor/src/text_utils.rs

1
.gitignore vendored

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

1
.vscode/settings.json vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
{}

13
text_editor/.vscode/lauch.json vendored

@ -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}"
}
]
}

1
text_editor/.vscode/settings.json vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
{}

4112
text_editor/Cargo.lock generated

File diff suppressed because it is too large Load Diff

23
text_editor/Cargo.toml

@ -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"

BIN
text_editor/assets/fronts/msyh.ttf

Binary file not shown.

150
text_editor/src/app.rs

@ -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);
}
}
}
}

25
text_editor/src/file_utils.rs

@ -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()
}

44
text_editor/src/main.rs

@ -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()))
}),
)
}

22
text_editor/src/text_utils.rs

@ -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…
Cancel
Save