fix: ensure version compatibility with Cursor and Windsurf editors
This commit is contained in:
parent
b8e323a575
commit
383b1d610f
@ -5,7 +5,7 @@
|
||||
"author": "Asadbek Karimov <contact@asadk.dev>",
|
||||
"publisher": "asadbek",
|
||||
"icon": "img/logo.png",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.7",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension/issues"
|
||||
@ -15,7 +15,7 @@
|
||||
"url": "https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension.git"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.100.0"
|
||||
"vscode": "^1.96.0"
|
||||
},
|
||||
"categories": [
|
||||
"Other"
|
||||
@ -147,7 +147,7 @@
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "20.x",
|
||||
"@types/vscode": "^1.100.0",
|
||||
"@types/vscode": "^1.96.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.31.1",
|
||||
"@typescript-eslint/parser": "^8.31.1",
|
||||
"@vscode/test-cli": "^0.0.10",
|
||||
|
@ -15,7 +15,7 @@ importers:
|
||||
specifier: 20.x
|
||||
version: 20.17.47
|
||||
'@types/vscode':
|
||||
specifier: ^1.100.0
|
||||
specifier: ^1.96.0
|
||||
version: 1.100.0
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^8.31.1
|
||||
@ -144,8 +144,8 @@ packages:
|
||||
'@jridgewell/trace-mapping@0.3.25':
|
||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||
|
||||
'@modelcontextprotocol/sdk@1.11.2':
|
||||
resolution: {integrity: sha512-H9vwztj5OAqHg9GockCQC06k1natgcxWQSRpQcPJf6i5+MWBzfKkRtxGbjQf0X2ihii0ffLZCRGbYV2f2bjNCQ==}
|
||||
'@modelcontextprotocol/sdk@1.11.3':
|
||||
resolution: {integrity: sha512-rmOWVRUbUJD7iSvJugjUbFZshTAuJ48MXoZ80Osx1GM0K/H1w7rSEvmw8m6vdWxNASgtaHIhAgre4H/E9GJiYQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
@ -563,8 +563,8 @@ packages:
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
electron-to-chromium@1.5.152:
|
||||
resolution: {integrity: sha512-xBOfg/EBaIlVsHipHl2VdTPJRSvErNUaqW8ejTq5OlOlIYx1wOllCHsAvAIrr55jD1IYEfdR86miUEt8H5IeJg==}
|
||||
electron-to-chromium@1.5.154:
|
||||
resolution: {integrity: sha512-G4VCFAyKbp1QJ+sWdXYIRYsPGvlV5sDACfCmoMFog3rjm1syLhI41WXm/swZypwCIWIm4IFLWzHY14joWMQ5Fw==}
|
||||
|
||||
emoji-regex@10.4.0:
|
||||
resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
|
||||
@ -1456,8 +1456,8 @@ packages:
|
||||
uglify-js:
|
||||
optional: true
|
||||
|
||||
terser@5.39.1:
|
||||
resolution: {integrity: sha512-Mm6+uad0ZuDtcV8/4uOZQDQ8RuiC5Pu+iZRedJtF7yA/27sPL7d++In/AJKpWZlU3SYMPPkVfwetn6sgZ66pUA==}
|
||||
terser@5.39.2:
|
||||
resolution: {integrity: sha512-yEPUmWve+VA78bI71BW70Dh0TuV4HHd+I5SHOAfS1+QBOmvmCiiffgjR8ryyEd3KIfvPGFqoADt8LdQ6XpXIvg==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
@ -1726,7 +1726,7 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
|
||||
'@modelcontextprotocol/sdk@1.11.2':
|
||||
'@modelcontextprotocol/sdk@1.11.3':
|
||||
dependencies:
|
||||
content-type: 1.0.5
|
||||
cors: 2.8.5
|
||||
@ -2065,7 +2065,7 @@ snapshots:
|
||||
browserslist@4.24.5:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001718
|
||||
electron-to-chromium: 1.5.152
|
||||
electron-to-chromium: 1.5.154
|
||||
node-releases: 2.0.19
|
||||
update-browserslist-db: 1.1.3(browserslist@4.24.5)
|
||||
|
||||
@ -2211,7 +2211,7 @@ snapshots:
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
electron-to-chromium@1.5.152: {}
|
||||
electron-to-chromium@1.5.154: {}
|
||||
|
||||
emoji-regex@10.4.0: {}
|
||||
|
||||
@ -2271,7 +2271,7 @@ snapshots:
|
||||
'@humanfs/node': 0.16.6
|
||||
'@humanwhocodes/module-importer': 1.0.1
|
||||
'@humanwhocodes/retry': 0.4.3
|
||||
'@modelcontextprotocol/sdk': 1.11.2
|
||||
'@modelcontextprotocol/sdk': 1.11.3
|
||||
'@types/estree': 1.0.7
|
||||
'@types/json-schema': 7.0.15
|
||||
ajv: 6.12.6
|
||||
@ -3112,10 +3112,10 @@ snapshots:
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 4.3.2
|
||||
serialize-javascript: 6.0.2
|
||||
terser: 5.39.1
|
||||
terser: 5.39.2
|
||||
webpack: 5.99.8(webpack-cli@6.0.1)
|
||||
|
||||
terser@5.39.1:
|
||||
terser@5.39.2:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.6
|
||||
acorn: 8.14.1
|
||||
|
@ -11,13 +11,13 @@ export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<
|
||||
|
||||
public static register(context: vscode.ExtensionContext): vscode.Disposable {
|
||||
return vscode.window.registerCustomEditorProvider(
|
||||
'excelViewer.spreadsheet',
|
||||
'excelViewer.spreadsheet',
|
||||
new ExcelEditorProvider(context),
|
||||
{ webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden
|
||||
);
|
||||
}
|
||||
|
||||
constructor(private readonly context: vscode.ExtensionContext) {}
|
||||
constructor(private readonly context: vscode.ExtensionContext) { }
|
||||
|
||||
async openCustomDocument(uri: vscode.Uri): Promise<ExcelDocument> {
|
||||
console.log(`Opening document: ${uri.fsPath}`);
|
||||
@ -26,14 +26,14 @@ export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<
|
||||
|
||||
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<void> {
|
||||
console.log(`Resolving editor for: ${document.uri.fsPath}`);
|
||||
|
||||
|
||||
webviewPanel.webview.options = { enableScripts: true };
|
||||
|
||||
|
||||
this.setLoadingView(webviewPanel);
|
||||
|
||||
|
||||
// small timeout to ensure the loading view is rendered before heavy processing begins
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
|
||||
try {
|
||||
// process file in a non-blocking way
|
||||
setImmediate(async () => {
|
||||
@ -69,7 +69,7 @@ export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<
|
||||
// check if we have a cached workbook for this file
|
||||
let workbook: XLSX.WorkBook;
|
||||
const cacheKey = document.uri.toString();
|
||||
|
||||
|
||||
if (this.workbookCache.has(cacheKey)) {
|
||||
console.log('Using cached workbook');
|
||||
workbook = this.workbookCache.get(cacheKey)!;
|
||||
@ -77,104 +77,104 @@ export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<
|
||||
} else {
|
||||
workbook = await this.loadWorkbook(document, webviewPanel);
|
||||
}
|
||||
|
||||
|
||||
// setup the initial view with just the sheet selector
|
||||
const sheetNames = workbook.SheetNames;
|
||||
this.setupWebviewContent(document, webviewPanel, workbook, sheetNames);
|
||||
}
|
||||
|
||||
private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<XLSX.WorkBook> {
|
||||
this.updateLoadingProgress(webviewPanel, 'Reading file...');
|
||||
|
||||
try {
|
||||
const data = await vscode.workspace.fs.readFile(document.uri);
|
||||
console.log(`Read ${data.byteLength} bytes`);
|
||||
|
||||
// very large files, update the progress message
|
||||
if (data.byteLength > 5 * 1024 * 1024) { // 5MB
|
||||
this.updateLoadingProgress(webviewPanel, 'Parsing large file...');
|
||||
}
|
||||
|
||||
// get file extension to optimize parsing options
|
||||
const fileExtension = document.uri.fsPath.split('.').pop()?.toLowerCase() || '';
|
||||
|
||||
// parse with SheetJS with options optimized for the file type
|
||||
console.log(`Parsing ${fileExtension} file...`);
|
||||
this.updateLoadingProgress(webviewPanel, `Parsing ${fileExtension} data...`);
|
||||
|
||||
// timeout to ensure UI updates before heavy parsing
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
const options: XLSX.ParsingOptions = {
|
||||
type: 'array',
|
||||
cellStyles: true,
|
||||
cellDates: true,
|
||||
};
|
||||
|
||||
// specific format handling
|
||||
if (fileExtension === 'csv') {
|
||||
options.cellDates = false;
|
||||
options.cellStyles = false;
|
||||
}
|
||||
|
||||
const workbook = XLSX.read(new Uint8Array(data), options);
|
||||
|
||||
this.updateLoadingProgress(webviewPanel, 'Preparing view...');
|
||||
|
||||
// cache the workbook
|
||||
const cacheKey = document.uri.toString();
|
||||
this.workbookCache.set(cacheKey, workbook);
|
||||
|
||||
return workbook;
|
||||
} catch (error) {
|
||||
console.error(`Error reading file: ${error}`);
|
||||
this.setErrorView(webviewPanel, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<XLSX.WorkBook> {
|
||||
this.updateLoadingProgress(webviewPanel, 'Reading file...');
|
||||
|
||||
private setupWebviewContent(
|
||||
document: ExcelDocument,
|
||||
webviewPanel: vscode.WebviewPanel,
|
||||
workbook: XLSX.WorkBook,
|
||||
sheetNames: string[]
|
||||
): void {
|
||||
// exit early if there are no sheets
|
||||
if (sheetNames.length === 0) {
|
||||
webviewPanel.webview.html = getErrorViewHtml(new Error("No sheets or tables found in this file."));
|
||||
return;
|
||||
try {
|
||||
const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri);
|
||||
console.log(`Read ${data.byteLength} bytes`);
|
||||
|
||||
// very large files, update the progress message
|
||||
if (data.byteLength > 5 * 1024 * 1024) { // 5MB
|
||||
this.updateLoadingProgress(webviewPanel, 'Parsing large file...');
|
||||
}
|
||||
|
||||
// get file extension to optimize parsing options
|
||||
const fileExtension = document.uri.fsPath.split('.').pop()?.toLowerCase() || '';
|
||||
|
||||
// parse with SheetJS with options optimized for the file type
|
||||
console.log(`Parsing ${fileExtension} file...`);
|
||||
this.updateLoadingProgress(webviewPanel, `Parsing ${fileExtension} data...`);
|
||||
|
||||
// timeout to ensure UI updates before heavy parsing
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
const options: XLSX.ParsingOptions = {
|
||||
type: 'array',
|
||||
cellStyles: true,
|
||||
cellDates: true,
|
||||
};
|
||||
|
||||
// specific format handling
|
||||
if (fileExtension === 'csv') {
|
||||
options.cellDates = false;
|
||||
options.cellStyles = false;
|
||||
}
|
||||
|
||||
const workbook: XLSX.WorkBook = XLSX.read(data, options);
|
||||
|
||||
this.updateLoadingProgress(webviewPanel, 'Preparing view...');
|
||||
|
||||
// cache the workbook
|
||||
const cacheKey = document.uri.toString();
|
||||
this.workbookCache.set(cacheKey, workbook);
|
||||
|
||||
return workbook;
|
||||
} catch (error) {
|
||||
console.error(`Error reading file: ${error}`);
|
||||
this.setErrorView(webviewPanel, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// create a dropdown for sheet selection
|
||||
let sheetSelector = `
|
||||
private setupWebviewContent(
|
||||
document: ExcelDocument,
|
||||
webviewPanel: vscode.WebviewPanel,
|
||||
workbook: XLSX.WorkBook,
|
||||
sheetNames: string[]
|
||||
): void {
|
||||
// exit early if there are no sheets
|
||||
if (sheetNames.length === 0) {
|
||||
webviewPanel.webview.html = getErrorViewHtml(new Error("No sheets or tables found in this file."));
|
||||
return;
|
||||
}
|
||||
|
||||
// create a dropdown for sheet selection
|
||||
let sheetSelector = `
|
||||
<div class="sheet-selector">
|
||||
<label for="sheet-select">Select worksheet: </label>
|
||||
<select id="sheet-select">
|
||||
`;
|
||||
|
||||
sheetNames.forEach((name, index) => {
|
||||
sheetSelector += `<option value="${index}">${name}</option>`;
|
||||
});
|
||||
|
||||
sheetSelector += `
|
||||
|
||||
sheetNames.forEach((name, index) => {
|
||||
sheetSelector += `<option value="${index}">${name}</option>`;
|
||||
});
|
||||
|
||||
sheetSelector += `
|
||||
</select>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// setup up the HTML with JS to handle sheet switching
|
||||
webviewPanel.webview.html = getExcelViewerHtml(sheetNames, sheetSelector);
|
||||
|
||||
// handle messages from the webview
|
||||
this.setupMessageHandlers(document, webviewPanel, workbook);
|
||||
}
|
||||
|
||||
// setup up the HTML with JS to handle sheet switching
|
||||
webviewPanel.webview.html = getExcelViewerHtml(sheetNames, sheetSelector);
|
||||
|
||||
// handle messages from the webview
|
||||
this.setupMessageHandlers(document, webviewPanel, workbook);
|
||||
}
|
||||
|
||||
private setupMessageHandlers(
|
||||
document: ExcelDocument,
|
||||
webviewPanel: vscode.WebviewPanel,
|
||||
document: ExcelDocument,
|
||||
webviewPanel: vscode.WebviewPanel,
|
||||
workbook: XLSX.WorkBook
|
||||
): void {
|
||||
const baseCacheKey = document.uri.toString();
|
||||
|
||||
|
||||
webviewPanel.webview.onDidReceiveMessage(async message => {
|
||||
if (message.type === 'getSheetPage') {
|
||||
await this.handleGetSheetPage(
|
||||
@ -195,35 +195,35 @@ private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.Webview
|
||||
): Promise<void> {
|
||||
const { sheetName, page, rowsPerPage, maxColumns } = message;
|
||||
const cacheKey = `${baseCacheKey}-${sheetName}-page-${page}`;
|
||||
|
||||
|
||||
this.updateLoadingProgress(webviewPanel, `Preparing page ${page + 1} of sheet: ${sheetName}`);
|
||||
|
||||
|
||||
// setTimeout to ensure loading message gets displayed
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
let sheetHtml: string;
|
||||
let rangeInfo: any = null;
|
||||
|
||||
|
||||
// check if this page is already cached
|
||||
if (this.sheetCache.has(cacheKey)) {
|
||||
sheetHtml = this.sheetCache.get(cacheKey)!;
|
||||
} else {
|
||||
const sheet = workbook.Sheets[sheetName];
|
||||
|
||||
|
||||
// get the range of the sheet (e.g., A1:Z100)
|
||||
const range = sheet['!ref'] || '';
|
||||
rangeInfo = parseRange(range);
|
||||
|
||||
|
||||
if (!rangeInfo) {
|
||||
sheetHtml = '<p>No data in this sheet</p>';
|
||||
} else {
|
||||
sheetHtml = this.processSheetPage(sheet, rangeInfo, page, rowsPerPage, maxColumns);
|
||||
|
||||
|
||||
// cache the result
|
||||
this.sheetCache.set(cacheKey, sheetHtml);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// send the sheet data back to the webview
|
||||
webviewPanel.webview.postMessage({
|
||||
type: 'sheetData',
|
||||
@ -243,39 +243,39 @@ private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.Webview
|
||||
}
|
||||
|
||||
private processSheetPage(
|
||||
sheet: XLSX.WorkSheet,
|
||||
rangeInfo: any,
|
||||
page: number,
|
||||
rowsPerPage: number,
|
||||
sheet: XLSX.WorkSheet,
|
||||
rangeInfo: any,
|
||||
page: number,
|
||||
rowsPerPage: number,
|
||||
maxColumns: number
|
||||
): string {
|
||||
// calc the range for this page
|
||||
const pageStartRow = Math.min(rangeInfo.startRow + (page * rowsPerPage), rangeInfo.endRow);
|
||||
const pageEndRow = Math.min(pageStartRow + rowsPerPage - 1, rangeInfo.endRow);
|
||||
|
||||
|
||||
// limit columns if there are too many
|
||||
const effectiveEndColNum = Math.min(rangeInfo.endColNum, rangeInfo.startColNum + maxColumns - 1);
|
||||
const effectiveEndCol = numToColLetter(effectiveEndColNum);
|
||||
|
||||
|
||||
// create a new range for this page
|
||||
const pageRange = `${rangeInfo.startCol}${pageStartRow}:${effectiveEndCol}${pageEndRow}`;
|
||||
|
||||
|
||||
// create a new sheet with just this page's data
|
||||
const newPageSheet: XLSX.WorkSheet = { '!ref': pageRange };
|
||||
|
||||
|
||||
// preserve important sheet properties
|
||||
if (sheet['!cols']) newPageSheet['!cols'] = sheet['!cols'];
|
||||
if (sheet['!rows']) newPageSheet['!rows'] = sheet['!rows'];
|
||||
if (sheet['!merges']) {
|
||||
// filter merges that are in this page's range
|
||||
newPageSheet['!merges'] = sheet['!merges'].filter(merge => {
|
||||
return merge.s.r >= pageStartRow - 1 &&
|
||||
merge.e.r <= pageEndRow - 1 &&
|
||||
merge.s.c >= rangeInfo.startColNum - 1 &&
|
||||
merge.e.c <= effectiveEndColNum - 1;
|
||||
return merge.s.r >= pageStartRow - 1 &&
|
||||
merge.e.r <= pageEndRow - 1 &&
|
||||
merge.s.c >= rangeInfo.startColNum - 1 &&
|
||||
merge.e.c <= effectiveEndColNum - 1;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// copy cells in range
|
||||
Object.keys(sheet).forEach(key => {
|
||||
if (key.charAt(0) !== '!') {
|
||||
@ -283,16 +283,16 @@ private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.Webview
|
||||
const cellCol = key.replace(/[0-9]/g, '');
|
||||
const cellRow = parseInt(key.replace(/[^0-9]/g, ''));
|
||||
const cellColNum = colLetterToNum(cellCol);
|
||||
|
||||
if (cellRow >= pageStartRow &&
|
||||
cellRow <= pageEndRow &&
|
||||
cellColNum >= rangeInfo.startColNum &&
|
||||
cellColNum <= effectiveEndColNum) {
|
||||
|
||||
if (cellRow >= pageStartRow &&
|
||||
cellRow <= pageEndRow &&
|
||||
cellColNum >= rangeInfo.startColNum &&
|
||||
cellColNum <= effectiveEndColNum) {
|
||||
newPageSheet[key] = sheet[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// convert to HTML
|
||||
return XLSX.utils.sheet_to_html(newPageSheet);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user