Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 10, 2025

When creating a PR from a single commit, the extension now unwraps commit message body lines that were wrapped at 72 characters, matching GitHub's native behavior.

Changes

  • Added unwrapCommitMessageBody function: Joins consecutive non-formatted lines while preserving:

    • Blank lines (paragraph breaks)
    • List items (-, *, +, numbered)
    • Blockquotes (>)
    • Indented code blocks (distinguishes between actual code blocks and list item continuations)
    • Fenced code blocks (```)
  • Updated titleAndBodyFrom: Applies unwrapping to commit message bodies before setting PR description

  • Test coverage: Added 17 test cases for wrapped paragraphs, lists, quotes, indented blocks, fenced code blocks, nested lists, list continuations, and mixed content

Example

Before:

This is a long commit message that has been wrapped at 72
characters to fit conventional Git formatting standards.

After:

This is a long commit message that has been wrapped at 72 characters to fit conventional Git formatting standards.

Implementation Details

The function uses state tracking to correctly handle:

  • Fenced code blocks: Content within ``` markers is preserved without modification
  • List context: Tracks when processing list items to distinguish between:
    • Indented code blocks (4+ spaces outside of lists)
    • List item continuations (2+ spaces within lists)
    • Nested list items (list markers with leading whitespace)
Original prompt

This section details on the original issue you should resolve

<issue_title>Join commit message lines on PR creation</issue_title>
<issue_description>Both on GitHub and this extension, there's functionality where if you're creating a PR from a single commit, it will use the commit subject as the PR title and the commit message body as the PR description. In Git commits, it's conventional to wrap commit messages at 72 characters (VS Code even has a default ruler for this) for command-line tooling.

In GitHub, there's some smartness to unwrap those lines when translating the commit message body into the PR description. It would be nice if this extension had that functionality as well.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI self-assigned this Dec 10, 2025
Copilot AI and others added 4 commits December 10, 2025 09:51
- Add unwrapCommitMessageBody function to join wrapped lines
- Preserve blank lines, list items, quotes, and indented content
- Add comprehensive tests for various unwrapping scenarios
- Matches GitHub's behavior when converting commit messages to PR descriptions

Co-authored-by: alexr00 <[email protected]>
- Extract regex pattern to named constant PRESERVE_LINE_PATTERN
- Replace deprecated substr() with slice()
- Improve regex to match only spaces/tabs explicitly instead of \s
- Add detailed comments explaining the pattern

Co-authored-by: alexr00 <[email protected]>
- Place hyphen at end of character class for clarity
- Extract hasBody condition to avoid duplication

Co-authored-by: alexr00 <[email protected]>
Copilot AI changed the title [WIP] Add functionality to unwrap commit message lines on PR creation Unwrap 72-character wrapped commit message lines when creating PRs Dec 10, 2025
Copilot AI requested a review from alexr00 December 10, 2025 10:04
Copy link

@justingrant justingrant left a comment

Choose a reason for hiding this comment

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

Great to see this PR, but I see a few problems.

Comment on lines 2890 to 2950
if (!body) {
return body;
}

// Pattern to detect lines that should be preserved (not joined):
// - Lines starting with whitespace (indented/code blocks)
// - Lines starting with list markers (*, -, +, >)
// - Lines starting with numbered list items (e.g., "1. ")
const PRESERVE_LINE_PATTERN = /^[ \t*+>\-]|^\d+\./;

const lines = body.split('\n');
const result: string[] = [];
let i = 0;

while (i < lines.length) {
const line = lines[i];

// Preserve blank lines
if (line.trim() === '') {
result.push(line);
i++;
continue;
}

// Check if this line should NOT be joined with the next
// Lines that start with special formatting characters should be preserved
const shouldPreserveLine = PRESERVE_LINE_PATTERN.test(line);

if (shouldPreserveLine) {
result.push(line);
i++;
continue;
}

// Start accumulating lines that should be joined
let joinedLine = line;
i++;

// Keep joining lines until we hit a blank line or a line that shouldn't be joined
while (i < lines.length) {
const nextLine = lines[i];

// Stop at blank lines
if (nextLine.trim() === '') {
break;
}

// Stop at lines that start with special formatting
if (PRESERVE_LINE_PATTERN.test(nextLine)) {
break;
}

// Join this line with a space
joinedLine += ' ' + nextLine;
i++;
}

result.push(joinedLine);
}

return result.join('\n');

Choose a reason for hiding this comment

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

A few problems with your code:

  • Having two nested loops is unnecessarily complicated.
  • You don't support code blocks that are fenced with ```
  • Detection of indented code is flawed because it doesn't account for nested list items or list item continuations that have 4+ spaces at the start of the line.

Here's a revised version:

Suggested change
if (!body) {
return body;
}
// Pattern to detect lines that should be preserved (not joined):
// - Lines starting with whitespace (indented/code blocks)
// - Lines starting with list markers (*, -, +, >)
// - Lines starting with numbered list items (e.g., "1. ")
const PRESERVE_LINE_PATTERN = /^[ \t*+>\-]|^\d+\./;
const lines = body.split('\n');
const result: string[] = [];
let i = 0;
while (i < lines.length) {
const line = lines[i];
// Preserve blank lines
if (line.trim() === '') {
result.push(line);
i++;
continue;
}
// Check if this line should NOT be joined with the next
// Lines that start with special formatting characters should be preserved
const shouldPreserveLine = PRESERVE_LINE_PATTERN.test(line);
if (shouldPreserveLine) {
result.push(line);
i++;
continue;
}
// Start accumulating lines that should be joined
let joinedLine = line;
i++;
// Keep joining lines until we hit a blank line or a line that shouldn't be joined
while (i < lines.length) {
const nextLine = lines[i];
// Stop at blank lines
if (nextLine.trim() === '') {
break;
}
// Stop at lines that start with special formatting
if (PRESERVE_LINE_PATTERN.test(nextLine)) {
break;
}
// Join this line with a space
joinedLine += ' ' + nextLine;
i++;
}
result.push(joinedLine);
}
return result.join('\n');
const rawLines = body.split(/\r?\n/);
const result: string[] = [];
let inFencedCodeBlock = false;
let prevWasCode = false;
for (const rawLine of rawLines) {
const line = rawLine.trimEnd(); // Remove trailing space
const trimmed = line.trim();
const prev = result[result.length - 1];
const isList = (s: string) => /^\s*[>\*\-\+]\s/.test(s);
const indentSpaces = line.match(/^( *)/)?.[1].length ?? 0;
const isListItemContinuation: boolean =
!prevWasCode && isList(prev) && indentSpaces >= 2;
const isIndentedCode: boolean =
!isListItemContinuation && (indentSpaces >= 4 || line.startsWith('\t'));
const isCode: boolean = inFencedCodeBlock || isIndentedCode;
if (line.startsWith('```')) {
// Start or end of fenced code block is never joined
inFencedCodeBlock = !inFencedCodeBlock;
result.push(line);
} else if (!line || isCode || isList(line) || !prev || !result.length) {
// Empty/code/list lines never join with the previous line.
// Also don't join the first line, or if previous line is blank.
result.push(line);
} else {
// Otherwise, join with previous line
result[result.length - 1] = prev + ' ' + trimmed;
}
prevWasCode = isCode;
}
return result.join('\n');

Copy link
Member

Choose a reason for hiding this comment

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

@copilot address this comment.

Copy link
Member

@alexr00 alexr00 left a comment

Choose a reason for hiding this comment

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

@copilot These notes from @justingrant are good, address them:

  • You don't support code blocks that are fenced with ```
  • Detection of indented code is flawed because it doesn't account for nested list items or list item continuations that have 4+ spaces at the start of the line.

- Support fenced code blocks with ``` markers
- Fix indented code detection to distinguish between:
  - Actual code blocks (4+ spaces, not in list context)
  - List item continuations (2+ spaces in list context)
  - Nested list items (detected by list markers with indentation)
- Track list context state to handle list continuations correctly
- Add comprehensive tests for all new scenarios

Co-authored-by: alexr00 <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 18, 2025

@copilot These notes from @justingrant are good, address them:

  • You don't support code blocks that are fenced with ```...

Addressed both issues in commit 1072b95:

  1. Fenced code blocks: Now detects and preserves code blocks with ``` markers, preventing lines within fenced blocks from being joined.

  2. Indented code detection: Fixed by tracking list context state:

    • Lines with 4+ spaces are preserved as code blocks only when NOT in a list context
    • When in a list (after seeing a list item), lines with 2+ spaces are treated as list continuations and preserved
    • Nested list items are detected by their list markers with leading whitespace
    • List context resets on blank lines

Added 8 new tests covering fenced code blocks, nested lists, list continuations, and complex mixed content scenarios.

Copilot AI requested a review from alexr00 December 18, 2025 11:51
Copy link
Member

@alexr00 alexr00 left a comment

Choose a reason for hiding this comment

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

@justingrant, thanks for pointing these out!

  • You don't support code blocks that are fenced with ```
  • Detection of indented code is flawed because it doesn't account for nested list items or list item continuations that have 4+ spaces at the start of the line.

@alexr00 alexr00 marked this pull request as ready for review December 18, 2025 12:05
@alexr00 alexr00 enabled auto-merge (squash) December 18, 2025 12:05
@vs-code-engineering vs-code-engineering bot added this to the December / January 2026 milestone Dec 18, 2025
@alexr00 alexr00 merged commit e1635cb into main Dec 18, 2025
6 checks passed
@alexr00 alexr00 deleted the copilot/add-unwrap-commit-message-functionality branch December 18, 2025 12:10
@justingrant
Copy link

@alexr00 @copilot - After testing this PR, there's a problem: line breaks are not removed inside list items. For example, I'd expect the following commit markdown to end up as 2 lines in the resulting PR markdown. But it remains as 4 lines:

  • This is a list item with two lines
    that have a line break between them
    • This is a nested list item that also has
      two lines that should have been merged

alexr00 added a commit that referenced this pull request Jan 5, 2026
@alexr00
Copy link
Member

alexr00 commented Jan 5, 2026

@justingrant thanks for trying it out! Opened #8335 to address this.

alexr00 added a commit that referenced this pull request Jan 5, 2026
@justingrant
Copy link

Opened #8335 to address this.

Thanks @alexr00 for improving this! Unfortunately I think the follow-up PR might have some problems too, and may need some more tests. See #8335 (comment)

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.

Join commit message lines on PR creation

5 participants