My personal project and infrastructure archive
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nomicon/prototypes/novelist/novelist-data/src/lib.rs

78 lines
2.4 KiB

pub mod file;
mod tags;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use tags::RangeState;
pub use tags::{BoundState, Format, TagEntry};
/// Main content buffer of a Novelist file
///
/// The content is a simple text buffer of UTF-8 strings. Formatting
/// tags are applied independently via the tags abstraction.
pub struct Buffer {
// TODO: how does mixed RTL and LTR text get handled here?
pub content: Mutex<String>,
pub tags: Mutex<VecDeque<TagEntry>>,
}
/// A glue trait to connect the storage buffer to a UI toolkit
pub trait PopulateBuffer {
/// Populate a UI text buffer from a storage buffer
fn populate(&self, buffer: &Buffer);
}
impl Buffer {
/// Create a new empty Buffer
pub fn new() -> Arc<Self> {
Arc::new(Self {
content: Mutex::new(String::new()),
tags: Mutex::new(vec![].into()),
})
}
/// Pass a UI buffer to populate from this storage buffer
pub fn populate_ui(self: &Arc<Self>, hook: &impl PopulateBuffer) {
hook.populate(self)
}
/// Toggle a style for a particular range of characters
///
/// This function MUST handle specific corner cases around
/// overlapping ranges.
///
/// Returns a set of styles that MUST be applied to the TextBuffer
pub fn toggle_style(
self: &Arc<Self>,
(start, end): (i32, i32),
style: Format,
) -> Vec<(i32, i32, Format)> {
// 1. Go through linked list and compare list-pos to new-pos
// 2. If NoOverlap, continue
// 3. If BeforeOverlap, expand start-number
// 4. If FullOverlap, ignore (return)
// 5. If AfterOverlap, expand end-number
// 6. If no match was found: insert && sort
// The action we would like to apply
let target = TagEntry { start, end, style };
// Lock existing tags and iterate through them
let mut tags = self.tags.lock().unwrap();
for entry in tags.iter_mut() {
// First perform a simple boundry check
match entry.in_range(&target) {
RangeState::Under => continue,
RangeState::Over => break,
RangeState::InRange => {},
}
// If full-overlap we invert the desired action
// Then handle before and after overlapjjjjjjtncthgki.iidukntxgbeubyx.ixptxddcdpexe
}
todo!()
}
}