extension.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. const vscode = require('vscode');
  2. const fs = require('fs');
  3. const path = require('path')
  4. const browserTemplate = require('./__browserTemplate')
  5. let treeView;
  6. let context;
  7. let panel;
  8. const previewKey = 'savedPreviewUrl'; // Key to store last opened URL
  9. const previewColumnKey = 'savedPreviewColumn'; // Key to store last panel position
  10. const mainEmitter = (type) => {
  11. Log(type)
  12. console.log(type)
  13. }
  14. const Log = (args) => {
  15. vscode.window.showInformationMessage.call(global, args)
  16. }
  17. const Storage = {
  18. get: (previewKey) => {
  19. return context.globalState.get(previewKey)
  20. },
  21. set: (key, value) => {
  22. context.globalState.update(key, value)
  23. }
  24. }
  25. const frame = {
  26. initFrame: () =>{},
  27. open:
  28. // Function to open a WebView preview
  29. function runFrame(url, column = vscode.ViewColumn.Active) {
  30. console.log("iframe open", url)
  31. if (panel) {
  32. // If panel exists, update the content and restore position
  33. Storage.set(previewKey, url);
  34. panel.webview.html = frame.getWebviewContent(url);
  35. panel.reveal(column);
  36. } else {
  37. // Create a new WebView panel in the last known position
  38. panel = vscode.window.createWebviewPanel(
  39. 'webPreview',
  40. 'Web Preview',
  41. column,
  42. {
  43. enableScripts: true, // Allows JavaScript execution
  44. retainContextWhenHidden: true, // Ensures WebView state is preserved
  45. }
  46. );
  47. panel.webview.html = frame.getWebviewContent(url);
  48. // Save URL & position for persistence
  49. Storage.set(previewKey, url);
  50. Storage.set(previewColumnKey, column);
  51. // Track panel movement
  52. panel.onDidChangeViewState(e => {
  53. if (panel.visible) {
  54. Storage.set(previewColumnKey, panel.viewColumn);
  55. }
  56. });
  57. // Handle WebView disposal (clear references)
  58. panel.onDidDispose(() => {
  59. panel = null;
  60. Storage.set(previewKey, undefined);
  61. Storage.set(previewColumnKey, undefined);
  62. });
  63. panel.webview.onDidReceiveMessage(
  64. message => {
  65. if (message.command === 'urlChanged') {
  66. console.log('New URL:', message.url);
  67. // You can trigger any action in your extension here
  68. Storage.set(previewKey, message.url);
  69. }
  70. if (message.command === 'inspectUrl') {
  71. console.log('inspect url')
  72. // vscode.commands.executeCommand("workbench.action.webview.openDeveloperTools");
  73. panel.webview.openDevTools(); // Opens DevTools for this WebView iframe only
  74. }
  75. },
  76. undefined,
  77. context.subscriptions
  78. );
  79. }
  80. tabs.backupTabs && tabs.backupTabs();
  81. },
  82. getWebviewContent: browserTemplate,
  83. getCurrentPreviewState: function getCurrentPreviewState() {
  84. return {
  85. url: Storage.get(previewKey),
  86. group: Storage.get(previewColumnKey) || vscode.ViewColumn.One
  87. }
  88. }
  89. }
  90. const menu = {
  91. updateCount(newMessagesCount) {
  92. treeView.badge = {
  93. value: newMessagesCount,
  94. tooltip: `You have ${newMessagesCount} new documentation`
  95. };
  96. },
  97. TabSaver: class TabSaverTreeDataProvider {
  98. constructor(tabs) {
  99. this.tabs = tabs;
  100. }
  101. getTreeItem(element) {
  102. return new vscode.TreeItem(element);
  103. }
  104. getChildren(element) {
  105. if (!element) {
  106. return Promise.resolve(this.tabs);
  107. }
  108. // If an element is provided, you can handle it accordingly
  109. return Promise.resolve([]);
  110. }
  111. },
  112. treeClickHandler: function treeClickHandler(event, context) {
  113. if (event.selection.length > 0) {
  114. const selectedItem = event.selection[0];
  115. console.log(`Clicked on: ${selectedItem}`); // Log the clicked item's label
  116. frame.open('https://itrum.ru?selectedItem=' + selectedItem, 2)
  117. // let cmds = {
  118. // Preview: openWelcomeFrame,
  119. // HTML: () => openHtml(null, '<h1>asdfasdf</h1>'),
  120. // 'Run Tests': openTestsFrame,
  121. // 'Close Tabs': closeAllTabs
  122. // }
  123. // let fn = cmds[selectedItem];
  124. // fn && fn();
  125. }
  126. },
  127. initTreeView: function initTreeView() {
  128. const view = vscode.window.createTreeView('itk.mainView', {
  129. treeDataProvider: new menu.TabSaver(['HTML', 'Preview', 'Close Tabs'])
  130. });
  131. context.subscriptions.push(view);
  132. treeView = view;
  133. const view2 = vscode.window.createTreeView('itk.runView', {
  134. treeDataProvider: new menu.TabSaver(['Run Tests', 'Close Tabs'])
  135. });
  136. context.subscriptions.push(view);
  137. context.subscriptions.push(view2);
  138. console.log('view', view)
  139. view.onDidChangeSelection((event) => menu.treeClickHandler(event, context));
  140. view2.onDidChangeSelection((event) => menu.treeClickHandler(event, context));
  141. },
  142. }
  143. const tabs = {
  144. init: () => {
  145. let disposable = vscode.commands.registerCommand('itk.getTabs', () => tabs.getTabs());
  146. context.subscriptions.push(disposable);
  147. },
  148. async restoreOrKeepCurrent() {
  149. try {
  150. let idKey = 'idSessionKey'
  151. let data = require('./files/openTabs')
  152. let curOpenTabsId = data[idKey];
  153. let curVsCodeId = Storage.get(idKey)
  154. console.log("{data!!!", curOpenTabsId, curVsCodeId)
  155. let isFromScratch = curVsCodeId != curOpenTabsId;
  156. if (isFromScratch) {
  157. await tabs.closeTabs()
  158. await tabs.restoreByArr(data.tabs)
  159. Storage.set(idKey, curOpenTabsId)
  160. }
  161. mainEmitter('openTabs')
  162. Log('FRAME OPEN START')
  163. console.log('data', data.preview)
  164. if (isFromScratch) {
  165. data.preview.url && await frame.open(data.preview.url, data.preview.group)
  166. }
  167. if (!isFromScratch) {
  168. await frame.open(Storage.get(previewKey), Storage.get(previewColumnKey))
  169. }
  170. mainEmitter('openFrame')
  171. } catch (e) {
  172. console.log('eee', e)
  173. }
  174. },
  175. async restoreByArr(groups) {
  176. const openPromises = [];
  177. let groupTabs = {};
  178. const workspaceFolder = vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0];
  179. if (!workspaceFolder) {
  180. vscode.window.showErrorMessage('No workspace folder is open. Please open a folder or workspace.');
  181. return;
  182. }
  183. groups.forEach((group, groupIndex) => {
  184. const groupId = groupIndex + 1; // Group ID corresponds to column
  185. // Open files first, in order
  186. group.filter(item => item.relPath).forEach((item, index) => {
  187. const filePath = vscode.Uri.joinPath(workspaceFolder.uri, item.relPath);
  188. openPromises.push(vscode.workspace.openTextDocument(filePath)
  189. .then(doc => {
  190. // Use groupId as the column index
  191. const columnToUse = groupId;
  192. // Manage the tab order per group
  193. let lastTab = groupTabs[groupId] || 1; // Start at tab 1 by default
  194. vscode.window.showTextDocument(doc, { viewColumn: columnToUse, preview: false }).then(() => {
  195. groupTabs[groupId] = lastTab + 1; // Increment tab order for next file
  196. });
  197. }));
  198. });
  199. // After files, open Webview (iframe) last for this group
  200. // group.filter(item => item.url).forEach(item => {
  201. // openPromises.push(openWebview(item.url, groupId));
  202. // });
  203. });
  204. // Wait for all files/URLs to be opened
  205. return Promise.all(openPromises).then(() => {
  206. console.log('All files and URLs have been opened.');
  207. }).catch(err => {
  208. console.error('Error opening files or URLs:', err);
  209. });
  210. },
  211. initFileChanges() {
  212. let disposable = vscode.window.onDidChangeVisibleTextEditors(tabs.backupTabs);
  213. context.subscriptions.push(disposable); // Add to subscriptions to prevent memory leaks
  214. },
  215. getCurrentPreviewState: frame.getCurrentPreviewState,
  216. async closeTabs() {
  217. try {
  218. await vscode.commands.executeCommand('workbench.action.closeAllEditors');
  219. console.log("all tabs are closed")
  220. } catch (e) {
  221. vscode.window.showInformationMessage("Tabs Closing Error");
  222. }
  223. },
  224. writeFile(relPath, content) {
  225. const filePath = path.join(__dirname, relPath);
  226. fs.writeFileSync(filePath, content);
  227. },
  228. async backupTabs() {
  229. let v = await tabs.getTabs()
  230. tabs.writeFile('./files/backupTabs.js', `module.exports = ${JSON.stringify(v, null, 4)}`)
  231. },
  232. getTabs() {
  233. const tabGroups = vscode.window.tabGroups.all;
  234. if (tabGroups.length === 0) {
  235. vscode.window.showInformationMessage('No open tabs found.');
  236. return;
  237. }
  238. let tabInfo = [];
  239. const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; // Get workspace folder
  240. tabGroups.forEach((group, index) => {
  241. let curTabsInGroup = []
  242. group.tabs.forEach(tab => {
  243. let filePath = "";
  244. if (tab.input instanceof vscode.TabInputText) {
  245. filePath = tab.input.uri.fsPath;
  246. }
  247. let relativePath = "";
  248. if (filePath) {
  249. relativePath = path.relative(workspaceFolder, filePath); // Use path.relative
  250. }
  251. curTabsInGroup.push({
  252. group: tab.group.viewColumn,
  253. label: tab.label,
  254. isActive: tab.isActive,
  255. isPinned: tab.isPinned,
  256. absPath: filePath,
  257. relPath: relativePath,
  258. });
  259. });
  260. tabInfo.push(curTabsInGroup)
  261. });
  262. // vscode.window.showInformationMessage(`Opened Tabs:\n${tabInfo.join('\n')}`);
  263. return { tabs: tabInfo, preview: tabs.getCurrentPreviewState() };
  264. }
  265. }
  266. function activate(_context) {
  267. console.log('Congratulations, your extension "itk" is now active!');
  268. context = _context;
  269. menu.initTreeView();
  270. menu.updateCount(117)
  271. frame.initFrame()
  272. tabs.init()
  273. tabs.initFileChanges();
  274. tabs.restoreOrKeepCurrent();
  275. }
  276. function deactivate() {
  277. console.log("ITK DEACTIVE")
  278. }
  279. module.exports = {
  280. activate,
  281. deactivate
  282. }