From 449ffa0cf953b1551499f3471b458c8384166cd4 Mon Sep 17 00:00:00 2001 From: EtherealAirRhyme <126517617+EtherealAirRhyme@users.noreply.github.com> Date: Wed, 10 Jun 2026 21:35:22 +0800 Subject: [PATCH] added eastasianwidth for new display width --- package.json | 1 + src/csvParser.ts | 25 ++++++++++++++++------ src/extension.ts | 3 ++- src/helpers/getHintAndCurrentPosfromCol.ts | 3 ++- src/helpers/getHintsFromCellLengths.ts | 7 ++++-- src/test/core.test.ts | 21 ++++++++++++++++++ 6 files changed, 50 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index ed773a9..5178ecb 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "typescript": "^5.3.3" }, "dependencies": { + "eastasianwidth": "^0.3.0", "papaparse": "^5.4.1" } } diff --git a/src/csvParser.ts b/src/csvParser.ts index 91fd330..f0362d7 100644 --- a/src/csvParser.ts +++ b/src/csvParser.ts @@ -8,18 +8,19 @@ */ import Papa from 'papaparse'; +import * as eaw from 'eastasianwidth'; /** * The output type of the ParseCSVWithPapa function. * It has the string length of all the data in the csv, and it * has the delimiter of the csv - * @property {number[][]} data - the string length of all the data in the csv. - * I believe it's matrix notation, so the first index is the row number, and the second - * index is the column number - * @property {string} delimiter - the delimiter of the csv. + * @property {number[][]} data - the display width of all the cells in the csv. + * @property {number[][]} rawLengths - the raw character count of all cells, for position tracking. + * @property {number} delimiterLength - the length of the delimiter. */ export interface CsvData { data: number[][]; + rawLengths: number[][]; delimiterLength: number; } @@ -41,12 +42,15 @@ export async function parseCSVWithPapa(csv: string): Promise { // Step 2: Reconstruct raw text and capture value lengths const valueLengths: number[][] = []; + const rawLengths: number[][] = []; const rows = csv.split(/\r?\n/); // Split raw content by newlines rows.forEach((row) => { let inQuotes = false; let valueStart = 0; + let displayWidth = 0; let rowLengths: number[] = []; + let rowRawLengths: number[] = []; for (let i = 0; i < row.length; i++) { const char = row[i]; @@ -56,17 +60,26 @@ export async function parseCSVWithPapa(csv: string): Promise { } if (char === delimiter && !inQuotes) { - rowLengths.push(i - valueStart); + const rawLen = i - valueStart; + rowRawLengths.push(rawLen); + rowLengths.push(displayWidth); + displayWidth = 0; valueStart = i + 1; + } else { + displayWidth += eaw.characterLength(char); } } - rowLengths.push(row.length - valueStart); + const rawLen = row.length - valueStart; + rowRawLengths.push(rawLen); + rowLengths.push(displayWidth); + rawLengths.push(rowRawLengths); valueLengths.push(rowLengths); }); return { data: valueLengths, + rawLengths: rawLengths, delimiterLength: delimiter.length }; } diff --git a/src/extension.ts b/src/extension.ts index 0b0ef9b..62a10dd 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -78,7 +78,7 @@ class CsvAlignInlayHintsProvider implements vscode.InlayHintsProvider { ? headerText : `${headerText}\n${bodyText}`; - const {data: cellLengths, delimiterLength} = await parseCSVWithPapa(textToParse); + const {data: cellLengths, rawLengths, delimiterLength} = await parseCSVWithPapa(textToParse); if (!cellLengths.length) { return []; @@ -88,6 +88,7 @@ class CsvAlignInlayHintsProvider implements vscode.InlayHintsProvider { const maxColumnWidths = getMaxColumnWidthsFromCellLengths(cellLengths); const hints: VsCodeInlayHintAdapter[] = getHintsFromCellLengths( cellLengths, + rawLengths, maxColumnWidths, delimiterLength, hintCharacter diff --git a/src/helpers/getHintAndCurrentPosfromCol.ts b/src/helpers/getHintAndCurrentPosfromCol.ts index fdca38c..8884956 100644 --- a/src/helpers/getHintAndCurrentPosfromCol.ts +++ b/src/helpers/getHintAndCurrentPosfromCol.ts @@ -45,13 +45,14 @@ export interface VsCodeInlayHintAdapter { export function getHintAndCurrentPosfromCol( cellLength: number, + rawCellLength: number, colMaxWidth: number, currentPos: number, rowIndex: number, delimiterLength: number, hintCharacter: string, ): [VsCodeInlayHintAdapter, number] { - const startPos = currentPos + cellLength; + const startPos = currentPos + rawCellLength; const spacesNeeded = colMaxWidth - cellLength; const position: VsCodePositionAdapter = {rowIndex: rowIndex, startPos: startPos}; diff --git a/src/helpers/getHintsFromCellLengths.ts b/src/helpers/getHintsFromCellLengths.ts index e1a0377..ec337b8 100644 --- a/src/helpers/getHintsFromCellLengths.ts +++ b/src/helpers/getHintsFromCellLengths.ts @@ -4,14 +4,16 @@ import { getHintAndCurrentPosfromCol, VsCodeInlayHintAdapter } from './getHintAn * Helper function to generate inlay hints from the cell lengths * of a CSV. * - * @param {string[][]} cellLengths - The lengths of the cells in the CSV - * @param {number[]} columnMaxWidths - The maximum width of each column + * @param {number[][]} cellLengths - The display widths of the cells in the CSV + * @param {number[][]} rawLengths - The raw character counts of the cells + * @param {number[]} columnMaxWidths - The maximum display width of each column * @param {number} delimiterLength - The length of the delimiter * @param {string} hintCharacter - The character to use for the hint * @returns {VsCodeInlayHintAdapter[]} - The inlay hints */ export function getHintsFromCellLengths( cellLengths: number[][], + rawLengths: number[][], columnMaxWidths: number[], delimiterLength: number, hintCharacter: string @@ -26,6 +28,7 @@ export function getHintsFromCellLengths( rowOfCellLengths.forEach((cellLength, colIndex) => { const returns: [VsCodeInlayHintAdapter, number] = getHintAndCurrentPosfromCol( cellLength, + rawLengths[rowIndex][colIndex], columnMaxWidths[colIndex], currentPos, rowIndex, diff --git a/src/test/core.test.ts b/src/test/core.test.ts index 023b8b7..b4f3cde 100644 --- a/src/test/core.test.ts +++ b/src/test/core.test.ts @@ -24,6 +24,7 @@ suite('Core helpers', () => { test('creates an inlay hint at the end of the current cell', () => { const [hint, nextPos] = getHintAndCurrentPosfromCol( + 5, 5, 7, 0, @@ -41,6 +42,10 @@ suite('Core helpers', () => { test('creates hints for every cell length', () => { const hints = getHintsFromCellLengths( + [ + [5, 6, 7], + [7, 2, 6], + ], [ [5, 6, 7], [7, 2, 6], @@ -102,6 +107,10 @@ suite('CSV parser', () => { [5, 6, 4], [7, 5, 1], ], + rawLengths: [ + [5, 6, 4], + [7, 5, 1], + ], delimiterLength: 1, }); }); @@ -114,6 +123,10 @@ suite('CSV parser', () => { [15, 1], [7, 1], ], + rawLengths: [ + [15, 1], + [7, 1], + ], delimiterLength: 1, }); }); @@ -126,6 +139,10 @@ suite('CSV parser', () => { [4, 5], [5, 2], ], + rawLengths: [ + [4, 5], + [5, 2], + ], delimiterLength: 1, }); }); @@ -138,6 +155,10 @@ suite('CSV parser', () => { [1, 1, 1], [6, 3], ], + rawLengths: [ + [1, 1, 1], + [6, 3], + ], delimiterLength: 1, }); });