microsoft / microsoft/vscode

Backspace over a flag emoji deletes only one Regional Indicator, leaving a dangling half-flag

Open
#334,807 0 comments 0 reactions 1 assignee Claimed by @hediet View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.