Scitano/src/editor.rs

193 lines
6.0 KiB
Rust
Executable File

use iced::widget::text_editor;
use std::fs;
use std::path::PathBuf;
pub struct EditorTab {
pub title: String,
pub content: text_editor::Content,
pub is_dirty: bool,
pub file_path: Option<PathBuf>,
pub override_syntax: Option<String>,
pub symbols: Vec<(usize, String)>,
pub bookmarks: Vec<usize>,
}
impl EditorTab {
pub fn new(title: &str, initial_text: &str) -> Self {
let mut tab = Self {
title: title.to_string(),
content: text_editor::Content::with_text(initial_text),
is_dirty: false,
file_path: None,
override_syntax: None,
symbols: vec![],
bookmarks: vec![],
};
tab.parse_symbols();
tab
}
pub fn parse_symbols(&mut self) {
self.symbols.clear();
for (i, line) in self.content.text().lines().enumerate() {
let t = line.trim_start();
if t.starts_with("fn ")
|| t.starts_with("def ")
|| t.starts_with("class ")
|| t.starts_with("struct ")
|| t.starts_with("impl ")
|| t.starts_with("enum ")
|| t.starts_with("trait ")
|| t.starts_with("mod ")
|| t.starts_with("pub fn ")
|| t.starts_with("pub struct ")
|| t.starts_with("pub enum ")
|| t.starts_with("pub trait ")
|| t.starts_with("pub mod ")
|| t.starts_with("macro_rules!")
{
let name = t
.split('{')
.next()
.unwrap_or(t)
.split('(')
.next()
.unwrap_or(t)
.split('!')
.next()
.unwrap_or(t)
.trim()
.to_string();
self.symbols.push((i + 1, name));
}
}
}
pub fn toggle_bookmark(&mut self, line: usize) {
if self.bookmarks.contains(&line) {
self.bookmarks.retain(|&b| b != line);
} else {
self.bookmarks.push(line);
self.bookmarks.sort();
}
}
pub fn save(&mut self) -> Result<String, std::io::Error> {
let path = self
.file_path
.clone()
.unwrap_or_else(|| PathBuf::from(&self.title));
let text = self.content.text();
fs::write(&path, text)?;
self.is_dirty = false;
self.file_path = Some(path.clone());
Ok(path.to_string_lossy().to_string())
}
pub fn save_as(&mut self, new_path: &str) -> Result<String, std::io::Error> {
let path = PathBuf::from(new_path);
let text = self.content.text();
fs::write(&path, text)?;
self.is_dirty = false;
self.file_path = Some(path.clone());
self.title = path
.file_name()
.unwrap_or_default()
.to_string_lossy()
.to_string();
Ok(path.to_string_lossy().to_string())
}
pub fn line_count(&self) -> usize {
self.content.text().lines().count().max(1)
}
pub fn byte_size(&self) -> usize {
self.content.text().len()
}
pub fn get_syntax(&self) -> &'static str {
if let Some(ref syn) = self.override_syntax {
return match syn.as_str() {
"Rust" => "rs",
"Python" => "py",
"C/C++" | "C" | "C++" => "cpp",
"Shell" | "Bash" => "sh",
"JavaScript" => "js",
"TypeScript" => "ts",
"Markdown" => "md",
"HTML" => "html",
"CSS" => "css",
"JSON" => "json",
"XML" => "xml",
"YAML" => "yaml",
"Go" => "go",
"Ruby" => "rb",
"PHP" => "php",
"Java" => "java",
"C#" => "cs",
"SQL" => "sql",
_ => "txt",
};
}
let name = self.title.to_lowercase();
if name.contains("dockerfile") || name.contains("containerfile") {
return "dockerfile";
}
if name.contains("nginx") {
return "nginx";
}
if name.contains("apache") || name.contains("httpd") {
return "apache";
}
if name.ends_with("rc") {
return "sh";
}
if name.ends_with("makefile") || name == "makefile" {
return "makefile";
}
let parts: Vec<&str> = name.split('.').collect();
if let Some(ext) = parts.last() {
match *ext {
"rs" => "rs",
"sh" | "bash" | "zsh" | "command" => "sh",
"ps1" | "psm1" => "ps1",
"bat" | "cmd" | "dosbat" => "bat",
"vbs" | "vbe" | "wscript" | "vbasic" => "vbs",
"conf" | "cfg" | "ini" | "service" | "target" => "ini",
"yaml" | "yml" => "yaml",
"toml" => "toml",
"json" => "json",
"xml" => "xml",
"html" | "htm" | "xhtml" => "html",
"css" | "scss" | "sass" | "less" => "css",
"js" | "mjs" | "cjs" => "js",
"ts" | "tsx" => "ts",
"py" | "pyw" => "py",
"c" | "h" => "c",
"cpp" | "hpp" | "cc" | "cxx" | "hxx" => "cpp",
"go" => "go",
"rb" => "rb",
"php" | "phtml" => "php",
"java" => "java",
"cs" => "cs",
"sql" => "sql",
"md" | "markdown" => "md",
"r" => "r",
"lua" => "lua",
"pl" | "pm" => "pl",
"ex" | "exs" => "ex",
"hs" => "hs",
"scala" => "scala",
"swift" => "swift",
"kt" | "kts" => "kt",
"dart" => "dart",
_ => "txt",
}
} else {
"txt"
}
}
}