#![forbid(unsafe_code)]
#![warn(missing_docs, clippy::pedantic)]
#![allow(clippy::must_use_candidate)]
mod editor;
mod job;
pub use editor::{Laid, RichEdit};
pub use job::{OffsetMap, ParagraphJob};
use std::fmt::Debug;
use std::hash::Hash;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Position<P> {
pub paragraph: P,
pub offset: usize,
}
impl<P> Position<P> {
pub fn new(paragraph: P, offset: usize) -> Self {
Self { paragraph, offset }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Selection<P> {
pub anchor: Position<P>,
pub focus: Position<P>,
}
impl<P: Clone + PartialEq> Selection<P> {
pub fn caret(at: Position<P>) -> Self {
Self {
anchor: at.clone(),
focus: at,
}
}
pub fn is_caret(&self) -> bool {
self.anchor == self.focus
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Edit<'a, P> {
Replace {
from: Position<P>,
to: Position<P>,
text: &'a str,
},
Split {
at: Position<P>,
},
Format {
from: Position<P>,
to: Position<P>,
mark: Mark,
on: bool,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Mark {
Bold,
Italic,
Underline,
Strike,
}
impl Mark {
pub const ALL: [Self; 4] = [Self::Bold, Self::Italic, Self::Underline, Self::Strike];
}
pub trait Model {
type Paragraph: Clone + Eq + Hash + Debug;
fn text(&self, paragraph: &Self::Paragraph) -> Option<String>;
fn next(&self, paragraph: &Self::Paragraph) -> Option<Self::Paragraph>;
fn previous(&self, paragraph: &Self::Paragraph) -> Option<Self::Paragraph>;
fn first(&self) -> Option<Self::Paragraph>;
fn last(&self) -> Option<Self::Paragraph>;
fn marked(
&self,
from: &Position<Self::Paragraph>,
to: &Position<Self::Paragraph>,
mark: Mark,
) -> Option<bool> {
let _ = (from, to, mark);
Some(false)
}
fn apply(
&mut self,
edit: Edit<'_, Self::Paragraph>,
new_step: bool,
) -> Option<Position<Self::Paragraph>>;
}