extension.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. const vscode = require('vscode');
  2. const fs = require('fs');
  3. const path = require('path')
  4. const browserTemplate = require('./__browserTemplate')
  5. const { getOpenedTabs } = require('./getOpenedTabs')
  6. const { restoreByArr } = require('./restoreByArr')
  7. let treeView;
  8. let context;
  9. let panel;
  10. global.tabsInfo = {};
  11. const previewKey = 'savedPreviewUrl'; // Key to store last opened URL
  12. const previewColumnKey = 'savedPreviewColumn'; // Key to store last panel position
  13. const mainEmitter = (type) => {
  14. Log(type)
  15. console.log(type)
  16. }
  17. const Log = (args) => {
  18. vscode.window.showInformationMessage.call(global, args)
  19. }
  20. const Storage = {
  21. get: (previewKey) => {
  22. return context.globalState.get(previewKey)
  23. },
  24. set: (key, value) => {
  25. context.globalState.update(key, value)
  26. }
  27. }
  28. const frame = {
  29. initFrame: () => { },
  30. open:
  31. // Function to open a WebView preview
  32. function runFrame(url, column = vscode.ViewColumn.Active) {
  33. console.log("iframe open", url)
  34. if (panel) {
  35. // If panel exists, update the content and restore position
  36. Storage.set(previewKey, url);
  37. panel.webview.html = frame.getWebviewContent(url);
  38. panel.reveal(column);
  39. } else {
  40. // Create a new WebView panel in the last known position
  41. panel = vscode.window.createWebviewPanel(
  42. 'webPreview',
  43. 'Web Preview',
  44. column,
  45. {
  46. enableScripts: true, // Allows JavaScript execution
  47. retainContextWhenHidden: true, // Ensures WebView state is preserved
  48. }
  49. );
  50. panel.webview.html = frame.getWebviewContent(url);
  51. // Save URL & position for persistence
  52. Storage.set(previewKey, url);
  53. Storage.set(previewColumnKey, column);
  54. // Track panel movement
  55. panel.onDidChangeViewState(e => {
  56. if (panel.visible) {
  57. Storage.set(previewColumnKey, panel.viewColumn);
  58. }
  59. });
  60. // Handle WebView disposal (clear references)
  61. panel.onDidDispose(() => {
  62. panel = null;
  63. Storage.set(previewKey, undefined);
  64. Storage.set(previewColumnKey, undefined);
  65. });
  66. panel.webview.onDidReceiveMessage(
  67. message => {
  68. if (message.command === 'urlChanged') {
  69. console.log('New URL:', message.url);
  70. // You can trigger any action in your extension here
  71. Storage.set(previewKey, message.url);
  72. }
  73. if (message.command === 'inspectUrl') {
  74. console.log('inspect url')
  75. // vscode.commands.executeCommand("workbench.action.webview.openDeveloperTools");
  76. panel.webview.openDevTools(); // Opens DevTools for this WebView iframe only
  77. }
  78. },
  79. undefined,
  80. context.subscriptions
  81. );
  82. }
  83. tabs.backupTabs && tabs.backupTabs();
  84. },
  85. getWebviewContent: browserTemplate,
  86. getCurrentPreviewState: function getCurrentPreviewState() {
  87. return {
  88. url: Storage.get(previewKey),
  89. group: Storage.get(previewColumnKey) || vscode.ViewColumn.One
  90. }
  91. }
  92. }
  93. const menu = {
  94. updateCount(newMessagesCount) {
  95. treeView.badge = {
  96. value: newMessagesCount,
  97. tooltip: `You have ${newMessagesCount} new documentation`
  98. };
  99. },
  100. TabSaver: class TabSaverTreeDataProvider {
  101. constructor(tabs) {
  102. this.tabs = tabs;
  103. }
  104. getTreeItem(element) {
  105. return new vscode.TreeItem(element);
  106. }
  107. getChildren(element) {
  108. if (!element) {
  109. return Promise.resolve(this.tabs);
  110. }
  111. // If an element is provided, you can handle it accordingly
  112. return Promise.resolve([]);
  113. }
  114. },
  115. treeClickHandler: function treeClickHandler(event, context) {
  116. if (event.selection.length > 0) {
  117. const selectedItem = event.selection[0];
  118. console.log(`Clicked on: ${selectedItem}`); // Log the clicked item's label
  119. frame.open('https://itrum.ru?selectedItem=' + selectedItem, 2)
  120. // let cmds = {
  121. // Preview: openWelcomeFrame,
  122. // HTML: () => openHtml(null, '<h1>asdfasdf</h1>'),
  123. // 'Run Tests': openTestsFrame,
  124. // 'Close Tabs': closeAllTabs
  125. // }
  126. // let fn = cmds[selectedItem];
  127. // fn && fn();
  128. }
  129. },
  130. initTreeView: function initTreeView() {
  131. const view = vscode.window.createTreeView('itk.mainView', {
  132. treeDataProvider: new menu.TabSaver(['HTML', 'Preview', 'Close Tabs'])
  133. });
  134. context.subscriptions.push(view);
  135. treeView = view;
  136. const view2 = vscode.window.createTreeView('itk.runView', {
  137. treeDataProvider: new menu.TabSaver(['Run Tests', 'Close Tabs'])
  138. });
  139. context.subscriptions.push(view);
  140. context.subscriptions.push(view2);
  141. console.log('view', view)
  142. view.onDidChangeSelection((event) => menu.treeClickHandler(event, context));
  143. view2.onDidChangeSelection((event) => menu.treeClickHandler(event, context));
  144. },
  145. }
  146. const tabs = {
  147. init: () => {
  148. let disposable = vscode.commands.registerCommand('itk.getTabs', () => tabs.getTabs());
  149. context.subscriptions.push(disposable);
  150. context.subscriptions.push(vscode.commands.registerCommand('itk.closeAllTabs', () => tabs.closeTabs()));
  151. context.subscriptions.push(vscode.commands.registerCommand('itk.openTabs', () => tabs.restoreOrKeepCurrent(true)));
  152. context.subscriptions.push(vscode.commands.registerCommand('itk.terminal', () => terminal.startAndCmd(`sshpass -p "root" ssh -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@t24`)));
  153. context.subscriptions.push(vscode.commands.registerCommand('itk.scrollTo',
  154. () => tabs.scrollTo(29)));
  155. },
  156. scrollTo:
  157. function scrollToLine(lineNumber) {
  158. const editor = vscode.window.activeTextEditor;
  159. mainEmitter(lineNumber)
  160. if (!editor) {
  161. vscode.window.showErrorMessage('No active editor found.');
  162. return;
  163. }
  164. const line = Math.max(0, lineNumber - 1); // Convert to zero-based index
  165. const range = new vscode.Range(line, 0, line, 0);
  166. editor.revealRange(range, vscode.TextEditorRevealType.InCenter);
  167. },
  168. async restoreOrKeepCurrent(isRestore) {
  169. try {
  170. let idKey = 'vsSessionId'
  171. let data = require('./files/openTabs')
  172. let curOpenTabsId = data[idKey];
  173. let curVsCodeId = Storage.get(idKey)
  174. console.log("{data!!!", curOpenTabsId, curVsCodeId)
  175. let isFromScratch = isRestore || (curVsCodeId != curOpenTabsId);
  176. isFromScratch = true;
  177. mainEmitter(curVsCodeId + '___' + curOpenTabsId + 'OPEN TABS. length =' + data?.tabs?.length + ' isfrom scratch ? ' + (isFromScratch ? 'YES' : 'no'))
  178. if (isFromScratch) {
  179. // await tabs.closeTabs()
  180. mainEmitter('All tabs closed')
  181. await tabs.restoreByArr(data.tabs)
  182. Storage.set(idKey, curOpenTabsId)
  183. }
  184. mainEmitter('openTabs Complete step 1')
  185. // Log('FRAME OPEN START')
  186. console.log('data', data.preview)
  187. // if (isFromScratch) {
  188. // data.preview.url && await frame.open(data.preview.url, data.preview.group)
  189. // }
  190. // if (!isFromScratch) {
  191. // await frame.open(Storage.get(previewKey), Storage.get(previewColumnKey))
  192. // }
  193. mainEmitter('openFrame Final Skip')
  194. } catch (e) {
  195. console.log('eee', e)
  196. }
  197. },
  198. restoreByArr: restoreByArr,
  199. // async restoreByArr(groups) {
  200. // const openPromises = [];
  201. // let groupTabs = {};
  202. // const workspaceFolder = vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0];
  203. // if (!workspaceFolder) {
  204. // vscode.window.showErrorMessage('No workspace folder is open. Please open a folder or workspace.');
  205. // return;
  206. // }
  207. // mainEmitter('workspaceFolder = ' + workspaceFolder)
  208. // groups.forEach((group, groupIndex) => {
  209. // const groupId = groupIndex + 1; // Group ID corresponds to column
  210. // // Open files first, in order
  211. // group.filter(item => item.relPath).forEach((item, index) => {
  212. // const filePath = vscode.Uri.joinPath(workspaceFolder.uri, item.relPath);
  213. // openPromises.push(vscode.workspace.openTextDocument(filePath)
  214. // .then(doc => {
  215. // // Use groupId as the column index
  216. // const columnToUse = groupId;
  217. // // Manage the tab order per group
  218. // let lastTab = groupTabs[groupId] || 1; // Start at tab 1 by default
  219. // vscode.window.showTextDocument(doc, { viewColumn: columnToUse, preview: false }).then(() => {
  220. // groupTabs[groupId] = lastTab + 1; // Increment tab order for next file
  221. // });
  222. // }));
  223. // });
  224. // // After files, open Webview (iframe) last for this group
  225. // // group.filter(item => item.url).forEach(item => {
  226. // // openPromises.push(openWebview(item.url, groupId));
  227. // // });
  228. // });
  229. // // Wait for all files/URLs to be opened
  230. // return Promise.all(openPromises).then(() => {
  231. // console.log('All files and URLs have been opened.');
  232. // }).catch(err => {
  233. // console.error('Error opening files or URLs:', err);
  234. // });
  235. // },
  236. initFileChanges() {
  237. // let disposable2 = vscode.commands.registerCommand('itk.openGit', async () => {
  238. // // Get the Git extension
  239. // // Get the Git extension
  240. // return;
  241. // const gitExtension = vscode.extensions.getExtension('vscode.git')?.exports;
  242. // if (!gitExtension) {
  243. // vscode.window.showErrorMessage('Git extension not found.');
  244. // return;
  245. // }
  246. // // Get the API from the Git extension
  247. // const git = gitExtension.getAPI(1);
  248. // if (git.repositories.length === 0) {
  249. // vscode.window.showErrorMessage('No Git repositories found.');
  250. // return;
  251. // }
  252. // // Get the first repository (you can loop through all repositories if needed)
  253. // const repo = git.repositories[0];
  254. // // Get the changes in the working tree
  255. // const changes = repo.state.workingTreeChanges;
  256. // if (changes.length === 0) {
  257. // vscode.window.showInformationMessage('No changes in the working tree.');
  258. // return;
  259. // }
  260. // // Loop through all changed files and open their diff views
  261. // for (const change of changes) {
  262. // const fileUri = change.uri;
  263. // const fileName = fileUri.fsPath.split('/').pop(); // Get the file name for the tab title
  264. // // Open the diff view for each file
  265. // await vscode.commands.executeCommand('vscode.diff', change.originalUri, fileUri, `Changes: ${fileName}`);
  266. // }
  267. // });
  268. // context.subscriptions.push(disposable2);
  269. let disposable = vscode.window.onDidChangeVisibleTextEditors(tabs.backupTabs);
  270. context.subscriptions.push(disposable); // Add to subscriptions to prevent memory leaks
  271. //on close tab, a more specific way to detect closes.
  272. disposable = vscode.workspace.onDidCloseTextDocument((document) => {
  273. // console.log(`Tab closed: ${document.fileName}`);
  274. //perform your logic here.
  275. tabs.backupTabs()
  276. });
  277. context.subscriptions.push(disposable);
  278. //on open tab.
  279. disposable = vscode.workspace.onDidOpenTextDocument((document) => {
  280. // console.log(`Tab opened: ${document.fileName}`);
  281. //perform your logic here.
  282. tabs.backupTabs()
  283. });
  284. context.subscriptions.push(disposable);
  285. // Add event on scroll
  286. disposable = vscode.window.onDidChangeTextEditorVisibleRanges((event) => {
  287. // Logic for scroll event
  288. // console.log(`Scroll event in ${event.textEditor.document.fileName}`);
  289. tabs.backupTabs()
  290. // You can access the visible ranges using event.visibleRanges
  291. // event.visibleRanges.forEach(range => {
  292. // console.log(`Visible range: ${range.start.line} - ${range.end.line}`);
  293. // });
  294. });
  295. context.subscriptions.push(disposable);
  296. // Add event on selection
  297. disposable = vscode.window.onDidChangeTextEditorSelection((event) => {
  298. // Logic for selection event
  299. // console.log(`Selection changed in ${event.textEditor.document.fileName}`);
  300. tabs.backupTabs()
  301. // You can access the selection using event.selections
  302. // event.selections.forEach(selection => {
  303. // console.log(`Selection: ${selection.start.line}:${selection.start.character} - ${selection.end.line}:${selection.end.character}`);
  304. // });
  305. });
  306. context.subscriptions.push(disposable);
  307. },
  308. getCurrentPreviewState: frame.getCurrentPreviewState,
  309. async closeTabs() {
  310. try {
  311. await vscode.commands.executeCommand('workbench.action.closeAllEditors');
  312. console.log("all tabs are closed")
  313. } catch (e) {
  314. vscode.window.showInformationMessage("Tabs Closing Error");
  315. }
  316. },
  317. writeFile(relPath, content) {
  318. const filePath = path.join(__dirname, relPath);
  319. fs.writeFileSync(filePath, content);
  320. },
  321. async backupTabs() {
  322. vscode.window.showInformationMessage('Tabs Chagnges!');
  323. let v = await tabs.getTabs()
  324. tabs.writeFile('./files/backupTabs.js', `module.exports = ${JSON.stringify(v, null, 4)}`)
  325. },
  326. getTabs: getOpenedTabs,
  327. // () {
  328. // const tabGroups = vscode.window.tabGroups.all;
  329. // if (tabGroups.length === 0) {
  330. // vscode.window.showInformationMessage('No open tabs found.');
  331. // return;
  332. // }
  333. // let tabInfo = [];
  334. // const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; // Get workspace folder
  335. // tabGroups.forEach((group, index) => {
  336. // let curTabsInGroup = []
  337. // group.tabs.forEach(tab => {
  338. // let filePath = "";
  339. // if (tab.input instanceof vscode.TabInputText) {
  340. // filePath = tab.input.uri.fsPath;
  341. // }
  342. // let relativePath = "";
  343. // if (filePath) {
  344. // relativePath = path.relative(workspaceFolder, filePath); // Use path.relative
  345. // }
  346. // curTabsInGroup.push({
  347. // group: tab.group.viewColumn,
  348. // label: tab.label,
  349. // isActive: tab.isActive,
  350. // isPinned: tab.isPinned,
  351. // absPath: filePath,
  352. // relPath: relativePath,
  353. // });
  354. // });
  355. // tabInfo.push(curTabsInGroup)
  356. // });
  357. // vscode.window.showInformationMessage(`Opened Tabs:\n${JSON.stringify(tabInfo, null, 4)}`);
  358. // return { tabs: tabInfo, preview: tabs.getCurrentPreviewState() };
  359. // }
  360. }
  361. let terminal = {
  362. startAndCmd(cmd, name) {
  363. // Open a terminal
  364. const terminal = vscode.window.createTerminal(name || "Auto Terminal");
  365. // Run a command
  366. terminal.show();
  367. terminal.sendText(cmd || "echo Hello, VS Code!");
  368. console.log("Auto Terminal Extension is active!");
  369. }
  370. }
  371. function activate(_context) {
  372. console.log('Congratulations, your extension "itk" is now active!');
  373. context = _context;
  374. // terminal.startAndCmd();
  375. menu.initTreeView();
  376. menu.updateCount(117)
  377. tabs.restoreOrKeepCurrent(false);
  378. tabs.init()
  379. tabs.initFileChanges();
  380. }
  381. function deactivate() {
  382. console.log("ITK DEACTIVE")
  383. }
  384. module.exports = {
  385. activate,
  386. deactivate
  387. }