Skip to content

Comment-based help examples now support optional titles#27387

Open
MariusStorhaug wants to merge 12 commits intoPowerShell:masterfrom
MariusStorhaug:feature/example-titles-in-comment-help
Open

Comment-based help examples now support optional titles#27387
MariusStorhaug wants to merge 12 commits intoPowerShell:masterfrom
MariusStorhaug:feature/example-titles-in-comment-help

Conversation

@MariusStorhaug
Copy link
Copy Markdown

@MariusStorhaug MariusStorhaug commented May 1, 2026

Comment-based help examples can now carry an optional title using the .EXAMPLE Title text syntax, mirroring the inline pattern already used by .PARAMETER <Name>. Previously, putting any text on the same line as .EXAMPLE fell through to an unhandled default: case in the parser and silently discarded the entire help block — now that text is captured as the example's title and rendered alongside the auto-generated heading. Examples without titles continue to work exactly as before, so no existing help content is affected.

New: Titled examples in comment-based help

Authors can now give each example a meaningful name on the same line as the .EXAMPLE keyword:

function Show-Example {
<#
    .SYNOPSIS
    Demonstrates titled and untitled examples.

    .EXAMPLE Retrieving an item from a directory
    Get-Item -Path C:\Temp

    Retrieves the item at C:\Temp.

    .EXAMPLE Listing files in a folder
    Get-ChildItem -Path C:\Temp

    Lists all files and folders in C:\Temp.

    .EXAMPLE
    Get-Process

    Gets all running processes (untitled — still works as before).
#>
    param()
}

Get-Help Show-Example -Examples renders titles alongside the auto-generated number, matching the format MAML-based help has always used for compiled cmdlets:

-------------------------- EXAMPLE 1: Retrieving an item from a directory --------------------------

Get-Item -Path C:\Temp

Retrieves the item at C:\Temp.

-------------------------- EXAMPLE 2: Listing files in a folder --------------------------

Get-ChildItem -Path C:\Temp

Lists all files and folders in C:\Temp.

-------------------------- EXAMPLE 3 --------------------------

Get-Process

Gets all running processes (untitled — still works as before).

Line-comment syntax (# .EXAMPLE Title) is supported as well.

New: CommentHelpInfo.ExampleTitles public property

External tools (PlatyPS, doc generators, formatters) can now read titles via a new public property on CommentHelpInfo:

public ReadOnlyCollection<string> ExampleTitles { get; internal set; }

ExampleTitles runs in parallel with the existing Examples collection — same length, same index mapping. An empty string entry means that example has no title.

var help = scriptBlockAst.GetHelpContent();
for (int i = 0; i < help.Examples.Count; i++)
{
    string title = help.ExampleTitles[i];
    string body  = help.Examples[i];
    if (!string.IsNullOrEmpty(title))
        Console.WriteLine($"EXAMPLE {i + 1}: {title}");
    else
        Console.WriteLine($"EXAMPLE {i + 1}");
    Console.WriteLine(body);
}

Round-trip preserved

Both serializers retain titles when regenerating comment-based help:

  • CommentHelpInfo.GetCommentBlock() emits .EXAMPLE <title> when the title is non-empty, and .EXAMPLE on its own line when empty.
  • ProxyCommand.GetHelpComments() reconstructs the user-supplied title from the decorated MAML heading via a new culture-agnostic helper (ExtractExampleTitle) that anchors on the dash-padding and : separator rather than the literal English word EXAMPLE — so it works under any UI culture.

Backward compatibility

Fully backward compatible:

  • .EXAMPLE with no trailing text continues to behave exactly as before.
  • The existing CommentHelpInfo.Examples property is unchanged (still ReadOnlyCollection<string> of bodies). ExampleTitles is purely additive.
  • Existing comment-based help across the ecosystem renders identically — the only observable difference is that .EXAMPLE <text> no longer breaks the help block.

Out of scope

These follow-ups are tracked in the linked issue and need separate work in other repositories:

Technical Details

Files changed:

  • src/System.Management.Automation/help/HelpCommentsParser.cs — Added a new case "EXAMPLE" to the Groups[3].Success == true branch of AnalyzeCommentBlock that captures match.Groups[3].Value.Trim() into a new parallel List<string> _exampleTitles field, then collects the body via GetSection(). The existing case "EXAMPLE" in the no-arguments branch appends an empty string to _exampleTitles to keep the title and body indices aligned. The XML-building section conditionally appends : <title> to the EXAMPLE N heading when the title is non-empty. After parsing, _sections.ExampleTitles is assigned as a ReadOnlyCollection<string>.
  • src/System.Management.Automation/engine/parser/ast.cs — Added the new ReadOnlyCollection<string> ExampleTitles { get; internal set; } property on CommentHelpInfo. Updated GetCommentBlock() to emit .EXAMPLE <title> when ExampleTitles[index] is non-empty, and .EXAMPLE on its own line otherwise. The existing Examples property type is unchanged — the design is intentionally a parallel collection, not a redesign of Examples, so the public API stays binary- and source-compatible.
  • src/System.Management.Automation/engine/ProxyCommand.cs — Updated GetHelpComments to emit .EXAMPLE <title> when the underlying MAML title contains a user-supplied portion. Added the private ExtractExampleTitle helper that recovers the user title from the decorated MAML heading by anchoring on the dash-padding and the : separator, deliberately avoiding the literal word EXAMPLE so the logic remains correct under non-English UI cultures.
  • test/powershell/Language/Scripting/ScriptHelp.Tests.ps1 — Added Pester coverage for: titled examples (verifying $help.examples.example.title), mixed titled/untitled examples, untitled-output regression (identical to current rendering), GetCommentBlock() round-tripping, regression test for the previous default: return false parser bug, line-comment syntax (# .EXAMPLE Title), edge cases (titles containing colons and dashes, titles ending with a dash), and a parity assertion that Examples.Count == ExampleTitles.Count.
  • test/powershell/engine/Api/ProxyCommand.Tests.ps1 — Added round-trip tests for ProxyCommand.GetHelpComments with titled examples.

Implementation plan progress (from #23966):

  • ✅ Parser changes — done
  • ✅ Data model changes — done (parallel ExampleTitles collection; non-breaking)
  • ✅ XML generation changes — done
  • ✅ Round-trip serialization (GetCommentBlock + ProxyCommand.GetHelpComments + culture-agnostic ExtractExampleTitle) — done
  • ✅ Tests — done
  • ⬜ PowerShell-Docs updates — separate PR
  • ⬜ PlatyPS update — separate PR (#627)
  • ⬜ vscode-powershell / EditorSyntax grammar updates — separate PRs

Design history. An earlier revision changed CommentHelpInfo.Examples to ReadOnlyCollection<KeyValuePair<string, string>> to carry title and body together. That was reverted in commit 38f9720 based on review feedback to keep the public API non-breaking — the parallel ExampleTitles collection delivers the same capability without altering the existing Examples signature.

PR Checklist

  • PR has a meaningful title
  • Summarized changes
  • Change is not breaking
  • Make sure all .h, .cpp, .cs, .ps1 and .psm1 files have the correct copyright header
  • Tests added/passed
  • Documentation updates — tracked separately for PowerShell-Docs (see "Out of scope" above)
  • Backward compatible
  • User-facing cmdlet changes are documented — N/A, no cmdlet changes (parser/help engine only)

…into feature/example-titles-in-comment-help
… tests

- Revert CommentHelpInfo.Examples to ReadOnlyCollection<string>; add parallel ExampleTitles property per issue spec (non-breaking)
- Update HelpCommentsParser to maintain parallel _exampleTitles list
- Make ProxyCommand.ExtractExampleTitle culture-agnostic (anchor on dashes/colon, not the literal English word EXAMPLE)
- Fix \n vs backtick-n in ProxyCommand round-trip tests
- Add tests: line-comment titled examples, ExampleTitles count parity, title ending with dash, untitled-output regression
@MariusStorhaug MariusStorhaug changed the title 🚀 [Feature]: Comment-based help examples now support optional titles Comment-based help examples now support optional titles May 1, 2026
@MariusStorhaug MariusStorhaug marked this pull request as ready for review May 1, 2026 23:07
@MariusStorhaug MariusStorhaug requested a review from daxian-dbw as a code owner May 1, 2026 23:07
Copilot AI review requested due to automatic review settings May 1, 2026 23:07
@MariusStorhaug
Copy link
Copy Markdown
Author

If this is interesting, ill continue with the other repos to align those with the added feature.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for optional titles on comment-based help examples using the .EXAMPLE <Title> syntax, and preserves those titles through XML generation and proxy help comment round-tripping.

Changes:

  • Extend comment-based help parsing and XML generation to capture/render optional .EXAMPLE titles.
  • Add a new CommentHelpInfo.ExampleTitles parallel collection and update GetCommentBlock() to round-trip titled examples.
  • Update ProxyCommand.GetHelpComments() to emit .EXAMPLE <title> when a user title can be recovered, and add Pester coverage for the new behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/System.Management.Automation/help/HelpCommentsParser.cs Captures .EXAMPLE <title> in the parser and appends titles to the generated example heading.
src/System.Management.Automation/engine/parser/ast.cs Adds CommentHelpInfo.ExampleTitles and updates GetCommentBlock() to emit .EXAMPLE <title> when present.
src/System.Management.Automation/engine/ProxyCommand.cs Extracts user titles from decorated MAML headings and emits .EXAMPLE <title> during proxy help comment generation.
test/powershell/Language/Scripting/ScriptHelp.ExampleTitles.Tests.ps1 New Pester coverage for titled .EXAMPLE parsing, round-trip via GetCommentBlock(), and backward compatibility.
test/powershell/engine/Api/ProxyCommand.Tests.ps1 Adds tests asserting ProxyCommand.GetHelpComments() preserves/emits titled examples and handles edge cases.

Comment thread test/powershell/Language/Scripting/ScriptHelp.ExampleTitles.Tests.ps1 Outdated
Comment thread src/System.Management.Automation/engine/ProxyCommand.cs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread test/powershell/engine/Api/ProxyCommand.Tests.ps1 Outdated
Comment thread src/System.Management.Automation/engine/ProxyCommand.cs Outdated
…hen ProxyCommand title round-trip tests

- Updated the XML doc on ExtractExampleTitle to say ':' (matching the
  IndexOf(':') implementation) instead of the misleading ': '.
- Changed the existing round-trip assertion from Should -Not -BeNullOrEmpty
  (trivially true for all examples) to exact title equality comparison.
- Added a dedicated test 'ProxyCommand.GetHelpComments preserves custom
  example titles' that defines a function with titled and untitled examples,
  round-trips through GetHelpComments, and asserts the custom title text
  survives.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@MariusStorhaug MariusStorhaug requested a review from Copilot May 2, 2026 00:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Supporting Titles in Comment-Based Help Examples for script-based functions

2 participants