ppt-rs 0.2.14

Create, read, and update PowerPoint 2007+ (.pptx) files with rich formatting, bullet styles, themes, and templates.
Documentation
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
//! Command-line argument parser using clap

use clap::{Parser as ClapParser, Subcommand, ValueEnum};

#[derive(ClapParser, Debug)]
#[command(name = "pptcli")]
#[command(about = "PowerPoint Generator - Create, read, and update PowerPoint 2007+ (.pptx) files")]
#[command(
    long_about = "pptcli - A command-line tool for generating PowerPoint presentations from Markdown, webpages, or programmatically.

Examples:
  # Create a simple presentation
  pptcli create output.pptx --title \"My Presentation\" --slides 5

  # Convert Markdown to PowerPoint
  pptcli md2ppt slides.md presentation.pptx

  # Auto-generate output filename from Markdown
  pptcli md2ppt slides.md

  # Convert webpage to PowerPoint (requires --features web2ppt)
  pptcli web2ppt https://example.com -o output.pptx

  # Validate a PPTX file
  pptcli validate presentation.pptx

  # Show presentation information
  pptcli info presentation.pptx"
)]
#[command(version)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,
}

#[derive(Subcommand, Debug)]
pub enum Commands {
    /// Create a new presentation
    #[command(
        long_about = "Create a new PowerPoint presentation with the specified number of slides.

Examples:
  pptcli create output.pptx --title \"My Presentation\" --slides 5
  pptcli create report.pptx --slides 10"
    )]
    Create {
        /// Output file path (.pptx)
        #[arg(value_name = "FILE", help = "Path to the output PPTX file")]
        output: String,

        /// Presentation title
        #[arg(long, help = "Title of the presentation (stored in metadata)")]
        title: Option<String>,

        /// Number of slides to create
        #[arg(long, default_value_t = 1, help = "Number of blank slides to create")]
        slides: usize,

        /// Template file to use
        #[arg(long, help = "Template PPTX file to use as base (not yet implemented)")]
        template: Option<String>,
    },

    /// Generate PPTX from Markdown file
    #[command(
        name = "md2ppt",
        alias = "from-md",
        alias = "from-markdown",
        long_about = "Convert a Markdown file to a PowerPoint presentation.

Supported Markdown Features:
  # Heading      → New slide with title
  ## Subheading  → Bold bullet point
  - Bullet       → Bullet points (also *, +)
  1. Numbered    → Numbered list items
  **bold**       → Bold text
  *italic*       → Italic text
  `code`         → Inline code
  > Blockquote   → Speaker notes
  | Table |      → Tables (GFM style)
  ```code```     → Code blocks (as shapes)
  ```mermaid     → Mermaid diagrams (12 types)
  ---            → Slide break (continuation)

Example Markdown:
  # Introduction
  - Welcome to the presentation
  - **Key point** with emphasis

  # Data
  | Name | Value |
  |------|-------|
  | A    | 100   |

  > Speaker notes go here

Examples:
  pptcli md2ppt slides.md presentation.pptx
  pptcli md2ppt slides.md --title \"My Presentation\"
  pptcli md2ppt slides.md  # Auto-generates slides.pptx"
    )]
    Md2Ppt {
        /// Input markdown file
        #[arg(value_name = "INPUT", help = "Path to the input Markdown file")]
        input: String,

        /// Output PPTX file (optional: auto-generated from input if not provided)
        #[arg(
            value_name = "OUTPUT",
            help = "Path to the output PPTX file (default: INPUT.pptx)"
        )]
        output: Option<String>,

        /// Presentation title
        #[arg(long, help = "Title of the presentation (overrides Markdown content)")]
        title: Option<String>,
    },

    /// Show presentation information
    #[command(long_about = "Display information about a PPTX file.

Shows file size, modification date, and basic metadata.

Example:
  pptcli info presentation.pptx")]
    Info {
        /// PPTX file to inspect
        #[arg(value_name = "FILE", help = "Path to the PPTX file to inspect")]
        file: String,
    },

    /// Validate a PPTX file
    #[command(long_about = "Validate a PPTX file structure and content.
        
Checks for:
- Valid ZIP structure
- Required parts (presentation.xml, slide masters, etc.)
- Content types
- Relationships")]
    Validate {
        /// PPTX file to validate
        #[arg(value_name = "FILE")]
        file: String,
    },

    /// Export presentation to other formats
    #[command(long_about = "Export PPTX to PDF, HTML, or images.

Formats:
- pdf:  Requires LibreOffice installed
- html: Self-contained HTML slideshow
- png:  Requires LibreOffice and pdftoppm")]
    Export {
        /// Input PPTX file
        #[arg(value_name = "INPUT")]
        input: String,

        /// Output file path
        #[arg(value_name = "OUTPUT")]
        output: String,

        /// Output format (overrides extension)
        #[arg(long, value_enum)]
        format: Option<ExportFormat>,
    },

    /// Merge multiple presentations
    #[command(long_about = "Merge multiple PPTX files into one.
        
Slides from all input files will be appended in order.")]
    Merge {
        /// Output PPTX file
        #[arg(short, long)]
        output: String,

        /// Input PPTX files
        #[arg(value_name = "INPUTS", required = true, num_args = 1..)]
        inputs: Vec<String>,
    },

    /// Convert PDF to PowerPoint
    #[command(
        name = "pdf2ppt",
        long_about = "Convert PDF pages to PowerPoint slides.
        
Requires `pdftoppm` (poppler) installed.
Each page becomes a slide with the page image."
    )]
    Pdf2Ppt {
        /// Input PDF file
        #[arg(value_name = "INPUT")]
        input: String,

        /// Output PPTX file
        #[arg(value_name = "OUTPUT")]
        output: Option<String>,
    },

    /// Generate PPTX from HTML file
    #[command(
        name = "html2ppt",
        alias = "from-html",
        alias = "from-html-file",
        long_about = "Convert an HTML file to a PowerPoint presentation.

Converts HTML content into PowerPoint slides:
  <h1>           → New slide with title
  <h2>-<h6>      → Bold section headers
  <p>            → Bullet points
  <ul>/<ol>      → List items
  <table>        → Tables with styled headers
  <pre>/<code>   → Code blocks
  <img>          → Image placeholders
  <blockquote>   → Speaker notes
  <hr>           → Slide break

Examples:
  pptcli html2ppt slides.html presentation.pptx
  pptcli html2ppt slides.html --title \"My Presentation\"
  pptcli html2ppt slides.html  # Auto-generates slides.pptx"
    )]
    Html2Ppt {
        /// Input HTML file
        #[arg(value_name = "INPUT", help = "Path to the input HTML file")]
        input: String,

        /// Output PPTX file (optional: auto-generated from input if not provided)
        #[arg(
            value_name = "OUTPUT",
            help = "Path to the output PPTX file (default: INPUT.pptx)"
        )]
        output: Option<String>,

        /// Presentation title
        #[arg(long, help = "Title of the presentation (overrides HTML <title>)")]
        title: Option<String>,

        /// Maximum number of slides
        #[arg(long, default_value_t = 50, help = "Maximum number of slides to generate")]
        max_slides: usize,

        /// Maximum bullets per slide
        #[arg(long, default_value_t = 10, help = "Maximum bullet points per slide")]
        max_bullets: usize,

        /// Disable image placeholders
        #[arg(long, help = "Disable image placeholder extraction")]
        no_images: bool,

        /// Disable table extraction
        #[arg(long, help = "Disable table extraction")]
        no_tables: bool,

        /// Disable code block extraction
        #[arg(long, help = "Disable code block extraction")]
        no_code: bool,
    },

    /// Generate PPTX from webpage (requires web2ppt feature)
    #[cfg(feature = "web2ppt")]
    #[command(
        name = "web2ppt",
        long_about = "Convert a webpage to a PowerPoint presentation.
        
Extracts:
- Title and headings
- Text content
- Images
- Tables
- Code blocks"
    )]
    Web2Ppt {
        /// URL to convert
        #[arg(value_name = "URL")]
        url: String,

        /// Output file path (.pptx)
        #[arg(short, long, default_value = "output.pptx")]
        output: String,

        /// Presentation title (overrides page title)
        #[arg(long)]
        title: Option<String>,

        /// Maximum number of slides to generate
        #[arg(long, default_value_t = 20)]
        max_slides: usize,

        /// Maximum bullet points per slide
        #[arg(long, default_value_t = 7)]
        max_bullets: usize,

        /// Disable image extraction
        #[arg(long)]
        no_images: bool,

        /// Disable table extraction
        #[arg(long)]
        no_tables: bool,

        /// Disable code block extraction
        #[arg(long)]
        no_code: bool,

        /// Don't add source URL to last slide
        #[arg(long)]
        no_source_url: bool,

        /// Request timeout in seconds
        #[arg(long, default_value_t = 30)]
        timeout: u64,

        /// Enable verbose logging
        #[arg(short, long)]
        verbose: bool,
    },
}

#[derive(ValueEnum, Clone, Debug)]
pub enum ExportFormat {
    Pdf,
    Html,
    Png,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_create() {
        let args = vec![
            "pptcli".to_string(),
            "create".to_string(),
            "test.pptx".to_string(),
            "--title".to_string(),
            "My Presentation".to_string(),
        ];
        let cli = Cli::parse_from(args.iter());
        match cli.command {
            Commands::Create { output, title, .. } => {
                assert_eq!(output, "test.pptx");
                assert_eq!(title, Some("My Presentation".to_string()));
            }
            _ => panic!("Expected Create command"),
        }
    }

    #[test]
    fn test_parse_md2ppt_with_output() {
        let args = vec![
            "pptcli".to_string(),
            "md2ppt".to_string(),
            "input.md".to_string(),
            "output.pptx".to_string(),
            "--title".to_string(),
            "From Markdown".to_string(),
        ];
        let cli = Cli::parse_from(args.iter());
        match cli.command {
            Commands::Md2Ppt {
                input,
                output,
                title,
            } => {
                assert_eq!(input, "input.md");
                assert_eq!(output, Some("output.pptx".to_string()));
                assert_eq!(title, Some("From Markdown".to_string()));
            }
            _ => panic!("Expected Md2Ppt command"),
        }
    }

    #[test]
    fn test_parse_md2ppt_auto_output() {
        let args = vec![
            "pptcli".to_string(),
            "md2ppt".to_string(),
            "input.md".to_string(),
            "--title".to_string(),
            "From Markdown".to_string(),
        ];
        let cli = Cli::parse_from(args.iter());
        match cli.command {
            Commands::Md2Ppt {
                input,
                output,
                title,
            } => {
                assert_eq!(input, "input.md");
                assert_eq!(output, None);
                assert_eq!(title, Some("From Markdown".to_string()));
            }
            _ => panic!("Expected Md2Ppt command"),
        }
    }

    #[test]
    fn test_parse_from_md_alias() {
        let args = vec![
            "pptcli".to_string(),
            "from-md".to_string(),
            "input.md".to_string(),
            "output.pptx".to_string(),
        ];
        let cli = Cli::parse_from(args.iter());
        match cli.command {
            Commands::Md2Ppt { input, output, .. } => {
                assert_eq!(input, "input.md");
                assert_eq!(output, Some("output.pptx".to_string()));
            }
            _ => panic!("Expected Md2Ppt command via from-md alias"),
        }
    }

    #[test]
    fn test_parse_info() {
        let args = vec![
            "pptcli".to_string(),
            "info".to_string(),
            "test.pptx".to_string(),
        ];
        let cli = Cli::parse_from(args.iter());
        match cli.command {
            Commands::Info { file } => {
                assert_eq!(file, "test.pptx");
            }
            _ => panic!("Expected Info command"),
        }
    }
}