const vscode = require('vscode');
const fs = require('fs');
const path = require('path')
const browserTemplate = require('./__browserTemplate')
let treeView;
let context;
let panel;
const previewKey = 'savedPreviewUrl'; // Key to store last opened URL
const previewColumnKey = 'savedPreviewColumn'; // Key to store last panel position
const mainEmitter = (type) => {
Log(type)
console.log(type)
}
const Log = (args) => {
vscode.window.showInformationMessage.call(global, args)
}
const Storage = {
get: (previewKey) => {
return context.globalState.get(previewKey)
},
set: (key, value) => {
context.globalState.update(key, value)
}
}
const frame = {
initFrame: () =>{},
open:
// Function to open a WebView preview
function runFrame(url, column = vscode.ViewColumn.Active) {
console.log("iframe open", url)
if (panel) {
// If panel exists, update the content and restore position
Storage.set(previewKey, url);
panel.webview.html = frame.getWebviewContent(url);
panel.reveal(column);
} else {
// Create a new WebView panel in the last known position
panel = vscode.window.createWebviewPanel(
'webPreview',
'Web Preview',
column,
{
enableScripts: true, // Allows JavaScript execution
retainContextWhenHidden: true, // Ensures WebView state is preserved
}
);
panel.webview.html = frame.getWebviewContent(url);
// Save URL & position for persistence
Storage.set(previewKey, url);
Storage.set(previewColumnKey, column);
// Track panel movement
panel.onDidChangeViewState(e => {
if (panel.visible) {
Storage.set(previewColumnKey, panel.viewColumn);
}
});
// Handle WebView disposal (clear references)
panel.onDidDispose(() => {
panel = null;
Storage.set(previewKey, undefined);
Storage.set(previewColumnKey, undefined);
});
panel.webview.onDidReceiveMessage(
message => {
if (message.command === 'urlChanged') {
console.log('New URL:', message.url);
// You can trigger any action in your extension here
Storage.set(previewKey, message.url);
}
if (message.command === 'inspectUrl') {
console.log('inspect url')
// vscode.commands.executeCommand("workbench.action.webview.openDeveloperTools");
panel.webview.openDevTools(); // Opens DevTools for this WebView iframe only
}
},
undefined,
context.subscriptions
);
}
tabs.backupTabs && tabs.backupTabs();
},
getWebviewContent: browserTemplate,
getCurrentPreviewState: function getCurrentPreviewState() {
return {
url: Storage.get(previewKey),
group: Storage.get(previewColumnKey) || vscode.ViewColumn.One
}
}
}
const menu = {
updateCount(newMessagesCount) {
treeView.badge = {
value: newMessagesCount,
tooltip: `You have ${newMessagesCount} new documentation`
};
},
TabSaver: class TabSaverTreeDataProvider {
constructor(tabs) {
this.tabs = tabs;
}
getTreeItem(element) {
return new vscode.TreeItem(element);
}
getChildren(element) {
if (!element) {
return Promise.resolve(this.tabs);
}
// If an element is provided, you can handle it accordingly
return Promise.resolve([]);
}
},
treeClickHandler: function treeClickHandler(event, context) {
if (event.selection.length > 0) {
const selectedItem = event.selection[0];
console.log(`Clicked on: ${selectedItem}`); // Log the clicked item's label
frame.open('https://itrum.ru?selectedItem=' + selectedItem, 2)
// let cmds = {
// Preview: openWelcomeFrame,
// HTML: () => openHtml(null, '
asdfasdf
'),
// 'Run Tests': openTestsFrame,
// 'Close Tabs': closeAllTabs
// }
// let fn = cmds[selectedItem];
// fn && fn();
}
},
initTreeView: function initTreeView() {
const view = vscode.window.createTreeView('itk.mainView', {
treeDataProvider: new menu.TabSaver(['HTML', 'Preview', 'Close Tabs'])
});
context.subscriptions.push(view);
treeView = view;
const view2 = vscode.window.createTreeView('itk.runView', {
treeDataProvider: new menu.TabSaver(['Run Tests', 'Close Tabs'])
});
context.subscriptions.push(view);
context.subscriptions.push(view2);
console.log('view', view)
view.onDidChangeSelection((event) => menu.treeClickHandler(event, context));
view2.onDidChangeSelection((event) => menu.treeClickHandler(event, context));
},
}
const tabs = {
init: () => {
let disposable = vscode.commands.registerCommand('itk.getTabs', () => tabs.getTabs());
context.subscriptions.push(disposable);
},
async restoreOrKeepCurrent() {
try {
let idKey = 'idSessionKey'
let data = require('./files/openTabs')
let curOpenTabsId = data[idKey];
let curVsCodeId = Storage.get(idKey)
console.log("{data!!!", curOpenTabsId, curVsCodeId)
let isFromScratch = curVsCodeId != curOpenTabsId;
if (isFromScratch) {
await tabs.closeTabs()
await tabs.restoreByArr(data.tabs)
Storage.set(idKey, curOpenTabsId)
}
mainEmitter('openTabs')
Log('FRAME OPEN START')
console.log('data', data.preview)
if (isFromScratch) {
data.preview.url && await frame.open(data.preview.url, data.preview.group)
}
if (!isFromScratch) {
await frame.open(Storage.get(previewKey), Storage.get(previewColumnKey))
}
mainEmitter('openFrame')
} catch (e) {
console.log('eee', e)
}
},
async restoreByArr(groups) {
const openPromises = [];
let groupTabs = {};
const workspaceFolder = vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0];
if (!workspaceFolder) {
vscode.window.showErrorMessage('No workspace folder is open. Please open a folder or workspace.');
return;
}
groups.forEach((group, groupIndex) => {
const groupId = groupIndex + 1; // Group ID corresponds to column
// Open files first, in order
group.filter(item => item.relPath).forEach((item, index) => {
const filePath = vscode.Uri.joinPath(workspaceFolder.uri, item.relPath);
openPromises.push(vscode.workspace.openTextDocument(filePath)
.then(doc => {
// Use groupId as the column index
const columnToUse = groupId;
// Manage the tab order per group
let lastTab = groupTabs[groupId] || 1; // Start at tab 1 by default
vscode.window.showTextDocument(doc, { viewColumn: columnToUse, preview: false }).then(() => {
groupTabs[groupId] = lastTab + 1; // Increment tab order for next file
});
}));
});
// After files, open Webview (iframe) last for this group
// group.filter(item => item.url).forEach(item => {
// openPromises.push(openWebview(item.url, groupId));
// });
});
// Wait for all files/URLs to be opened
return Promise.all(openPromises).then(() => {
console.log('All files and URLs have been opened.');
}).catch(err => {
console.error('Error opening files or URLs:', err);
});
},
initFileChanges() {
let disposable = vscode.window.onDidChangeVisibleTextEditors(tabs.backupTabs);
context.subscriptions.push(disposable); // Add to subscriptions to prevent memory leaks
},
getCurrentPreviewState: frame.getCurrentPreviewState,
async closeTabs() {
try {
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
console.log("all tabs are closed")
} catch (e) {
vscode.window.showInformationMessage("Tabs Closing Error");
}
},
writeFile(relPath, content) {
const filePath = path.join(__dirname, relPath);
fs.writeFileSync(filePath, content);
},
async backupTabs() {
let v = await tabs.getTabs()
tabs.writeFile('./files/backupTabs.js', `module.exports = ${JSON.stringify(v, null, 4)}`)
},
getTabs() {
const tabGroups = vscode.window.tabGroups.all;
if (tabGroups.length === 0) {
vscode.window.showInformationMessage('No open tabs found.');
return;
}
let tabInfo = [];
const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; // Get workspace folder
tabGroups.forEach((group, index) => {
let curTabsInGroup = []
group.tabs.forEach(tab => {
let filePath = "";
if (tab.input instanceof vscode.TabInputText) {
filePath = tab.input.uri.fsPath;
}
let relativePath = "";
if (filePath) {
relativePath = path.relative(workspaceFolder, filePath); // Use path.relative
}
curTabsInGroup.push({
group: tab.group.viewColumn,
label: tab.label,
isActive: tab.isActive,
isPinned: tab.isPinned,
absPath: filePath,
relPath: relativePath,
});
});
tabInfo.push(curTabsInGroup)
});
// vscode.window.showInformationMessage(`Opened Tabs:\n${tabInfo.join('\n')}`);
return { tabs: tabInfo, preview: tabs.getCurrentPreviewState() };
}
}
function activate(_context) {
console.log('Congratulations, your extension "itk" is now active!');
context = _context;
menu.initTreeView();
menu.updateCount(117)
frame.initFrame()
tabs.init()
tabs.initFileChanges();
tabs.restoreOrKeepCurrent();
}
function deactivate() {
console.log("ITK DEACTIVE")
}
module.exports = {
activate,
deactivate
}