pure-tui 0.2.2

A modern terminal-based word processor for Markdown and other structured text documents
Documentation
use super::*;

fn pointer_to_root_span(root_index: usize) -> CursorPointer {
    CursorPointer {
        paragraph_path: ParagraphPath::new_root(root_index),
        span_path: SpanPath::new(vec![0]),
        offset: 0,
        segment_kind: SegmentKind::Text,
    }
}

fn pointer_to_checklist_item_span(root_index: usize, item_index: usize) -> CursorPointer {
    let mut path = ParagraphPath::new_root(root_index);
    path.push_checklist_item(vec![item_index]);
    CursorPointer {
        paragraph_path: path,
        span_path: SpanPath::new(vec![0]),
        offset: 0,
        segment_kind: SegmentKind::Text,
    }
}

fn text_paragraph(text: &str) -> Paragraph {
    Paragraph::new_text().with_content(vec![Span::new_text(text)])
}

fn checklist(items: &[&str]) -> Paragraph {
    let checklist_items = items
        .iter()
        .map(|text| ChecklistItem::new(false).with_content(vec![Span::new_text(*text)]))
        .collect::<Vec<_>>();
    Paragraph::new_checklist().with_checklist_items(checklist_items)
}

#[test]
fn apply_inline_style_splits_span() {
    let document = Document::new().with_paragraphs(vec![text_paragraph("hello world")]);
    let mut editor = DocumentEditor::new(document);

    let mut start = pointer_to_root_span(0);
    start.offset = 0;
    let mut end = pointer_to_root_span(0);
    end.offset = 5;

    assert!(
        editor.apply_inline_style_to_selection(&(start.clone(), end.clone()), InlineStyle::Bold)
    );

    let doc = editor.document();
    let paragraph = &doc.paragraphs[0];
    assert_eq!(paragraph.content().len(), 2);
    assert_eq!(paragraph.content()[0].text, "hello");
    assert_eq!(paragraph.content()[0].style, InlineStyle::Bold);
    assert_eq!(paragraph.content()[1].text, " world");
    assert_eq!(paragraph.content()[1].style, InlineStyle::None);
}

#[test]
fn apply_inline_style_across_segments() {
    let paragraph =
        Paragraph::new_text().with_content(vec![Span::new_text("hello "), Span::new_text("world")]);
    let document = Document::new().with_paragraphs(vec![paragraph]);
    let mut editor = DocumentEditor::new(document);

    let mut start = pointer_to_root_span(0);
    start.span_path = SpanPath::new(vec![0]);
    start.offset = 3;

    let mut end = pointer_to_root_span(0);
    end.span_path = SpanPath::new(vec![1]);
    end.offset = 2;

    assert!(editor.apply_inline_style_to_selection(&(start, end), InlineStyle::Underline));

    let doc = editor.document();
    let spans = doc.paragraphs[0].content();
    assert_eq!(spans.len(), 3);
    assert_eq!(spans[0].text, "hel");
    assert_eq!(spans[0].style, InlineStyle::None);
    assert_eq!(spans[1].text, "lo wo");
    assert_eq!(spans[1].style, InlineStyle::Underline);
    assert_eq!(spans[2].text, "rld");
    assert_eq!(spans[2].style, InlineStyle::None);
}

#[test]
fn clear_inline_style_resets_to_plain() {
    let document = Document::new().with_paragraphs(vec![text_paragraph("styled text")]);
    let mut editor = DocumentEditor::new(document);

    let mut start = pointer_to_root_span(0);
    start.offset = 0;
    let mut end = pointer_to_root_span(0);
    end.offset = 6;

    assert!(
        editor.apply_inline_style_to_selection(&(start.clone(), end.clone()), InlineStyle::Code)
    );
    assert!(editor.apply_inline_style_to_selection(&(start, end), InlineStyle::None));

    let doc = editor.document();
    let spans = doc.paragraphs[0].content();
    assert_eq!(spans.len(), 1);
    assert_eq!(spans[0].text, "styled text");
    assert_eq!(spans[0].style, InlineStyle::None);
}

#[test]
fn apply_inline_style_in_checklist_item() {
    let document = Document::new().with_paragraphs(vec![checklist(&["make tea"])]);
    let mut editor = DocumentEditor::new(document);

    let start = pointer_to_checklist_item_span(0, 0);
    let mut end = start.clone();
    end.offset = 4;

    assert!(
        editor.apply_inline_style_to_selection(&(start.clone(), end.clone()), InlineStyle::Italic)
    );

    let doc = editor.document();
    let Paragraph::Checklist { items } = &doc.paragraphs[0] else {
        panic!("expected checklist paragraph");
    };
    assert_eq!(items.len(), 1);
    let item = &items[0];
    assert_eq!(item.content.len(), 2);
    assert_eq!(item.content[0].text, "make");
    assert_eq!(item.content[0].style, InlineStyle::Italic);
    assert_eq!(item.content[1].text, " tea");
    assert_eq!(item.content[1].style, InlineStyle::None);
}