Added Markdown rendering cmdlets#6926
Conversation
|
@SteveL-MSFT We need an (formal) approvement from PowerShell Committee to use third party application - markdig. |
There was a problem hiding this comment.
LitPathParamSet looks bad. I'd prefer LiteralPathParameterSet and PathParameterSet.
There was a problem hiding this comment.
Seems we should use Markdown in all comments (starting with capital letter).
There was a problem hiding this comment.
Could you please address this?
There was a problem hiding this comment.
Please set final dot in all public comments.
There was a problem hiding this comment.
Can we move this in BeginProcessing method?
There was a problem hiding this comment.
For long paths it is better to place '{0}' at the very end.
There was a problem hiding this comment.
Please use C# syntax. Below too.
There was a problem hiding this comment.
We should use a cache for the space string.
https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/utils/StringUtil.cs#L69
There was a problem hiding this comment.
The property (and below) is already defined in PowerShell.Common.props.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
|
@iSazonov We are ok to use markdig |
|
@SteveL-MSFT Please set the Committee label then. |
|
@PowerShell/powershell-committee reviewed this and approves of using MarkDig |
|
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. |
|
I will be resuming work on this. |
There was a problem hiding this comment.
Should we use PSObject.Base()?
There was a problem hiding this comment.
There was a problem hiding this comment.
We need useful public comments.
There was a problem hiding this comment.
The same - PSObject.Base()?
There was a problem hiding this comment.
There was a problem hiding this comment.
Seems we already fixed this and can remove the workaround.
There was a problem hiding this comment.
I will test this and update if workaround is not needed anymore.
There was a problem hiding this comment.
Can obj be null?
Below I see some methods with such pattern.
Suggestion:
if (obj == null)
{
return;
}There was a problem hiding this comment.
No obj cannot be null. Renderer will not be called in that case.
7492db9 to
aa80db2
Compare
There was a problem hiding this comment.
BeginProcess -> BeginProcessing()
There was a problem hiding this comment.
Please remove the unneeded comment.
There was a problem hiding this comment.
endproessing -> EndProcessing()
There was a problem hiding this comment.
Why we duplicate the code from StringUtil.cs?
There was a problem hiding this comment.
StringUtil class is internal.
|
@iSazonov Can you have another look? |
JamesWTruher
left a comment
There was a problem hiding this comment.
there's only 1 where i think there's a real issue (your UseBrowser handling) - the rest are just comments.
There was a problem hiding this comment.
could you describe what you're doing here, rather than the generic?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
In ReadContentFromFile() we have Assert - I believe we should replace it with writing non-terminating error if file access failed.
There was a problem hiding this comment.
Added a non-terminating error.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
The reason we did not use System.ConsoleColor is to be in parity with PSReadline. I do not expect the user the provide ESCAPE.
There was a problem hiding this comment.
I'm not sure about this. I think it would miss Show-Markdown -UseBrowser:$false
what about (bool)UseBrowser
There was a problem hiding this comment.
Seems we could use UseBrowser.IsPresent .
There was a problem hiding this comment.
Does something reasonable happen on non-Windows systems?
There was a problem hiding this comment.
Seems we have startInfo.UseShellExecute = true working on Unix systems now.
There was a problem hiding this comment.
I tested it, UseShellExecute works on non-Windows now.
There was a problem hiding this comment.
since you're reusing a bunch of these, I'd be happier if they were constants
There was a problem hiding this comment.
nice, i wonder if you should check for empty string and include this as "image"
There was a problem hiding this comment.
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
There was a problem hiding this comment.
ah - now I understand - you don't actually expect the user to give you the actual escape sequence.
There was a problem hiding this comment.
We could use MarkdownOptionInfoVariableName const.
There was a problem hiding this comment.
They are in different classes. Too much overhead to define a single string.
There was a problem hiding this comment.
I see we define the const twice. Could we use one definition for all uses?
There was a problem hiding this comment.
They are in different classes. Too much overhead to define a single string.
There was a problem hiding this comment.
In ReadContentFromFile() we have Assert - I believe we should replace it with writing non-terminating error if file access failed.
There was a problem hiding this comment.
As mentioned above we should replace the assert with writing non-terminating error if file access failed in StreamReader() or FileStream() (FileNotFound, Access Denied ...)
There was a problem hiding this comment.
Should baseObj.GetType() be explicitly baseObj.GetType().ToString()?
There was a problem hiding this comment.
It is unnecessary.
There was a problem hiding this comment.
We have this is most csproj files. So kept it consistent.
There was a problem hiding this comment.
Can we exclude the reflection?
Maybe use HashSet? Or switch()?
There was a problem hiding this comment.
Good idea, added switch.
There was a problem hiding this comment.
I see such definition above. Can we define this in one place?
There was a problem hiding this comment.
They are in different classes. Too much overhead to have separate class for defining a character.
There was a problem hiding this comment.
Should we define the color with other colors in one place?
There was a problem hiding this comment.
made a constant in this class. It is not a color but width and is not settable by user.
There was a problem hiding this comment.
Please remove $FullCLR. Below too.
b3dac3c to
b5601cf
Compare
|
Filed issue #7283 to track @daxian-dbw non-blocking feedback. |
|
@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))) |
There was a problem hiding this comment.
I believe we could use one try block instead of try-using.
| return mdContent; | ||
| } | ||
| } | ||
| catch(FileNotFoundException fnfe) |
There was a problem hiding this comment.
Maybe use one catch for all exceptions with custom (more useful) message and place original exception in InnerException?
There was a problem hiding this comment.
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))) |
There was a problem hiding this comment.
The same - we could use one try block instead of try-using.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Make sense send startInfo argument?
There was a problem hiding this comment.
startInfo is internally generated. I think seeing it in the error will be more confusing than useful.
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
I don't like this. Given that this method is public can we use enum type parameter like
string propertyName -> EscapeSequenceEnum propertyName ?
There was a problem hiding this comment.
Changed it to an enum
|
It looks @iSazonov's comments are new, although they are shown as |
There was a problem hiding this comment.
Could you please address this?
| { | ||
| var subListItemBlock = subListItem as ListItemBlock; | ||
|
|
||
| if (subListItemBlock != null) |
There was a problem hiding this comment.
Please use C# 7.0 syntax.
|
Only Question is that if you are adding a ConvertFrom-Markdown why aren't you adding a ConvertTo-Markdown cmdlet as well for consistency ? |
|
@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. |
…ig version to latest
557b664 to
a1627a3
Compare
|
@iSazonov I believe all your comments have been addressed. I will merge this PR soon. |
| # 8359D422-E0C4-4A0D-94EB-3C9DD16B7932 - PowerShell-Win | ||
| # Linux is invalid and mapped to Release | ||
| # | ||
| # 73EA0BE6-C0C5-4B56-A5AA-DADA4C01D690 - powershell-unix |
There was a problem hiding this comment.
@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).
There was a problem hiding this comment.
@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.
There was a problem hiding this comment.
And, we apologize for the inconvenience.
|
@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... |
|
@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: |

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
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:to the beginning of the title and remove the prefix when the PR is ready.[feature]if the change is significant or affects feature tests