- 1
//! Vakyartha's built-in blank packages, where a file created from scratch - 2
//! starts (docs/design/72-openxml-documents.md, "Creating from scratch"). - 3
//! - 4
//! They are written for Vakyartha, not copied from any application, and - 5
//! zipped with fixed timestamps, so one version always yields the same - 6
//! bytes. The parts are plain XML under `blank/` beside this crate. A blank - 7
//! has no content: a new file's content comes only from ops, which the edit - 8
//! engine checks by a re-read like any other edit. - 9
- 10
use std::io::{Cursor, Write}; - 11
- 12
use crate::{Format, FormatKind, Vocabulary}; - 13
- 14
const THEME: &str = include_str!("../blank/shared/theme.xml"); - 15
const PACKAGE_RELS: &str = include_str!("../blank/shared/package.rels"); - 16
const CORE: &str = include_str!("../blank/shared/core.xml"); - 17
const APP: &str = include_str!("../blank/shared/app.xml"); - 18
- 19
const WORD: &[(&str, &str)] = &[ - 20
( - 21
"[Content_Types].xml", - 22
include_str!("../blank/word/content-types.xml"), - 23
), - 24
( - 25
"word/document.xml", - 26
include_str!("../blank/word/document.xml"), - 27
), - 28
( - 29
"word/_rels/document.xml.rels", - 30
include_str!("../blank/word/document.xml.rels"), - 31
), - 32
("word/styles.xml", include_str!("../blank/word/styles.xml")), - 33
( - 34
"word/numbering.xml", - 35
include_str!("../blank/word/numbering.xml"), - 36
), - 37
( - 38
"word/settings.xml", - 39
include_str!("../blank/word/settings.xml"), - 40
), - 41
( - 42
"word/fontTable.xml", - 43
include_str!("../blank/word/fontTable.xml"), - 44
), - 45
]; - 46
- 47
const EXCEL: &[(&str, &str)] = &[ - 48
( - 49
"[Content_Types].xml", - 50
include_str!("../blank/excel/content-types.xml"), - 51
), - 52
( - 53
"xl/workbook.xml", - 54
include_str!("../blank/excel/workbook.xml"), - 55
), - 56
( - 57
"xl/_rels/workbook.xml.rels", - 58
include_str!("../blank/excel/workbook.xml.rels"), - 59
), - 60
( - 61
"xl/worksheets/sheet1.xml", - 62
include_str!("../blank/excel/sheet1.xml"), - 63
), - 64
("xl/styles.xml", include_str!("../blank/excel/styles.xml")), - 65
]; - 66
- 67
const POWERPOINT: &[(&str, &str)] = &[ - 68
( - 69
"[Content_Types].xml", - 70
include_str!("../blank/powerpoint/content-types.xml"), - 71
), - 72
( - 73
"ppt/presentation.xml", - 74
include_str!("../blank/powerpoint/presentation.xml"), - 75
), - 76
( - 77
"ppt/_rels/presentation.xml.rels", - 78
include_str!("../blank/powerpoint/presentation.xml.rels"), - 79
), - 80
( - 81
"ppt/slideMasters/slideMaster1.xml", - 82
include_str!("../blank/powerpoint/slideMaster1.xml"), - 83
), - 84
( - 85
"ppt/slideMasters/_rels/slideMaster1.xml.rels", - 86
include_str!("../blank/powerpoint/slideMaster1.xml.rels"), - 87
), - 88
( - 89
"ppt/slideLayouts/slideLayout1.xml", - 90
include_str!("../blank/powerpoint/slideLayout1.xml"), - 91
), - 92
( - 93
"ppt/slideLayouts/_rels/slideLayout1.xml.rels", - 94
include_str!("../blank/powerpoint/slideLayout1.xml.rels"), - 95
), - 96
( - 97
"ppt/slideLayouts/slideLayout2.xml", - 98
include_str!("../blank/powerpoint/slideLayout2.xml"), - 99
), - 100
( - 101
"ppt/slideLayouts/_rels/slideLayout2.xml.rels", - 102
include_str!("../blank/powerpoint/slideLayout2.xml.rels"), - 103
), - 104
( - 105
"ppt/slideLayouts/slideLayout3.xml", - 106
include_str!("../blank/powerpoint/slideLayout3.xml"), - 107
), - 108
( - 109
"ppt/slideLayouts/_rels/slideLayout3.xml.rels", - 110
include_str!("../blank/powerpoint/slideLayout3.xml.rels"), - 111
), - 112
( - 113
"ppt/slideLayouts/slideLayout4.xml", - 114
include_str!("../blank/powerpoint/slideLayout4.xml"), - 115
), - 116
( - 117
"ppt/slideLayouts/_rels/slideLayout4.xml.rels", - 118
include_str!("../blank/powerpoint/slideLayout4.xml.rels"), - 119
), - 120
( - 121
"ppt/slideLayouts/slideLayout5.xml", - 122
include_str!("../blank/powerpoint/slideLayout5.xml"), - 123
), - 124
( - 125
"ppt/slideLayouts/_rels/slideLayout5.xml.rels", - 126
include_str!("../blank/powerpoint/slideLayout5.xml.rels"), - 127
), - 128
( - 129
"ppt/slideLayouts/slideLayout6.xml", - 130
include_str!("../blank/powerpoint/slideLayout6.xml"), - 131
), - 132
( - 133
"ppt/slideLayouts/_rels/slideLayout6.xml.rels", - 134
include_str!("../blank/powerpoint/slideLayout6.xml.rels"), - 135
), - 136
( - 137
"ppt/notesMasters/notesMaster1.xml", - 138
include_str!("../blank/powerpoint/notesMaster1.xml"), - 139
), - 140
( - 141
"ppt/notesMasters/_rels/notesMaster1.xml.rels", - 142
include_str!("../blank/powerpoint/notesMaster1.xml.rels"), - 143
), - 144
( - 145
"ppt/presProps.xml", - 146
include_str!("../blank/powerpoint/presProps.xml"), - 147
), - 148
( - 149
"ppt/viewProps.xml", - 150
include_str!("../blank/powerpoint/viewProps.xml"), - 151
), - 152
( - 153
"ppt/tableStyles.xml", - 154
include_str!("../blank/powerpoint/tableStyles.xml"), - 155
), - 156
]; - 157
- 158
/// The layouts a blank deck offers, by the names `add_slide_from_layout` - 159
/// takes, each with the placeholder keys its slides fill. - 160
pub const DECK_LAYOUTS: &[(&str, &str)] = &[ - 161
("Title Slide", "title, subtitle"), - 162
("Title and Content", "title, body"), - 163
("Section Header", "title, body"), - 164
("Two Content", "title, idx:1, idx:2"), - 165
("Title Only", "title"), - 166
("Blank", "no placeholders"), - 167
]; - 168
- 169
/// The paragraph styles a blank Word document offers, by name. - 170
pub const DOCUMENT_STYLES: &[&str] = &[ - 171
"Normal", - 172
"Title", - 173
"Subtitle", - 174
"Heading 1", - 175
"Heading 2", - 176
"Heading 3", - 177
"List Bullet", - 178
"List Number", - 179
"Quote", - 180
]; - 181
- 182
/// The one sheet a blank workbook has. - 183
pub const WORKBOOK_SHEET: &str = "Sheet1"; - 184
- 185
/// The blank package a new file named as `format` starts from. It is the - 186
/// document form of the vocabulary; a template name (`.dotx`, `.xltx`, - 187
/// `.potx`) is made by the edit engine changing the main part's content - 188
/// type, exactly as it does when a template is the source. Refuses a - 189
/// macro-enabled format (O10) and Visio, which has no editing engine yet. - 190
pub fn blank(format: Format) -> Result<Vec<u8>, String> { - 191
if format.macro_enabled || format.kind == FormatKind::AddIn { - 192
return Err(format!( - 193
"Vakyartha never makes a macro-enabled file, so a .{} cannot be created; name it .{} instead", - 194
format.extension(), - 195
Format { - 196
macro_enabled: false, - 197
kind: if format.kind == FormatKind::AddIn { - 198
FormatKind::Document - 199
} else { - 200
format.kind - 201
}, - 202
..format - 203
} - 204
.extension() - 205
)); - 206
} - 207
let (main, parts, major, minor, theme) = match format.vocabulary { - 208
Vocabulary::Word => ( - 209
"word/document.xml", - 210
WORD, - 211
"Aptos Display", - 212
"Aptos", - 213
&["word/theme/theme1.xml"][..], - 214
), - 215
Vocabulary::Excel => ( - 216
"xl/workbook.xml", - 217
EXCEL, - 218
"Aptos Display", - 219
"Aptos Narrow", - 220
&["xl/theme/theme1.xml"][..], - 221
), - 222
Vocabulary::PowerPoint => ( - 223
"ppt/presentation.xml", - 224
POWERPOINT, - 225
"Aptos Display", - 226
"Aptos", - 227
&["ppt/theme/theme1.xml", "ppt/theme/theme2.xml"][..], - 228
), - 229
Vocabulary::Visio => { - 230
return Err( - 231
"a Visio drawing cannot be created from scratch yet; Vakyartha reads Visio files but has no Visio editing yet. Tell the person so, and do not build one with a command or script".into(), - 232
); - 233
} - 234
}; - 235
let theme_xml = THEME - 236
.replace("{{MAJOR}}", major) - 237
.replace("{{MINOR}}", minor); - 238
let package_rels = PACKAGE_RELS.replace("{{MAIN}}", main); - 239
let mut entries: Vec<(&str, &str)> = Vec::with_capacity(parts.len() + 6); - 240
entries.push(parts[0]); - 241
entries.push(("_rels/.rels", &package_rels)); - 242
entries.push(("docProps/core.xml", CORE)); - 243
entries.push(("docProps/app.xml", APP)); - 244
entries.extend_from_slice(&parts[1..]); - 245
for name in theme { - 246
entries.push((name, &theme_xml)); - 247
} - 248
zip(&entries) - 249
} - 250
- 251
/// Zips the parts in order with Deflate and a fixed timestamp. - 252
fn zip(entries: &[(&str, &str)]) -> Result<Vec<u8>, String> { - 253
let mut writer = zip::ZipWriter::new(Cursor::new(Vec::new())); - 254
let options = zip::write::SimpleFileOptions::default() - 255
.compression_method(zip::CompressionMethod::Deflated) - 256
.last_modified_time(zip::DateTime::default()); - 257
for (name, text) in entries { - 258
writer - 259
.start_file(*name, options) - 260
.and_then(|()| writer.write_all(text.as_bytes()).map_err(Into::into)) - 261
.map_err(|error| format!("could not build the blank package: {error}"))?; - 262
} - 263
writer - 264
.finish() - 265
.map(Cursor::into_inner) - 266
.map_err(|error| format!("could not build the blank package: {error}")) - 267
} - 268
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.