/// <summary> /// Writes the specified Markdown object. /// </summary> /// <typeparam name="T">A MarkdownObject type</typeparam> /// <param name="obj">The Markdown object to write to this renderer.</param> public void Write <T>(T obj) where T : MarkdownObject { if (obj == null) { return; } var objectType = obj.GetType(); // Calls before writing an object var writeBefore = ObjectWriteBefore; writeBefore?.Invoke(this, obj); // Handle regular renderers IMarkdownObjectRenderer renderer = previousObjectType == objectType ? previousRenderer : null; if (renderer == null && !renderersPerType.TryGetValue(objectType, out renderer)) { for (int i = 0; i < ObjectRenderers.Count; i++) { var testRenderer = ObjectRenderers[i]; if (testRenderer.Accept(this, obj)) { renderersPerType[objectType] = renderer = testRenderer; break; } } } if (renderer != null) { renderer.Write(this, obj); } else { var containerBlock = obj as ContainerBlock; if (containerBlock != null) { WriteChildren(containerBlock); } else { var containerInline = obj as ContainerInline; if (containerInline != null) { WriteChildren(containerInline); } } } previousObjectType = objectType; previousRenderer = renderer; // Calls after writing an object var writeAfter = ObjectWriteAfter; writeAfter?.Invoke(this, obj); }
/// <summary> /// Writes the specified Markdown object. /// </summary> /// <typeparam name="T">A MarkdownObject type</typeparam> /// <param name="obj">The Markdown object to write to this renderer.</param> /// <remarks> /// Write{T}(T obj) cannot be overridden. Therefore, copy 'n paste the complete impl /// of Render and modify it slightly so that errors are rendered. /// </remarks> public void WriteInternal <T>(T obj, bool isSummary = false) where T : MarkdownObject { if (obj == null) { return; } bool isError = false; if (obj is IExtensionBlock block && _blockErrors.ContainsKey(block)) { if (!isSummary) { var errors = _blockErrors[block]; var sb = new StringBuilder(); sb.AppendLine("<ul class='error-list'>"); foreach (var error in errors.Errors) { sb.AppendLine("<li class='error'>"); IExtension extension = _extensionByBlock[block]; string extensionName = extension.GetType().Name; var parseError = error as IParseError; if (parseError != null) { sb.Append($@"<span class='Range'>{parseError.Range}</span> "); } sb.Append($@"<span class='extension-name'>{extensionName}:</span>"); sb.Append($@"<span class='message'>{error.Message}</span>"); sb.AppendLine("</li>"); } sb.AppendLine("</ul>"); WriteLine(sb.ToString()); } isError = true; } if (obj is IExtensionInline inline && _inlineErrors.ContainsKey(inline)) { // TODO: implement and design a nice inline error visual isError = true; } if (!isError) { // Calls before writing an object //var writeBefore = ObjectWriteBefore; //ObjectWriteBefore?.Invoke(this, obj); // Handle regular renderers var objectType = obj.GetType(); var extensionBlock = obj as IExtensionBlock; bool isSummaryExtension = extensionBlock != null && _extensionByBlock.ContainsKey(extensionBlock) && _extensionByBlock[extensionBlock].IsSummary; bool shouldRender = obj is MarkdownDocument || (isSummary && isSummaryExtension) || (!isSummary && !isSummaryExtension); IMarkdownObjectRenderer renderer = _previousObjectType == objectType ? _previousRenderer : null; if (renderer == null && !_renderersPerType.TryGetValue(objectType, out renderer)) { for (int i = 0; i < ObjectRenderers.Count; i++) { var testRenderer = ObjectRenderers[i]; if (testRenderer.Accept(this, obj)) { _renderersPerType[objectType] = renderer = testRenderer; break; } } } if (renderer != null && shouldRender) { renderer.Write(this, obj); } else { var containerBlock = obj as ContainerBlock; if (containerBlock != null && shouldRender) { WriteChildrenInternal(containerBlock, isSummary); } else { var containerInline = obj as ContainerInline; if (containerInline != null && shouldRender) { WriteChildrenInternal(containerInline); } } } _previousObjectType = objectType; _previousRenderer = renderer; } // Calls after writing an object //var writeAfter = ObjectWriteAfter; //writeAfter?.Invoke(this, obj); }