@theia/plugin-ext 1.77.0-next.7 → 1.77.0-next.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/lib/common/character-classifier.js.map +1 -1
  2. package/lib/common/plugin-api-rpc.d.ts +2 -0
  3. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  4. package/lib/common/plugin-api-rpc.js.map +1 -1
  5. package/lib/common/plugin-protocol.d.ts +9 -0
  6. package/lib/common/plugin-protocol.d.ts.map +1 -1
  7. package/lib/common/plugin-protocol.js +19 -1
  8. package/lib/common/plugin-protocol.js.map +1 -1
  9. package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
  10. package/lib/hosted/browser/hosted-plugin.js +4 -2
  11. package/lib/hosted/browser/hosted-plugin.js.map +1 -1
  12. package/lib/hosted/browser/hosted-plugin.spec.d.ts +2 -0
  13. package/lib/hosted/browser/hosted-plugin.spec.d.ts.map +1 -0
  14. package/lib/hosted/browser/hosted-plugin.spec.js +59 -0
  15. package/lib/hosted/browser/hosted-plugin.spec.js.map +1 -0
  16. package/lib/hosted/browser/worker/worker-main.js +2 -1
  17. package/lib/hosted/browser/worker/worker-main.js.map +1 -1
  18. package/lib/hosted/browser-only/browser-only-plugin-paths-service.js +1 -1
  19. package/lib/hosted/browser-only/browser-only-plugin-paths-service.js.map +1 -1
  20. package/lib/hosted/browser-only/browser-only-plugin-paths-service.spec.js +2 -1
  21. package/lib/hosted/browser-only/browser-only-plugin-paths-service.spec.js.map +1 -1
  22. package/lib/hosted/node/hosted-plugin-localization-service.js +2 -2
  23. package/lib/hosted/node/hosted-plugin-localization-service.js.map +1 -1
  24. package/lib/hosted/node/hosted-plugin-process.js +1 -1
  25. package/lib/hosted/node/hosted-plugin-process.js.map +1 -1
  26. package/lib/hosted/node/plugin-deployer-handler-impl.js +1 -1
  27. package/lib/hosted/node/plugin-deployer-handler-impl.js.map +1 -1
  28. package/lib/hosted/node/plugin-ext-hosted-backend-module.js +2 -1
  29. package/lib/hosted/node/plugin-ext-hosted-backend-module.js.map +1 -1
  30. package/lib/hosted/node/plugin-host-proxy.d.ts.map +1 -1
  31. package/lib/hosted/node/plugin-host-proxy.js +10 -6
  32. package/lib/hosted/node/plugin-host-proxy.js.map +1 -1
  33. package/lib/hosted/node/plugin-host-rpc.js +1 -1
  34. package/lib/hosted/node/plugin-host-rpc.js.map +1 -1
  35. package/lib/hosted/node/plugin-host.js +2 -1
  36. package/lib/hosted/node/plugin-host.js.map +1 -1
  37. package/lib/hosted/node/plugin-reader.js +6 -6
  38. package/lib/hosted/node/plugin-reader.js.map +1 -1
  39. package/lib/hosted/node/plugin-reader.spec.js +4 -3
  40. package/lib/hosted/node/plugin-reader.spec.js.map +1 -1
  41. package/lib/hosted/node/plugin-require-override.d.ts.map +1 -1
  42. package/lib/hosted/node/plugin-require-override.js +3 -1
  43. package/lib/hosted/node/plugin-require-override.js.map +1 -1
  44. package/lib/hosted/node/plugin-require-override.spec.d.ts +2 -0
  45. package/lib/hosted/node/plugin-require-override.spec.d.ts.map +1 -0
  46. package/lib/hosted/node/plugin-require-override.spec.js +40 -0
  47. package/lib/hosted/node/plugin-require-override.spec.js.map +1 -0
  48. package/lib/hosted/node/scanners/file-plugin-uri-factory.js +1 -1
  49. package/lib/hosted/node/scanners/file-plugin-uri-factory.js.map +1 -1
  50. package/lib/hosted/node/scanners/scanner-theia.js +2 -2
  51. package/lib/hosted/node/scanners/scanner-theia.js.map +1 -1
  52. package/lib/hosted/node/scanners/scanner-theia.spec.js +5 -4
  53. package/lib/hosted/node/scanners/scanner-theia.spec.js.map +1 -1
  54. package/lib/hosted/node-electron/scanner-theia-electron.js +1 -1
  55. package/lib/hosted/node-electron/scanner-theia-electron.js.map +1 -1
  56. package/lib/main/browser/commands.js +1 -1
  57. package/lib/main/browser/commands.js.map +1 -1
  58. package/lib/main/browser/comments/comment-thread-widget.js +3 -2
  59. package/lib/main/browser/comments/comment-thread-widget.js.map +1 -1
  60. package/lib/main/browser/comments/comments-contribution.js +1 -1
  61. package/lib/main/browser/comments/comments-contribution.js.map +1 -1
  62. package/lib/main/browser/custom-editors/custom-editor-opener.spec.js +3 -2
  63. package/lib/main/browser/custom-editors/custom-editor-opener.spec.js.map +1 -1
  64. package/lib/main/browser/custom-editors/custom-editor-widget.js +1 -1
  65. package/lib/main/browser/custom-editors/custom-editor-widget.js.map +1 -1
  66. package/lib/main/browser/custom-editors/custom-editors-main.js +2 -1
  67. package/lib/main/browser/custom-editors/custom-editors-main.js.map +1 -1
  68. package/lib/main/browser/decorations/decorations-main.js +2 -1
  69. package/lib/main/browser/decorations/decorations-main.js.map +1 -1
  70. package/lib/main/browser/dialogs-main.js +2 -1
  71. package/lib/main/browser/dialogs-main.js.map +1 -1
  72. package/lib/main/browser/documents-main.js +3 -2
  73. package/lib/main/browser/documents-main.js.map +1 -1
  74. package/lib/main/browser/file-system-main-impl.js +3 -2
  75. package/lib/main/browser/file-system-main-impl.js.map +1 -1
  76. package/lib/main/browser/hierarchy/hierarchy-types-converters.js +3 -2
  77. package/lib/main/browser/hierarchy/hierarchy-types-converters.js.map +1 -1
  78. package/lib/main/browser/languages-main.js +3 -3
  79. package/lib/main/browser/languages-main.js.map +1 -1
  80. package/lib/main/browser/languages-main.spec.js +2 -1
  81. package/lib/main/browser/languages-main.spec.js.map +1 -1
  82. package/lib/main/browser/main-file-system-event-service.d.ts +1 -22
  83. package/lib/main/browser/main-file-system-event-service.d.ts.map +1 -1
  84. package/lib/main/browser/main-file-system-event-service.js +2 -48
  85. package/lib/main/browser/main-file-system-event-service.js.map +1 -1
  86. package/lib/main/browser/menus/menus-contribution-handler.d.ts.map +1 -1
  87. package/lib/main/browser/menus/menus-contribution-handler.js +1 -12
  88. package/lib/main/browser/menus/menus-contribution-handler.js.map +1 -1
  89. package/lib/main/browser/notebooks/renderers/output-webview-internal.d.ts.map +1 -1
  90. package/lib/main/browser/notebooks/renderers/output-webview-internal.js +3 -2
  91. package/lib/main/browser/notebooks/renderers/output-webview-internal.js.map +1 -1
  92. package/lib/main/browser/plugin-contribution-handler.js +1 -1
  93. package/lib/main/browser/plugin-contribution-handler.js.map +1 -1
  94. package/lib/main/browser/plugin-ext-widget.js +1 -1
  95. package/lib/main/browser/plugin-ext-widget.js.map +1 -1
  96. package/lib/main/browser/plugin-icon-service.js +1 -1
  97. package/lib/main/browser/plugin-icon-service.js.map +1 -1
  98. package/lib/main/browser/plugin-icon-theme-service.d.ts +2 -2
  99. package/lib/main/browser/plugin-icon-theme-service.d.ts.map +1 -1
  100. package/lib/main/browser/plugin-icon-theme-service.js +2 -2
  101. package/lib/main/browser/plugin-icon-theme-service.js.map +1 -1
  102. package/lib/main/browser/plugin-icon-theme-service.spec.js +2 -1
  103. package/lib/main/browser/plugin-icon-theme-service.spec.js.map +1 -1
  104. package/lib/main/browser/plugin-shared-style.js.map +1 -1
  105. package/lib/main/browser/scm-main.d.ts +3 -1
  106. package/lib/main/browser/scm-main.d.ts.map +1 -1
  107. package/lib/main/browser/scm-main.js +6 -3
  108. package/lib/main/browser/scm-main.js.map +1 -1
  109. package/lib/main/browser/scm-main.spec.js +31 -0
  110. package/lib/main/browser/scm-main.spec.js.map +1 -1
  111. package/lib/main/browser/status-bar-message-registry-main.js +2 -1
  112. package/lib/main/browser/status-bar-message-registry-main.js.map +1 -1
  113. package/lib/main/browser/text-editor-main.js +2 -1
  114. package/lib/main/browser/text-editor-main.js.map +1 -1
  115. package/lib/main/browser/text-editors-main.js +2 -1
  116. package/lib/main/browser/text-editors-main.js.map +1 -1
  117. package/lib/main/browser/view/plugin-tree-view-node-label-provider.js +1 -1
  118. package/lib/main/browser/view/plugin-tree-view-node-label-provider.js.map +1 -1
  119. package/lib/main/browser/view/plugin-view-registry.d.ts +17 -2
  120. package/lib/main/browser/view/plugin-view-registry.d.ts.map +1 -1
  121. package/lib/main/browser/view/plugin-view-registry.js +72 -21
  122. package/lib/main/browser/view/plugin-view-registry.js.map +1 -1
  123. package/lib/main/browser/view/plugin-view-registry.spec.js +188 -9
  124. package/lib/main/browser/view/plugin-view-registry.spec.js.map +1 -1
  125. package/lib/main/browser/view/tree-view-decorator-service.js +1 -1
  126. package/lib/main/browser/view/tree-view-decorator-service.js.map +1 -1
  127. package/lib/main/browser/view/tree-view-widget.js +2 -2
  128. package/lib/main/browser/view/tree-view-widget.js.map +1 -1
  129. package/lib/main/browser/webview/pre/main.spec.d.ts +2 -0
  130. package/lib/main/browser/webview/pre/main.spec.d.ts.map +1 -0
  131. package/lib/main/browser/webview/pre/main.spec.js +45 -0
  132. package/lib/main/browser/webview/pre/main.spec.js.map +1 -0
  133. package/lib/main/browser/webview/webview-theme-data-provider.d.ts +1 -1
  134. package/lib/main/browser/webview/webview-theme-data-provider.d.ts.map +1 -1
  135. package/lib/main/browser/webview/webview.d.ts.map +1 -1
  136. package/lib/main/browser/webview/webview.js +6 -3
  137. package/lib/main/browser/webview/webview.js.map +1 -1
  138. package/lib/main/browser/window-state-main.js +2 -1
  139. package/lib/main/browser/window-state-main.js.map +1 -1
  140. package/lib/main/browser/workspace-main.js +1 -1
  141. package/lib/main/browser/workspace-main.js.map +1 -1
  142. package/lib/main/common/plugin-theia-environment.js +1 -1
  143. package/lib/main/common/plugin-theia-environment.js.map +1 -1
  144. package/lib/main/node/handlers/plugin-theia-directory-handler.js +4 -4
  145. package/lib/main/node/handlers/plugin-theia-directory-handler.js.map +1 -1
  146. package/lib/main/node/handlers/plugin-theia-file-handler.js +3 -3
  147. package/lib/main/node/handlers/plugin-theia-file-handler.js.map +1 -1
  148. package/lib/main/node/paths/plugin-paths-service.js +4 -4
  149. package/lib/main/node/paths/plugin-paths-service.js.map +1 -1
  150. package/lib/main/node/plugin-deployer-directory-handler-context-impl.js +2 -1
  151. package/lib/main/node/plugin-deployer-directory-handler-context-impl.js.map +1 -1
  152. package/lib/main/node/plugin-deployer-file-handler-context-impl.js +3 -2
  153. package/lib/main/node/plugin-deployer-file-handler-context-impl.js.map +1 -1
  154. package/lib/main/node/plugin-deployer-impl.d.ts.map +1 -1
  155. package/lib/main/node/plugin-deployer-impl.js +7 -2
  156. package/lib/main/node/plugin-deployer-impl.js.map +1 -1
  157. package/lib/main/node/plugin-deployer-impl.spec.d.ts +2 -0
  158. package/lib/main/node/plugin-deployer-impl.spec.d.ts.map +1 -0
  159. package/lib/main/node/plugin-deployer-impl.spec.js +66 -0
  160. package/lib/main/node/plugin-deployer-impl.spec.js.map +1 -0
  161. package/lib/main/node/plugin-github-resolver.js +1 -1
  162. package/lib/main/node/plugin-github-resolver.js.map +1 -1
  163. package/lib/main/node/plugin-http-resolver.js +1 -1
  164. package/lib/main/node/plugin-http-resolver.js.map +1 -1
  165. package/lib/main/node/plugin-service.d.ts +1 -1
  166. package/lib/main/node/plugin-service.d.ts.map +1 -1
  167. package/lib/main/node/plugin-service.js +4 -4
  168. package/lib/main/node/plugin-service.js.map +1 -1
  169. package/lib/main/node/plugins-key-value-storage.js +2 -2
  170. package/lib/main/node/plugins-key-value-storage.js.map +1 -1
  171. package/lib/main/node/plugins-key-value-storage.spec.js +2 -1
  172. package/lib/main/node/plugins-key-value-storage.spec.js.map +1 -1
  173. package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.js +2 -2
  174. package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.js.map +1 -1
  175. package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.spec.js +4 -3
  176. package/lib/main/node/resolvers/local-directory-plugin-deployer-resolver.spec.js.map +1 -1
  177. package/lib/main/node/resolvers/local-plugin-deployer-resolver.js +3 -3
  178. package/lib/main/node/resolvers/local-plugin-deployer-resolver.js.map +1 -1
  179. package/lib/main/node/temp-dir-util.js +3 -2
  180. package/lib/main/node/temp-dir-util.js.map +1 -1
  181. package/lib/plugin/comments.d.ts +1 -1
  182. package/lib/plugin/comments.d.ts.map +1 -1
  183. package/lib/plugin/custom-editors.js +2 -1
  184. package/lib/plugin/custom-editors.js.map +1 -1
  185. package/lib/plugin/decorations.spec.js +2 -1
  186. package/lib/plugin/decorations.spec.js.map +1 -1
  187. package/lib/plugin/document-data.d.ts.map +1 -1
  188. package/lib/plugin/document-data.js +0 -1
  189. package/lib/plugin/document-data.js.map +1 -1
  190. package/lib/plugin/documents.js +2 -1
  191. package/lib/plugin/documents.js.map +1 -1
  192. package/lib/plugin/editors-and-documents.js +1 -1
  193. package/lib/plugin/editors-and-documents.js.map +1 -1
  194. package/lib/plugin/file-system-event-service-ext-impl.d.ts +1 -1
  195. package/lib/plugin/file-system-event-service-ext-impl.d.ts.map +1 -1
  196. package/lib/plugin/file-system-event-service-ext-impl.js +3 -2
  197. package/lib/plugin/file-system-event-service-ext-impl.js.map +1 -1
  198. package/lib/plugin/file-system-ext-impl.js +5 -4
  199. package/lib/plugin/file-system-ext-impl.js.map +1 -1
  200. package/lib/plugin/file-system-watcher.spec.js +2 -1
  201. package/lib/plugin/file-system-watcher.spec.js.map +1 -1
  202. package/lib/plugin/known-commands.js +5 -5
  203. package/lib/plugin/known-commands.js.map +1 -1
  204. package/lib/plugin/known-commands.spec.js +2 -1
  205. package/lib/plugin/known-commands.spec.js.map +1 -1
  206. package/lib/plugin/languages/call-hierarchy.js +2 -1
  207. package/lib/plugin/languages/call-hierarchy.js.map +1 -1
  208. package/lib/plugin/languages/code-action.js +2 -1
  209. package/lib/plugin/languages/code-action.js.map +1 -1
  210. package/lib/plugin/languages/color.js +2 -1
  211. package/lib/plugin/languages/color.js.map +1 -1
  212. package/lib/plugin/languages/completion.js +2 -1
  213. package/lib/plugin/languages/completion.js.map +1 -1
  214. package/lib/plugin/languages/declaration.js +3 -2
  215. package/lib/plugin/languages/declaration.js.map +1 -1
  216. package/lib/plugin/languages/definition.js +3 -2
  217. package/lib/plugin/languages/definition.js.map +1 -1
  218. package/lib/plugin/languages/document-drop-edit.js +4 -3
  219. package/lib/plugin/languages/document-drop-edit.js.map +1 -1
  220. package/lib/plugin/languages/document-formatting.js +2 -1
  221. package/lib/plugin/languages/document-formatting.js.map +1 -1
  222. package/lib/plugin/languages/document-highlight.js +3 -2
  223. package/lib/plugin/languages/document-highlight.js.map +1 -1
  224. package/lib/plugin/languages/evaluatable-expression.js +2 -1
  225. package/lib/plugin/languages/evaluatable-expression.js.map +1 -1
  226. package/lib/plugin/languages/folding.js +2 -1
  227. package/lib/plugin/languages/folding.js.map +1 -1
  228. package/lib/plugin/languages/hover.js +2 -1
  229. package/lib/plugin/languages/hover.js.map +1 -1
  230. package/lib/plugin/languages/implementation.js +3 -2
  231. package/lib/plugin/languages/implementation.js.map +1 -1
  232. package/lib/plugin/languages/inlay-hints.js +2 -1
  233. package/lib/plugin/languages/inlay-hints.js.map +1 -1
  234. package/lib/plugin/languages/inline-completion.js +2 -1
  235. package/lib/plugin/languages/inline-completion.js.map +1 -1
  236. package/lib/plugin/languages/inline-values.js +2 -1
  237. package/lib/plugin/languages/inline-values.js.map +1 -1
  238. package/lib/plugin/languages/lens.js +2 -1
  239. package/lib/plugin/languages/lens.js.map +1 -1
  240. package/lib/plugin/languages/link-provider.js +2 -1
  241. package/lib/plugin/languages/link-provider.js.map +1 -1
  242. package/lib/plugin/languages/multi-document-highlight.js +3 -2
  243. package/lib/plugin/languages/multi-document-highlight.js.map +1 -1
  244. package/lib/plugin/languages/on-type-formatting.js +2 -1
  245. package/lib/plugin/languages/on-type-formatting.js.map +1 -1
  246. package/lib/plugin/languages/outline.js +3 -2
  247. package/lib/plugin/languages/outline.js.map +1 -1
  248. package/lib/plugin/languages/range-formatting.js +2 -1
  249. package/lib/plugin/languages/range-formatting.js.map +1 -1
  250. package/lib/plugin/languages/reference.js +2 -1
  251. package/lib/plugin/languages/reference.js.map +1 -1
  252. package/lib/plugin/languages/rename.js +2 -1
  253. package/lib/plugin/languages/rename.js.map +1 -1
  254. package/lib/plugin/languages/selection-range.js +2 -1
  255. package/lib/plugin/languages/selection-range.js.map +1 -1
  256. package/lib/plugin/languages/signature.js +2 -1
  257. package/lib/plugin/languages/signature.js.map +1 -1
  258. package/lib/plugin/languages/type-definition.js +3 -2
  259. package/lib/plugin/languages/type-definition.js.map +1 -1
  260. package/lib/plugin/languages/type-hierarchy.js +2 -1
  261. package/lib/plugin/languages/type-hierarchy.js.map +1 -1
  262. package/lib/plugin/languages/util.js +2 -1
  263. package/lib/plugin/languages/util.js.map +1 -1
  264. package/lib/plugin/languages/workspace-symbol.js +2 -1
  265. package/lib/plugin/languages/workspace-symbol.js.map +1 -1
  266. package/lib/plugin/node/debug/debug.spec.js +2 -1
  267. package/lib/plugin/node/debug/debug.spec.js.map +1 -1
  268. package/lib/plugin/node/debug/plugin-node-debug-adapter-creator.js +3 -2
  269. package/lib/plugin/node/debug/plugin-node-debug-adapter-creator.js.map +1 -1
  270. package/lib/plugin/node/env-node-ext.js +1 -1
  271. package/lib/plugin/node/env-node-ext.js.map +1 -1
  272. package/lib/plugin/notebook/notebook-document.js +3 -2
  273. package/lib/plugin/notebook/notebook-document.js.map +1 -1
  274. package/lib/plugin/notebook/notebook-editors.js +2 -1
  275. package/lib/plugin/notebook/notebook-editors.js.map +1 -1
  276. package/lib/plugin/notebook/notebooks.js +2 -1
  277. package/lib/plugin/notebook/notebooks.js.map +1 -1
  278. package/lib/plugin/path.spec.js +2 -1
  279. package/lib/plugin/path.spec.js.map +1 -1
  280. package/lib/plugin/plugin-context.js +1 -1
  281. package/lib/plugin/plugin-context.js.map +1 -1
  282. package/lib/plugin/plugin-icon-path.js +2 -1
  283. package/lib/plugin/plugin-icon-path.js.map +1 -1
  284. package/lib/plugin/plugin-manager.js +2 -2
  285. package/lib/plugin/plugin-manager.js.map +1 -1
  286. package/lib/plugin/preference-registry.spec.js +2 -1
  287. package/lib/plugin/preference-registry.spec.js.map +1 -1
  288. package/lib/plugin/quick-open.js +2 -1
  289. package/lib/plugin/quick-open.js.map +1 -1
  290. package/lib/plugin/relative-pattern.spec.js +3 -2
  291. package/lib/plugin/relative-pattern.spec.js.map +1 -1
  292. package/lib/plugin/scm.d.ts.map +1 -1
  293. package/lib/plugin/scm.js +14 -1
  294. package/lib/plugin/scm.js.map +1 -1
  295. package/lib/plugin/scm.spec.js +56 -1
  296. package/lib/plugin/scm.spec.js.map +1 -1
  297. package/lib/plugin/tasks/task-provider.js +2 -1
  298. package/lib/plugin/tasks/task-provider.js.map +1 -1
  299. package/lib/plugin/tasks/tasks.js +2 -1
  300. package/lib/plugin/tasks/tasks.js.map +1 -1
  301. package/lib/plugin/telemetry-ext.spec.js +2 -1
  302. package/lib/plugin/telemetry-ext.spec.js.map +1 -1
  303. package/lib/plugin/terminal-ext.js +1 -1
  304. package/lib/plugin/terminal-ext.js.map +1 -1
  305. package/lib/plugin/terminal-ext.spec.js +2 -1
  306. package/lib/plugin/terminal-ext.spec.js.map +1 -1
  307. package/lib/plugin/tests.js +1 -1
  308. package/lib/plugin/tests.js.map +1 -1
  309. package/lib/plugin/text-editor.js +2 -1
  310. package/lib/plugin/text-editor.js.map +1 -1
  311. package/lib/plugin/text-editors.js +2 -1
  312. package/lib/plugin/text-editors.js.map +1 -1
  313. package/lib/plugin/tree/tree-views.d.ts.map +1 -1
  314. package/lib/plugin/tree/tree-views.js +2 -1
  315. package/lib/plugin/tree/tree-views.js.map +1 -1
  316. package/lib/plugin/type-converters.js +6 -5
  317. package/lib/plugin/type-converters.js.map +1 -1
  318. package/lib/plugin/type-converters.spec.js +5 -4
  319. package/lib/plugin/type-converters.spec.js.map +1 -1
  320. package/lib/plugin/types-impl.d.ts +10 -0
  321. package/lib/plugin/types-impl.d.ts.map +1 -1
  322. package/lib/plugin/types-impl.js +7 -1
  323. package/lib/plugin/types-impl.js.map +1 -1
  324. package/lib/plugin/types-impl.spec.js +25 -2
  325. package/lib/plugin/types-impl.spec.js.map +1 -1
  326. package/lib/plugin/workspace.js +2 -2
  327. package/lib/plugin/workspace.js.map +1 -1
  328. package/lib/plugin/workspace.spec.js +2 -1
  329. package/lib/plugin/workspace.spec.js.map +1 -1
  330. package/lib/plugin-ext-frontend-electron-module.js +2 -1
  331. package/lib/plugin-ext-frontend-electron-module.js.map +1 -1
  332. package/lib/plugin-ext-frontend-module.js +2 -1
  333. package/lib/plugin-ext-frontend-module.js.map +1 -1
  334. package/package.json +32 -32
  335. package/src/common/character-classifier.ts +1 -1
  336. package/src/common/plugin-api-rpc.ts +2 -0
  337. package/src/common/plugin-protocol.ts +18 -0
  338. package/src/hosted/browser/hosted-plugin.spec.ts +66 -0
  339. package/src/hosted/browser/hosted-plugin.ts +3 -1
  340. package/src/hosted/node/plugin-host-proxy.ts +6 -3
  341. package/src/hosted/node/plugin-reader.ts +1 -1
  342. package/src/hosted/node/plugin-require-override.spec.ts +44 -0
  343. package/src/hosted/node/plugin-require-override.ts +1 -0
  344. package/src/main/browser/file-system-main-impl.ts +1 -1
  345. package/src/main/browser/main-file-system-event-service.ts +2 -49
  346. package/src/main/browser/menus/menus-contribution-handler.ts +6 -13
  347. package/src/main/browser/notebooks/renderers/output-webview-internal.ts +6 -3
  348. package/src/main/browser/plugin-shared-style.ts +2 -2
  349. package/src/main/browser/scm-main.spec.ts +32 -0
  350. package/src/main/browser/scm-main.ts +6 -2
  351. package/src/main/browser/view/plugin-view-registry.spec.ts +277 -12
  352. package/src/main/browser/view/plugin-view-registry.ts +76 -21
  353. package/src/main/browser/view/tree-view-widget.tsx +1 -1
  354. package/src/main/browser/webview/pre/main.js +19 -10
  355. package/src/main/browser/webview/pre/main.spec.ts +46 -0
  356. package/src/main/browser/webview/webview.ts +7 -3
  357. package/src/main/node/handlers/plugin-theia-directory-handler.ts +1 -1
  358. package/src/main/node/handlers/plugin-theia-file-handler.ts +1 -1
  359. package/src/main/node/plugin-deployer-file-handler-context-impl.ts +1 -1
  360. package/src/main/node/plugin-deployer-impl.spec.ts +75 -0
  361. package/src/main/node/plugin-deployer-impl.ts +7 -2
  362. package/src/main/node/plugin-service.ts +1 -1
  363. package/src/plugin/document-data.ts +0 -1
  364. package/src/plugin/file-system-event-service-ext-impl.ts +1 -1
  365. package/src/plugin/file-system-ext-impl.ts +2 -2
  366. package/src/plugin/known-commands.ts +5 -5
  367. package/src/plugin/plugin-context.ts +4 -4
  368. package/src/plugin/plugin-manager.ts +1 -1
  369. package/src/plugin/scm.spec.ts +67 -1
  370. package/src/plugin/scm.ts +18 -1
  371. package/src/plugin/tests.ts +2 -2
  372. package/src/plugin/tree/tree-views.ts +2 -1
  373. package/src/plugin/type-converters.spec.ts +1 -1
  374. package/src/plugin/types-impl.spec.ts +25 -0
  375. package/src/plugin/types-impl.ts +7 -0
  376. package/lib/main/browser/main-file-system-event-service.spec.d.ts +0 -2
  377. package/lib/main/browser/main-file-system-event-service.spec.d.ts.map +0 -1
  378. package/lib/main/browser/main-file-system-event-service.spec.js +0 -100
  379. package/lib/main/browser/main-file-system-event-service.spec.js.map +0 -1
  380. package/src/main/browser/main-file-system-event-service.spec.ts +0 -125
@@ -23,9 +23,10 @@ import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/front
23
23
  FrontendApplicationConfigProvider.set({});
24
24
 
25
25
  import { expect } from 'chai';
26
- import { Disposable } from '@theia/core/lib/common';
26
+ import { Command, Disposable } from '@theia/core/lib/common';
27
27
  import { PluginViewRegistry, ViewContainerInfo, PLUGIN_VIEW_DATA_FACTORY_ID } from './plugin-view-registry';
28
- import type { ViewWelcome } from '../../../common';
28
+ import { PluginViewType, ViewWelcome } from '../../../common';
29
+ import { BaseWidget, Panel, Widget } from '@theia/core/lib/browser/widgets/widget';
29
30
 
30
31
  disableJSDOM();
31
32
 
@@ -54,7 +55,6 @@ describe('PluginViewRegistry - view menu labels', () => {
54
55
  let registry: PluginViewRegistry;
55
56
  let menus: RecordingMenuModelRegistry;
56
57
 
57
- const toggleCommandId = (id: string): string => `plugin.view-container.${id}.toggle`;
58
58
  const internals = (): {
59
59
  viewContainers: Map<string, ViewContainerInfo>;
60
60
  registerViewMenuAction(containerId: string, label: string): Disposable;
@@ -76,21 +76,21 @@ describe('PluginViewRegistry - view menu labels', () => {
76
76
 
77
77
  it('uses the plain label for a single container', () => {
78
78
  registerContainer('a', 'Claude Code', 'left');
79
- expect(menus.actions.get(toggleCommandId('a'))?.label).to.equal('Claude Code');
79
+ expect(menus.actions.get('a')?.label).to.equal('Claude Code');
80
80
  });
81
81
 
82
82
  it('leaves distinct labels unsuffixed', () => {
83
83
  registerContainer('a', 'Explorer', 'left');
84
84
  registerContainer('b', 'Claude Code', 'right');
85
- expect(menus.actions.get(toggleCommandId('a'))?.label).to.equal('Explorer');
86
- expect(menus.actions.get(toggleCommandId('b'))?.label).to.equal('Claude Code');
85
+ expect(menus.actions.get('a')?.label).to.equal('Explorer');
86
+ expect(menus.actions.get('b')?.label).to.equal('Claude Code');
87
87
  });
88
88
 
89
89
  it('suffixes the location when two containers share a label', () => {
90
90
  registerContainer('a', 'Claude Code', 'left');
91
91
  registerContainer('b', 'Claude Code', 'right');
92
- expect(menus.actions.get(toggleCommandId('a'))?.label).to.equal('Claude Code (Side Bar)');
93
- expect(menus.actions.get(toggleCommandId('b'))?.label).to.equal('Claude Code (Secondary Side Bar)');
92
+ expect(menus.actions.get('a')?.label).to.equal('Claude Code (Side Bar)');
93
+ expect(menus.actions.get('b')?.label).to.equal('Claude Code (Secondary Side Bar)');
94
94
  });
95
95
 
96
96
  it('drops the suffix from the remaining container once the duplicate is removed', () => {
@@ -99,12 +99,14 @@ describe('PluginViewRegistry - view menu labels', () => {
99
99
 
100
100
  disposeB.dispose();
101
101
 
102
- expect(menus.actions.get(toggleCommandId('a'))?.label).to.equal('Claude Code');
103
- expect(menus.actions.has(toggleCommandId('b'))).to.equal(false);
102
+ expect(menus.actions.get('a')?.label).to.equal('Claude Code');
103
+ expect(menus.actions.has('b')).to.equal(false);
104
104
  });
105
105
 
106
106
  });
107
107
 
108
+ const welcome = (view: string): ViewWelcome => ({ view, content: `[Hi](command:${view}.hi)`, order: 0 });
109
+
108
110
  describe('PluginViewRegistry - welcome-only views', () => {
109
111
 
110
112
  interface FakeTreeViewWidget {
@@ -117,8 +119,6 @@ describe('PluginViewRegistry - welcome-only views', () => {
117
119
  let createdWidget: FakeTreeViewWidget;
118
120
  let getOrCreateCalls: Array<{ factoryId: string; options: unknown }>;
119
121
 
120
- const welcome = (view: string): ViewWelcome => ({ view, content: `[Hi](command:${view}.hi)`, order: 0 });
121
-
122
122
  const internals = (): {
123
123
  views: Map<string, [string, { type?: unknown }]>;
124
124
  viewDataProviders: Map<string, unknown>;
@@ -171,3 +171,268 @@ describe('PluginViewRegistry - welcome-only views', () => {
171
171
  });
172
172
 
173
173
  });
174
+
175
+ describe('PluginViewRegistry - welcome-only views on expand', () => {
176
+
177
+ const noop = () => Disposable.NULL;
178
+
179
+ let registry: PluginViewRegistry;
180
+ let view: { widgets: unknown[] };
181
+ let prepared: unknown[];
182
+
183
+ const internals = (): {
184
+ views: Map<string, [string, { type?: unknown }]>;
185
+ viewDataProviders: Map<string, unknown>;
186
+ viewsWelcome: Map<string, ViewWelcome[]>;
187
+ onDidExpandViewEmitter: { fire(viewId: string): void };
188
+ init(): void;
189
+ } => registry as unknown as {
190
+ views: Map<string, [string, { type?: unknown }]>;
191
+ viewDataProviders: Map<string, unknown>;
192
+ viewsWelcome: Map<string, ViewWelcome[]>;
193
+ onDidExpandViewEmitter: { fire(viewId: string): void };
194
+ init(): void;
195
+ };
196
+
197
+ async function expand(viewId: string): Promise<void> {
198
+ internals().onDidExpandViewEmitter.fire(viewId);
199
+ await new Promise(resolve => setTimeout(resolve));
200
+ }
201
+
202
+ beforeEach(() => {
203
+ registry = new PluginViewRegistry();
204
+ view = { widgets: [] };
205
+ prepared = [];
206
+ Object.assign(registry, {
207
+ shell: { activeWidget: undefined, onDidChangeActiveWidget: noop, initialized: new Promise(() => { }) },
208
+ viewContextKeys: { focusedView: { reset: () => { } } },
209
+ contextKeyService: { onDidChange: noop },
210
+ widgetManager: { onWillCreateWidget: noop, onDidCreateWidget: noop, getWidget: async () => view },
211
+ prepareView: async (widget: unknown) => { prepared.push(widget); }
212
+ });
213
+ internals().init();
214
+ internals().views.set('actions', ['container', {}]);
215
+ internals().viewsWelcome.set('actions', [welcome('actions')]);
216
+ });
217
+
218
+ it('prepares an empty welcome-only view when it is expanded, as after restoring a saved layout', async () => {
219
+ await expand('actions');
220
+
221
+ expect(prepared).to.deep.equal([view]);
222
+ });
223
+
224
+ it('leaves a view with a data provider to the provider', async () => {
225
+ internals().viewDataProviders.set('actions', () => undefined);
226
+
227
+ await expand('actions');
228
+
229
+ expect(prepared).to.have.lengthOf(0);
230
+ });
231
+
232
+ it('leaves a view that already has content alone', async () => {
233
+ view.widgets.push({});
234
+
235
+ await expand('actions');
236
+
237
+ expect(prepared).to.have.lengthOf(0);
238
+ });
239
+
240
+ it('leaves a view without welcomes alone', async () => {
241
+ internals().viewsWelcome.delete('actions');
242
+
243
+ await expand('actions');
244
+
245
+ expect(prepared).to.have.lengthOf(0);
246
+ });
247
+
248
+ it('leaves a webview view alone', async () => {
249
+ internals().views.set('actions', ['container', { type: PluginViewType.Webview }]);
250
+
251
+ await expand('actions');
252
+
253
+ expect(prepared).to.have.lengthOf(0);
254
+ });
255
+
256
+ });
257
+
258
+ describe('PluginViewRegistry - prepareView', () => {
259
+
260
+ interface FakeViewWidget {
261
+ options: { viewId: string };
262
+ title: { label: string };
263
+ widgets: unknown[];
264
+ isDisposed: boolean;
265
+ addWidget(widget: unknown): void;
266
+ }
267
+
268
+ let registry: PluginViewRegistry;
269
+ let view: FakeViewWidget;
270
+ let dataWidget: { isDisposed: boolean; dispose(): void };
271
+
272
+ beforeEach(() => {
273
+ registry = new PluginViewRegistry();
274
+ view = {
275
+ options: { viewId: 'actions' },
276
+ title: { label: '' },
277
+ widgets: [],
278
+ isDisposed: false,
279
+ addWidget(widget: unknown): void {
280
+ this.widgets.push(widget);
281
+ }
282
+ };
283
+ dataWidget = { isDisposed: false, dispose: () => { } };
284
+ (registry as unknown as { views: Map<string, unknown> }).views.set('actions', ['container', { id: 'actions', name: 'Actions' }]);
285
+ (registry as unknown as { createViewDataWidget: unknown }).createViewDataWidget = async () => dataWidget;
286
+ });
287
+
288
+ const prepareView = (): Promise<void> => (registry as unknown as { prepareView(widget: FakeViewWidget): Promise<void> }).prepareView(view);
289
+
290
+ it('adds the created data widget to the view', async () => {
291
+ await prepareView();
292
+
293
+ expect(view.widgets).to.deep.equal([dataWidget]);
294
+ });
295
+
296
+ it('leaves the view empty when its data widget was disposed before it could be added', async () => {
297
+ dataWidget.isDisposed = true;
298
+
299
+ await prepareView();
300
+
301
+ expect(view.widgets).to.have.lengthOf(0);
302
+ });
303
+
304
+ });
305
+
306
+ describe('PluginViewRegistry - VS Code view commands', () => {
307
+
308
+ let registry: PluginViewRegistry;
309
+ let commands: Map<string, Command>;
310
+
311
+ const internals = (): {
312
+ doRegisterViewContainer(id: string, location: string, options: { label: string }): Disposable;
313
+ } => registry as unknown as {
314
+ doRegisterViewContainer(id: string, location: string, options: { label: string }): Disposable;
315
+ };
316
+
317
+ beforeEach(() => {
318
+ registry = new PluginViewRegistry();
319
+ commands = new Map();
320
+ (registry as unknown as { commands: unknown }).commands = {
321
+ registerCommand: (command: Command) => {
322
+ commands.set(command.id, command);
323
+ return Disposable.create(() => commands.delete(command.id));
324
+ }
325
+ };
326
+ (registry as unknown as { menus: unknown }).menus = new RecordingMenuModelRegistry();
327
+ (registry as unknown as { quickView: unknown }).quickView = { registerItem: () => Disposable.NULL };
328
+ });
329
+
330
+ it('registers the container id and the view focus and open commands once a view is added', () => {
331
+ const containerId = 'workbench.view.extension.sample';
332
+ internals().doRegisterViewContainer(containerId, 'left', { label: 'Sample' });
333
+ expect(commands.has(containerId)).to.equal(false);
334
+
335
+ const disposeView = registry.registerView('sample', { id: 'sample.view', name: 'Sample View' });
336
+
337
+ expect(commands.get(containerId)).to.include({ label: 'Toggle Sample', category: 'View' });
338
+ expect(commands.get('plugin.view-container.workbench.view.extension.sample.toggle')?.label).to.equal(undefined);
339
+ expect(commands.get('sample.view.focus')).to.include({ label: 'Focus on Sample View View', category: 'Sample' });
340
+ expect(commands.has('sample.view.open')).to.equal(true);
341
+
342
+ disposeView.dispose();
343
+ expect(commands.has('sample.view.focus')).to.equal(false);
344
+ expect(commands.has('sample.view.open')).to.equal(false);
345
+ });
346
+
347
+ });
348
+
349
+ describe('PluginViewRegistry - webview view resolution', () => {
350
+
351
+ class FakeWebviewWidget extends BaseWidget {
352
+ setContentOptions(): void { }
353
+ }
354
+
355
+ const viewId = 'test.webviewView';
356
+ let registry: PluginViewRegistry;
357
+ let webview: FakeWebviewWidget;
358
+ let resolveCount: number;
359
+ let disableDom: () => void;
360
+
361
+ const createWebviewView = (): Promise<unknown> =>
362
+ (registry as unknown as { createNewWebviewView(id: string): Promise<unknown> }).createNewWebviewView(viewId);
363
+ const registerResolver = (): Promise<Disposable> =>
364
+ registry.registerWebviewView(viewId, { resolve: async () => { resolveCount++; } });
365
+ const settle = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 0));
366
+
367
+ before(() => disableDom = enableJSDOM());
368
+ after(() => disableDom());
369
+
370
+ beforeEach(() => {
371
+ registry = new PluginViewRegistry();
372
+ webview = new FakeWebviewWidget();
373
+ resolveCount = 0;
374
+ (registry as unknown as { widgetManager: unknown }).widgetManager = { getOrCreateWidget: async () => webview };
375
+ });
376
+
377
+ afterEach(() => webview.dispose());
378
+
379
+ it('does not resolve a webview view that has not been shown', async () => {
380
+ await createWebviewView();
381
+ await registerResolver();
382
+ await settle();
383
+
384
+ expect(resolveCount).to.equal(0);
385
+ });
386
+
387
+ it('resolves a webview view once it is shown', async () => {
388
+ await createWebviewView();
389
+ await registerResolver();
390
+ await settle();
391
+
392
+ Widget.attach(webview, document.body);
393
+ await settle();
394
+
395
+ expect(resolveCount).to.equal(1);
396
+ });
397
+
398
+ it('resolves a webview view that is shown before its provider is registered', async () => {
399
+ await createWebviewView();
400
+ Widget.attach(webview, document.body);
401
+ await settle();
402
+
403
+ await registerResolver();
404
+ await settle();
405
+
406
+ expect(resolveCount).to.equal(1);
407
+ });
408
+
409
+ it('resolves a webview view in a hidden parent only once the parent is shown', async () => {
410
+ const parent = new Panel();
411
+ parent.hide();
412
+ parent.addWidget(webview);
413
+ Widget.attach(parent, document.body);
414
+ await createWebviewView();
415
+ await registerResolver();
416
+ await settle();
417
+ expect(resolveCount).to.equal(0);
418
+
419
+ parent.show();
420
+ await settle();
421
+ parent.hide();
422
+ parent.show();
423
+ await settle();
424
+
425
+ expect(resolveCount).to.equal(1);
426
+ parent.dispose();
427
+ });
428
+
429
+ it('does not resolve a webview view that is disposed before it is shown', async () => {
430
+ await createWebviewView();
431
+ webview.dispose();
432
+ await registerResolver();
433
+ await settle();
434
+
435
+ expect(resolveCount).to.equal(0);
436
+ });
437
+
438
+ });
@@ -160,6 +160,7 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
160
160
 
161
161
  this.updateFocusedView();
162
162
  this.shell.onDidChangeActiveWidget(() => this.updateFocusedView());
163
+ this.onDidExpandView(viewId => this.prepareWelcomeOnlyView(viewId).catch(e => this.logger.error(e)));
163
164
 
164
165
  this.widgetManager.onWillCreateWidget(({ factoryId, widget, waitUntil }) => {
165
166
  if (factoryId === EXPLORER_VIEW_CONTAINER_ID && widget instanceof ViewContainerWidget) {
@@ -347,15 +348,30 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
347
348
  return toDispose;
348
349
  }
349
350
 
351
+ /**
352
+ * Toggles the view container the same way as {@link AbstractViewContribution.toggleView}:
353
+ * collapses its panel if it is the visible tab, otherwise opens and activates it.
354
+ */
350
355
  protected async toggleViewContainer(id: string): Promise<void> {
351
- let widget = await this.getPluginViewContainer(id);
352
- if (widget && widget.isAttached) {
353
- widget.dispose();
354
- } else {
355
- widget = await this.openViewContainer(id);
356
- if (widget) {
357
- this.shell.activateWidget(widget.id);
356
+ const existing = await this.getPluginViewContainer(id);
357
+ const tabBar = existing && this.shell.getTabBarFor(existing);
358
+ const area = existing && this.shell.getAreaFor(existing);
359
+ if (existing && tabBar && area && this.shell.isExpanded(area) && tabBar.currentTitle === existing.title) {
360
+ if (area === 'left' || area === 'right') {
361
+ await this.shell.collapsePanel(area);
362
+ } else if (area === 'bottom') {
363
+ // Don't collapse the bottom panel if it's currently split
364
+ if (this.shell.bottomAreaTabBars.length === 1) {
365
+ await this.shell.collapsePanel('bottom');
366
+ }
367
+ } else {
368
+ existing.dispose();
358
369
  }
370
+ return;
371
+ }
372
+ const widget = await this.openViewContainer(id);
373
+ if (widget) {
374
+ await this.shell.activateWidget(widget.id);
359
375
  }
360
376
  }
361
377
 
@@ -369,18 +385,22 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
369
385
  toDispose.push(Disposable.create(() => this.viewContainerClauseContexts.delete(id)));
370
386
  }
371
387
  }
372
- const toggleCommandId = `plugin.view-container.${id}.toggle`;
373
388
  // Some plugins may register empty view containers.
374
389
  // We should not register commands for them immediately, as that leads to bad UX.
375
390
  // Instead, we register commands the first time we add a view to them.
376
391
  let activate = () => {
392
+ // Like VS Code, use the container's id, e.g. `workbench.view.extension.${id}`, as the command id
377
393
  toDispose.push(this.commands.registerCommand({
378
- id: toggleCommandId,
394
+ id,
379
395
  category: nls.localizeByDefault('View'),
380
396
  label: nls.localizeByDefault('Toggle {0}', options.label)
381
397
  }, {
382
398
  execute: () => this.toggleViewContainer(id)
383
399
  }));
400
+ // Kept for backward compatibility with keybindings that use the former command id
401
+ toDispose.push(this.commands.registerCommand({ id: `plugin.view-container.${id}.toggle` }, {
402
+ execute: () => this.toggleViewContainer(id)
403
+ }));
384
404
  toDispose.push(this.registerViewMenuAction(id, options.label));
385
405
  toDispose.push(this.quickView?.registerItem({
386
406
  label: options.label,
@@ -486,7 +506,7 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
486
506
  }
487
507
  }
488
508
  const disposable = this.menus.registerMenuAction(CommonMenus.VIEW_VIEWS, {
489
- commandId: `plugin.view-container.${id}.toggle`,
509
+ commandId: id,
490
510
  label: menuLabel,
491
511
  when: containerInfo.when
492
512
  });
@@ -561,15 +581,24 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
561
581
  when: view.when,
562
582
  open: () => this.openView(view.id, { activate: true })
563
583
  }));
564
- toDispose.push(this.commands.registerCommand({ id: `${view.id}.focus` }, {
565
- execute: async () => { await this.openView(view.id, { activate: true }); }
584
+ toDispose.push(this.commands.registerCommand({
585
+ id: `${view.id}.focus`,
586
+ category: this.viewContainers.get(viewContainerId)?.options.label,
587
+ label: nls.localizeByDefault('Focus on {0} View', view.name)
588
+ }, {
589
+ execute: async (options?: { preserveFocus?: boolean }) => { await this.openView(view.id, this.toOpenViewOptions(options)); },
590
+ isVisible: () => this.isViewVisible(view.id)
566
591
  }));
567
592
  toDispose.push(this.commands.registerCommand({ id: `${view.id}.open` }, {
568
- execute: async () => { await this.openView(view.id, { activate: true }); }
593
+ execute: async (options?: { preserveFocus?: boolean }) => { await this.openView(view.id, this.toOpenViewOptions(options)); }
569
594
  }));
570
595
  return toDispose;
571
596
  }
572
597
 
598
+ protected toOpenViewOptions(options?: { preserveFocus?: boolean }): { activate?: boolean, reveal?: boolean } {
599
+ return options?.preserveFocus ? { reveal: true } : { activate: true };
600
+ }
601
+
573
602
  async resolveWebviewView(viewId: string, webview: WebviewView, cancellation: CancellationToken): Promise<void> {
574
603
  const resolver = this.webviewViewResolvers.get(viewId);
575
604
  if (resolver) {
@@ -652,14 +681,24 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
652
681
  }
653
682
  };
654
683
 
655
- const toDispose = this.onNewResolverRegistered(resolver => {
656
- if (resolver.viewType === viewId) {
657
- // Potentially re-activate if we have a new resolver
684
+ // Like VS Code, resolve a webview view only once it is visible: extensions start work in
685
+ // `resolveWebviewView`, and views that are hidden or never opened should not pay for it.
686
+ const resolveIfVisible = () => {
687
+ if (webview.isVisible) {
658
688
  webviewView.resolve();
659
689
  }
660
- });
690
+ };
691
+ const toDispose = new DisposableCollection(
692
+ this.onNewResolverRegistered(resolver => {
693
+ if (resolver.viewType === viewId) {
694
+ // Potentially re-activate if we have a new resolver
695
+ resolveIfVisible();
696
+ }
697
+ }),
698
+ webview.onDidChangeVisibility(resolveIfVisible)
699
+ );
661
700
 
662
- webviewView.resolve();
701
+ resolveIfVisible();
663
702
  return webviewView;
664
703
  }
665
704
 
@@ -758,7 +797,8 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
758
797
  const currentDataWidget = widget.widgets[0];
759
798
  const webviewId = currentDataWidget instanceof WebviewWidget ? currentDataWidget.identifier?.id : undefined;
760
799
  const viewDataWidget = await this.createViewDataWidget(view.id, webviewId);
761
- if (widget.isDisposed) {
800
+ // `onDidInitializeLayout` can dispose the data widget before it is added here.
801
+ if (widget.isDisposed || viewDataWidget?.isDisposed) {
762
802
  viewDataWidget?.dispose();
763
803
  return;
764
804
  }
@@ -1001,8 +1041,8 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
1001
1041
  }
1002
1042
 
1003
1043
  /**
1004
- * retrieve restored layout state from previous user session but close widgets
1005
- * widgets should be opened only when view data providers are registered
1044
+ * Retrieves the restored state of the data widgets and disposes them: a view gets a new data widget
1045
+ * once its data provider registers or, for a view with only welcome content, once it is expanded.
1006
1046
  */
1007
1047
  onDidInitializeLayout(): void {
1008
1048
  const widgets = this.widgetManager.getWidgets(PLUGIN_VIEW_DATA_FACTORY_ID);
@@ -1080,6 +1120,21 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
1080
1120
  return widget;
1081
1121
  }
1082
1122
 
1123
+ /**
1124
+ * Gives an expanded view that has `viewsWelcome` content but neither a data provider nor a
1125
+ * content widget its welcome widget, which `onDidInitializeLayout` disposes when it was restored.
1126
+ */
1127
+ protected async prepareWelcomeOnlyView(viewId: string): Promise<void> {
1128
+ if (this.views.get(viewId)?.[1]?.type === PluginViewType.Webview
1129
+ || this.viewDataProviders.has(viewId) || !this.getViewWelcomes(viewId).length) {
1130
+ return;
1131
+ }
1132
+ const view = await this.getView(viewId);
1133
+ if (view && !view.widgets.length) {
1134
+ await this.prepareView(view);
1135
+ }
1136
+ }
1137
+
1083
1138
  protected async createViewWelcomeWidget(viewId: string): Promise<TreeViewWidget> {
1084
1139
  const widget = await this.widgetManager.getOrCreateWidget<TreeViewWidget>(PLUGIN_VIEW_DATA_FACTORY_ID, { id: viewId });
1085
1140
  if (!widget.model.root) {
@@ -811,7 +811,7 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
811
811
  }
812
812
  const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS, actionMenuNode.icon, ACTION_ITEM, 'theia-tree-view-inline-action'].join(' ');
813
813
  const tabIndex = tabbable ? 0 : undefined;
814
- const titleString = actionMenuNode.label + (AcceleratorSource.is(actionMenuNode) ? actionMenuNode.getAccelerator(undefined).join('+') : '');
814
+ const titleString = actionMenuNode.label + (AcceleratorSource.is(actionMenuNode) ? actionMenuNode.getAccelerator(undefined, 'logical').join('+') : '');
815
815
 
816
816
  return <div key={index} className={className} title={titleString} tabIndex={tabIndex} onClick={e => {
817
817
  e.stopPropagation();
@@ -34,6 +34,23 @@
34
34
  (function () {
35
35
  'use strict';
36
36
 
37
+ /**
38
+ * @param {KeyboardEvent} event
39
+ */
40
+ const toNormalizedKeyboardInput = event => ({
41
+ key: event.key,
42
+ keyCode: event.keyCode,
43
+ code: event.code,
44
+ shiftKey: event.shiftKey,
45
+ altKey: event.altKey,
46
+ ctrlKey: event.ctrlKey,
47
+ metaKey: event.metaKey,
48
+ altGraph: event.getModifierState('AltGraph'),
49
+ repeat: event.repeat,
50
+ isComposing: event.isComposing,
51
+ location: event.location
52
+ });
53
+
37
54
  /**
38
55
  * Use polling to track focus of main webview and iframes within the webview
39
56
  *
@@ -300,16 +317,7 @@ window.frameElement = null;
300
317
  const handleInnerKeydown = (e) => {
301
318
  preventDefaultBrowserHotkeys(e);
302
319
 
303
- host.postMessage('did-keydown', {
304
- key: e.key,
305
- keyCode: e.keyCode,
306
- code: e.code,
307
- shiftKey: e.shiftKey,
308
- altKey: e.altKey,
309
- ctrlKey: e.ctrlKey,
310
- metaKey: e.metaKey,
311
- repeat: e.repeat
312
- });
320
+ host.postMessage('did-keydown', toNormalizedKeyboardInput(e));
313
321
  };
314
322
 
315
323
  /**
@@ -678,6 +686,7 @@ window.frameElement = null;
678
686
 
679
687
  if (typeof module !== 'undefined') {
680
688
  module.exports = createWebviewManager;
689
+ module.exports.toNormalizedKeyboardInput = toNormalizedKeyboardInput;
681
690
  } else {
682
691
  window.createWebviewManager = createWebviewManager;
683
692
  }
@@ -0,0 +1,46 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2026 EclipseSource and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // https://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
9
+ // *****************************************************************************
10
+
11
+ import { expect } from 'chai';
12
+
13
+ const { toNormalizedKeyboardInput } = require('../../../../../src/main/browser/webview/pre/main.js');
14
+
15
+ describe('webview keyboard transport', () => {
16
+ it('serializes explicit AltGraph and normalized keyboard fields', () => {
17
+ const input = toNormalizedKeyboardInput({
18
+ key: '[',
19
+ keyCode: 56,
20
+ code: 'Digit8',
21
+ shiftKey: false,
22
+ altKey: false,
23
+ ctrlKey: true,
24
+ metaKey: false,
25
+ repeat: true,
26
+ isComposing: false,
27
+ location: 2,
28
+ getModifierState: (modifier: string) => modifier === 'AltGraph'
29
+ });
30
+
31
+ expect(input).to.deep.equal({
32
+ key: '[',
33
+ keyCode: 56,
34
+ code: 'Digit8',
35
+ shiftKey: false,
36
+ altKey: false,
37
+ ctrlKey: true,
38
+ metaKey: false,
39
+ altGraph: true,
40
+ repeat: true,
41
+ isComposing: false,
42
+ location: 2
43
+ });
44
+ expect(input).not.to.have.property('getModifierState');
45
+ });
46
+ });
@@ -54,6 +54,7 @@ import { ContextMenuRenderer } from '@theia/core/lib/browser';
54
54
  import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
55
55
  import { PluginViewWidget } from '../view/plugin-view-widget';
56
56
  import { WebviewPreferences } from '../../common/webview-preferences';
57
+ import { NormalizedKeyboardInput } from '@theia/core/lib/browser/keyboard/keys';
57
58
 
58
59
  // Style from core
59
60
  const TRANSPARENT_OVERLAY_STYLE = 'theia-transparent-overlay';
@@ -325,11 +326,14 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
325
326
  this.toHide.push(this.on(WebviewMessageChannels.loadLocalhost, (entry: any) =>
326
327
  this.loadLocalhost(entry.origin)
327
328
  ));
328
- this.toHide.push(this.on(WebviewMessageChannels.didKeydown, (data: KeyboardEvent) => {
329
+ this.toHide.push(this.on(WebviewMessageChannels.didKeydown, (data: NormalizedKeyboardInput) => {
329
330
  // Electron: workaround for https://github.com/electron/electron/issues/14258
330
331
  // We have to detect keyboard events in the <webview> and dispatch them to our
331
332
  // keybinding service because these events do not bubble to the parent window anymore.
332
- this.keybindings.dispatchKeyDown(data, this.element);
333
+ this.keybindings.dispatchNormalizedKeyDown(data, this.element);
334
+ // DOM capture listeners must still observe the emulated event. Mark it as already handled so the registry's
335
+ // capture listener does not execute the keybinding a second time.
336
+ this.keybindings.dispatchKeyDown(data, this.element, true);
333
337
  }));
334
338
  this.toHide.push(this.on(WebviewMessageChannels.didMouseDown, (data: MouseEvent) => {
335
339
  // We have to dispatch mousedown events so menus will be closed when clicking inside webviews.
@@ -415,7 +419,7 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
415
419
  }
416
420
 
417
421
  setContentOptions(contentOptions: WebviewContentOptions): void {
418
- if (JSONExt.deepEqual(<any>this.contentOptions, <any>contentOptions)) {
422
+ if (JSONExt.deepEqual(this.contentOptions as any, contentOptions as any)) {
419
423
  return;
420
424
  }
421
425
  this._contentOptions = contentOptions;
@@ -15,7 +15,7 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import * as path from 'path';
18
- import * as filenamify from 'filenamify';
18
+ import filenamify from 'filenamify';
19
19
  import * as fs from '@theia/core/shared/fs-extra';
20
20
  import { URI, ILogger } from '@theia/core';
21
21
  import { inject, injectable, named } from '@theia/core/shared/inversify';