-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Markdown preview pane #1128
Markdown preview pane #1128
Changes from 10 commits
6b492ea
067fa4e
fd87968
8845702
3dea213
251f729
7bb6f5f
14f721a
abc1bc0
c3c9434
f3a1e3b
cf269ae
84bcdf5
c894a16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.IO; | ||
using Markdig; | ||
using Markdig.Extensions.Figures; | ||
using Markdig.Extensions.Tables; | ||
using Markdig.Renderers; | ||
using Markdig.Renderers.Html; | ||
using Markdig.Syntax; | ||
using Markdig.Syntax.Inlines; | ||
|
||
namespace MarkdownPreviewHandler | ||
{ | ||
/// <summary> | ||
/// Markdig Extension to process html nodes in markdown AST. | ||
/// </summary> | ||
public class HTMLParsingExtension : IMarkdownExtension | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="HTMLParsingExtension"/> class. | ||
/// </summary> | ||
public HTMLParsingExtension(string baseUrl = "") | ||
{ | ||
this.BaseUrl = baseUrl; | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets path to directory containing markdown file. | ||
/// </summary> | ||
public string BaseUrl { get; set; } | ||
|
||
/// <inheritdoc/> | ||
public void Setup(MarkdownPipelineBuilder pipeline) | ||
{ | ||
// Make sure we don't have a delegate twice | ||
pipeline.DocumentProcessed -= this.PipelineOnDocumentProcessed; | ||
pipeline.DocumentProcessed += this.PipelineOnDocumentProcessed; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Process nodes in markdown AST. | ||
/// </summary> | ||
/// <param name="document">Markdown Document.</param> | ||
public void PipelineOnDocumentProcessed(MarkdownDocument document) | ||
{ | ||
foreach (var node in document.Descendants()) | ||
{ | ||
if (node is Block) | ||
{ | ||
if (node is Table) | ||
{ | ||
node.GetAttributes().AddClass("table table-striped table-bordered"); | ||
} | ||
else if (node is QuoteBlock) | ||
{ | ||
node.GetAttributes().AddClass("blockquote"); | ||
} | ||
else if (node is Figure) | ||
{ | ||
node.GetAttributes().AddClass("figure"); | ||
} | ||
else if (node is FigureCaption) | ||
{ | ||
node.GetAttributes().AddClass("figure-caption"); | ||
} | ||
} | ||
else if (node is Inline) | ||
{ | ||
if (node is LinkInline link && link.IsImage) | ||
{ | ||
if (!Uri.TryCreate(link.Url, UriKind.Absolute, out Uri uriLink)) | ||
{ | ||
link.Url = link.Url.TrimStart('/'); | ||
this.BaseUrl = this.BaseUrl.TrimEnd('/'); | ||
uriLink = new Uri(Path.Combine(this.BaseUrl, link.Url)); | ||
link.Url = uriLink.ToString(); | ||
} | ||
|
||
link.GetAttributes().AddClass("img-fluid"); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProjectGuid>{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}</ProjectGuid> | ||
<OutputType>Library</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>MarkdownPreviewHandler</RootNamespace> | ||
<AssemblyName>MarkdownPreviewHandler</AssemblyName> | ||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
<Deterministic>true</Deterministic> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' "> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
arjunbalgovind marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | ||
<DocumentationFile>bin/Debug/MarkdownPreviewPaneDocumentation.xml</DocumentationFile> | ||
<PlatformTarget>x64</PlatformTarget> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' "> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
arjunbalgovind marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | ||
<DocumentationFile>bin/Release/commonDocumentation.xml</DocumentationFile> | ||
<PlatformTarget>x64</PlatformTarget> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<SignAssembly>true</SignAssembly> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<AssemblyOriginatorKeyFile>MarkdownPreviewHandler.snk</AssemblyOriginatorKeyFile> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Reference Include="System" /> | ||
<Reference Include="System.Core" /> | ||
<Reference Include="System.Windows.Forms" /> | ||
<Reference Include="System.Xml.Linq" /> | ||
<Reference Include="System.Data.DataSetExtensions" /> | ||
<Reference Include="Microsoft.CSharp" /> | ||
<Reference Include="System.Data" /> | ||
<Reference Include="System.Net.Http" /> | ||
<Reference Include="System.Xml" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Compile Include="HTMLParsingExtension.cs" /> | ||
<Compile Include="MarkdownPreviewHandler.cs" /> | ||
<Compile Include="MarkdownPreviewHandlerControl.cs"> | ||
<SubType>Form</SubType> | ||
</Compile> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<PackageReference Include="Markdig.Signed"> | ||
<Version>0.18.0</Version> | ||
</PackageReference> | ||
<PackageReference Include="StyleCop.Analyzers"> | ||
<Version>1.1.118</Version> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
<PrivateAssets>all</PrivateAssets> | ||
</PackageReference> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json"> | ||
<Link>StyleCop.json</Link> | ||
</AdditionalFiles> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="..\common\Common.csproj"> | ||
arjunbalgovind marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<Project>{af2349b8-e5b6-4004-9502-687c1c7730b1}</Project> | ||
<Name>Common</Name> | ||
</ProjectReference> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="MarkdownPreviewHandler.snk" /> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Reflection; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
// General Information about an assembly is controlled through the following | ||
// set of attributes. Change these attribute values to modify the information | ||
// associated with an assembly. | ||
[assembly: AssemblyTitle("MarkdownPreviewHandler")] | ||
arjunbalgovind marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[assembly: AssemblyDescription("")] | ||
[assembly: AssemblyConfiguration("")] | ||
[assembly: AssemblyCompany("")] | ||
[assembly: AssemblyProduct("MarkdownPreviewHandler")] | ||
[assembly: AssemblyCopyright("Copyright © 2020")] | ||
[assembly: AssemblyTrademark("")] | ||
[assembly: AssemblyCulture("")] | ||
|
||
// Setting ComVisible to false makes the types in this assembly not visible | ||
// to COM components. If you need to access a type in this assembly from | ||
// COM, set the ComVisible attribute to true on that type. | ||
[assembly: ComVisible(false)] | ||
|
||
// The following GUID is for the ID of the typelib if this project is exposed to COM | ||
[assembly: Guid("6a71162e-fc4c-4a2c-b90f-3cf94f59a9bb")] | ||
|
||
// Version information for an assembly consists of the following four values: | ||
// | ||
// Major Version | ||
// Minor Version | ||
// Build Number | ||
// Revision | ||
// | ||
// You can specify all the values or you can default the Build and Revision Numbers | ||
// by using the '*' as shown below: | ||
// [assembly: AssemblyVersion("1.0.*")] | ||
[assembly: AssemblyVersion("1.0.0.1")] | ||
[assembly: AssemblyFileVersion("1.0.0.1")] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Runtime.InteropServices; | ||
using Common; | ||
|
||
namespace MarkdownPreviewHandler | ||
{ | ||
/// <summary> | ||
/// This is a example custom handler to show how to extend the library. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Markdown handler. |
||
/// </summary> | ||
[PreviewHandler("MarkdownPreviewPaneHandler", ".md", "{88235ab2-bfce-4be8-9ed0-0408cd8da792}")] | ||
[ProgId("MarkdownPreviewPaneHandler")] | ||
[Guid("45769bcc-e8fd-42d0-947e-02beef77a1f5")] | ||
[ClassInterface(ClassInterfaceType.None)] | ||
[ComVisible(true)] | ||
public class MarkdownPreviewHandler : FileBasedPreviewHandler | ||
{ | ||
private MarkdownPreviewHandlerControl markdownPreviewHandlerControl; | ||
|
||
/// <inheritdoc /> | ||
public override void DoPreview() | ||
{ | ||
this.markdownPreviewHandlerControl.DoPreview(this.FilePath); | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override IPreviewHandlerControl CreatePreviewHandlerControl() | ||
{ | ||
this.markdownPreviewHandlerControl = new MarkdownPreviewHandlerControl(); | ||
return this.markdownPreviewHandlerControl; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.IO; | ||
using System.Windows.Forms; | ||
using Common; | ||
using Markdig; | ||
|
||
namespace MarkdownPreviewHandler | ||
{ | ||
/// <summary> | ||
/// Win Form Implementation for Markdown Preview Handler. | ||
/// </summary> | ||
public class MarkdownPreviewHandlerControl : FormHandlerControl | ||
{ | ||
/// <summary> | ||
/// Extension to modify markdown AST. | ||
/// </summary> | ||
private readonly HTMLParsingExtension extension; | ||
|
||
/// <summary> | ||
/// Markdig Pipeline builder. | ||
/// </summary> | ||
private readonly MarkdownPipelineBuilder pipelineBuilder; | ||
|
||
/// <summary> | ||
/// Markdown HTML header. | ||
/// </summary> | ||
private readonly string htmlHeader = "<!doctype html><html lang=\"en\"><head></head><style>body img{max-width:100%;height:auto}body h1,body h2,body h3,body h4,body h5,body h6{margin-top:24px;margin-bottom:16px;font-weight:600;line-height:1.25}body h1,body h2{padding-bottom:.3em;border-bottom:1px solid #eaecef}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji}body h3{font-size:1.25em}body h4{font-size:1em}body h5{font-size:.875em}body h6{font-size:.85em;color:#6a737d}pre{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;background-color:#f6f8fa;border-radius:3px;padding:16px;font-size:85%}a{color:#0366d6}strong{font-weight:600}em{font-style:italic}code{padding:.2em .4em;margin:0;font-size:85%;background-color:#f6f8fa;border-radius:3px}hr{-moz-border-bottom-colors:none;-moz-border-image:none;-moz-border-left-colors:none;-moz-border-right-colors:none;-moz-border-top-colors:none;border-color:#EEE -moz-use-text-color #FFF;border-style:solid none;border-width:.5px 0;margin:18px 0}table{display:block;width:100%;overflow:auto;border-spacing:0;border-collapse:collapse}tbody{display:table-row-group;vertical-align:middle;border-color:inherit;display:table-row;vertical-align:inherit;border-color:inherit}table tr{background-color:#fff;border-top:1px solid #c6cbd1}tr{display:table-row;vertical-align:inherit;border-color:inherit}table td,table th{padding:6px 13px;border:1px solid #dfe2e5}th{font-weight:600;display:table-cell;vertical-align:inherit;font-weight:bold;text-align:-internal-center}thead{display:table-header-group;vertical-align:middle;border-color:inherit}td{display:table-cell;vertical-align:inherit}code,pre,tt{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;color:#24292e}blockquote{background-color:#fff;border-radius:3px;padding:15px;font-size:14px;display:block;margin-block-start:1em;margin-block-end:1em;margin-inline-start:40px;margin-inline-end:40px;padding:0 1em;color:#6a737d;border-left:.25em solid #dfe2e5}body{width:90%}</style><body><div class=\"container\">"; | ||
arjunbalgovind marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// <summary> | ||
/// Markdown HTML footer. | ||
/// </summary> | ||
private readonly string htmlFooter = "</div></body></html>"; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="MarkdownPreviewHandlerControl"/> class. | ||
/// </summary> | ||
public MarkdownPreviewHandlerControl() | ||
{ | ||
this.extension = new HTMLParsingExtension(); | ||
this.pipelineBuilder = new MarkdownPipelineBuilder().UseAdvancedExtensions().UseEmojiAndSmiley(); | ||
this.pipelineBuilder.Extensions.Add(this.extension); | ||
} | ||
|
||
/// <summary> | ||
/// Start the preview on the Control. | ||
/// </summary> | ||
/// <param name="dataSource">Path to the file.</param> | ||
public override void DoPreview<T>(T dataSource) | ||
{ | ||
this.InvokeOnControlThread(() => | ||
{ | ||
string filePath = dataSource as string; | ||
string fileText = File.ReadAllText(filePath); | ||
this.extension.BaseUrl = Path.GetDirectoryName(filePath); | ||
|
||
MarkdownPipeline pipeline = this.pipelineBuilder.Build(); | ||
string parsedMarkdown = Markdown.ToHtml(fileText, pipeline); | ||
string html = this.htmlHeader + parsedMarkdown + this.htmlFooter; | ||
|
||
// File.WriteAllText("C:\\Users\\divyan\\Desktop\\output.html", html); | ||
arjunbalgovind marked this conversation as resolved.
Show resolved
Hide resolved
|
||
WebBrowser browser = new WebBrowser(); | ||
browser.DocumentText = html; | ||
browser.Dock = DockStyle.Fill; | ||
browser.IsWebBrowserContextMenuEnabled = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about Unit Test to check these property are set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will update this! |
||
browser.ScriptErrorsSuppressed = true; | ||
browser.ScrollBarsEnabled = true; | ||
this.Controls.Add(browser); | ||
base.DoPreview(dataSource); | ||
}); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
> Blockquotes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify, is this intended to be an empty definition? Can you add the summary tags for the Setup functions as well since I'm not sure what's it used for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is empty if extension is renderer independent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add the summary comments for those two functions? Or is it there in some other file that I'm missing?