1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use super::*;
use crate::walkers::*;
use failure::Error;
use oatie::doc::*;
use oatie::rtf::{
Attrs,
RtfSchema,
};
use oatie::stepper::DocStepper;
use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct CaretState {
pub block: String,
pub in_list: bool,
pub styles: HashSet<RtfStyle>,
}
pub fn identify_styles(ctx: &ActionContext) -> Result<StyleSet, Error> {
let (mut walker_start, walker_end) =
match (ctx.get_walker(Pos::Start), ctx.get_walker(Pos::End)) {
(Ok(walker_start), Ok(walker_end)) => (walker_start, walker_end),
_ => {
return Ok(StyleSet::new());
}
};
let delta = walker_end.delta(&walker_start).unwrap_or(0);
if delta == 0 {
loop {
match walker_start.doc().unhead() {
Some(DocGroup(ref attrs, _)) => {
if let Attrs::Caret { .. } = attrs {
walker_start.stepper.doc.prev();
} else {
break;
}
}
Some(DocText(ref styles, _)) => {
return Ok(styles.clone());
}
_ => break,
}
}
return Ok(StyleSet::new());
}
let mut existing_styles: HashSet<RtfStyle> = hashset![];
let mut doc1: DocStepper<RtfSchema> = walker_start.doc().to_owned();
let doc2: DocStepper<RtfSchema> = walker_end.doc().to_owned();
while doc1 != doc2 {
match doc1.head() {
Some(DocGroup(..)) => {
doc1.enter();
}
Some(DocText(ref styles, ref text)) => {
existing_styles.extend(styles.styles());
doc1.skip(text.char_len());
}
None => {
doc1.exit();
}
}
}
return Ok(StyleSet::from(existing_styles));
}
pub fn identify_block(ctx: ActionContext) -> Result<CaretState, Error> {
let styles = identify_styles(&ctx)?;
let mut walker = ctx.get_walker(Pos::Focus)?;
assert!(walker.back_block());
if let Some(DocGroup(ref attrs, _)) = walker.doc().head() {
let tag = match attrs {
Attrs::Header(level) => format!("h{}", level),
Attrs::Html => format!("html"),
Attrs::Code => format!("pre"),
Attrs::Rule => format!("hr"),
Attrs::Caret { .. } => format!("caret"),
Attrs::Para => format!("p"),
Attrs::ListItem => format!("bullet"),
};
let mut in_list = false;
if walker.parent() {
if let Some(DocGroup(ref attrs_2, _)) = walker.doc().head() {
in_list = *attrs_2 == Attrs::ListItem
}
}
Ok(CaretState {
block: tag,
in_list,
styles: styles.styles(),
})
} else {
bail!("Expected a DocGroup from back_block");
}
}