fix(cursor): keep the visual selection whole over characters outside the BMP (#2683)
* fix(cursor): keep the visual selection whole over characters outside the BMP The inclusive Nvim end column was turned into an exclusive VSCode one by adding a single UTF-16 unit. A character outside the BMP is two of them, so the selection ended in the middle of a surrogate pair and drifted away from where Nvim had the cursor: moving right over it took two presses and the selected region no longer matched. Step over the whole character instead, using its byte length. Closes #2535 * test(cursor): add visual selection tests for non-BMP characters * test(cursor): expect the astral pair to be whole in the mixed-character selection --------- Co-authored-by: wongxy <xiyao.wong@foxmail.com>
This commit is contained in:
1 parent
aacc554f30
commit
5cc37c9f0a
2 files changed
+65
-2
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { NeovimClient } from "neovim";
|
||||
import vscode from "vscode";
|
||||
|
||||
import {
|
||||
attachTestNvimClient,
|
||||
@@ -286,4 +287,54 @@ describe("Multi-width characters", () => {
|
||||
client,
|
||||
);
|
||||
});
|
||||
|
||||
it("Works - visual mode over chars outside the BMP", async () => {
|
||||
// 𝕜 is U+1D55C: one Nvim character, but two UTF-16 units for VSCode
|
||||
await openTextDocument({ content: ["a𝕜b"].join("\n") });
|
||||
|
||||
await assertContent({ content: ["a𝕜b"], cursor: [0, 0] }, client);
|
||||
|
||||
await sendVSCodeKeys("v");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 1)] }, client);
|
||||
|
||||
await sendVSCodeKeys("l");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 3)] }, client);
|
||||
|
||||
await sendVSCodeKeys("l");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 4)] }, client);
|
||||
|
||||
await sendEscapeKey();
|
||||
});
|
||||
|
||||
it("Works - visual mode over consecutive non-BMP chars", async () => {
|
||||
await openTextDocument({ content: ["a𝕜𝕝b"].join("\n") });
|
||||
|
||||
await sendVSCodeKeys("v");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 1)] }, client);
|
||||
|
||||
await sendVSCodeKeys("ll");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 5)] }, client);
|
||||
|
||||
await sendVSCodeKeys("l");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 6)] }, client);
|
||||
|
||||
await sendEscapeKey();
|
||||
});
|
||||
|
||||
it("Works - visual mode across mixed BMP and non-BMP chars", async () => {
|
||||
await openTextDocument({ content: ["aᵩ𝕜b"].join("\n") });
|
||||
|
||||
await sendVSCodeKeys("v");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 1)] }, client);
|
||||
|
||||
// the cursor sits on the astral char, whose two UTF-16 units both belong to
|
||||
// the selection: a, the modifier letter and the pair take offsets 0 to 4
|
||||
await sendVSCodeKeys("ll");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 4)] }, client);
|
||||
|
||||
await sendVSCodeKeys("l");
|
||||
await assertContent({ vsCodeSelections: [new vscode.Selection(0, 0, 0, 5)] }, client);
|
||||
|
||||
await sendEscapeKey();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user