use std::hash::{Hash, Hasher};
use crate::widgets::{
code_widget::foundation::CodeLanguage,
document_viewer::{
CacheState, DisplaySettings, DocumentOutlineItem, ScrollState, SelectionState, SourceState,
VimState,
},
};
#[derive(Debug, Clone, Default)]
pub struct CodeState {
pub source: SourceState,
pub scroll: ScrollState,
pub selection: SelectionState,
pub vim: VimState,
pub display: DisplaySettings,
pub cache: CacheState,
pub outline: Vec<DocumentOutlineItem>,
pub outline_hovered: bool,
pub outline_hovered_entry: Option<usize>,
pub language_override: Option<String>,
}
impl CodeState {
pub fn set_language_override(&mut self, language: impl Into<String>) {
self.language_override = Some(language.into());
}
pub fn selected_text(&self) -> Option<String> {
let range = self.selection.selected_range()?;
let lines: Vec<&str> = self.source.content().lines().collect();
let selected: Vec<&str> = range
.filter_map(|index| lines.get(index).copied())
.collect();
if selected.is_empty() {
None
} else {
Some(selected.join("\n"))
}
}
pub fn copy_selection(&mut self) -> Option<String> {
let text = self.selected_text()?;
self.selection.last_copied_text = Some(text.clone());
Some(text)
}
pub fn language_override(&self) -> Option<&str> {
self.language_override.as_deref()
}
pub fn remember_render_cache(
&mut self,
content: &str,
display: &DisplaySettings,
language: &CodeLanguage,
) {
let mut hasher = std::collections::hash_map::DefaultHasher::new();
content.hash(&mut hasher);
language.hash(&mut hasher);
display.show_line_numbers.hash(&mut hasher);
display.relative_line_numbers.hash(&mut hasher);
display.highlight_current_line.hash(&mut hasher);
display.show_outline.hash(&mut hasher);
display.tab_width.hash(&mut hasher);
self.cache.set_content_hash(hasher.finish());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cache_hash_changes_with_content() {
let mut state = CodeState::default();
let display = DisplaySettings::default();
state.remember_render_cache("one", &display, &CodeLanguage::Rust);
let first = state.cache.content_hash;
state.remember_render_cache("two", &display, &CodeLanguage::Rust);
assert_ne!(first, state.cache.content_hash);
}
#[test]
fn cache_hash_changes_with_display() {
let mut state = CodeState::default();
let mut display = DisplaySettings::default();
state.remember_render_cache("one", &display, &CodeLanguage::Rust);
let first = state.cache.content_hash;
display.show_outline = !display.show_outline;
state.remember_render_cache("one", &display, &CodeLanguage::Rust);
assert_ne!(first, state.cache.content_hash);
}
}