Skip to content

fix(web): Tab nests numbered list items in the composer - #17138

Open
michal-billtech wants to merge 1 commit into
pingdotgg:mainfrom
michal-billtech:fix/composer-nested-ordered-list
Open

michal-billtech wants to merge 1 commit into
pingdotgg:mainfrom
michal-billtech:fix/composer-nested-ordered-list

Conversation

@michal-billtech

@michal-billtech michal-billtech commented Oct 8, 2026 •

Copy link
Copy Markdown

Problem

In the composer, Tab on a numbered list item prepends two spaces and keeps the number, so 1. first → Shift+Enter → Tab gives 2. instead of a nested 1.. Two spaces under 1. is not nesting in CommonMark (a child must reach the parent's content column), so the agent and the sent message get a flat list. In the plain composer, Shift+Enter on an empty nested item also drops out of the whole list instead of moving up one level.

Fixes #17124.

Change

  • Tab (listIndentForTab) nests the item at the content column of the item above: 3 spaces under 1. , 4 under 10. , 2 under - (unchanged for bullets). A nested ordered item starts at 1., or continues the sublist the item above already has. With no item to nest under, it keeps today's two-space indent.
  • Shift+Enter on an empty nested item (listContinuationForEnter) moves it to the parent's indent with the parent's next marker, which is what the rich-text composer already does through splitOrLiftListItem. An empty top-level item still leaves the list.
  • ComposerListEdit gets an optional cursor, so the caret stays on the item text when the marker width changes; ChatComposer passes it through instead of assuming a pure insertion.
  • docs/user/composer.md describes the nesting.

Both composer modes route Tab through listIndentForTab, and rich mode rebuilds from the stored Markdown, so the one change fixes both. Mobile has no list continuation in its composer; desktop uses the web composer.

Not included:

Scope and approval

Bug report #17124, triaged (bug, via-triage) and confirmed in #17124 (comment), which also suggested this fix direction and keeping Shift+Tab out.

Verification

Focused tests:

vp test run apps/web/src/composer-list-continuation.test.ts apps/web/src/composer-list-split.test.ts apps/web/src/composer-rich-text-doc.test.ts
# 3 files, 322 tests passed

New cases in composer-list-continuation.test.ts cover Tab nesting under 1., 10), bullets and tasks, joining and continuing an existing sublist (including one written at a non-standard indent), the caret position after the marker changes width, the two-space fallback, and Shift+Enter leaving one level of nesting (ordered → ordered, bullet parent, task child, two levels deep) or the list at the top level. The existing rich-mode test for lifting 1. a\n 1. x writes the same 3-space indent that Tab now produces, so both modes agree. tsc --noEmit for apps/web passes, and vp lint reports no new warnings on the changed files.

CommonMark check with mdast-util-from-markdown: "1. foo\n 2. bar" parses as one flat list with 2 items, and "1. foo\n 1. bar" parses as a nested list.

Manual check in the web client (vp run dev on isolated worktree state, macOS, Node 24). Before is main @ 30cc78897, after is this branch. Steps: type 1. first, Shift+Enter, Tab, type nested. For the third pair, then Shift+Enter, Shift+Enter, and type second.

Rich-text composer, Tab

Before:

1-before-rich-text

After:

1-after-rich-text

Plain composer (the raw Markdown the agent receives), Tab

Before:

2-before-plain-text

After:

2-after-plain-text

Plain composer, Shift+Enter twice after the nested item

Before:

3-before-plain-text-shift-enter

After:

3-after-plain-text-shift-enter

Not checked: sending the prompt to a provider (no provider configured in the test state), and the desktop shell, which wraps the same web composer.

Local dev pairing on Node 24 needed #16730 applied locally (issue #16797); that change is not part of this PR.

Work done with Claude Opus 5.5 in Claude Code, running inside T3 Code.

🤖 Generated with Claude Code

Tab on a list item only prepended two spaces and kept the marker, so
`1. a` / Shift+Enter / Tab produced `  2. ` instead of a nested `1.`.
Two spaces under `1. ` is also not nesting in CommonMark (the child must
reach the parent's content column), so the agent received a flat list.

- Tab nests the item at the content column of the item above and numbers
  a nested ordered list from 1, or continues an existing sublist.
- Shift+Enter on an empty nested item moves it up one level and continues
  the parent's numbering (the rich-text composer already did this; the
  plain composer left the whole list).

Fixes pingdotgg#17124
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 8, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 0b4e119

Macroscope's review found this PR approvable — This is a focused composer bug fix that corrects Markdown list nesting and caret placement for Tab and nested empty-item handling. Runtime changes are confined to list editing, with targeted tests covering ordered, bullet, task, multi-level, and fallback cases.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 19158ec7-1ce7-452a-927f-658d372afb53
📥 Commits

Reviewing files that changed from the base of the PR and between 0647c48 and 0b4e119.

📒 Files selected for processing (4)
  • apps/web/src/components/chat/ChatComposer.tsx
  • apps/web/src/composer-list-continuation.test.ts
  • apps/web/src/composer-list-continuation.ts
  • docs/user/composer.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The composer now moves out of empty nested list items one level at a time. Tab nests list items at the preceding item's content column and updates ordered-list numbering. Tests and composer documentation cover these behaviors.

Changes

Composer list editing

Layer / File(s) Summary
Empty nested-item continuation
apps/web/src/composer-list-continuation.ts, apps/web/src/composer-list-continuation.test.ts
ComposerListEdit now supports an optional cursor offset. Enter on an empty nested item moves up one level and continues the parent marker. An empty item without a parent removes its marker.
Tab nesting and caret placement
apps/web/src/composer-list-continuation.ts, apps/web/src/components/chat/ChatComposer.tsx, apps/web/src/composer-list-continuation.test.ts, docs/user/composer.md
Tab nests an item at a preceding item's content column and updates compatible ordered-list numbering. When no parent item is available, it adds two spaces. The composer uses the edit's cursor offset when provided. Tests cover caret placement and cases where Tab does not edit the line. Documentation describes the keyboard behavior.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to 0b4e1

This change makes Tab nest numbered list items and Shift+Enter move out of empty nested items one level at a time in the composer. No concrete merge-blocking risk was identified.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR addresses the coding requirements in #17124. listIndentForTab now places ordered children at the parent content column, starts or continues nested numbering, and keeps the two-space fallback …
Out of Scope Changes check ✅ Passed The reported changes are limited to composer list handling, its focused tests, cursor propagation, and related user documentation. These changes support #17124. The PR does not include the excluded Sh…
Title check ✅ Passed The title clearly identifies the primary change: fixing Tab-based nesting for numbered list items in the web composer.
Description check ✅ Passed The description includes all required sections. It explains the problem, implementation, scope, linked issue and approval, focused verification, manual UI checks, screenshots, limitations, and agent d…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

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

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Tab in a composer numbered list keeps the number and does not nest the item in the sent Markdown

1 participant