feat: commands to disable/enable viewer; re-validation on file edit
This commit is contained in:
parent
21f4542e5f
commit
19abeee875
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "${defaultBuildTask}"
|
||||
}
|
||||
]
|
||||
}
|
||||
18
.vscode/tasks.json
vendored
Normal file
18
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "watch",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -12,3 +12,4 @@ vsc-extension-quickstart.md
|
||||
**/*.map
|
||||
**/*.ts
|
||||
**/.vscode-test.*
|
||||
*.vsix
|
||||
|
||||
15
CHANGELOG.md
15
CHANGELOG.md
@ -2,8 +2,17 @@
|
||||
|
||||
All notable changes to the "sheetjs-demo" extension will be documented in this file.
|
||||
|
||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
||||
## [0.1.0]
|
||||
|
||||
## [Unreleased]
|
||||
- Added commands to disable/enable viewer for specific file extensions
|
||||
- Added right-click context menu options for spreadsheet files
|
||||
- Automatic file reloading when files are edited externally
|
||||
- Command palette integration for quick toggling
|
||||
|
||||
- Initial release
|
||||
## [0.0.9]
|
||||
|
||||
- View spreadsheets directly in VSCode
|
||||
- Support for 30+ file formats (XLSX, XLS, CSV, ODS, and more)
|
||||
- Multi-level caching for workbooks and sheets
|
||||
- On-demand sheet loading
|
||||
- Pagination for large files
|
||||
2
LICENSE
2
LICENSE
@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2014-present SheetJS LLC
|
||||
Copyright (C) 2025-present Asadbek Karimov
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
49
README.md
49
README.md
@ -17,19 +17,12 @@ Powered by [SheetJS](http://sheetjs.com/) a powerful VSCode extension that lets
|
||||
|
||||
|
||||
## Key Features
|
||||
The extension uses sophisticated optimization techniques to ensure smooth performance:
|
||||
|
||||
- **Multi-level Caching**
|
||||
- Workbook cache prevents redundant parsing of the same files
|
||||
- Sheet HTML cache eliminates regeneration of previously viewed sheets
|
||||
- **Smart Loading Strategy**
|
||||
- First sheet loads immediately for instant feedback
|
||||
- Additional sheets load on-demand when selected
|
||||
- Preserved webview context maintains your state even when hidden
|
||||
- **Responsive Interface**
|
||||
- Immediate loading spinner provides visual feedback
|
||||
- Sheet-switching indicators keep you informed
|
||||
- Persistent state across view changes
|
||||
- Caches workbooks and sheets to avoid re-parsing files
|
||||
- Loads sheets on-demand when switching between them
|
||||
- Automatically reloads when files are edited externally
|
||||
- Handles mega large files with pagination
|
||||
- Toggle viewer on/off for specific file extensions via command palette or context menu
|
||||
|
||||
## Supported File Formats
|
||||
|
||||
@ -65,11 +58,41 @@ The extension uses sophisticated optimization techniques to ensure smooth perfor
|
||||
| *.wb3 |
|
||||
| *.qpw |
|
||||
| *.xlr |
|
||||
| *.eth |
|
||||
| *.eth |
|
||||
|
||||
## Usage
|
||||
|
||||
### Disabling/Enabling the Viewer
|
||||
|
||||
You can easily disable the SheetJS viewer for specific file extensions:
|
||||
|
||||
<img src="https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension/raw/branch/main/asset/toggle_context_menu.png" alt="SheetJS VSCode Extension Preview" width="600"/>
|
||||
<img src="https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension/raw/branch/main/asset/toggle_ext_via_palette.png" alt="SheetJS VSCode Extension Preview" width="600"/>
|
||||
|
||||
**Command Palette** (Ctrl/Cmd+Shift+P):
|
||||
- `SheetJS: Disable Viewer for Current File Extension` - Switches to default text editor for that extension
|
||||
- `SheetJS: Enable Viewer for Current File Extension` - Re-enables the viewer
|
||||
|
||||
**Context Menu**: Right-click any spreadsheet file in the Explorer to access the same commands.
|
||||
|
||||
**Built-in VSCode**: Right-click any file and select "Open With..." to choose between SheetJS Viewer and other editors.
|
||||
|
||||
## Getting Started
|
||||
Want to integrate SheetJS in your own VSCode extension? Check out our [detailed tutorial](https://docs.sheetjs.com/docs/) to learn how to implement these capabilities in your projects.
|
||||
|
||||
## Development
|
||||
|
||||
To run the extension in development mode, install dependencies with `pnpm install` and press F5 in VSCode. This opens a new Extension Development Host window where you can test the extension by opening any spreadsheet file.
|
||||
|
||||
|
||||
Build for production with `pnpm run package`.
|
||||
|
||||
## Publishing
|
||||
```bash
|
||||
npx vsce login foo
|
||||
npx vsce publish
|
||||
```
|
||||
|
||||
## Learn More
|
||||
For more information on using this extension and integrating SheetJS capabilities in your own projects, visit our [documentation](https://docs.sheetjs.com/docs/).
|
||||
|
||||
|
||||
BIN
asset/toggle_context_menu.png
Normal file
BIN
asset/toggle_context_menu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
asset/toggle_ext_via_palette.png
Normal file
BIN
asset/toggle_ext_via_palette.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
43
package.json
43
package.json
@ -5,7 +5,7 @@
|
||||
"author": "Asadbek Karimov <contact@asadk.dev>",
|
||||
"publisher": "asadbek",
|
||||
"icon": "img/logo.png",
|
||||
"version": "0.0.8",
|
||||
"version": "0.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension/issues"
|
||||
@ -30,6 +30,47 @@
|
||||
"activationEvents": [],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "sheetjs.disableForExtension",
|
||||
"title": "SheetJS: Disable Viewer for Current File Extension"
|
||||
},
|
||||
{
|
||||
"command": "sheetjs.enableForExtension",
|
||||
"title": "SheetJS: Enable Viewer for Current File Extension"
|
||||
},
|
||||
{
|
||||
"command": "sheetjs.openWithViewer",
|
||||
"title": "SheetJS: Open with Spreadsheet Viewer"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "sheetjs.disableForExtension",
|
||||
"when": "editorIsOpen"
|
||||
},
|
||||
{
|
||||
"command": "sheetjs.enableForExtension",
|
||||
"when": "editorIsOpen"
|
||||
},
|
||||
{
|
||||
"command": "sheetjs.openWithViewer"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
{
|
||||
"command": "sheetjs.disableForExtension",
|
||||
"group": "2_workspace",
|
||||
"when": "resourceExtname =~ /\\.(xlsx|xls|csv|ods|xlsm|xlsb|numbers)$/"
|
||||
},
|
||||
{
|
||||
"command": "sheetjs.enableForExtension",
|
||||
"group": "2_workspace",
|
||||
"when": "resourceExtname =~ /\\.(xlsx|xls|csv|ods|xlsm|xlsb|numbers)$/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"customEditors": [
|
||||
{
|
||||
"viewType": "excelViewer.spreadsheet",
|
||||
|
||||
@ -7,7 +7,9 @@ import { WorkbookCache } from './cacheManagement/workbookCache';
|
||||
|
||||
export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<ExcelDocument> {
|
||||
private cache: WorkbookCache;
|
||||
|
||||
private fileWatchers: Map<string, vscode.Disposable> = new Map();
|
||||
private webviewPanels: Map<string, vscode.WebviewPanel> = new Map();
|
||||
|
||||
public static register(context: vscode.ExtensionContext): vscode.Disposable {
|
||||
return vscode.window.registerCustomEditorProvider(
|
||||
'excelViewer.spreadsheet',
|
||||
@ -30,6 +32,45 @@ export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<
|
||||
|
||||
webviewPanel.webview.options = { enableScripts: true };
|
||||
|
||||
// store the webview panel for this document
|
||||
const uriKey = document.uri.toString();
|
||||
this.webviewPanels.set(uriKey, webviewPanel);
|
||||
|
||||
// setup file watcher for changes to this specific file
|
||||
const watcher = vscode.workspace.createFileSystemWatcher(
|
||||
document.uri.fsPath
|
||||
);
|
||||
|
||||
watcher.onDidChange(async () => {
|
||||
console.log(`File changed: ${document.uri.fsPath}, reloading...`);
|
||||
|
||||
// clear the cache for this file
|
||||
this.cache.clearCachesForUri(document.uri.toString());
|
||||
|
||||
// reload the file
|
||||
this.setLoadingView(webviewPanel);
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
try {
|
||||
await this.processExcelFile(document, webviewPanel);
|
||||
} catch (error) {
|
||||
console.error('Error reloading file:', error);
|
||||
this.setErrorView(webviewPanel, error);
|
||||
}
|
||||
});
|
||||
|
||||
this.fileWatchers.set(uriKey, watcher);
|
||||
|
||||
// clean up when the panel is disposed
|
||||
webviewPanel.onDidDispose(() => {
|
||||
this.webviewPanels.delete(uriKey);
|
||||
const watcher = this.fileWatchers.get(uriKey);
|
||||
if (watcher) {
|
||||
watcher.dispose();
|
||||
this.fileWatchers.delete(uriKey);
|
||||
}
|
||||
});
|
||||
|
||||
this.setLoadingView(webviewPanel);
|
||||
|
||||
// small timeout to ensure the loading view is rendered before heavy processing begins
|
||||
|
||||
118
src/extension.ts
118
src/extension.ts
@ -3,10 +3,124 @@ import { ExcelEditorProvider } from './excelEditorProvider';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
console.log('SheetJS Spreadsheet Viewer extension activating...');
|
||||
|
||||
|
||||
const provider = ExcelEditorProvider.register(context);
|
||||
context.subscriptions.push(provider);
|
||||
|
||||
|
||||
// Command to disable viewer for current file extension
|
||||
const disableCommand = vscode.commands.registerCommand('sheetjs.disableForExtension', async (uri?: vscode.Uri) => {
|
||||
// Try to get URI from parameter, active text editor, or prompt user
|
||||
if (!uri) {
|
||||
const activeTab = vscode.window.tabGroups.activeTabGroup.activeTab;
|
||||
if (activeTab?.label) {
|
||||
// Try to find the file by label in workspace
|
||||
const files = await vscode.workspace.findFiles(`**/${activeTab.label}`);
|
||||
if (files.length > 0) {
|
||||
uri = files[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!uri) {
|
||||
vscode.window.showWarningMessage('No file is currently open or could not determine file path');
|
||||
return;
|
||||
}
|
||||
|
||||
const ext = uri.fsPath.split('.').pop()?.toLowerCase();
|
||||
if (!ext) {
|
||||
vscode.window.showWarningMessage('Could not determine file extension');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update workbench.editorAssociations to use default editor
|
||||
const workbenchConfig = vscode.workspace.getConfiguration('workbench');
|
||||
const associations = workbenchConfig.get<Record<string, string>>('editorAssociations') || {};
|
||||
|
||||
if (associations[`*.${ext}`] === 'default') {
|
||||
vscode.window.showInformationMessage(`SheetJS viewer is already disabled for .${ext} files`);
|
||||
return;
|
||||
}
|
||||
|
||||
associations[`*.${ext}`] = 'default';
|
||||
await workbenchConfig.update('editorAssociations', associations, vscode.ConfigurationTarget.Global);
|
||||
|
||||
// Close the current tab and reopen with default editor
|
||||
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
|
||||
await vscode.commands.executeCommand('vscode.open', uri);
|
||||
|
||||
vscode.window.showInformationMessage(`SheetJS viewer disabled for .${ext} files`);
|
||||
});
|
||||
|
||||
// Command to enable viewer for current file extension
|
||||
const enableCommand = vscode.commands.registerCommand('sheetjs.enableForExtension', async (uri?: vscode.Uri) => {
|
||||
// Try to get URI from parameter or active tab
|
||||
if (!uri) {
|
||||
uri = vscode.window.activeTextEditor?.document.uri;
|
||||
if (!uri) {
|
||||
const activeTab = vscode.window.tabGroups.activeTabGroup.activeTab;
|
||||
if (activeTab?.label) {
|
||||
const files = await vscode.workspace.findFiles(`**/${activeTab.label}`);
|
||||
if (files.length > 0) {
|
||||
uri = files[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!uri) {
|
||||
vscode.window.showWarningMessage('No file is currently open or could not determine file path');
|
||||
return;
|
||||
}
|
||||
|
||||
const ext = uri.fsPath.split('.').pop()?.toLowerCase();
|
||||
if (!ext) {
|
||||
vscode.window.showWarningMessage('Could not determine file extension');
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove from workbench.editorAssociations
|
||||
const workbenchConfig = vscode.workspace.getConfiguration('workbench');
|
||||
const associations = workbenchConfig.get<Record<string, string>>('editorAssociations') || {};
|
||||
|
||||
// If not set to 'default', it's already enabled
|
||||
if (associations[`*.${ext}`] !== 'default') {
|
||||
vscode.window.showInformationMessage(`SheetJS viewer is already enabled for .${ext} files`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new object without the extension (to avoid proxy issues)
|
||||
const newAssociations: Record<string, string> = {};
|
||||
for (const key in associations) {
|
||||
if (key !== `*.${ext}`) {
|
||||
newAssociations[key] = associations[key];
|
||||
}
|
||||
}
|
||||
await workbenchConfig.update('editorAssociations', newAssociations, vscode.ConfigurationTarget.Global);
|
||||
|
||||
// Close the current tab and reopen with SheetJS viewer
|
||||
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
|
||||
await vscode.commands.executeCommand('vscode.openWith', uri, 'excelViewer.spreadsheet');
|
||||
|
||||
vscode.window.showInformationMessage(`SheetJS viewer enabled for .${ext} files`);
|
||||
});
|
||||
|
||||
// Command to open with viewer
|
||||
const openCommand = vscode.commands.registerCommand('sheetjs.openWithViewer', async () => {
|
||||
const uris = await vscode.window.showOpenDialog({
|
||||
canSelectMany: false,
|
||||
openLabel: 'Open with SheetJS Viewer',
|
||||
filters: {
|
||||
'Spreadsheets': ['xlsx', 'xls', 'csv', 'ods', 'xlsm', 'xlsb', 'numbers']
|
||||
}
|
||||
});
|
||||
|
||||
if (uris && uris[0]) {
|
||||
await vscode.commands.executeCommand('vscode.openWith', uris[0], 'excelViewer.spreadsheet');
|
||||
}
|
||||
});
|
||||
|
||||
context.subscriptions.push(disableCommand, enableCommand, openCommand);
|
||||
|
||||
console.log('SheetJS Spreadsheet Viewer extension is now active');
|
||||
vscode.window.showInformationMessage('SheetJS Spreadsheet Viewer is ready!');
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user