file diffs are kept separate
This commit is contained in:
parent
fd489fb156
commit
5dc0b6d638
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ced"
|
name = "ced"
|
||||||
version = "0.0.9"
|
version = "0.1.3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -16,3 +16,4 @@ libc = "0.2.174"
|
|||||||
syntect = "5.2.0"
|
syntect = "5.2.0"
|
||||||
plist = "1.7.4"
|
plist = "1.7.4"
|
||||||
diffy = "0.4.2"
|
diffy = "0.4.2"
|
||||||
|
uuid = { version = "1.0", features = ["v4"] }
|
||||||
|
|||||||
@ -9,7 +9,7 @@ There is a disturbing lack of simple GUI text editors available on Linux nativel
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Sane text editing with standard keybindings (`Ctrl+A`, `Ctrl+C`, etc.).
|
* Sane text editing with standard keybindings (`Ctrl+A`, `Ctrl+C`, etc.).
|
||||||
* Opens with a blank slate for quick typing, remember Notepad?
|
* Choose between opening fresh every time, like Notepad, or maintaining a consistent state like Notepad++.
|
||||||
* Separate UI zoom that doesn't affect font size (`Ctrl+Shift` + `+`/`-`).
|
* Separate UI zoom that doesn't affect font size (`Ctrl+Shift` + `+`/`-`).
|
||||||
* Ricers rejoice, your `pywal` colors will be used!
|
* Ricers rejoice, your `pywal` colors will be used!
|
||||||
* Weirdly smooth typing experience.
|
* Weirdly smooth typing experience.
|
||||||
@ -39,6 +39,7 @@ sudo install -Dm644 ced.desktop /usr/share/applications/ced.desktop
|
|||||||
Here is an example `config.toml`:
|
Here is an example `config.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
state_cache = true
|
||||||
auto_hide_toolbar = false
|
auto_hide_toolbar = false
|
||||||
show_line_numbers = false
|
show_line_numbers = false
|
||||||
word_wrap = false
|
word_wrap = false
|
||||||
@ -53,6 +54,7 @@ syntax_highlighting = true
|
|||||||
|
|
||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
|--------|---------|-------------|
|
|--------|---------|-------------|
|
||||||
|
| `state_cache` | `false` | If `true`, open files will have their unsaved changes cached and will be automatically opened when starting a new session. |
|
||||||
| `auto_hide_toolbar` | `false` | If `true`, the menu bar at the top will be hidden. Move your mouse to the top of the window to reveal it. |
|
| `auto_hide_toolbar` | `false` | If `true`, the menu bar at the top will be hidden. Move your mouse to the top of the window to reveal it. |
|
||||||
| `hide_tab_bar` | 'true' | If `false`, a separate tab bar will be drawn below the toolbar. |
|
| `hide_tab_bar` | 'true' | If `false`, a separate tab bar will be drawn below the toolbar. |
|
||||||
| `show_line_numbers` | `false` | If `true`, line numbers will be displayed on the side specified by `line_side`. |
|
| `show_line_numbers` | `false` | If `true`, line numbers will be displayed on the side specified by `line_side`. |
|
||||||
@ -67,7 +69,6 @@ syntax_highlighting = true
|
|||||||
In order of importance.
|
In order of importance.
|
||||||
| Feature | Info |
|
| Feature | Info |
|
||||||
| ------- | ---- |
|
| ------- | ---- |
|
||||||
| **State/Cache:** | A toggleable option to keep an application state and prevent "Quit without saving" warnings. |
|
|
||||||
| **LSP:** | Looking at allowing you to use/attach your own tools for this. |
|
| **LSP:** | Looking at allowing you to use/attach your own tools for this. |
|
||||||
| **Choose Font** | More than just Monospace/Proportional. |
|
| **Choose Font** | More than just Monospace/Proportional. |
|
||||||
| **Vim Mode:** | It's in-escapable. |
|
| **Vim Mode:** | It's in-escapable. |
|
||||||
|
|||||||
@ -22,7 +22,6 @@ impl TextEditor {
|
|||||||
pub fn from_config_with_context(config: Config, cc: &eframe::CreationContext<'_>) -> Self {
|
pub fn from_config_with_context(config: Config, cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
let mut editor = Self::from_config(config);
|
let mut editor = Self::from_config(config);
|
||||||
|
|
||||||
// Load state cache if enabled
|
|
||||||
if let Err(e) = editor.load_state_cache() {
|
if let Err(e) = editor.load_state_cache() {
|
||||||
eprintln!("Failed to load state cache: {e}");
|
eprintln!("Failed to load state cache: {e}");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,6 @@ impl TextEditor {
|
|||||||
let search_slice = if search_content.is_char_boundary(start) {
|
let search_slice = if search_content.is_char_boundary(start) {
|
||||||
&search_content[start..]
|
&search_content[start..]
|
||||||
} else {
|
} else {
|
||||||
// Find next valid boundary
|
|
||||||
while start < search_content.len() && !search_content.is_char_boundary(start) {
|
while start < search_content.len() && !search_content.is_char_boundary(start) {
|
||||||
start += 1;
|
start += 1;
|
||||||
}
|
}
|
||||||
@ -45,7 +44,6 @@ impl TextEditor {
|
|||||||
self.find_matches
|
self.find_matches
|
||||||
.push((absolute_pos, absolute_pos + query.len()));
|
.push((absolute_pos, absolute_pos + query.len()));
|
||||||
|
|
||||||
// Advance to next valid character boundary instead of just +1
|
|
||||||
start = absolute_pos + 1;
|
start = absolute_pos + 1;
|
||||||
while start < search_content.len() && !search_content.is_char_boundary(start) {
|
while start < search_content.len() && !search_content.is_char_boundary(start) {
|
||||||
start += 1;
|
start += 1;
|
||||||
|
|||||||
@ -2,10 +2,11 @@ use super::editor::TextEditor;
|
|||||||
use crate::app::tab::{Tab, compute_content_hash};
|
use crate::app::tab::{Tab, compute_content_hash};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct CachedTab {
|
pub struct CachedTab {
|
||||||
pub diff: Option<String>,
|
pub diff_file: Option<PathBuf>, // Path to diff file for modified tabs
|
||||||
pub full_content: Option<String>, // This is used for 'new files' that don't have a path
|
pub full_content: Option<String>, // This is used for 'new files' that don't have a path
|
||||||
pub file_path: Option<PathBuf>,
|
pub file_path: Option<PathBuf>,
|
||||||
pub is_modified: bool,
|
pub is_modified: bool,
|
||||||
@ -20,18 +21,40 @@ pub struct StateCache {
|
|||||||
pub tab_counter: usize,
|
pub tab_counter: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_diff_file(diff_content: &str) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||||
|
let diffs_dir = TextEditor::diffs_cache_dir().ok_or("Cannot determine cache directory")?;
|
||||||
|
std::fs::create_dir_all(&diffs_dir)?;
|
||||||
|
|
||||||
|
let diff_filename = format!("{}.diff", Uuid::new_v4());
|
||||||
|
let diff_path = diffs_dir.join(diff_filename);
|
||||||
|
|
||||||
|
std::fs::write(&diff_path, diff_content)?;
|
||||||
|
Ok(diff_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_diff_file(diff_path: &PathBuf) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
|
Ok(std::fs::read_to_string(diff_path)?)
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&Tab> for CachedTab {
|
impl From<&Tab> for CachedTab {
|
||||||
fn from(tab: &Tab) -> Self {
|
fn from(tab: &Tab) -> Self {
|
||||||
if let Some(file_path) = &tab.file_path {
|
if let Some(file_path) = &tab.file_path {
|
||||||
let original_content = std::fs::read_to_string(file_path).unwrap_or_default();
|
let original_content = std::fs::read_to_string(file_path).unwrap_or_default();
|
||||||
let diff = if tab.is_modified {
|
let diff_file = if tab.is_modified {
|
||||||
Some(diffy::create_patch(&original_content, &tab.content).to_string())
|
let diff_content = diffy::create_patch(&original_content, &tab.content);
|
||||||
|
match create_diff_file(&diff_content.to_string()) {
|
||||||
|
Ok(path) => Some(path),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Warning: Failed to create diff file: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
diff,
|
diff_file,
|
||||||
full_content: None,
|
full_content: None,
|
||||||
file_path: tab.file_path.clone(),
|
file_path: tab.file_path.clone(),
|
||||||
is_modified: tab.is_modified,
|
is_modified: tab.is_modified,
|
||||||
@ -40,7 +63,7 @@ impl From<&Tab> for CachedTab {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Self {
|
Self {
|
||||||
diff: None,
|
diff_file: None,
|
||||||
full_content: Some(tab.content.clone()),
|
full_content: Some(tab.content.clone()),
|
||||||
file_path: None,
|
file_path: None,
|
||||||
is_modified: tab.is_modified,
|
is_modified: tab.is_modified,
|
||||||
@ -55,21 +78,30 @@ impl From<CachedTab> for Tab {
|
|||||||
fn from(cached: CachedTab) -> Self {
|
fn from(cached: CachedTab) -> Self {
|
||||||
if let Some(file_path) = cached.file_path {
|
if let Some(file_path) = cached.file_path {
|
||||||
let original_content = std::fs::read_to_string(&file_path).unwrap_or_default();
|
let original_content = std::fs::read_to_string(&file_path).unwrap_or_default();
|
||||||
let current_content = if let Some(diff_str) = cached.diff {
|
let current_content = if let Some(diff_path) = cached.diff_file {
|
||||||
match diffy::Patch::from_str(&diff_str) {
|
match load_diff_file(&diff_path) {
|
||||||
Ok(patch) => {
|
Ok(diff_content) => {
|
||||||
match diffy::apply(&original_content, &patch) {
|
match diffy::Patch::from_str(&diff_content) {
|
||||||
Ok(content) => content,
|
Ok(patch) => {
|
||||||
|
match diffy::apply(&original_content, &patch) {
|
||||||
|
Ok(content) => content,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("Warning: Failed to apply diff for {}, using original content",
|
||||||
|
file_path.display());
|
||||||
|
original_content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
eprintln!("Warning: Failed to apply diff for {}, using original content",
|
eprintln!("Warning: Failed to parse diff for {}, using original content",
|
||||||
file_path.display());
|
file_path.display());
|
||||||
original_content
|
original_content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
eprintln!("Warning: Failed to parse diff for {}, using original content",
|
eprintln!("Warning: Failed to load diff file {:?}: {}, using original content",
|
||||||
file_path.display());
|
diff_path, e);
|
||||||
original_content
|
original_content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,6 +148,35 @@ impl TextEditor {
|
|||||||
Some(cache_dir.join("state.json"))
|
Some(cache_dir.join("state.json"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn diffs_cache_dir() -> Option<PathBuf> {
|
||||||
|
let cache_dir = if let Some(cache_dir) = dirs::cache_dir() {
|
||||||
|
cache_dir.join(env!("CARGO_PKG_NAME"))
|
||||||
|
} else if let Some(home_dir) = dirs::home_dir() {
|
||||||
|
home_dir.join(".cache").join(env!("CARGO_PKG_NAME"))
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(cache_dir.join("diffs"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup_orphaned_diffs(active_diff_files: &[PathBuf]) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if let Some(diffs_dir) = Self::diffs_cache_dir() {
|
||||||
|
if diffs_dir.exists() {
|
||||||
|
for entry in std::fs::read_dir(diffs_dir)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
if path.extension().and_then(|s| s.to_str()) == Some("diff") {
|
||||||
|
if !active_diff_files.contains(&path) {
|
||||||
|
let _ = std::fs::remove_file(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_state_cache(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn load_state_cache(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if !self.state_cache {
|
if !self.state_cache {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -157,6 +218,12 @@ impl TextEditor {
|
|||||||
tab_counter: self.tab_counter,
|
tab_counter: self.tab_counter,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let active_diff_files: Vec<PathBuf> = state_cache.tabs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|tab| tab.diff_file.clone())
|
||||||
|
.collect();
|
||||||
|
let _ = Self::cleanup_orphaned_diffs(&active_diff_files);
|
||||||
|
|
||||||
let content = serde_json::to_string_pretty(&state_cache)?;
|
let content = serde_json::to_string_pretty(&state_cache)?;
|
||||||
std::fs::write(&cache_path, content)?;
|
std::fs::write(&cache_path, content)?;
|
||||||
|
|
||||||
@ -169,6 +236,13 @@ impl TextEditor {
|
|||||||
std::fs::remove_file(cache_path)?;
|
std::fs::remove_file(cache_path)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(diffs_dir) = Self::diffs_cache_dir() {
|
||||||
|
if diffs_dir.exists() {
|
||||||
|
let _ = std::fs::remove_dir_all(diffs_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,7 +19,6 @@ impl TextEditor {
|
|||||||
}
|
}
|
||||||
self.text_needs_processing = true;
|
self.text_needs_processing = true;
|
||||||
|
|
||||||
// Save state cache after adding new tab
|
|
||||||
if let Err(e) = self.save_state_cache() {
|
if let Err(e) = self.save_state_cache() {
|
||||||
eprintln!("Failed to save state cache: {e}");
|
eprintln!("Failed to save state cache: {e}");
|
||||||
}
|
}
|
||||||
@ -38,7 +37,6 @@ impl TextEditor {
|
|||||||
}
|
}
|
||||||
self.text_needs_processing = true;
|
self.text_needs_processing = true;
|
||||||
|
|
||||||
// Save state cache after closing tab
|
|
||||||
if let Err(e) = self.save_state_cache() {
|
if let Err(e) = self.save_state_cache() {
|
||||||
eprintln!("Failed to save state cache: {e}");
|
eprintln!("Failed to save state cache: {e}");
|
||||||
}
|
}
|
||||||
@ -53,7 +51,6 @@ impl TextEditor {
|
|||||||
}
|
}
|
||||||
self.text_needs_processing = true;
|
self.text_needs_processing = true;
|
||||||
|
|
||||||
// Save state cache after switching tabs
|
|
||||||
if let Err(e) = self.save_state_cache() {
|
if let Err(e) = self.save_state_cache() {
|
||||||
eprintln!("Failed to save state cache: {e}");
|
eprintln!("Failed to save state cache: {e}");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,6 @@ impl TextEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the configured font ID based on the editor's font settings
|
|
||||||
pub fn get_font_id(&self) -> egui::FontId {
|
pub fn get_font_id(&self) -> egui::FontId {
|
||||||
let font_family = match self.font_family.as_str() {
|
let font_family = match self.font_family.as_str() {
|
||||||
"Monospace" => egui::FontFamily::Monospace,
|
"Monospace" => egui::FontFamily::Monospace,
|
||||||
@ -32,13 +31,11 @@ impl TextEditor {
|
|||||||
egui::FontId::new(self.font_size, font_family)
|
egui::FontId::new(self.font_size, font_family)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Immediately apply theme and save to configuration
|
|
||||||
pub fn set_theme(&mut self, ctx: &egui::Context) {
|
pub fn set_theme(&mut self, ctx: &egui::Context) {
|
||||||
theme::apply(self.theme, ctx);
|
theme::apply(self.theme, ctx);
|
||||||
self.save_config();
|
self.save_config();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply font settings with immediate text reprocessing
|
|
||||||
pub fn apply_font_settings(&mut self, ctx: &egui::Context) {
|
pub fn apply_font_settings(&mut self, ctx: &egui::Context) {
|
||||||
let font_family = match self.font_family.as_str() {
|
let font_family = match self.font_family.as_str() {
|
||||||
"Monospace" => egui::FontFamily::Monospace,
|
"Monospace" => egui::FontFamily::Monospace,
|
||||||
@ -56,21 +53,18 @@ impl TextEditor {
|
|||||||
self.save_config();
|
self.save_config();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply font settings with immediate text reprocessing
|
|
||||||
pub fn apply_font_settings_with_ui(&mut self, ctx: &egui::Context, ui: &egui::Ui) {
|
pub fn apply_font_settings_with_ui(&mut self, ctx: &egui::Context, ui: &egui::Ui) {
|
||||||
self.apply_font_settings(ctx);
|
self.apply_font_settings(ctx);
|
||||||
self.reprocess_text_for_font_change(ui);
|
self.reprocess_text_for_font_change(ui);
|
||||||
self.font_settings_changed = false;
|
self.font_settings_changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trigger immediate text reprocessing when font settings change
|
|
||||||
pub fn reprocess_text_for_font_change(&mut self, ui: &egui::Ui) {
|
pub fn reprocess_text_for_font_change(&mut self, ui: &egui::Ui) {
|
||||||
if let Some(active_tab) = self.get_active_tab() {
|
if let Some(active_tab) = self.get_active_tab() {
|
||||||
self.process_text_for_rendering(&active_tab.content.to_string(), ui);
|
self.process_text_for_rendering(&active_tab.content.to_string(), ui);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the available width for the text editor, accounting for line numbers and separator
|
|
||||||
pub fn calculate_editor_dimensions(&self, ui: &egui::Ui) -> EditorDimensions {
|
pub fn calculate_editor_dimensions(&self, ui: &egui::Ui) -> EditorDimensions {
|
||||||
let total_available_width = ui.available_width();
|
let total_available_width = ui.available_width();
|
||||||
|
|
||||||
@ -114,7 +108,6 @@ impl TextEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the available width for non-word-wrapped content based on processed text data
|
|
||||||
pub fn calculate_content_based_width(&self, ui: &egui::Ui) -> f32 {
|
pub fn calculate_content_based_width(&self, ui: &egui::Ui) -> f32 {
|
||||||
let processing_result = self.get_text_processing_result();
|
let processing_result = self.get_text_processing_result();
|
||||||
|
|
||||||
|
|||||||
@ -261,7 +261,6 @@ fn build_custom_theme_plist(
|
|||||||
|
|
||||||
let mut settings_array = Vec::new();
|
let mut settings_array = Vec::new();
|
||||||
|
|
||||||
// Global settings
|
|
||||||
let mut global_settings_dict = Dictionary::new();
|
let mut global_settings_dict = Dictionary::new();
|
||||||
let mut inner_global_settings = Dictionary::new();
|
let mut inner_global_settings = Dictionary::new();
|
||||||
inner_global_settings.insert("background".to_string(), Value::String(background_color.to_string()));
|
inner_global_settings.insert("background".to_string(), Value::String(background_color.to_string()));
|
||||||
@ -269,7 +268,6 @@ fn build_custom_theme_plist(
|
|||||||
global_settings_dict.insert("settings".to_string(), Value::Dictionary(inner_global_settings));
|
global_settings_dict.insert("settings".to_string(), Value::Dictionary(inner_global_settings));
|
||||||
settings_array.push(Value::Dictionary(global_settings_dict));
|
settings_array.push(Value::Dictionary(global_settings_dict));
|
||||||
|
|
||||||
// Comment scope
|
|
||||||
let mut comment_scope_dict = Dictionary::new();
|
let mut comment_scope_dict = Dictionary::new();
|
||||||
comment_scope_dict.insert("name".to_string(), Value::String("Comment".to_string()));
|
comment_scope_dict.insert("name".to_string(), Value::String("Comment".to_string()));
|
||||||
comment_scope_dict.insert("scope".to_string(), Value::String("comment".to_string()));
|
comment_scope_dict.insert("scope".to_string(), Value::String("comment".to_string()));
|
||||||
@ -279,7 +277,6 @@ fn build_custom_theme_plist(
|
|||||||
comment_scope_dict.insert("settings".to_string(), Value::Dictionary(comment_settings));
|
comment_scope_dict.insert("settings".to_string(), Value::Dictionary(comment_settings));
|
||||||
settings_array.push(Value::Dictionary(comment_scope_dict));
|
settings_array.push(Value::Dictionary(comment_scope_dict));
|
||||||
|
|
||||||
// String scope
|
|
||||||
let mut string_scope_dict = Dictionary::new();
|
let mut string_scope_dict = Dictionary::new();
|
||||||
string_scope_dict.insert("name".to_string(), Value::String("String".to_string()));
|
string_scope_dict.insert("name".to_string(), Value::String("String".to_string()));
|
||||||
string_scope_dict.insert("scope".to_string(), Value::String("string".to_string()));
|
string_scope_dict.insert("scope".to_string(), Value::String("string".to_string()));
|
||||||
@ -288,7 +285,6 @@ fn build_custom_theme_plist(
|
|||||||
string_scope_dict.insert("settings".to_string(), Value::Dictionary(string_settings));
|
string_scope_dict.insert("settings".to_string(), Value::Dictionary(string_settings));
|
||||||
settings_array.push(Value::Dictionary(string_scope_dict));
|
settings_array.push(Value::Dictionary(string_scope_dict));
|
||||||
|
|
||||||
// Keyword scope
|
|
||||||
let mut keyword_scope_dict = Dictionary::new();
|
let mut keyword_scope_dict = Dictionary::new();
|
||||||
keyword_scope_dict.insert("name".to_string(), Value::String("Keyword".to_string()));
|
keyword_scope_dict.insert("name".to_string(), Value::String("Keyword".to_string()));
|
||||||
keyword_scope_dict.insert("scope".to_string(), Value::String("keyword".to_string()));
|
keyword_scope_dict.insert("scope".to_string(), Value::String("keyword".to_string()));
|
||||||
@ -297,8 +293,6 @@ fn build_custom_theme_plist(
|
|||||||
keyword_scope_dict.insert("settings".to_string(), Value::Dictionary(keyword_settings));
|
keyword_scope_dict.insert("settings".to_string(), Value::Dictionary(keyword_settings));
|
||||||
settings_array.push(Value::Dictionary(keyword_scope_dict));
|
settings_array.push(Value::Dictionary(keyword_scope_dict));
|
||||||
|
|
||||||
// Add more scopes as needed...
|
|
||||||
|
|
||||||
root_dict.insert("settings".to_string(), Value::Array(settings_array));
|
root_dict.insert("settings".to_string(), Value::Array(settings_array));
|
||||||
|
|
||||||
Value::Dictionary(root_dict)
|
Value::Dictionary(root_dict)
|
||||||
|
|||||||
@ -158,7 +158,6 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Save state cache when content changes (after releasing the borrow)
|
|
||||||
if content_changed {
|
if content_changed {
|
||||||
if let Err(e) = app.save_state_cache() {
|
if let Err(e) = app.save_state_cache() {
|
||||||
eprintln!("Failed to save state cache: {e}");
|
eprintln!("Failed to save state cache: {e}");
|
||||||
|
|||||||
@ -32,9 +32,9 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
|
|||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui
|
if ui
|
||||||
.checkbox(&mut app.state_cache, "State Cache")
|
.checkbox(&mut app.state_cache, "Cache State")
|
||||||
.on_hover_text(
|
.on_hover_text(
|
||||||
"Save and restore open tabs and unsaved changes between sessions"
|
"Unsaved changes will be cached between sessions"
|
||||||
)
|
)
|
||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
@ -56,6 +56,12 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
|
|||||||
{
|
{
|
||||||
app.save_config();
|
app.save_config();
|
||||||
}
|
}
|
||||||
|
if ui
|
||||||
|
.checkbox(&mut app.syntax_highlighting, "Syntax Highlighting")
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
app.save_config();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
@ -79,11 +85,6 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
|
|||||||
{
|
{
|
||||||
app.save_config();
|
app.save_config();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
ui.add_space(4.0);
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
if ui
|
if ui
|
||||||
.checkbox(&mut app.hide_tab_bar, "Hide Tab Bar")
|
.checkbox(&mut app.hide_tab_bar, "Hide Tab Bar")
|
||||||
.on_hover_text("Hide the tab bar and show tab title in menu bar instead")
|
.on_hover_text("Hide the tab bar and show tab title in menu bar instead")
|
||||||
@ -91,6 +92,7 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
|
|||||||
{
|
{
|
||||||
app.save_config();
|
app.save_config();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user