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
109
110
111
112
113
114
115
116
117
118
use super::*;
use crate::walkers::*;
use failure::Error;
use oatie::doc::*;
use oatie::rtf::*;
use oatie::stepper::DocStepper;
#[derive(Debug)]
pub enum StyleOp {
AddStyle(RtfStyle, Option<String>),
RemoveStyle(RtfStyle),
}
pub fn apply_style(
ctx: ActionContext,
style: RtfStyle,
value: Option<String>,
) -> Result<Op<RtfSchema>, Error> {
restyle(ctx, vec![StyleOp::AddStyle(style, value)])
}
pub fn remove_styles(ctx: ActionContext, styles: StyleSet) -> Result<Op<RtfSchema>, Error> {
restyle(
ctx,
styles
.styles()
.into_iter()
.map(|style| StyleOp::RemoveStyle(style))
.collect(),
)
}
pub fn restyle(ctx: ActionContext, ops: Vec<StyleOp>) -> Result<Op<RtfSchema>, Error> {
let (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(Op::empty());
}
};
let delta = walker_end.delta(&walker_start).unwrap_or(0);
if delta == 0 {
return Ok(Op::empty());
}
let mut add_styles = hashset![];
for op in &ops {
if let &StyleOp::AddStyle(ref style, _) = op {
add_styles.insert(style.to_owned());
}
}
let mut remove_styles = hashset![];
for op in &ops {
if let &StyleOp::RemoveStyle(ref style) = op {
remove_styles.insert(style.to_owned());
}
}
let mut writer = walker_start.to_writer();
if !remove_styles.is_empty() {
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(..)) => {
writer.del.begin();
doc1.enter();
}
Some(DocText(_, ref text)) => {
writer.del.place(&DelStyles(
text.char_len(),
StyleSet::from(remove_styles.clone()),
));
doc1.skip(text.char_len());
}
None => {
writer.del.exit();
doc1.exit();
}
}
}
}
if !add_styles.is_empty() {
let mut doc1 = walker_start.doc().to_owned();
let doc2 = walker_end.doc().to_owned();
while doc1 != doc2 {
match doc1.head() {
Some(DocGroup(..)) => {
writer.add.begin();
doc1.enter();
}
Some(DocText(_, ref text)) => {
writer.add.place(&AddStyles(
text.char_len(),
StyleSet::from(add_styles.clone()),
));
doc1.skip(text.char_len());
}
None => {
writer.add.exit();
doc1.exit();
}
}
}
}
Ok(writer.exit_result())
}