diff --git a/src/Commands/CommandLineOptions.cs b/src/Commands/CommandLineOptions.cs index 87536bd..0465e4c 100644 --- a/src/Commands/CommandLineOptions.cs +++ b/src/Commands/CommandLineOptions.cs @@ -191,6 +191,7 @@ private static bool TryParseInputOptions(CommandLineOptions commandLineOptions, "web get" => new WebGetCommand(), "help" => new HelpCommand(), "run" => new RunCommand(), + "export" => new ExportCommand(), _ => new FindFilesCommand() }; diff --git a/src/Commands/ExportCommand.cs b/src/Commands/ExportCommand.cs new file mode 100644 index 0000000..6f1eca2 --- /dev/null +++ b/src/Commands/ExportCommand.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; +using System.Linq; + +public class ExportCommand : Command +{ + public override string[] Names => new[] { "export" }; + + public override string Description => "Export markdown to other formats (PDF/DOCX/PPTX)"; + + public override string ExtendedDescription => @"Exports markdown files to various document formats. + +Examples: + mdx export document.md document.pdf + mdx export notes.md presentation.pptx + mdx export report.md report.docx + +Supported output formats: " + string.Join(", ", MarkdownExporters.GetSupportedExtensions()); + + public override void Run(CommandLineOptions options) + { + if (options.Arguments.Count != 2) + { + throw new CommandLineException(this, "Export command requires 2 arguments: "); + } + + var inputPath = options.Arguments[0]; + var outputPath = options.Arguments[1]; + + if (!File.Exists(inputPath)) + { + throw new CommandLineException(this, $"Input file not found: {inputPath}"); + } + + if (!inputPath.EndsWith(".md", StringComparison.OrdinalIgnoreCase)) + { + throw new CommandLineException(this, $"Input file must be a markdown file (.md extension)"); + } + + try + { + var markdown = File.ReadAllText(inputPath); + var exporter = MarkdownExporters.GetExporter(outputPath); + exporter.ExportMarkdown(markdown, outputPath); + Console.WriteLine($"Successfully exported to {outputPath}"); + } + catch (ArgumentException ex) + { + throw new CommandLineException(this, ex.Message); + } + catch (Exception ex) + { + throw new CommandLineException(this, $"Export failed: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/src/Exporters/DocxMarkdownExporter.cs b/src/Exporters/DocxMarkdownExporter.cs new file mode 100644 index 0000000..e6c7850 --- /dev/null +++ b/src/Exporters/DocxMarkdownExporter.cs @@ -0,0 +1,32 @@ +using System; +using System.IO; +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using Markdig; + +/// +/// Exports markdown to DOCX format using OpenXML +/// +public class DocxMarkdownExporter : IMarkdownExporter +{ + public string OutputExtension => ".docx"; + + public void ExportMarkdown(string markdown, string outputPath) + { + using var doc = WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document); + var mainPart = doc.AddMainDocumentPart(); + mainPart.Document = new Document(); + var body = mainPart.Document.AppendChild(new Body()); + + // Convert markdown to simple paragraphs + var html = Markdown.ToHtml(markdown); + foreach (var line in html.Split('\n', StringSplitOptions.RemoveEmptyEntries)) + { + if (string.IsNullOrWhiteSpace(line)) continue; + + var para = new Paragraph(new Run(new Text(line.Trim()))); + body.AppendChild(para); + } + } +} \ No newline at end of file diff --git a/src/Exporters/IMarkdownExporter.cs b/src/Exporters/IMarkdownExporter.cs new file mode 100644 index 0000000..9822312 --- /dev/null +++ b/src/Exporters/IMarkdownExporter.cs @@ -0,0 +1,17 @@ +/// +/// Interface for converting markdown content to different document formats +/// +public interface IMarkdownExporter +{ + /// + /// Gets the file extension this exporter produces (e.g. ".pdf", ".docx", ".pptx") + /// + string OutputExtension { get; } + + /// + /// Converts markdown content to the target format and saves to the specified file + /// + /// The markdown content to convert + /// The output file path where the converted document should be saved + void ExportMarkdown(string markdown, string outputPath); +} \ No newline at end of file diff --git a/src/Exporters/MarkdownExporters.cs b/src/Exporters/MarkdownExporters.cs new file mode 100644 index 0000000..6633c0c --- /dev/null +++ b/src/Exporters/MarkdownExporters.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +/// +/// Factory class for creating markdown exporters +/// +public static class MarkdownExporters +{ + private static readonly Dictionary _exporters = new() + { + { ".pdf", new PdfMarkdownExporter() }, + { ".docx", new DocxMarkdownExporter() }, + { ".pptx", new PptxMarkdownExporter() } + }; + + /// + /// Gets an exporter for the specified output format + /// + public static IMarkdownExporter GetExporter(string outputPath) + { + var extension = System.IO.Path.GetExtension(outputPath).ToLowerInvariant(); + if (_exporters.TryGetValue(extension, out var exporter)) + { + return exporter; + } + + throw new ArgumentException($"No exporter available for {extension} format"); + } + + /// + /// Gets all supported output extensions + /// + public static IEnumerable GetSupportedExtensions() + { + return _exporters.Keys; + } +} \ No newline at end of file diff --git a/src/Exporters/PdfMarkdownExporter.cs b/src/Exporters/PdfMarkdownExporter.cs new file mode 100644 index 0000000..a4c82f2 --- /dev/null +++ b/src/Exporters/PdfMarkdownExporter.cs @@ -0,0 +1,32 @@ +using System; +using System.IO; +using iText.Kernel.Pdf; +using iText.Layout; +using iText.Layout.Element; +using Markdig; + +/// +/// Exports markdown to PDF format using iText7 +/// +public class PdfMarkdownExporter : IMarkdownExporter +{ + public string OutputExtension => ".pdf"; + + public void ExportMarkdown(string markdown, string outputPath) + { + // Convert markdown to HTML first + var html = Markdown.ToHtml(markdown); + + using var writer = new PdfWriter(outputPath); + using var pdf = new PdfDocument(writer); + using var document = new Document(pdf); + + // Simple conversion - future enhancement would be to properly style and format + foreach (var line in html.Split('\n', StringSplitOptions.RemoveEmptyEntries)) + { + if (string.IsNullOrWhiteSpace(line)) continue; + var text = new Paragraph(line.Trim()); + document.Add(text); + } + } +} \ No newline at end of file diff --git a/src/Exporters/PptxMarkdownExporter.cs b/src/Exporters/PptxMarkdownExporter.cs new file mode 100644 index 0000000..3c5ffdd --- /dev/null +++ b/src/Exporters/PptxMarkdownExporter.cs @@ -0,0 +1,64 @@ +using System; +using System.IO; +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Presentation; +using Markdig; +using P = DocumentFormat.OpenXml.Presentation; +using A = DocumentFormat.OpenXml.Drawing; + +/// +/// Exports markdown to PPTX format using OpenXML +/// +public class PptxMarkdownExporter : IMarkdownExporter +{ + public string OutputExtension => ".pptx"; + + public void ExportMarkdown(string markdown, string outputPath) + { + using var presentation = PresentationDocument.Create(outputPath, PresentationDocumentType.Presentation); + var presentationPart = presentation.AddPresentationPart(); + presentationPart.Presentation = new Presentation(); + + var slideMasterPart = presentationPart.AddNewPart(); + var slideMaster = new SlideMaster( + new CommonSlideData(new ShapeTree( + new P.Shape( + new P.ShapeProperties())))); + slideMaster.Save(slideMasterPart); + + var slideLayoutPart = slideMasterPart.AddNewPart(); + var slideLayout = new SlideLayout( + new CommonSlideData(new ShapeTree( + new P.Shape( + new P.ShapeProperties())))); + slideLayout.Save(slideLayoutPart); + + // Add slides for each markdown section + var sections = markdown.Split("\n\n", StringSplitOptions.RemoveEmptyEntries); + foreach (var section in sections) + { + if (string.IsNullOrWhiteSpace(section)) continue; + + var slidePart = presentationPart.AddNewPart(); + var slide = new Slide(new CommonSlideData(new ShapeTree())); + + // Create text box with markdown content + var textBox = new P.Shape( + new P.NonVisualShapeProperties( + new P.NonVisualDrawingProperties() { Id = 2U, Name = "Text Box" }, + new P.NonVisualShapeDrawingProperties(new A.ShapeStyle()), + new P.ApplicationNonVisualDrawingProperties()), + new P.ShapeProperties(), + new P.TextBody( + new A.BodyProperties(), + new A.ListStyle(), + new A.Paragraph(new A.Run(new A.Text(section.Trim()))))); + + slide.CommonSlideData.ShapeTree.AppendChild(textBox); + slide.Save(slidePart); + } + + presentation.Close(); + } +} \ No newline at end of file diff --git a/src/assets/help/export.txt b/src/assets/help/export.txt new file mode 100644 index 0000000..ef7c85a --- /dev/null +++ b/src/assets/help/export.txt @@ -0,0 +1,17 @@ +Export command +------------- + +The export command converts markdown files to various document formats. + +Usage: + mdx export + +Where can be one of: +- .pdf - Export as PDF document +- .docx - Export as Word document +- .pptx - Export as PowerPoint presentation + +Examples: + mdx export document.md document.pdf + mdx export notes.md presentation.pptx + mdx export report.md report.docx \ No newline at end of file diff --git a/src/mdx.csproj b/src/mdx.csproj index 22a7f98..701f6e8 100644 --- a/src/mdx.csproj +++ b/src/mdx.csproj @@ -21,6 +21,8 @@ + +