Backspace over a flag emoji deletes only one Regional Indicator, leaving a dangling half-flag
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
# Description
`getLeftDeleteOffset` in [`strings.ts`](https://github.com/microsoft/vscode/blob/main/src/vs/base/common/strings.ts) special-cases backspace over emoji so a full emoji (e.g. a skin-tone modifier sequence like 👶🏾) is deleted as one unit instead of leaving a dangling half-emoji behind — this was the fix for #99629.
However, this special-casing does not account for **flag emoji**, which are two Regional Indicator Symbol code points (e.g. 🇺🇸 = U+1F1FA U+1F1F8). Backspacing over a complete flag deletes only one of the two code points, leaving a dangling, meaningless lone Regional Indicator character behind — exactly the class of bug #99629 was meant to prevent, just for a different emoji construct.
## Steps to Reproduce
1. Type a flag emoji, e.g. 🇺🇸, into an editor.
2. Press Backspace once.
### Expected
The whole flag (both code points) is removed in one Backspace, matching how a skin-tone-modified emoji is already handled.
### Actual
Only one Regional Indicator code point is removed, leaving a dangling `🇺` (a lone Regional Indicator Symbol, rendered as a boxed letter or similar depending on font) behind. A second Backspace is needed to remove it.
This also affects adjacent flags, e.g. 🇺🇸🇬🇧 (US + GB back to back, 4 Regional Indicator code points): Backspace removes them one code point at a time, each intermediate step leaving a dangling indicator, instead of removing one whole flag (2 code points) per Backspace.
## Analysis
In `getOffsetBeforeLastEmojiComponent` (used by `getLeftDeleteOffset`), once a Regional Indicator is identified as the "base emoji", the function falls through to the generic "skip an optional trailing ZWJ" step, which does nothing for Regional Indicators (they aren't ZWJ-joined). There's no check for whether the Regional Indicator is paired with the one before it, per Unicode UAX #29 rules GB12/GB13 ("do not break within emoji flag sequences").
I have a fix and regression tests ready and will open a PR referencing this issue.
## Logs
N/A — pure text-editing logic, not platform/build specific. Reproduces in any text input backed by this code path (editor, terminal input line, etc.), with extensions disabled.
Contributor guide
Assessment
This issue has not been assessed yet.