Skip to content

Conversation

@adityapatwardhan
Copy link
Member

@adityapatwardhan adityapatwardhan commented May 24, 2018

PR Summary

  • ConvertFrom-Markdown is used for converting a markdown document or string to a MarkdownInfo object. It can optionally return a HTML or VT100 encoded string in addition to a AST of the markdown document.

  • Show-Markdown is used to either display the VT100 encoded string on console or redirect the HTML string to the browser.

  • Set/Get-MarkdownOption cmdlets get be used to view or set markdown rendering options.## PR Checklist

@iSazonov
Copy link
Collaborator

@SteveL-MSFT We need an (formal) approvement from PowerShell Committee to use third party application - markdig.

Copy link
Collaborator

@iSazonov iSazonov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave a comment

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LitPathParamSet looks bad. I'd prefer LiteralPathParameterSet and PathParameterSet.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we should use Markdown in all comments (starting with capital letter).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please address this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra line.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please set final dot in all public comments.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this in BeginProcessing method?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For long paths it is better to place '{0}' at the very end.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use C# syntax. Below too.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property (and below) is already defined in PowerShell.Common.props.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Markdown document can be large and such methods will allocate many temporary strings. Can we implement the rendering as methods which write to target buffer/string?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Markdown document is loaded by markdig in an efficient way see this post

The formatting done here is typically on small strings like headers, links etc. We can revisit this if we see a performance bottleneck here.

@SteveL-MSFT
Copy link
Member

@iSazonov We are ok to use markdig

@iSazonov
Copy link
Collaborator

@SteveL-MSFT Please set the Committee label then.

@SteveL-MSFT SteveL-MSFT added Review - Committee The PR/Issue needs a review from the PowerShell Committee Committee-Reviewed PS-Committee has reviewed this and made a decision and removed Review - Committee The PR/Issue needs a review from the PowerShell Committee labels May 30, 2018
@SteveL-MSFT
Copy link
Member

@PowerShell/powershell-committee reviewed this and approves of using MarkDig

@stale
Copy link

stale bot commented Jun 29, 2018

This PR has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed if no further activity occurs within 10 days.
Thank you for your contributions.
Community members are welcome to grab these works.

@stale stale bot added the Stale label Jun 29, 2018
@adityapatwardhan
Copy link
Member Author

I will be resuming work on this.

@stale stale bot removed the Stale label Jul 2, 2018
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use PSObject.Base()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need useful public comments.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same - PSObject.Base()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we already fixed this and can remove the workaround.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will test this and update if workaround is not needed anymore.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can obj be null?

Below I see some methods with such pattern.

Suggestion:

if (obj == null)
{
    return;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No obj cannot be null. Renderer will not be called in that case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BeginProcess -> BeginProcessing()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the unneeded comment.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

endproessing -> EndProcessing()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we duplicate the code from StringUtil.cs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StringUtil class is internal.

@adityapatwardhan adityapatwardhan changed the title WIP: Added Markdown rendering cmdlets Added Markdown rendering cmdlets Jul 11, 2018
@adityapatwardhan
Copy link
Member Author

@iSazonov Can you have another look?
@daxian-dbw @SteveL-MSFT can you have a look?

Copy link
Collaborator

@JamesWTruher JamesWTruher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's only 1 where i think there's a real issue (your UseBrowser handling) - the rest are just comments.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you describe what you're doing here, rather than the generic?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you might include a check fileInfo.Exists - I'm not sure what might happen if you call the rest of the code if the file doesn't exist. If there's a simple error and nothing dire happens, then ok.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ReadContentFromFile() we have Assert - I believe we should replace it with writing non-terminating error if file access failed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a non-terminating error.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little surprised that this regex catches an actual color escape sequence <ESC>[32;1m (it didn't for me since it doesn't include ESCAPE. Since these are all colors, is there a reason why you don't actually just allow the user to provide 'System.ConsoleColor'?

Mind you, this approach does allow for supporting those terminals which have support for RGB colors, which is definitely cool.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason we did not use System.ConsoleColor is to be in parity with PSReadline. I do not expect the user the provide ESCAPE.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this. I think it would miss Show-Markdown -UseBrowser:$false
what about (bool)UseBrowser

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we could use UseBrowser.IsPresent .

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does something reasonable happen on non-Windows systems?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we have startInfo.UseShellExecute = true working on Unix systems now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it, UseShellExecute works on non-Windows now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since you're reusing a bunch of these, I'd be happier if they were constants

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, i wonder if you should check for empty string and include this as "image"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the scenario I mentioned above was this scenario:
[io.fileinfo]::new("lol-I-dont-exist") | ConvertFrom-Markdown
it's a pretty corner-case scenario, I'll admit

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added test.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah - now I understand - you don't actually expect the user to give you the actual escape sequence.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use MarkdownOptionInfoVariableName const.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are in different classes. Too much overhead to define a single string.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we define the const twice. Could we use one definition for all uses?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are in different classes. Too much overhead to define a single string.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ReadContentFromFile() we have Assert - I believe we should replace it with writing non-terminating error if file access failed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above we should replace the assert with writing non-terminating error if file access failed in StreamReader() or FileStream() (FileNotFound, Access Denied ...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should baseObj.GetType() be explicitly baseObj.GetType().ToString()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is unnecessary.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra line.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have this is most csproj files. So kept it consistent.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we exclude the reflection?
Maybe use HashSet? Or switch()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, added switch.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see such definition above. Can we define this in one place?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are in different classes. Too much overhead to have separate class for defining a character.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we define the color with other colors in one place?

Copy link
Member Author

@adityapatwardhan adityapatwardhan Jul 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made a constant in this class. It is not a color but width and is not settable by user.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove $FullCLR. Below too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

@adityapatwardhan
Copy link
Member Author

Filed issue #7283 to track @daxian-dbw non-blocking feedback.

@adityapatwardhan
Copy link
Member Author

@daxian-dbw All tests passed.

using (StreamReader reader = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)))
try
{
using (StreamReader reader = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we could use one try block instead of try-using.

return mdContent;
}
}
catch(FileNotFoundException fnfe)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use one catch for all exceptions with custom (more useful) message and place original exception in InnerException?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are catching individual exceptions, I think the default messages are correct, without the need of custom messages. Examples below.

ConvertFrom-Markdown : Access to the path 'C:\Windows\System32\Configuration' is denied.
At line:1 char:1
+ ConvertFrom-Markdown -Path C:\Windows\System32\Configuration
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : SecurityError: (C:\Windows\System32\Configuration:String) [ConvertFrom-Markdown], UnauthorizedAccessException
+ FullyQualifiedErrorId : FileUnauthorizedAccess,Microsoft.PowerShell.Commands.ConvertFromMarkdownCommand
ConvertFrom-Markdown : Cannot find path 'D:\temp\sdfsdfs.md' because it does not exist.
At line:1 char:1
+ ConvertFrom-Markdown -Path D:\temp\\sdfsdfs.md
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ResourceUnavailable: (D:\temp\\sdfsdfs.md:String) [ConvertFrom-Markdown], ItemNotFoundException
+ FullyQualifiedErrorId : FileNotFound,Microsoft.PowerShell.Commands.ConvertFromMarkdownCommand

try
{
writer.Write(html);
using (var writer = new StreamWriter(new FileStream(tmpFilePath, FileMode.Create, FileAccess.Write, FileShare.Write)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same - we could use one try block instead of try-using.

Copy link
Member Author

@adityapatwardhan adityapatwardhan Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer using since there are multiple catch blocks and disposing in finally will be far too disjoint from where StreamWriter / FileStream are used.

e,
"ErrorLaunchingDefaultApplication",
ErrorCategory.InvalidOperation,
targetObject : null);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense send startInfo argument?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

startInfo is internally generated. I think seeing it in the error will be more confusing than useful.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still wonder that we don't use latest version for the initial PR.

public string AsEscapeSequence(string propertyName)
{
var propertyValue = this.GetType().GetProperty(propertyName)?.GetValue(this) as string;
var propName = propertyName?.ToLower();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this. Given that this method is public can we use enum type parameter like
string propertyName -> EscapeSequenceEnum propertyName ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to an enum

@daxian-dbw
Copy link
Member

It looks @iSazonov's comments are new, although they are shown as outdated. @adityapatwardhan can you please respond to @iSazonov's comments?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please address this?

{
var subListItemBlock = subListItem as ListItemBlock;

if (subListItemBlock != null)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use C# 7.0 syntax.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

@kilasuit
Copy link
Collaborator

Only Question is that if you are adding a ConvertFrom-Markdown why aren't you adding a ConvertTo-Markdown cmdlet as well for consistency ?

@iSazonov
Copy link
Collaborator

iSazonov commented Jul 13, 2018

@kilasuit The goal here is to open the way for native supporting help files in Mardown format. So currently we only need "convert from Markdown" and rendering. Later we could add other cmdlets.

@daxian-dbw
Copy link
Member

@iSazonov I believe all your comments have been addressed. I will merge this PR soon.

@daxian-dbw daxian-dbw merged commit 6f3e9d0 into PowerShell:master Jul 13, 2018
# 8359D422-E0C4-4A0D-94EB-3C9DD16B7932 - PowerShell-Win
# Linux is invalid and mapped to Release
#
# 73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690 - powershell-unix
Copy link
Contributor

@bergmeister bergmeister Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TravisEz13 This PR has removed all your comments about the configurations in the sln and changed those configurations as well (this always happens locally by default when one saves the solution).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bergmeister Thanks for catching this. I thought this was part of the markdown changes, and didn't realize it's unintentional. @adityapatwardhan will submit a PR to revert this shortly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, we apologize for the inconvenience.

@bergmeister
Copy link
Contributor

bergmeister commented Jul 13, 2018

@daxian-dbw This PR seems to have not been squash-merged. This makes it very hard to track changes in master now as this or some other PR seems to have invalided some of the PowerShell.sln VS solution configuration causing my PR below to not work any more...

@daxian-dbw
Copy link
Member

daxian-dbw commented Jul 13, 2018

@bergmeister Yes, this PR was merged with a commit node on purpose. For big features, we prefer to merge using a merge commit as long as the history is reasonably clean.

However, @adityapatwardhan merged #7284 with a merge commit by accident (that one should be squashed), and now the history on master looks a little confusing:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Committee-Reviewed PS-Committee has reviewed this and made a decision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants