1#[path = "../src/flush.rs"]
2mod flush;
3#[path = "support/typing.rs"]
4mod typing;
5
6use onestore::{
7 document::{Format, Layout},
8 op::{Edit, Op, PageOp},
9 page::{
10 Outline, PageObject, PageParagraph, Paragraph, ParagraphContent, TextObject, text::new_id,
11 },
12};
13use std::{fs, io::Write};
14
15/// A paragraph holding `text` in OneNote's default text style.
16fn paragraph(text: &str) -> Result<PageParagraph, Box<dyn std::error::Error>> {
17 let format = Format {
18 font: Some("Calibri".into()),
19 font_size: Some(11.0),
20 language: Some(0x409),
21 ..Format::default()
22 };
23 Ok(PageParagraph {
24 id: new_id()?,
25 parent: None,
26 level: 1,
27 style: None,
28 format: Format::default(),
29 content: ParagraphContent::Text(TextObject {
30 id: new_id()?,
31 date_field: None,
32 text: Paragraph::new(text.into(), format),
33 tags: Vec::new(),
34 }),
35 lists: Vec::new(),
36 tags: Vec::new(),
37 media: Default::default(),
38 collapsed: false,
39 })
40}
41
42fn main() -> Result<(), Box<dyn std::error::Error>> {
43 let args: Vec<_> = std::env::args().skip(1).collect();
44 let usage = "Usage: insert paragraph INPUT OUTPUT|--in-place SPACE CONTAINER BEFORE|- TEXT AUTHOR\n insert outline INPUT OUTPUT|--in-place SPACE X Y TEXT AUTHOR";
45 let (op, object, text, author) = match args.first().map(String::as_str) {
46 Some("paragraph") if args.len() == 8 => {
47 let paragraph = paragraph(&args[6])?;
48 let (object, text) = (paragraph.id, paragraph.text().unwrap().id);
49 let op = PageOp::Insert {
50 container: args[4].parse()?,
51 before: if args[5] == "-" {
52 None
53 } else {
54 Some(args[5].parse()?)
55 },
56 paragraphs: vec![paragraph],
57 };
58 (op, object, text, &args[7])
59 }
60 Some("outline") if args.len() == 8 => {
61 let paragraph = paragraph(&args[6])?;
62 let text = paragraph.text().unwrap().id;
63 let object = new_id()?;
64 let op = PageOp::Add {
65 object: PageObject::Outline(Outline {
66 id: object,
67 title: false,
68 min_width: None,
69 layout: Layout {
70 x: Some(args[4].parse()?),
71 y: Some(args[5].parse()?),
72 ..Layout::default()
73 },
74 indents: Vec::new(),
75 paragraphs: vec![paragraph],
76 unsupported: Vec::new(),
77 }),
78 before: None,
79 };
80 (op, object, text, &args[7])
81 }
82 _ => return Err(usage.into()),
83 };
84 let source = onestore::read_file(&args[1])?;
85 let edit = Edit {
86 at: typing::now(),
87 ops: vec![Op::Page {
88 space: args[3].parse()?,
89 op,
90 }],
91 };
92 let transaction =
93 typing::sealed(&source, author, &edit)?.ok_or("The insertion stores nothing")?;
94 let mut record = serde_json::json!({"edit": edit, "object": object, "text_object": text});
95 if args[2] == "--in-place" {
96 if let Err(error) = transaction.commit_file(&args[1]) {
97 record["state"] = format!("{:?}", error.state).into();
98 record["error"] = error.error.to_string().into();
99 println!("{record}");
100 std::process::exit(2);
101 }
102 record["state"] = "Committed".into();
103 } else {
104 let mut written = source;
105 transaction.apply(&mut written)?;
106 let mut file = fs::OpenOptions::new()
107 .write(true)
108 .create_new(true)
109 .open(&args[2])?;
110 file.write_all(&written)?;
111 flush::flush(&file)?;
112 record["state"] = "Created".into();
113 }
114 println!("{record}");
115 Ok(())
116}