mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Add support for passing files and markdown directly to Show-Markdown (#7354)
* add support for -Path/-LiteralPath and piping strings directly to Show-Markdown * update tests to set vt100 support
This commit is contained in:
committed by
Aditya Patwardhan
parent
5717a5dffc
commit
f8b3abaac7
+151
-100
@@ -6,6 +6,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Internal;
|
||||
@@ -20,6 +21,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
[Cmdlet(
|
||||
VerbsCommon.Show, "Markdown",
|
||||
DefaultParameterSetName = "Path",
|
||||
HelpUri = "https://go.microsoft.com/fwlink/?linkid=2006266")]
|
||||
[OutputType(typeof(string))]
|
||||
public class ShowMarkdownCommand : PSCmdlet
|
||||
@@ -28,28 +30,43 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// Gets or sets InputObject of type Microsoft.PowerShell.MarkdownRender.MarkdownInfo to display.
|
||||
/// </summary>
|
||||
[ValidateNotNullOrEmpty]
|
||||
[Parameter(Mandatory = true, ValueFromPipeline = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = "InputObject")]
|
||||
public PSObject InputObject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets path to markdown file(s) to display.
|
||||
/// </summary>
|
||||
[ValidateNotNullOrEmpty]
|
||||
[Parameter(Position = 0, Mandatory = true,
|
||||
ValueFromPipelineByPropertyName = true, ParameterSetName = "Path")]
|
||||
public string[] Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the literal path parameter to markdown files(s) to display.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = "LiteralPath",
|
||||
Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]
|
||||
[Alias("PSPath", "LP")]
|
||||
public string[] LiteralPath
|
||||
{
|
||||
get { return Path; }
|
||||
set { Path = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the switch to view Html in default browser.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public SwitchParameter UseBrowser { get; set; }
|
||||
|
||||
private SteppablePipeline stepPipe;
|
||||
private System.Management.Automation.PowerShell _powerShell;
|
||||
|
||||
/// <summary>
|
||||
/// Override BeginProcessing.
|
||||
/// </summary>
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
if (!UseBrowser.IsPresent)
|
||||
{
|
||||
// Since UseBrowser is not bound, we use proxy to Out-Default
|
||||
stepPipe = ScriptBlock.Create(@"Microsoft.PowerShell.Core\Out-Default @PSBoundParameters").GetSteppablePipeline(this.MyInvocation.CommandOrigin);
|
||||
stepPipe.Begin(this);
|
||||
}
|
||||
_powerShell = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,114 +74,148 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
object inpObj = InputObject.BaseObject;
|
||||
|
||||
if (inpObj is MarkdownInfo markdownInfo)
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
if (UseBrowser)
|
||||
{
|
||||
var html = markdownInfo.Html;
|
||||
|
||||
if (!string.IsNullOrEmpty(html))
|
||||
case "InputObject":
|
||||
if (InputObject.BaseObject is MarkdownInfo markdownInfo)
|
||||
{
|
||||
string tmpFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".html");
|
||||
|
||||
try
|
||||
{
|
||||
using (var writer = new StreamWriter(new FileStream(tmpFilePath, FileMode.Create, FileAccess.Write, FileShare.Write)))
|
||||
{
|
||||
writer.Write(html);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var errorRecord = new ErrorRecord(
|
||||
e,
|
||||
"ErrorWritingTempFile",
|
||||
ErrorCategory.WriteError,
|
||||
tmpFilePath);
|
||||
|
||||
WriteError(errorRecord);
|
||||
return;
|
||||
}
|
||||
|
||||
if (InternalTestHooks.ShowMarkdownOutputBypass)
|
||||
{
|
||||
WriteObject(html);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo();
|
||||
startInfo.FileName = tmpFilePath;
|
||||
startInfo.UseShellExecute = true;
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var errorRecord = new ErrorRecord(
|
||||
e,
|
||||
"ErrorLaunchingDefaultApplication",
|
||||
ErrorCategory.InvalidOperation,
|
||||
targetObject : null);
|
||||
|
||||
WriteError(errorRecord);
|
||||
return;
|
||||
}
|
||||
ProcessMarkdownInfo(markdownInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = StringUtil.Format(ConvertMarkdownStrings.MarkdownInfoInvalid, "Html");
|
||||
ConvertFromMarkdown("InputObject", InputObject.BaseObject);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "Path":
|
||||
case "LiteralPath":
|
||||
ConvertFromMarkdown(ParameterSetName, Path);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ConvertMarkdownStrings.InvalidParameterSet, ParameterSetName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process markdown as path.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Name of parameter to pass to `ConvertFrom-Markdown`.</param>
|
||||
/// <param name="input">Value of parameter.</param>
|
||||
private void ConvertFromMarkdown(string parameter, object input)
|
||||
{
|
||||
_powerShell.AddCommand("Microsoft.PowerShell.Utility\\ConvertFrom-Markdown").AddParameter(parameter, input);
|
||||
if (!UseBrowser)
|
||||
{
|
||||
_powerShell.AddParameter("AsVT100EncodedString");
|
||||
}
|
||||
|
||||
Collection<MarkdownInfo> output = _powerShell.Invoke<MarkdownInfo>();
|
||||
|
||||
if (_powerShell.HadErrors)
|
||||
{
|
||||
foreach (ErrorRecord errorRecord in _powerShell.Streams.Error)
|
||||
{
|
||||
WriteError(errorRecord);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MarkdownInfo result in output)
|
||||
{
|
||||
ProcessMarkdownInfo(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process markdown as input objects.
|
||||
/// </summary>
|
||||
/// <param name="markdownInfo">Markdown object to process.</param>
|
||||
private void ProcessMarkdownInfo(MarkdownInfo markdownInfo)
|
||||
{
|
||||
if (UseBrowser)
|
||||
{
|
||||
var html = markdownInfo.Html;
|
||||
|
||||
if (!string.IsNullOrEmpty(html))
|
||||
{
|
||||
string tmpFilePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString() + ".html");
|
||||
|
||||
try
|
||||
{
|
||||
using (var writer = new StreamWriter(new FileStream(tmpFilePath, FileMode.Create, FileAccess.Write, FileShare.Write)))
|
||||
{
|
||||
writer.Write(html);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var errorRecord = new ErrorRecord(
|
||||
new InvalidDataException(errorMessage),
|
||||
"HtmlIsNullOrEmpty",
|
||||
ErrorCategory.InvalidData,
|
||||
html);
|
||||
e,
|
||||
"ErrorWritingTempFile",
|
||||
ErrorCategory.WriteError,
|
||||
tmpFilePath);
|
||||
|
||||
WriteError(errorRecord);
|
||||
return;
|
||||
}
|
||||
|
||||
if (InternalTestHooks.ShowMarkdownOutputBypass)
|
||||
{
|
||||
WriteObject(html);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo();
|
||||
startInfo.FileName = tmpFilePath;
|
||||
startInfo.UseShellExecute = true;
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var errorRecord = new ErrorRecord(
|
||||
e,
|
||||
"ErrorLaunchingDefaultApplication",
|
||||
ErrorCategory.InvalidOperation,
|
||||
targetObject: null);
|
||||
|
||||
WriteError(errorRecord);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var vt100String = markdownInfo.VT100EncodedString;
|
||||
string errorMessage = StringUtil.Format(ConvertMarkdownStrings.MarkdownInfoInvalid, "Html");
|
||||
var errorRecord = new ErrorRecord(
|
||||
new InvalidDataException(errorMessage),
|
||||
"HtmlIsNullOrEmpty",
|
||||
ErrorCategory.InvalidData,
|
||||
html);
|
||||
|
||||
if (!string.IsNullOrEmpty(vt100String))
|
||||
{
|
||||
if (InternalTestHooks.ShowMarkdownOutputBypass)
|
||||
{
|
||||
WriteObject(vt100String);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stepPipe != null)
|
||||
{
|
||||
stepPipe.Process(vt100String);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = StringUtil.Format(ConvertMarkdownStrings.MarkdownInfoInvalid, "VT100EncodedString");
|
||||
var errorRecord = new ErrorRecord(
|
||||
new InvalidDataException(errorMessage),
|
||||
"VT100EncodedStringIsNullOrEmpty",
|
||||
ErrorCategory.InvalidData,
|
||||
vt100String);
|
||||
|
||||
WriteError(errorRecord);
|
||||
}
|
||||
WriteError(errorRecord);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = StringUtil.Format(ConvertMarkdownStrings.InvalidInputObjectType, inpObj.GetType());
|
||||
var errorRecord = new ErrorRecord(
|
||||
new ArgumentException(errorMessage),
|
||||
"InvalidInputObject",
|
||||
ErrorCategory.InvalidArgument,
|
||||
InputObject);
|
||||
var vt100String = markdownInfo.VT100EncodedString;
|
||||
|
||||
WriteError(errorRecord);
|
||||
if (!string.IsNullOrEmpty(vt100String))
|
||||
{
|
||||
WriteObject(vt100String);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = StringUtil.Format(ConvertMarkdownStrings.MarkdownInfoInvalid, "VT100EncodedString");
|
||||
var errorRecord = new ErrorRecord(
|
||||
new InvalidDataException(errorMessage),
|
||||
"VT100EncodedStringIsNullOrEmpty",
|
||||
ErrorCategory.InvalidData,
|
||||
vt100String);
|
||||
|
||||
WriteError(errorRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,9 +224,9 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
protected override void EndProcessing()
|
||||
{
|
||||
if (stepPipe != null)
|
||||
if (_powerShell != null)
|
||||
{
|
||||
stepPipe.End();
|
||||
_powerShell.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,4 +129,7 @@
|
||||
<data name="MarkdownInfoInvalid" xml:space="preserve">
|
||||
<value>The property {0} of the given object is null or empty.</value>
|
||||
</data>
|
||||
<data name="InvalidParameterSet" xml:space="preserve">
|
||||
<value>Invalid parameter set name: {0}.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -448,7 +448,7 @@ bool function()`n{`n}
|
||||
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("ShowMarkdownOutputBypass", $false)
|
||||
}
|
||||
|
||||
It "can show VT100 converted from markdown" {
|
||||
It "Can show VT100 converted from markdown" {
|
||||
$text = "Bold"
|
||||
$mdText = "**$text**"
|
||||
$expectedString = GetExpectedString -ElementType 'Bold' -Text $text -VT100Support $true
|
||||
@@ -457,7 +457,7 @@ bool function()`n{`n}
|
||||
$result | Should -BeExactly $expectedString
|
||||
}
|
||||
|
||||
It "can show HTML converted from markdown" {
|
||||
It "Can show HTML converted from markdown" {
|
||||
$text = "Bold"
|
||||
$mdText = "**$text**"
|
||||
$expectedString = GetExpectedHTML -ElementType 'Bold' -Text $text
|
||||
@@ -466,7 +466,45 @@ bool function()`n{`n}
|
||||
$result | Should -BeExactly $expectedString
|
||||
}
|
||||
|
||||
It "Gets an error if the input object is missing the <propertyname> property." -TestCases @(@{propertyname = 'Html'}, @{propertyname = 'VT100EncodedString'}) {
|
||||
It "Markdown files work with cmdlet: <pathParam>" -TestCases @(
|
||||
@{ pathParam = "Path" }
|
||||
@{ pathParam = "LiteralPath" }
|
||||
) {
|
||||
param($pathParam)
|
||||
|
||||
$text = "Header"
|
||||
$mdText = "# $text"
|
||||
$expectedString = GetExpectedString -ElementType Header1 -Text $text -VT100Support $true
|
||||
$mdFile = Join-Path $TestDrive "test.md"
|
||||
Set-Content -Path $mdFile -Value $mdText
|
||||
|
||||
$params = @{ $pathParam = $mdFile }
|
||||
$result = Show-Markdown @params
|
||||
$result | Should -BeExactly $expectedString
|
||||
}
|
||||
|
||||
It "Can show markdown piped directly to cmdlet" {
|
||||
$text = "Header"
|
||||
$mdText = "# $text"
|
||||
$expectedString = GetExpectedString -ElementType Header1 -Text $text -VT100Support $true
|
||||
|
||||
$result = $mdText | Show-Markdown
|
||||
$result | Should -BeExactly $expectedString
|
||||
}
|
||||
|
||||
It "Can show markdown piped directly to cmdlet as HTML" {
|
||||
$text = "Header"
|
||||
$mdText = "# $text"
|
||||
$expectedString = GetExpectedHTML -ElementType Header1 -Text $text
|
||||
|
||||
$result = $mdText | Show-Markdown -UseBrowser
|
||||
$result | Should -BeExactly $expectedString
|
||||
}
|
||||
|
||||
It "Gets an error if the input object is missing the <propertyname> property." -TestCases @(
|
||||
@{ propertyname = 'Html' }
|
||||
@{ propertyname = 'VT100EncodedString' }
|
||||
) {
|
||||
param($propertyname)
|
||||
|
||||
$markdownInfo = [Microsoft.PowerShell.MarkdownRender.MarkdownInfo]::new()
|
||||
|
||||
Reference in New Issue
Block a user