use std::{
collections::HashMap,
sync::{LazyLock, Mutex},
};
use crate::text::RegexHaystack;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ScrollOff {
pub x: u8,
pub y: u8,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PrintOpts {
pub wrap_lines: bool,
pub wrap_on_word: bool,
pub wrapping_cap: Option<u32>,
pub indent_wraps: bool,
pub tabstop: u8,
pub print_new_line: bool,
pub scrolloff: ScrollOff,
pub force_scrolloff: bool,
pub extra_word_chars: &'static [char],
pub show_ghosts: bool,
pub allow_overscroll: bool,
}
impl PrintOpts {
pub const fn new() -> Self {
Self {
wrap_lines: false,
wrap_on_word: false,
wrapping_cap: None,
indent_wraps: true,
tabstop: 4,
print_new_line: false,
scrolloff: ScrollOff { x: 3, y: 3 },
extra_word_chars: &[],
force_scrolloff: false,
show_ghosts: true,
allow_overscroll: false,
}
}
pub const fn default_for_input() -> Self {
Self {
wrap_lines: false,
wrap_on_word: false,
wrapping_cap: None,
indent_wraps: true,
tabstop: 4,
print_new_line: true,
scrolloff: ScrollOff { x: 3, y: 3 },
extra_word_chars: &[],
force_scrolloff: false,
show_ghosts: true,
allow_overscroll: true,
}
}
#[inline]
pub const fn wrap_width(&self, width: u32) -> Option<u32> {
if !self.wrap_lines {
None
} else if let Some(cap) = self.wrapping_cap {
Some(cap)
} else {
Some(width)
}
}
#[inline]
pub fn tabstop_spaces_at(&self, x: u32) -> u32 {
self.tabstop as u32 - (x % self.tabstop as u32)
}
pub fn word_chars_regex(&self) -> &'static str {
PATTERNS
.lock()
.unwrap()
.entry(self.extra_word_chars)
.or_insert_with(|| {
format!(
r"[\w{}]",
escape_special(self.extra_word_chars.iter().collect()),
)
.leak()
})
}
pub fn is_word_char(&self, char: char) -> bool {
let pat = *PATTERNS
.lock()
.unwrap()
.entry(self.extra_word_chars)
.or_insert_with(|| {
format!(
r"[\w{}]",
escape_special(self.extra_word_chars.iter().collect()),
)
.leak()
});
let mut bytes = [b'\0'; 4];
let str = char.encode_utf8(&mut bytes);
str.matches_pat(pat).unwrap()
}
}
impl Default for PrintOpts {
fn default() -> Self {
Self::new()
}
}
#[doc(hidden)]
pub fn escape_special(mut regex: String) -> String {
for (i, char) in regex.char_indices().collect::<Vec<_>>() {
if let '(' | ')' | '{' | '}' | '[' | ']' | '$' | '^' | '.' | '*' | '+' | '?' | '|' = char {
regex.insert(i, '\\');
}
}
regex
}
static PATTERNS: LazyLock<Mutex<HashMap<&[char], &'static str>>> = LazyLock::new(|| {
let mut map: HashMap<&[char], _> = HashMap::new();
map.insert(&[], r"[\w]");
Mutex::new(map)
});