Beispiel #1
0
        /// <summary>
        /// Exports the specified <see cref="TextDocument"/> to an external markdown file.
        /// </summary>
        /// <param name="document">The document to export.</param>
        /// <param name="fileName">Full name of the Maml file to export to. Note that if exporting to multiple Maml files,
        /// this is the base file name only; the file names will be derived from this name.</param>
        /// <param name="errors">A list that collects error messages.</param>
        public void Export(TextDocument document, string fileName, List <MarkdownError> errors = null)
        {
            if (null == document)
            {
                throw new ArgumentNullException(nameof(document));
            }
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }
            var basePathName = Path.GetDirectoryName(fileName);


            if (ExpandChildDocuments)
            {
                document = ChildDocumentExpander.ExpandDocumentToNewDocument(document, errors: errors);
            }

            if (RenumerateFigures)
            {
                document.SourceText = FigureRenumerator.RenumerateFigures(document.SourceText);
            }

            // now export the markdown document as Maml file(s)

            // first parse it with Markdig
            var pipeline = new MarkdownPipelineBuilder();

            pipeline = MarkdownUtilities.UseSupportedExtensions(pipeline);

            var markdownDocument = Markdig.Markdown.Parse(document.SourceText, pipeline.Build());

            var renderer = new OpenXMLRenderer(
                wordDocumentFileName: OutputFileName,
                localImages: document.Images,
                textDocumentFolder: document.Folder
                );


            if (MaximumImageWidth.HasValue)
            {
                renderer.MaxImageWidthIn96thInch = MaximumImageWidth.Value.AsValueIn(Altaxo.Units.Length.Inch.Instance) * 96.0;
            }
            if (MaximumImageHeight.HasValue)
            {
                renderer.MaxImageHeigthIn96thInch = MaximumImageHeight.Value.AsValueIn(Altaxo.Units.Length.Inch.Instance) * 96.0;
            }
            if (null != ThemeName)
            {
                renderer.ThemeName = ThemeName;
            }
            renderer.RemoveOldContentsOfTemplateFile = RemoveOldContentsOfTemplateFile;
            renderer.ImageResolution                    = ImageResolutionDpi;
            renderer.UseAutomaticFigureNumbering        = UseAutomaticFigureNumbering;
            renderer.DoNotFormatFigureLinksAsHyperlinks = DoNotFormatFigureLinksAsHyperlinks;

            renderer.Render(markdownDocument);
        }
Beispiel #2
0
        /// <summary>
        /// Renumerates all figures, all elements that are enclosed in ^^^ and that have a figure caption.
        /// The links to those figures are updated, too.
        /// </summary>
        /// <param name="documentText">The document text.</param>
        /// <returns>The modified document text, with renumerated figure captions and updated links.</returns>
        public static string RenumerateFigures(string documentText)
        {
            // first parse the document with markdig
            var pipeline = new MarkdownPipelineBuilder();

            pipeline = MarkdownUtilities.UseSupportedExtensions(pipeline);
            var builtPipeline    = pipeline.Build();
            var markdownDocument = Markdig.Markdown.Parse(documentText, builtPipeline);

            return(RenumerateFigures(markdownDocument, documentText));
        }
Beispiel #3
0
        /// <summary>
        /// Gets a list of all referenced image Urls.
        /// We use this only in the serialization code to serialize only those local images which are referenced in the markdown.
        /// </summary>
        /// <returns>A new list containing all image Urls together with the begin and and of the Url span.</returns>
        public static List <(string Url, int urlSpanStart, int urlSpanEnd)> GetReferencedImageUrls(MarkdownDocument markdownDocument)
        {
            var list = new List <(string Url, int urlSpanStart, int urlSpanEnd)>();

            foreach (var mdo in MarkdownUtilities.EnumerateAllMarkdownObjectsRecursively(markdownDocument))
            {
                if (mdo is LinkInline link)
                {
                    if (link.IsImage && link.UrlSpan.HasValue)
                    {
                        list.Add((link.Url, link.UrlSpan.Value.Start, link.UrlSpan.Value.End));
                    }
                }
            }
            return(list);
        }
Beispiel #4
0
        /// <summary>
        /// Determines whether the given <paramref name="url"/> points to anywhere inside the given Markdig <paramref name="element"/>.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="element">The Markdig element.</param>
        /// <returns>
        /// <c>true</c> if the given <paramref name="url"/> points to anywhere inside the given Markdig <paramref name="element"/>.; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsLinkInElement(string url, Markdig.Syntax.MarkdownObject element)
        {
            if (url.StartsWith("#"))
            {
                url = url.Substring(1);
            }

            foreach (var child in MarkdownUtilities.EnumerateAllMarkdownObjectsRecursively(element))
            {
                var    attr          = (Markdig.Renderers.Html.HtmlAttributes)child.GetData(typeof(Markdig.Renderers.Html.HtmlAttributes));
                string uniqueAddress = attr?.Id; // this header has a user defined address
                if (uniqueAddress == url)
                {
                    return(true);
                }
            }
            return(false);
        }
Beispiel #5
0
        /// <summary>
        /// Exports the specified <see cref="TextDocument"/> to an external markdown file.
        /// </summary>
        /// <param name="document">The document to export.</param>
        /// <param name="fileName">Full name of the Maml file to export to. Note that if exporting to multiple Maml files,
        /// this is the base file name only; the file names will be derived from this name.</param>
        /// <param name="errors">A list that collects error messages.</param>
        public void Export(TextDocument document, string fileName, List <MarkdownError> errors = null)
        {
            if (null == document)
            {
                throw new ArgumentNullException(nameof(document));
            }
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }
            var basePathName = Path.GetDirectoryName(fileName);


            if (ExpandChildDocuments)
            {
                document = ChildDocumentExpander.ExpandDocumentToNewDocument(document, errors: errors);
            }

            if (RenumerateFigures)
            {
                document.SourceText = FigureRenumerator.RenumerateFigures(document.SourceText);
            }

            // remove the old content
            if (EnableRemoveOldContentsOfContentFolder)
            {
                var fullContentFolderName = Path.Combine(basePathName, ContentFolderName);
                MamlRenderer.RemoveOldContentsOfContentFolder(fullContentFolderName);
            }

            // remove old images
            var fullImageFolderName = Path.Combine(basePathName, ImageFolderName);

            if (EnableRemoveOldContentsOfImageFolder)
            {
                MamlRenderer.RemoveOldContentsOfImageFolder(fullImageFolderName);
            }
            if (!Directory.Exists(fullImageFolderName))
            {
                Directory.CreateDirectory(fullImageFolderName);
            }

            // First, export the images
            var(oldToNewImageUrl, listOfReferencedImageFileNames) = ExportImages(document, basePathName);

            // now export the markdown document as Maml file(s)

            // first parse it with Markdig
            var pipeline = new MarkdownPipelineBuilder();

            pipeline = MarkdownUtilities.UseSupportedExtensions(pipeline);

            var markdownDocument = Markdig.Markdown.Parse(document.SourceText, pipeline.Build());

            var renderer = new MamlRenderer(
                projectOrContentFileName: fileName,
                contentFolderName: ContentFolderName,
                contentFileNameBase: ContentFileNameBase,
                imageFolderName: ImageFolderName,
                splitLevel: SplitLevel,
                enableHtmlEscape: EnableHtmlEscape,
                autoOutline: EnableAutoOutline,
                enableLinkToPreviousSection: EnableLinkToPreviousSection,
                linkToPreviousSectionLabelText: LinkToPreviousSectionLabelText,
                enableLinkToNextSection: EnableLinkToNextSection,
                linkToNextSectionLabelText: LinkToNextSectionLabelText,
                imagesFullFileNames: listOfReferencedImageFileNames,
                oldToNewImageUris: oldToNewImageUrl,
                bodyTextFontFamily: BodyTextFontFamily,
                bodyTextFontSize: BodyTextFontSize,
                isIntendedForHelp1File: IsIntendedForHtmlHelp1File
                );

            renderer.Render(markdownDocument);
        }
Beispiel #6
0
        /// <summary>
        /// Expands the document to include child documents directly. This process is recursively, i.e. if the child documents contain child-child documents,
        /// they are expanded, too.
        /// </summary>
        /// <param name="textDocument">The original text document. This document is not changed during the expansion.</param>
        /// <param name="convertGraphsToImages">If true, links to Altaxo graphs will be converted to images. If false, the links to the graphs were kept, but the path to the graphs is changed appropriately.</param>
        /// <param name="newPath">Folder path of the final document that is the target of the expansion process.</param>
        /// <param name="recursionLevel">The recursion level. Start with 0 here.</param>
        /// <param name="errors">A list that collects error messages.</param>
        /// <returns>A new <see cref="TextDocument"/>. This text document contains the expanded markdown text. In addition, all Altaxo graphs are converted to local images.</returns>
        /// <remarks>Since finding Altaxo graphs embedded in the markdown is depended on the context (location of the TextDocument and location of the graph),
        /// and we somewhat loose this context during the expansion, we convert the graphs to local images before we insert the document into the master document.</remarks>
        private static TextDocument ExpandDocumentToNewDocument(TextDocument textDocument, bool convertGraphsToImages, string newPath, int recursionLevel = 0, List <MarkdownError> errors = null)
        {
            var resultDocument = new TextDocument();

            resultDocument.AddImagesFrom(textDocument);
            resultDocument.Name = textDocument.Name;

            // first parse the document with markdig
            var pipeline = new MarkdownPipelineBuilder();

            pipeline = MarkdownUtilities.UseSupportedExtensions(pipeline);
            var builtPipeline    = pipeline.Build();
            var markdownDocument = Markdig.Markdown.Parse(textDocument.SourceText, builtPipeline);

            var markdownToProcess = new List <MarkdownObject>();

            foreach (var mdo in MarkdownUtilities.EnumerateAllMarkdownObjectsRecursively(markdownDocument))
            {
                if (mdo is LinkInline link)
                {
                    if (link.Url.ToLowerInvariant().StartsWith(ImagePretext.GraphRelativePathPretext))
                    {
                        markdownToProcess.Add(mdo);
                    }
                }
                else if (mdo is CodeBlock blk)
                {
                    var attr = (Markdig.Renderers.Html.HtmlAttributes)mdo.GetData(typeof(Markdig.Renderers.Html.HtmlAttributes));
                    if (attr != null && attr.Properties != null && attr.Properties.Count >= 2 && attr.Properties[0].Key == "Altaxo" && attr.Properties[1].Key == "child")
                    {
                        var childDoc = attr.Properties[1].Value;
                        if (null != childDoc)
                        {
                            markdownToProcess.Add(mdo);
                        }
                    }
                }
            }

            // now we process the list backwards and change the source

            var documentAsStringBuilder = new StringBuilder(textDocument.SourceText);
            var imageStreamProvider     = new ImageStreamProvider();

            markdownToProcess.Reverse(); // we start from the end of the document, in order not to change the positions of unprocessed markdown
            foreach (var mdo in markdownToProcess)
            {
                if (mdo is LinkInline link)
                {
                    if (convertGraphsToImages) // convert links to graphs to images
                    {
                        using (var stream = new System.IO.MemoryStream())
                        {
                            var streamResult = imageStreamProvider.GetImageStream(stream, link.Url, 300, Altaxo.Main.ProjectFolder.GetFolderPart(textDocument.Name), textDocument.Images);
                            if (null == streamResult.ErrorMessage)
                            {
                                stream.Seek(0, System.IO.SeekOrigin.Begin);
                                var proxy = MemoryStreamImageProxy.FromStream(stream, streamResult.Extension);
                                resultDocument.AddImage(proxy);
                                documentAsStringBuilder.Remove(link.UrlSpan.Value.Start, link.UrlSpan.Value.Length);
                                documentAsStringBuilder.Insert(link.UrlSpan.Value.Start, "local:" + proxy.ContentHash);
                            }
                        }
                    }
                    else // keep link to graphs, but change their path
                    {
                        var newUrl = ConvertGraphUrl(link.Url, textDocument.Name, newPath);
                        if (newUrl != link.Url)
                        {
                            documentAsStringBuilder.Remove(link.UrlSpan.Value.Start, link.UrlSpan.Value.Length);
                            documentAsStringBuilder.Insert(link.UrlSpan.Value.Start, newUrl);
                        }
                    }
                }
                else if (mdo is CodeBlock blk)
                {
                    var attr         = (Markdig.Renderers.Html.HtmlAttributes)mdo.GetData(typeof(Markdig.Renderers.Html.HtmlAttributes));
                    var childDocName = attr.Properties[1].Value;
                    // first, we assume a relative name
                    var fullName = Altaxo.Main.ProjectFolder.GetFolderPart(textDocument.Name) + childDocName;
                    var success  = Current.Project.TextDocumentCollection.TryGetValue(fullName, out var childTextDocument);
                    if (!success) // relative name failed, we try it with the unmodified (absolute) name
                    {
                        success = Current.Project.TextDocumentCollection.TryGetValue(childDocName, out childTextDocument);
                    }

                    if (success)
                    {
                        var expandedChild = ExpandDocumentToNewDocument(childTextDocument, convertGraphsToImages, newPath, recursionLevel + 1, errors);
                        // exchange the source text
                        documentAsStringBuilder.Remove(mdo.Span.Start, mdo.Span.Length);
                        documentAsStringBuilder.Insert(mdo.Span.Start, expandedChild.SourceText);
                        // insert images
                        resultDocument.AddImagesFrom(expandedChild);
                    }
                    else if (null != errors) // report an error
                    {
                        var error = new MarkdownError()
                        {
                            AltaxoDocumentName = textDocument.Name,
                            LineNumber         = blk.Line,
                            ColumnNumber       = blk.Column,
                            ErrorMessage       = string.Format("Could not expand child document \"{0}\" because this name could not be resolved!", childDocName)
                        };

                        errors.Add(error);
                    }
                }
            }

            resultDocument.SourceText = documentAsStringBuilder.ToString();

            if (0 == recursionLevel) // if we are about to return the master document, we must restore the list of referenced image Urls
            {
                markdownDocument = Markdig.Markdown.Parse(resultDocument.SourceText, builtPipeline);
                resultDocument.ReferencedImageUrls = MarkdownUtilities.GetReferencedImageUrls(markdownDocument);
            }

            return(resultDocument);
        }