Markdown smart select: a single-asterisk italic span on the line discards all Markdown selection ranges
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Type: Bug
VS Code version: 1.137.0 (x64, Windows 11)
Extensions: reproduces with no extension contributing Markdown selection ranges
## Steps to reproduce
1. Create a Markdown file:
```md
# Section
alpha *beta* gamma delta
# Next
```
2. Put the cursor on the word `alpha` (anywhere on that line *outside* the `*beta*` span).
3. Press Expand Selection (Shift+Alt+RightArrow) repeatedly.
## Expected
`alpha` → the line → the paragraph → the section → the document.
## Actual
`alpha` → the line → **the whole document**. Every Markdown range (paragraph, section) is missing. The Extension Host log shows:
```
INVALID selection range, must contain the previous range: Error: INVALID selection range, must contain the previous range
```
Putting the cursor inside `*beta*` gives the full chain, so the loss depends only on where the cursor is relative to the italic span. `**bold**` and `` `code` `` on the line do not trigger it; a single-asterisk span does. A line without any `*` is fine.
## Cause
[`createOtherInlineRange`](https://github.com/microsoft/vscode-markdown-languageservice/blob/main/src/languageFeatures/smartSelect.ts#L315) matches the italic span *together with the text around it* — the pattern is `(?:[^*]+)(\*…\*)(?:[^*]+)`, with the span itself in group 1 — but then tests the cursor against the whole match, `match[0]`, instead of against group 1:
```ts
matches = [...lineText.matchAll(italicRegexes[0])].filter(match =>
lineText.indexOf(match[0]) <= cursorChar &&
lineText.indexOf(match[0]) + match[0].length >= cursorChar);
```
So a cursor anywhere on the line counts as being inside the italic, and the provider returns a chain whose innermost range (`*beta*`) does not contain the cursor. The extension host's selection-range adapter validates the chain and throws on the first range that fails to contain the position, which discards the provider's entire result for that position — hence not just a wrong innermost range, but no Markdown ranges at all.
The same `lineText.indexOf(...)` is then used to place the range, which mislocates it when the same text occurs earlier on the line.
`createBoldRange` is unaffected: its regex matches only the bold span, so the same containment test is correct there.
## Suggested fix
Filter and position on group 1's own offsets rather than `match[0]`'s — e.g. by adding the `d` flag to the italic regexes and using `match.indices[1]`:
```ts
const [start, end] = match.indices[1];
return start <= cursorChar && cursorChar <= end;
```
## Impact
Any single-asterisk emphasis in a paragraph breaks Expand Selection for the rest of that line, and with it anything built on `vscode.executeSelectionRangeProvider` for those positions.
Contributor guide
Assessment
This issue has not been assessed yet.