@theia/core 1.77.0-next.49 → 1.77.0-next.57

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 (377) hide show
  1. package/lib/browser/breadcrumbs/breadcrumbs-renderer.js +1 -1
  2. package/lib/browser/breadcrumbs/breadcrumbs-renderer.js.map +1 -1
  3. package/lib/browser/catalog.json +81 -0
  4. package/lib/browser/color-application-contribution.d.ts +1 -1
  5. package/lib/browser/color-application-contribution.d.ts.map +1 -1
  6. package/lib/browser/color-registry.d.ts +1 -1
  7. package/lib/browser/color-registry.d.ts.map +1 -1
  8. package/lib/browser/common-frontend-contribution.d.ts +6 -1
  9. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  10. package/lib/browser/common-frontend-contribution.js +20 -3
  11. package/lib/browser/common-frontend-contribution.js.map +1 -1
  12. package/lib/browser/common-frontend-contribution.spec.js +2 -1
  13. package/lib/browser/common-frontend-contribution.spec.js.map +1 -1
  14. package/lib/browser/components/card.d.ts +1 -1
  15. package/lib/browser/components/card.d.ts.map +1 -1
  16. package/lib/browser/components/card.js +3 -2
  17. package/lib/browser/components/card.js.map +1 -1
  18. package/lib/browser/connection-status-service.spec.js +2 -1
  19. package/lib/browser/connection-status-service.spec.js.map +1 -1
  20. package/lib/browser/context-key-service.d.ts +11 -0
  21. package/lib/browser/context-key-service.d.ts.map +1 -1
  22. package/lib/browser/context-key-service.js +7 -0
  23. package/lib/browser/context-key-service.js.map +1 -1
  24. package/lib/browser/decorations-service.spec.js +2 -1
  25. package/lib/browser/decorations-service.spec.js.map +1 -1
  26. package/lib/browser/dialogs/react-dialog.spec.js +2 -1
  27. package/lib/browser/dialogs/react-dialog.spec.js.map +1 -1
  28. package/lib/browser/diff-uris.js +1 -1
  29. package/lib/browser/diff-uris.js.map +1 -1
  30. package/lib/browser/endpoint.js +2 -1
  31. package/lib/browser/endpoint.js.map +1 -1
  32. package/lib/browser/endpoint.spec.js +2 -1
  33. package/lib/browser/endpoint.spec.js.map +1 -1
  34. package/lib/browser/keybinding.d.ts +95 -17
  35. package/lib/browser/keybinding.d.ts.map +1 -1
  36. package/lib/browser/keybinding.js +406 -76
  37. package/lib/browser/keybinding.js.map +1 -1
  38. package/lib/browser/keybinding.spec.js +789 -33
  39. package/lib/browser/keybinding.spec.js.map +1 -1
  40. package/lib/browser/keyboard/browser-keyboard-frontend-contribution.js +1 -1
  41. package/lib/browser/keyboard/browser-keyboard-frontend-contribution.js.map +1 -1
  42. package/lib/browser/keyboard/browser-keyboard-layout-provider.d.ts +3 -4
  43. package/lib/browser/keyboard/browser-keyboard-layout-provider.d.ts.map +1 -1
  44. package/lib/browser/keyboard/browser-keyboard-layout-provider.js +3 -3
  45. package/lib/browser/keyboard/browser-keyboard-layout-provider.js.map +1 -1
  46. package/lib/browser/keyboard/browser-keyboard-layout-provider.spec.js +42 -3
  47. package/lib/browser/keyboard/browser-keyboard-layout-provider.spec.js.map +1 -1
  48. package/lib/browser/keyboard/keyboard-layout-service.d.ts +67 -15
  49. package/lib/browser/keyboard/keyboard-layout-service.d.ts.map +1 -1
  50. package/lib/browser/keyboard/keyboard-layout-service.js +309 -98
  51. package/lib/browser/keyboard/keyboard-layout-service.js.map +1 -1
  52. package/lib/browser/keyboard/keyboard-layout-service.spec.js +541 -15
  53. package/lib/browser/keyboard/keyboard-layout-service.spec.js.map +1 -1
  54. package/lib/browser/keyboard/keys.spec.js +187 -3
  55. package/lib/browser/keyboard/keys.spec.js.map +1 -1
  56. package/lib/browser/label-provider.d.ts.map +1 -1
  57. package/lib/browser/label-provider.js +5 -3
  58. package/lib/browser/label-provider.js.map +1 -1
  59. package/lib/browser/label-provider.spec.js +2 -1
  60. package/lib/browser/label-provider.spec.js.map +1 -1
  61. package/lib/browser/markdown-rendering/markdown-link-handler.js +2 -1
  62. package/lib/browser/markdown-rendering/markdown-link-handler.js.map +1 -1
  63. package/lib/browser/markdown-rendering/markdown-renderer.d.ts +1 -1
  64. package/lib/browser/markdown-rendering/markdown-renderer.d.ts.map +1 -1
  65. package/lib/browser/markdown-rendering/markdown-renderer.js +4 -4
  66. package/lib/browser/markdown-rendering/markdown-renderer.js.map +1 -1
  67. package/lib/browser/markdown-rendering/markdown.js +2 -1
  68. package/lib/browser/markdown-rendering/markdown.js.map +1 -1
  69. package/lib/browser/markdown-rendering/markdown.spec.js +2 -1
  70. package/lib/browser/markdown-rendering/markdown.spec.js.map +1 -1
  71. package/lib/browser/menu/action-menu-node.d.ts +5 -3
  72. package/lib/browser/menu/action-menu-node.d.ts.map +1 -1
  73. package/lib/browser/menu/action-menu-node.js +2 -11
  74. package/lib/browser/menu/action-menu-node.js.map +1 -1
  75. package/lib/browser/menu/action-menu-node.spec.d.ts +2 -0
  76. package/lib/browser/menu/action-menu-node.spec.d.ts.map +1 -0
  77. package/lib/browser/menu/action-menu-node.spec.js +54 -0
  78. package/lib/browser/menu/action-menu-node.spec.js.map +1 -0
  79. package/lib/browser/menu/browser-menu-plugin.js +1 -1
  80. package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
  81. package/lib/browser/menu/menu.spec.js +2 -1
  82. package/lib/browser/menu/menu.spec.js.map +1 -1
  83. package/lib/browser/opener-service.spec.js +3 -2
  84. package/lib/browser/opener-service.spec.js.map +1 -1
  85. package/lib/browser/perspective-service.spec.js +2 -1
  86. package/lib/browser/perspective-service.spec.js.map +1 -1
  87. package/lib/browser/preferences/preference-proxy.spec.js +2 -1
  88. package/lib/browser/preferences/preference-proxy.spec.js.map +1 -1
  89. package/lib/browser/preferences/preference-schema-provider.spec.js +2 -1
  90. package/lib/browser/preferences/preference-schema-provider.spec.js.map +1 -1
  91. package/lib/browser/preferences/preference-service.spec.js +2 -1
  92. package/lib/browser/preferences/preference-service.spec.js.map +1 -1
  93. package/lib/browser/preferences/preference-validation-service.spec.js +78 -77
  94. package/lib/browser/preferences/preference-validation-service.spec.js.map +1 -1
  95. package/lib/browser/quick-input/quick-command-service.d.ts +10 -1
  96. package/lib/browser/quick-input/quick-command-service.d.ts.map +1 -1
  97. package/lib/browser/quick-input/quick-command-service.js +31 -6
  98. package/lib/browser/quick-input/quick-command-service.js.map +1 -1
  99. package/lib/browser/quick-input/quick-command-service.spec.d.ts +2 -0
  100. package/lib/browser/quick-input/quick-command-service.spec.d.ts.map +1 -0
  101. package/lib/browser/quick-input/quick-command-service.spec.js +130 -0
  102. package/lib/browser/quick-input/quick-command-service.spec.js.map +1 -0
  103. package/lib/browser/quick-input/quick-help-service.js +1 -1
  104. package/lib/browser/quick-input/quick-help-service.js.map +1 -1
  105. package/lib/browser/quick-input/quick-input-service.spec.js +2 -1
  106. package/lib/browser/quick-input/quick-input-service.spec.js.map +1 -1
  107. package/lib/browser/quick-input/quick-pick-service-impl.d.ts +6 -6
  108. package/lib/browser/quick-input/quick-pick-service-impl.d.ts.map +1 -1
  109. package/lib/browser/quick-input/quick-view-service.spec.js +2 -1
  110. package/lib/browser/quick-input/quick-view-service.spec.js.map +1 -1
  111. package/lib/browser/secondary-window-handler.d.ts +4 -4
  112. package/lib/browser/secondary-window-handler.d.ts.map +1 -1
  113. package/lib/browser/shell/application-shell.js +1 -1
  114. package/lib/browser/shell/application-shell.js.map +1 -1
  115. package/lib/browser/shell/application-shell.spec.js +2 -1
  116. package/lib/browser/shell/application-shell.spec.js.map +1 -1
  117. package/lib/browser/shell/shell-layout-restorer.spec.js +2 -1
  118. package/lib/browser/shell/shell-layout-restorer.spec.js.map +1 -1
  119. package/lib/browser/shell/side-panel-toolbar.d.ts +1 -1
  120. package/lib/browser/shell/side-panel-toolbar.d.ts.map +1 -1
  121. package/lib/browser/shell/sidebar-menu-widget.js +1 -1
  122. package/lib/browser/shell/sidebar-menu-widget.js.map +1 -1
  123. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +1 -1
  124. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
  125. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js +2 -1
  126. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js.map +1 -1
  127. package/lib/browser/shell/tab-bars.js +2 -1
  128. package/lib/browser/shell/tab-bars.js.map +1 -1
  129. package/lib/browser/status-bar/status-bar.js +1 -1
  130. package/lib/browser/status-bar/status-bar.js.map +1 -1
  131. package/lib/browser/storage-service.spec.js +2 -1
  132. package/lib/browser/storage-service.spec.js.map +1 -1
  133. package/lib/browser/test/jsdom.d.ts.map +1 -1
  134. package/lib/browser/test/jsdom.js +11 -0
  135. package/lib/browser/test/jsdom.js.map +1 -1
  136. package/lib/browser/tooltip-service.js +1 -1
  137. package/lib/browser/tooltip-service.js.map +1 -1
  138. package/lib/browser/tree/tree-consistency.spec.js +1 -1
  139. package/lib/browser/tree/tree-consistency.spec.js.map +1 -1
  140. package/lib/browser/tree/tree-container.spec.js +6 -5
  141. package/lib/browser/tree/tree-container.spec.js.map +1 -1
  142. package/lib/browser/tree/tree-iterator.js +1 -1
  143. package/lib/browser/tree/tree-iterator.js.map +1 -1
  144. package/lib/browser/tree/tree-model.js +2 -2
  145. package/lib/browser/tree/tree-model.js.map +1 -1
  146. package/lib/browser/tree/tree-view-welcome-widget.js +1 -1
  147. package/lib/browser/tree/tree-view-welcome-widget.js.map +1 -1
  148. package/lib/browser/tree/tree-widget.d.ts +2 -2
  149. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  150. package/lib/browser/tree/tree-widget.js +1 -1
  151. package/lib/browser/tree/tree-widget.js.map +1 -1
  152. package/lib/browser/tree/tree.spec.js +2 -1
  153. package/lib/browser/tree/tree.spec.js.map +1 -1
  154. package/lib/browser/user-working-directory-provider.js +1 -1
  155. package/lib/browser/user-working-directory-provider.js.map +1 -1
  156. package/lib/browser/widgets/react-renderer.js +1 -1
  157. package/lib/browser/widgets/react-renderer.js.map +1 -1
  158. package/lib/browser/widgets/react-widget.js +1 -1
  159. package/lib/browser/widgets/react-widget.js.map +1 -1
  160. package/lib/browser/widgets/select-component.js +4 -3
  161. package/lib/browser/widgets/select-component.js.map +1 -1
  162. package/lib/browser/widgets/select-component.spec.js +3 -2
  163. package/lib/browser/widgets/select-component.spec.js.map +1 -1
  164. package/lib/browser/widgets/widget.js +1 -1
  165. package/lib/browser/widgets/widget.js.map +1 -1
  166. package/lib/common/buffer.js +3 -2
  167. package/lib/common/buffer.js.map +1 -1
  168. package/lib/common/cancellation.js.map +1 -1
  169. package/lib/common/command.spec.js +2 -1
  170. package/lib/common/command.spec.js.map +1 -1
  171. package/lib/common/disposable.spec.js +3 -2
  172. package/lib/common/disposable.spec.js.map +1 -1
  173. package/lib/common/encoding-service.js +2 -2
  174. package/lib/common/encoding-service.js.map +1 -1
  175. package/lib/common/event.d.ts +1 -1
  176. package/lib/common/event.d.ts.map +1 -1
  177. package/lib/common/event.js +0 -1
  178. package/lib/common/event.js.map +1 -1
  179. package/lib/common/file-uri.js +2 -1
  180. package/lib/common/file-uri.js.map +1 -1
  181. package/lib/common/fuzzy-search.js +1 -1
  182. package/lib/common/fuzzy-search.js.map +1 -1
  183. package/lib/common/glob.d.ts.map +1 -1
  184. package/lib/common/glob.js +9 -15
  185. package/lib/common/glob.js.map +1 -1
  186. package/lib/common/index.js +1 -1
  187. package/lib/common/index.js.map +1 -1
  188. package/lib/common/keyboard/keyboard-layout-provider.d.ts +7 -0
  189. package/lib/common/keyboard/keyboard-layout-provider.d.ts.map +1 -1
  190. package/lib/common/keyboard/keyboard-layout-provider.js.map +1 -1
  191. package/lib/common/keys.d.ts +86 -3
  192. package/lib/common/keys.d.ts.map +1 -1
  193. package/lib/common/keys.js +263 -24
  194. package/lib/common/keys.js.map +1 -1
  195. package/lib/common/message-rpc/channel.spec.js +3 -2
  196. package/lib/common/message-rpc/channel.spec.js.map +1 -1
  197. package/lib/common/messaging/proxy-factory.js +2 -2
  198. package/lib/common/messaging/proxy-factory.js.map +1 -1
  199. package/lib/common/messaging/proxy-factory.spec.js +2 -1
  200. package/lib/common/messaging/proxy-factory.spec.js.map +1 -1
  201. package/lib/common/messaging/web-socket-channel.d.ts +1 -1
  202. package/lib/common/messaging/web-socket-channel.d.ts.map +1 -1
  203. package/lib/common/path.spec.js +2 -1
  204. package/lib/common/path.spec.js.map +1 -1
  205. package/lib/common/performance/stopwatch.spec.js +2 -1
  206. package/lib/common/performance/stopwatch.spec.js.map +1 -1
  207. package/lib/common/preferences/preference-schema-service.d.ts +2 -2
  208. package/lib/common/preferences/preference-schema-service.d.ts.map +1 -1
  209. package/lib/common/preferences/preference-service.js +1 -1
  210. package/lib/common/preferences/preference-service.js.map +1 -1
  211. package/lib/common/promise-util.spec.js +2 -1
  212. package/lib/common/promise-util.spec.js.map +1 -1
  213. package/lib/common/quick-pick-service.d.ts +5 -0
  214. package/lib/common/quick-pick-service.d.ts.map +1 -1
  215. package/lib/common/quick-pick-service.js +2 -1
  216. package/lib/common/quick-pick-service.js.map +1 -1
  217. package/lib/common/reference.spec.js +2 -1
  218. package/lib/common/reference.spec.js.map +1 -1
  219. package/lib/common/resource.js +1 -1
  220. package/lib/common/resource.js.map +1 -1
  221. package/lib/common/selection-service.spec.js +2 -1
  222. package/lib/common/selection-service.spec.js.map +1 -1
  223. package/lib/common/selection.js +2 -1
  224. package/lib/common/selection.js.map +1 -1
  225. package/lib/common/stream.d.ts.map +1 -1
  226. package/lib/common/stream.js +2 -1
  227. package/lib/common/stream.js.map +1 -1
  228. package/lib/common/strings.d.ts.map +1 -1
  229. package/lib/common/strings.js +1 -2
  230. package/lib/common/strings.js.map +1 -1
  231. package/lib/common/ternary-search-tree.js +2 -2
  232. package/lib/common/ternary-search-tree.js.map +1 -1
  233. package/lib/common/ternary-search-tree.spec.js +12 -0
  234. package/lib/common/ternary-search-tree.spec.js.map +1 -1
  235. package/lib/common/test/mock-resource-provider.js +1 -1
  236. package/lib/common/test/mock-resource-provider.js.map +1 -1
  237. package/lib/common/types.spec.js +2 -1
  238. package/lib/common/types.spec.js.map +1 -1
  239. package/lib/common/uri-command-handler.js +4 -3
  240. package/lib/common/uri-command-handler.js.map +1 -1
  241. package/lib/common/uri-command-handler.spec.js +3 -2
  242. package/lib/common/uri-command-handler.spec.js.map +1 -1
  243. package/lib/common/uri.spec.js +3 -2
  244. package/lib/common/uri.spec.js.map +1 -1
  245. package/lib/electron-browser/keyboard/electron-keyboard-module.d.ts +2 -0
  246. package/lib/electron-browser/keyboard/electron-keyboard-module.d.ts.map +1 -1
  247. package/lib/electron-browser/keyboard/electron-keyboard-module.js +8 -1
  248. package/lib/electron-browser/keyboard/electron-keyboard-module.js.map +1 -1
  249. package/lib/electron-browser/keyboard/electron-keyboard-module.spec.d.ts +2 -0
  250. package/lib/electron-browser/keyboard/electron-keyboard-module.spec.d.ts.map +1 -0
  251. package/lib/electron-browser/keyboard/electron-keyboard-module.spec.js +28 -0
  252. package/lib/electron-browser/keyboard/electron-keyboard-module.spec.js.map +1 -0
  253. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  254. package/lib/electron-browser/menu/electron-main-menu-factory.js +3 -2
  255. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  256. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  257. package/lib/electron-browser/menu/electron-menu-contribution.js +3 -0
  258. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  259. package/lib/electron-browser/window/window-zoom-action-bar.js +2 -1
  260. package/lib/electron-browser/window/window-zoom-action-bar.js.map +1 -1
  261. package/lib/electron-common/electron-api.d.ts +5 -0
  262. package/lib/electron-common/electron-api.d.ts.map +1 -1
  263. package/lib/electron-common/electron-api.js +21 -0
  264. package/lib/electron-common/electron-api.js.map +1 -1
  265. package/lib/electron-common/electron-api.spec.d.ts +2 -0
  266. package/lib/electron-common/electron-api.spec.d.ts.map +1 -0
  267. package/lib/electron-common/electron-api.spec.js +40 -0
  268. package/lib/electron-common/electron-api.spec.js.map +1 -0
  269. package/lib/electron-main/electron-api-main.d.ts +0 -1
  270. package/lib/electron-main/electron-api-main.d.ts.map +1 -1
  271. package/lib/electron-main/electron-api-main.js +3 -14
  272. package/lib/electron-main/electron-api-main.js.map +1 -1
  273. package/lib/electron-main/electron-main-application.js +2 -2
  274. package/lib/electron-main/electron-main-application.js.map +1 -1
  275. package/lib/electron-node/hosting/electron-backend-hosting-module.spec.js +2 -1
  276. package/lib/electron-node/hosting/electron-backend-hosting-module.spec.js.map +1 -1
  277. package/lib/electron-node/keyboard/electron-keyboard-layout-provider.js +1 -1
  278. package/lib/electron-node/keyboard/electron-keyboard-layout-provider.js.map +1 -1
  279. package/lib/electron-node/token/electron-token-validator.js +2 -2
  280. package/lib/electron-node/token/electron-token-validator.js.map +1 -1
  281. package/lib/node/backend-application.d.ts +1 -1
  282. package/lib/node/backend-application.d.ts.map +1 -1
  283. package/lib/node/backend-application.js +7 -7
  284. package/lib/node/backend-application.js.map +1 -1
  285. package/lib/node/backend-application.spec.js +1 -1
  286. package/lib/node/backend-application.spec.js.map +1 -1
  287. package/lib/node/bundled-resource-provider.js +4 -4
  288. package/lib/node/bundled-resource-provider.js.map +1 -1
  289. package/lib/node/bundled-resource-provider.spec.js +5 -4
  290. package/lib/node/bundled-resource-provider.spec.js.map +1 -1
  291. package/lib/node/cli.d.ts +1 -1
  292. package/lib/node/cli.d.ts.map +1 -1
  293. package/lib/node/cli.js +2 -2
  294. package/lib/node/cli.js.map +1 -1
  295. package/lib/node/cli.spec.js +3 -2
  296. package/lib/node/cli.spec.js.map +1 -1
  297. package/lib/node/console-logger-server.js +1 -1
  298. package/lib/node/console-logger-server.js.map +1 -1
  299. package/lib/node/env-variables/env-variables-server.js +1 -1
  300. package/lib/node/env-variables/env-variables-server.js.map +1 -1
  301. package/lib/node/environment-utils.spec.js +2 -1
  302. package/lib/node/environment-utils.spec.js.map +1 -1
  303. package/lib/node/file-uri.spec.js +4 -3
  304. package/lib/node/file-uri.spec.js.map +1 -1
  305. package/lib/node/filesystem-locking.js +1 -1
  306. package/lib/node/filesystem-locking.js.map +1 -1
  307. package/lib/node/hosting/browser-connection-token.js +2 -2
  308. package/lib/node/hosting/browser-connection-token.js.map +1 -1
  309. package/lib/node/i18n/localization-contribution.js +1 -1
  310. package/lib/node/i18n/localization-contribution.js.map +1 -1
  311. package/lib/node/key-store-server.js +1 -1
  312. package/lib/node/key-store-server.js.map +1 -1
  313. package/lib/node/logger-cli-contribution.js +2 -2
  314. package/lib/node/logger-cli-contribution.js.map +1 -1
  315. package/lib/node/logger-cli-contribution.spec.js +17 -16
  316. package/lib/node/logger-cli-contribution.spec.js.map +1 -1
  317. package/lib/node/messaging/ipc-connection-provider.js +2 -2
  318. package/lib/node/messaging/ipc-connection-provider.js.map +1 -1
  319. package/lib/node/process-utils.js +1 -1
  320. package/lib/node/process-utils.js.map +1 -1
  321. package/lib/node/process-utils.spec.js +2 -1
  322. package/lib/node/process-utils.spec.js.map +1 -1
  323. package/lib/node/request/backend-request-facade.spec.js +2 -1
  324. package/lib/node/request/backend-request-facade.spec.js.map +1 -1
  325. package/lib/node/setting-service.spec.js +2 -1
  326. package/lib/node/setting-service.spec.js.map +1 -1
  327. package/package.json +4 -4
  328. package/src/browser/common-frontend-contribution.ts +17 -1
  329. package/src/browser/components/card.tsx +1 -1
  330. package/src/browser/context-key-service.ts +15 -0
  331. package/src/browser/keybinding.spec.ts +878 -34
  332. package/src/browser/keybinding.ts +470 -85
  333. package/src/browser/keyboard/browser-keyboard-frontend-contribution.ts +1 -1
  334. package/src/browser/keyboard/browser-keyboard-layout-provider.spec.ts +52 -1
  335. package/src/browser/keyboard/browser-keyboard-layout-provider.ts +5 -5
  336. package/src/browser/keyboard/keyboard-layout-service.spec.ts +640 -15
  337. package/src/browser/keyboard/keyboard-layout-service.ts +358 -106
  338. package/src/browser/keyboard/keys.spec.ts +206 -1
  339. package/src/browser/label-provider.ts +3 -1
  340. package/src/browser/markdown-rendering/markdown-renderer.ts +1 -1
  341. package/src/browser/menu/action-menu-node.spec.ts +60 -0
  342. package/src/browser/menu/action-menu-node.ts +8 -14
  343. package/src/browser/menu/browser-menu-plugin.ts +1 -1
  344. package/src/browser/preferences/preference-validation-service.spec.ts +1 -1
  345. package/src/browser/quick-input/quick-command-service.spec.ts +159 -0
  346. package/src/browser/quick-input/quick-command-service.ts +36 -9
  347. package/src/browser/quick-input/quick-help-service.ts +1 -1
  348. package/src/browser/test/jsdom.ts +11 -0
  349. package/src/browser/tree/tree-container.spec.ts +1 -1
  350. package/src/browser/tree/tree-iterator.ts +1 -1
  351. package/src/browser/tree/tree-model.ts +2 -2
  352. package/src/browser/tree/tree-widget.tsx +2 -2
  353. package/src/common/cancellation.ts +1 -1
  354. package/src/common/disposable.spec.ts +1 -1
  355. package/src/common/event.ts +1 -2
  356. package/src/common/glob.ts +13 -30
  357. package/src/common/json-schema.ts +1 -1
  358. package/src/common/keyboard/keyboard-layout-provider.ts +8 -0
  359. package/src/common/keys.ts +312 -27
  360. package/src/common/message-rpc/channel.spec.ts +1 -1
  361. package/src/common/messaging/proxy-factory.ts +2 -2
  362. package/src/common/quick-pick-service.ts +5 -0
  363. package/src/common/stream.ts +4 -3
  364. package/src/common/strings.ts +2 -5
  365. package/src/common/ternary-search-tree.spec.ts +14 -0
  366. package/src/common/ternary-search-tree.ts +3 -3
  367. package/src/common/uri-command-handler.ts +2 -2
  368. package/src/electron-browser/keyboard/electron-keyboard-module.spec.ts +29 -0
  369. package/src/electron-browser/keyboard/electron-keyboard-module.ts +9 -2
  370. package/src/electron-browser/menu/electron-main-menu-factory.ts +3 -3
  371. package/src/electron-browser/menu/electron-menu-contribution.ts +4 -0
  372. package/src/electron-common/electron-api.spec.ts +42 -0
  373. package/src/electron-common/electron-api.ts +23 -0
  374. package/src/electron-main/electron-api-main.ts +2 -13
  375. package/src/node/backend-application.ts +1 -1
  376. package/src/node/cli.ts +1 -1
  377. package/src/node/logger-cli-contribution.spec.ts +1 -1
@@ -17,7 +17,7 @@
17
17
  import { enableJSDOM } from '../../browser/test/jsdom';
18
18
  let disableJSDOM = enableJSDOM();
19
19
 
20
- import { KeyCode, Key, KeyModifier, KeySequence } from './keys';
20
+ import { KeyCode, Key, KeyModifier, KeySequence, NormalizedKeyboardInput, normalizeKeyboardInput, readAltGraph } from './keys';
21
21
  import * as os from '../../common/os';
22
22
  import * as chai from 'chai';
23
23
  import * as sinon from 'sinon';
@@ -117,6 +117,139 @@ describe('keys api', () => {
117
117
  expect(equalKeyCode(parsedKeyCode, keyCode)).to.be.true;
118
118
  });
119
119
 
120
+ it('should keep dispatch strings equivalent to serialized strings', () => {
121
+ const keyCodes = [
122
+ ...Array.from({ length: 16 }, (_, modifiers) => new KeyCode({
123
+ key: Key.KEY_A,
124
+ ctrl: !!(modifiers & 1),
125
+ shift: !!(modifiers & 2),
126
+ alt: !!(modifiers & 4),
127
+ meta: !!(modifiers & 8)
128
+ })),
129
+ new KeyCode({}),
130
+ KeyCode.parse('ctrl+['),
131
+ KeyCode.parse('shift+/'),
132
+ ...KeySequence.parse('ctrlcmd+k ctrlcmd+c')
133
+ ];
134
+ for (const keyCode of keyCodes) {
135
+ expect(keyCode.dispatchString()).to.equal(keyCode.toString());
136
+ }
137
+ });
138
+
139
+ it('should distinguish layout modifiers in dispatch identity without changing serialization', () => {
140
+ const command = new KeyCode({ key: Key.DIGIT8, ctrl: true, alt: true });
141
+ const layout = new KeyCode({ key: Key.DIGIT8, ctrl: true, layoutModifiers: 'altGraph', character: '[' });
142
+ const shiftedLayout = new KeyCode({ key: Key.SLASH, layoutModifiers: 'shift', character: '/' });
143
+
144
+ expect(command.toString()).to.equal('alt+ctrl+8');
145
+ expect(layout.toString()).to.equal('ctrl+8');
146
+ expect(layout.dispatchString()).to.equal('ctrl+8@altgraph');
147
+ expect(shiftedLayout.toString()).to.equal('/');
148
+ expect(shiftedLayout.dispatchString()).to.equal('/@shift');
149
+ expect(command.equals(layout)).to.be.false;
150
+ });
151
+
152
+ it('should keep equality and dispatch identity equivalent for layout modifiers', () => {
153
+ const layers = ['none', 'shift', 'altGraph', 'shiftAltGraph'] as const;
154
+ const keyCodes = Array.from({ length: 64 }, (_, modifiers) => new KeyCode({
155
+ key: Key.KEY_A,
156
+ ctrl: !!(modifiers & 1),
157
+ shift: !!(modifiers & 2),
158
+ alt: !!(modifiers & 4),
159
+ meta: !!(modifiers & 8),
160
+ layoutModifiers: layers[modifiers >> 4]
161
+ }));
162
+ for (const left of keyCodes) {
163
+ for (const right of keyCodes) {
164
+ expect(left.equals(right)).to.equal(left.dispatchString() === right.dispatchString());
165
+ }
166
+ }
167
+ });
168
+
169
+ it('should keep interpretation provenance outside dispatch identity', () => {
170
+ const command = new KeyCode({ key: Key.DIGIT8, ctrl: true, interpretation: 'commandModifiers' });
171
+ const layout = new KeyCode({ key: Key.DIGIT8, ctrl: true, interpretation: 'layoutModifiers' });
172
+
173
+ expect(command.dispatchString()).to.equal(layout.dispatchString());
174
+ expect(command.equals(layout)).to.be.true;
175
+ expect(command.interpretation).to.equal('commandModifiers');
176
+ expect(layout.interpretation).to.equal('layoutModifiers');
177
+ });
178
+
179
+ it('should normalize explicit and native AltGraph state', () => {
180
+ expect(readAltGraph({ altGraph: false, getModifierState: () => true })).to.be.false;
181
+ expect(readAltGraph({ getModifierState: modifier => modifier === 'AltGraph' })).to.be.true;
182
+ expect(readAltGraph({ code: 'Digit8' })).to.be.false;
183
+
184
+ expect(normalizeKeyboardInput({
185
+ key: '[',
186
+ code: 'Digit8',
187
+ keyCode: 56,
188
+ ctrlKey: true,
189
+ altGraph: true,
190
+ location: 0
191
+ })).to.deep.equal({
192
+ key: '[',
193
+ code: 'Digit8',
194
+ keyCode: 56,
195
+ charCode: undefined,
196
+ ctrlKey: true,
197
+ shiftKey: undefined,
198
+ altKey: undefined,
199
+ metaKey: undefined,
200
+ altGraph: true,
201
+ repeat: undefined,
202
+ isComposing: undefined,
203
+ location: 0,
204
+ timeStamp: undefined,
205
+ keyIdentifier: undefined,
206
+ getModifierState: undefined
207
+ });
208
+ });
209
+
210
+ it('should preserve every normalized keyboard input field', () => {
211
+ const getModifierState = (modifier: string) => modifier === 'AltGraph';
212
+ const input: Required<NormalizedKeyboardInput> = {
213
+ key: '[',
214
+ code: 'Digit8',
215
+ keyCode: 56,
216
+ charCode: 91,
217
+ ctrlKey: true,
218
+ shiftKey: true,
219
+ altKey: false,
220
+ metaKey: true,
221
+ altGraph: true,
222
+ repeat: true,
223
+ isComposing: false,
224
+ location: 2,
225
+ timeStamp: 42,
226
+ keyIdentifier: 'U+005B',
227
+ getModifierState
228
+ };
229
+
230
+ const normalized = normalizeKeyboardInput(input);
231
+
232
+ expect({ ...normalized, getModifierState: undefined }).to.deep.equal({ ...input, getModifierState: undefined });
233
+ expect(normalized.getModifierState?.('AltGraph')).to.be.true;
234
+ });
235
+
236
+ it('should create key codes from normalized plain data', () => {
237
+ const keyCode = KeyCode.createKeyCode({
238
+ key: '[',
239
+ code: 'Digit8',
240
+ keyCode: 56,
241
+ ctrlKey: true
242
+ });
243
+ expect(keyCode.key).to.equal(Key.DIGIT8);
244
+ expect(keyCode.ctrl).to.be.true;
245
+ expect(keyCode.character).to.equal('[');
246
+ });
247
+
248
+ it('should preserve legacy key identifier fallback in normalized data', () => {
249
+ const input = normalizeKeyboardInput({ keyIdentifier: Key.F1.code });
250
+ expect(KeyCode.createKeyCode(input).key).to.equal(Key.F1);
251
+ });
252
+
120
253
  it('the order of the modifiers should not matter when parsing the key code', () => {
121
254
  const left = KeySequence.parse('shift+alt+a');
122
255
  const right = KeySequence.parse('alt+shift+a');
@@ -231,6 +364,78 @@ describe('keys api', () => {
231
364
  expect(second.key).is.equal(Key.KEY_B);
232
365
  });
233
366
 
367
+ it('should parse physical scan codes and preserve them when serializing', () => {
368
+ const keycode = KeyCode.parse('ctrl+[BracketLeft]');
369
+ expect(keycode.ctrl).to.be.true;
370
+ expect(keycode.key).to.equal(Key.BRACKET_LEFT);
371
+ expect(keycode.physical).to.be.true;
372
+ expect(keycode.toString()).to.equal('ctrl+[BracketLeft]');
373
+ expect(() => KeyCode.parse('[UnknownPhysicalKey]')).to.throw(/Unknown scan code/);
374
+ });
375
+
376
+ it('should parse bare and escaped logical characters', () => {
377
+ for (const character of ['^', '§', '²', 'ä']) {
378
+ const keycode = KeyCode.parse(`ctrl+${character}`);
379
+ expect(keycode.character).to.equal(character);
380
+ expect(keycode.toString()).to.equal(`ctrl+${character}`);
381
+ }
382
+ expect(KeyCode.parse('ctrl+[char:0x2B]').character).to.equal('+');
383
+ expect(KeyCode.parse('ctrl+[char:0x20]').character).to.equal(' ');
384
+ expect(KeyCode.parse('ctrl+[char:0x5D]').character).to.equal(']');
385
+ expect(KeyCode.parse('ctrl+[char:§]').character).to.equal('§');
386
+ expect(KeyCode.parse('ctrl+[char:0x2B]').toString()).to.equal('ctrl+[char:0x2B]');
387
+ });
388
+
389
+ it('should keep bracketed separators and whitespace within one key token', () => {
390
+ expect(KeySequence.parse('ctrl+[char:0x20] ctrl+[BracketLeft]')).to.have.length(2);
391
+ expect(KeySequence.parse('ctrl+[ ctrl+]')).to.have.length(2);
392
+ expect(KeySequence.parse('ctrl+] ctrl+[')).to.have.length(2);
393
+ expect(KeyCode.parse('ctrl+[char:0x2B]').character).to.equal('+');
394
+ expect(KeyCode.parse('ctrl+[char:0x2D]').character).to.equal('-');
395
+ });
396
+
397
+ it('should reject invalid and multi-code-point logical characters', () => {
398
+ expect(() => KeyCode.parse('[char:0x110000]')).to.throw(/Invalid Unicode/);
399
+ expect(() => KeyCode.parse('[char:0xD800]')).to.throw(/Invalid Unicode/);
400
+ expect(() => KeyCode.parse('[char:ab]')).to.throw(/Invalid Unicode/);
401
+ expect(() => KeyCode.parse('👨‍👩‍👧‍👦')).to.throw(/Unrecognized key/);
402
+ });
403
+
404
+ it('should serialize recorder strokes as logical characters, named keys, or physical scan codes', () => {
405
+ expect(new KeyCode({ key: Key.DIGIT8, ctrl: true, character: '[' }).toAuthoredKeybindingString()).to.equal('ctrl+[');
406
+ expect(new KeyCode({ key: Key.EQUAL, ctrl: true, character: '+' }).toAuthoredKeybindingString()).to.equal('ctrl+[char:0x2B]');
407
+
408
+ const namedKeys: Array<[Key, string]> = [
409
+ [Key.F1, 'f1'],
410
+ [Key.DELETE, 'delete'],
411
+ [Key.BACKSPACE, 'backspace'],
412
+ [Key.ENTER, 'enter'],
413
+ [Key.ARROW_LEFT, 'left'],
414
+ [Key.SPACE, 'space'],
415
+ [Key.ESCAPE, 'escape']
416
+ ];
417
+ for (const [key, name] of namedKeys) {
418
+ const serialized = new KeyCode({ key, ctrl: true }).toAuthoredKeybindingString();
419
+ expect(serialized).to.equal(`ctrl+${name}`);
420
+ expect(KeyCode.parse(serialized).key).to.equal(key);
421
+ }
422
+
423
+ const physicalPrintable = new KeyCode({ key: Key.DIGIT8, ctrl: true }).toAuthoredKeybindingString();
424
+ expect(physicalPrintable).to.equal('ctrl+[Digit8]');
425
+ expect(KeyCode.parse(physicalPrintable).key).to.equal(Key.DIGIT8);
426
+
427
+ const shiftedLetter = new KeyCode({ key: Key.KEY_P, ctrl: true, shift: true, character: 'P' });
428
+ expect(shiftedLetter.toAuthoredKeybindingString()).to.equal('shift+ctrl+p');
429
+ expect(KeyCode.parse(shiftedLetter.toAuthoredKeybindingString()).dispatchString()).to.equal('shift+ctrl+p');
430
+ });
431
+
432
+ it('should serialize recorder strokes for Space and numpad keys by name', () => {
433
+ expect(new KeyCode({ key: Key.SPACE, meta: true, shift: true, character: ' ' }).toAuthoredKeybindingString()).to.equal('meta+shift+space');
434
+ expect(new KeyCode({ key: Key.ADD, ctrl: true, character: '+' }).toAuthoredKeybindingString()).to.equal('ctrl+add');
435
+ expect(new KeyCode({ key: Key.DECIMAL, ctrl: true, character: '.' }).toAuthoredKeybindingString()).to.equal('ctrl+decimal');
436
+ expect(new KeyCode({ key: Key.DIGIT1, ctrl: true, character: '1' }).toAuthoredKeybindingString()).to.equal('ctrl+1');
437
+ });
438
+
234
439
  it('should parse minus as key', () => {
235
440
  const keycode = KeyCode.parse('ctrl+-');
236
441
  expect(keycode.ctrl).to.be.true;
@@ -15,7 +15,9 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { inject, injectable, named, postConstruct } from 'inversify';
18
- import * as fileIcons from 'file-icons-js';
18
+ // The default import returns the exported FileIcons instance itself; a namespace import would be an interop copy of its own
19
+ // properties only, and getClass/getClassWithColor live on the prototype.
20
+ import fileIcons from 'file-icons-js';
19
21
  import URI from '../common/uri';
20
22
  import { ContributionProvider } from '../common/contribution-provider';
21
23
  import { Event, Emitter, Disposable, isObject, Path, Prioritizeable } from '../common';
@@ -16,7 +16,7 @@
16
16
 
17
17
  import * as DOMPurify from 'dompurify';
18
18
  import { injectable, inject, postConstruct } from 'inversify';
19
- import * as markdownit from 'markdown-it';
19
+ import markdownit from 'markdown-it';
20
20
  import * as markdownitemoji from 'markdown-it-emoji';
21
21
  import { MarkdownString } from '../../common/markdown-rendering/markdown-string';
22
22
  import { Disposable, DisposableGroup } from '../../common';
@@ -0,0 +1,60 @@
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
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { expect } from 'chai';
18
+ import { Key, KeyCode } from '../keyboard/keys';
19
+ import { KeybindingRegistry } from '../keybinding';
20
+ import { ActionMenuNode } from './action-menu-node';
21
+
22
+ describe('ActionMenuNode accelerators', () => {
23
+ it('selects logical and physical accelerator forms explicitly', () => {
24
+ const binding = { command: 'test.command', keybinding: 'ctrl+[' };
25
+ const state = { inactive: false };
26
+ const keybindingRegistry = Object.create(KeybindingRegistry.prototype) as KeybindingRegistry;
27
+ keybindingRegistry.getKeybindingsForCommand = () => [{ ...binding, scope: 0 }];
28
+ keybindingRegistry.isEnabledInScope = () => true;
29
+ keybindingRegistry.isKeybindingInactive = () => state.inactive;
30
+ keybindingRegistry.resolveKeybinding = () => [new KeyCode({
31
+ key: Key.DIGIT8,
32
+ ctrl: true,
33
+ character: '[',
34
+ layoutModifiers: 'altGraph'
35
+ })];
36
+ Object.defineProperty(keybindingRegistry, 'keyboardLayoutService', {
37
+ value: { getKeyboardCharacter: (key: Key) => key.easyString }
38
+ });
39
+ const commands = {
40
+ getAllHandlers: () => [],
41
+ getCommand: () => ({ id: 'test.command' })
42
+ };
43
+ const contextKeyService = {
44
+ parseKeys: () => undefined
45
+ };
46
+ const node = new ActionMenuNode(
47
+ { commandId: 'test.command' },
48
+ commands as never,
49
+ keybindingRegistry,
50
+ contextKeyService as never
51
+ );
52
+
53
+ expect(node.getAccelerator(undefined, 'logical')).to.deep.equal(['Ctrl+[']);
54
+ expect(node.getAccelerator(undefined, 'physical')).to.deep.equal(['Ctrl+AltGr+8']);
55
+
56
+ state.inactive = true;
57
+ expect(node.getAccelerator(undefined, 'logical')).to.deep.equal(['Ctrl+[']);
58
+ expect(node.getAccelerator(undefined, 'physical')).to.deep.equal([]);
59
+ });
60
+ });
@@ -14,13 +14,16 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { KeybindingRegistry } from '../keybinding';
17
+ import { AcceleratorForm, KeybindingRegistry } from '../keybinding';
18
18
  import { ContextKeyService } from '../context-key-service';
19
- import { DisposableCollection, isObject, CommandRegistry, Emitter, environment } from '../../common';
19
+ import { DisposableCollection, isObject, CommandRegistry, Emitter } from '../../common';
20
20
  import { CommandMenu, ContextExpressionMatcher, MenuAction, MenuPath } from '../../common/menu/menu-types';
21
21
 
22
+ export { AcceleratorForm } from '../keybinding';
23
+
22
24
  export interface AcceleratorSource {
23
- getAccelerator(context: HTMLElement | undefined): string[];
25
+ /** Return the accelerator rendered in the explicitly requested logical or physical form. */
26
+ getAccelerator(context: HTMLElement | undefined, form: AcceleratorForm): string[];
24
27
  }
25
28
 
26
29
  export namespace AcceleratorSource {
@@ -80,17 +83,8 @@ export class ActionMenuNode implements CommandMenu {
80
83
  return true;
81
84
  }
82
85
 
83
- getAccelerator(context: HTMLElement | undefined): string[] {
84
- const bindings = this.keybindingRegistry.getKeybindingsForCommand(this.action.commandId);
85
- // Only consider the first active keybinding.
86
- if (bindings.length) {
87
- const binding = bindings.find(b => this.keybindingRegistry.isEnabledInScope(b, context));
88
- if (binding) {
89
- const asciiOnly = environment.electron.is();
90
- return this.keybindingRegistry.acceleratorFor(binding, '+', asciiOnly);
91
- }
92
- }
93
- return [];
86
+ getAccelerator(context: HTMLElement | undefined, form: AcceleratorForm): string[] {
87
+ return this.keybindingRegistry.acceleratorForCommand(this.action.commandId, context, form);
94
88
  }
95
89
 
96
90
  isEnabled(effeciveMenuPath: MenuPath, ...args: unknown[]): boolean {
@@ -368,7 +368,7 @@ export class DynamicMenuWidget extends MenuWidget {
368
368
  iconClass: node.icon,
369
369
  });
370
370
 
371
- const accelerator = (AcceleratorSource.is(node) ? node.getAccelerator(this.options.context) : []);
371
+ const accelerator = (AcceleratorSource.is(node) ? node.getAccelerator(this.options.context, 'logical') : []);
372
372
  if (accelerator.length > 0) {
373
373
  phCommandRegistry.addKeyBinding({
374
374
  command: id,
@@ -16,7 +16,7 @@
16
16
 
17
17
  import { Container } from 'inversify';
18
18
  import { PreferenceValidationService } from './preference-validation-service';
19
- import * as assert from 'assert';
19
+ import assert from 'assert';
20
20
  import { JSONValue } from '@lumino/coreutils';
21
21
  import { IJSONSchema, JsonType } from '../../common/json-schema';
22
22
  import {
@@ -0,0 +1,159 @@
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
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { enableJSDOM } from '../test/jsdom';
18
+ let disableJSDOM = enableJSDOM();
19
+
20
+ import { FrontendApplicationConfigProvider } from '../frontend-application-config-provider';
21
+ FrontendApplicationConfigProvider.set({});
22
+
23
+ import * as chai from 'chai';
24
+ import { Container } from 'inversify';
25
+ import { CancellationToken, CommandRegistry, Emitter } from '../../common';
26
+ import { CorePreferences } from '../../common/core-preferences';
27
+ import { ContextKeyService, ContextKeyServiceDummyImpl } from '../context-key-service';
28
+ import { KeybindingRegistry } from '../keybinding';
29
+ import { QuickAccessRegistry } from './quick-access';
30
+ import { QuickCommandService } from './quick-command-service';
31
+ import { QuickInputService, QuickPickItem } from './quick-input-service';
32
+
33
+ disableJSDOM();
34
+
35
+ const expect = chai.expect;
36
+
37
+ class RecordingContextKeyService extends ContextKeyServiceDummyImpl {
38
+ activeContext: unknown;
39
+
40
+ override withContext<T>(context: unknown, callback: () => T): T {
41
+ const previous = this.activeContext;
42
+ this.activeContext = context;
43
+ try {
44
+ return callback();
45
+ } finally {
46
+ this.activeContext = previous;
47
+ }
48
+ }
49
+ }
50
+
51
+ describe('quick-command-service', () => {
52
+
53
+ let editor: HTMLElement;
54
+ let quickInput: HTMLInputElement;
55
+ let contextKeyService: RecordingContextKeyService;
56
+ let commandRegistry: CommandRegistry;
57
+ let onHideEmitter: Emitter<void>;
58
+ let quickInputService: { previousFocusElement?: HTMLElement, onHide: Emitter<void>['event'] };
59
+ let service: QuickCommandService;
60
+
61
+ before(() => {
62
+ disableJSDOM = enableJSDOM();
63
+ });
64
+
65
+ after(() => {
66
+ disableJSDOM();
67
+ });
68
+
69
+ beforeEach(() => {
70
+ editor = document.createElement('div');
71
+ editor.tabIndex = 0;
72
+ quickInput = document.createElement('input');
73
+ document.body.append(editor, quickInput);
74
+ // Focus has moved to the quick input, as it does while the palette is open.
75
+ quickInput.focus();
76
+
77
+ contextKeyService = new RecordingContextKeyService();
78
+ commandRegistry = new CommandRegistry({ getContributions: () => [] });
79
+ onHideEmitter = new Emitter<void>();
80
+ quickInputService = { previousFocusElement: editor, onHide: onHideEmitter.event };
81
+
82
+ const container = new Container();
83
+ container.bind(ContextKeyService).toConstantValue(contextKeyService);
84
+ container.bind(CommandRegistry).toConstantValue(commandRegistry);
85
+ container.bind(CorePreferences).toConstantValue(<CorePreferences>{ 'workbench.commandPalette.history': 50 });
86
+ container.bind(QuickAccessRegistry).toConstantValue(<QuickAccessRegistry>{});
87
+ container.bind(KeybindingRegistry).toConstantValue(<KeybindingRegistry><unknown>{ getKeybindingsForCommand: () => [] });
88
+ container.bind(QuickInputService).toConstantValue(<QuickInputService><unknown>quickInputService);
89
+ container.bind(QuickCommandService).toSelf();
90
+ service = container.get(QuickCommandService);
91
+ });
92
+
93
+ afterEach(() => {
94
+ editor.remove();
95
+ quickInput.remove();
96
+ onHideEmitter.dispose();
97
+ });
98
+
99
+ function inEditorContext(): boolean {
100
+ return contextKeyService.activeContext === editor;
101
+ }
102
+
103
+ function picks(): QuickPickItem[] {
104
+ return service.getPicks('', CancellationToken.None).filter((pick): pick is QuickPickItem => pick.type !== 'separator');
105
+ }
106
+
107
+ it('evaluates command enablement against the element focused before the quick input opened', () => {
108
+ commandRegistry.registerCommand({ id: 'test.editorOnly', label: 'Editor Only' }, { execute: () => { }, isEnabled: inEditorContext });
109
+
110
+ expect(picks().map(pick => pick.label)).to.deep.equal(['Editor Only']);
111
+ });
112
+
113
+ it('evaluates item state against the element focused before the quick input opened', () => {
114
+ commandRegistry.registerCommand({ id: 'test.toggle', label: 'Toggle' }, { execute: () => { }, isEnabled: inEditorContext, isToggled: inEditorContext });
115
+
116
+ const [item] = picks();
117
+ expect(item.alwaysShow).to.be.true;
118
+ expect(item.iconClasses).to.not.be.undefined;
119
+ });
120
+
121
+ it('evaluates pushed command contexts against the element focused before the quick input opened', () => {
122
+ contextKeyService.match = () => inEditorContext();
123
+ commandRegistry.registerCommand({ id: 'test.when', label: 'When' }, { execute: () => { } });
124
+ service.pushCommandContext('test.when', 'editorFocus');
125
+
126
+ expect(picks().map(pick => pick.label)).to.deep.equal(['When']);
127
+ });
128
+
129
+ it('restores focus to the element focused before the quick input opened on execute', () => {
130
+ commandRegistry.registerCommand({ id: 'test.command', label: 'Command' }, { execute: () => { } });
131
+
132
+ picks()[0].execute!();
133
+
134
+ expect(document.activeElement).to.equal(editor);
135
+ });
136
+
137
+ it('falls back to the active element when items are created without a reset', () => {
138
+ commandRegistry.registerCommand({ id: 'test.command', label: 'Command' }, { execute: () => { } });
139
+ const item = service.toItem({ id: 'test.command', label: 'Command' });
140
+ editor.focus();
141
+
142
+ item.execute!();
143
+
144
+ expect(document.activeElement).to.equal(quickInput);
145
+ });
146
+
147
+ it('forgets the context element when the quick input is hidden', () => {
148
+ commandRegistry.registerCommand({ id: 'test.command', label: 'Command' }, { execute: () => { } });
149
+ service.reset();
150
+ onHideEmitter.fire();
151
+
152
+ const item = service.toItem({ id: 'test.command', label: 'Command' });
153
+ editor.focus();
154
+ item.execute!();
155
+
156
+ expect(document.activeElement).to.equal(quickInput);
157
+ });
158
+
159
+ });
@@ -14,13 +14,13 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { inject, injectable } from 'inversify';
17
+ import { inject, injectable, optional, postConstruct } from 'inversify';
18
18
  import { KeybindingRegistry } from '../keybinding';
19
19
  import { Disposable, Command, CommandRegistry, CancellationToken, nls } from '../../common';
20
20
  import { ContextKeyService } from '../context-key-service';
21
21
  import { CorePreferences } from '../../common/core-preferences';
22
22
  import { QuickAccessContribution, QuickAccessProvider, QuickAccessRegistry } from './quick-access';
23
- import { filterItems, QuickPickItem, QuickPicks } from './quick-input-service';
23
+ import { filterItems, QuickInputService, QuickPickItem, QuickPicks } from './quick-input-service';
24
24
  import { KeySequence } from '../keys';
25
25
  import { codiconArray } from '../widgets';
26
26
 
@@ -56,6 +56,9 @@ export class QuickCommandService implements QuickAccessContribution, QuickAccess
56
56
  @inject(KeybindingRegistry)
57
57
  protected readonly keybindingRegistry: KeybindingRegistry;
58
58
 
59
+ @inject(QuickInputService) @optional()
60
+ protected readonly quickInputService: QuickInputService | undefined;
61
+
59
62
  // The list of exempted commands not to be displayed in the recently used list.
60
63
  readonly exemptedCommands: Command[] = [
61
64
  CLEAR_COMMAND_HISTORY,
@@ -64,6 +67,17 @@ export class QuickCommandService implements QuickAccessContribution, QuickAccess
64
67
  private recentItems: QuickPickItem[] = [];
65
68
  private otherItems: QuickPickItem[] = [];
66
69
 
70
+ /**
71
+ * The element that was focused when the quick input was opened.
72
+ * Commands are evaluated against its context, since focus moves to the quick input while the palette is open.
73
+ */
74
+ protected commandContextElement: HTMLElement | undefined;
75
+
76
+ @postConstruct()
77
+ protected init(): void {
78
+ this.quickInputService?.onHide(() => this.commandContextElement = undefined);
79
+ }
80
+
67
81
  registerQuickAccessProvider(): void {
68
82
  this.quickAccessRegistry.registerQuickAccessProvider({
69
83
  getInstance: () => this,
@@ -74,11 +88,12 @@ export class QuickCommandService implements QuickAccessContribution, QuickAccess
74
88
  }
75
89
 
76
90
  reset(): void {
77
- const { recent, other } = this.getCommands();
78
- this.recentItems = [];
79
- this.otherItems = [];
80
- this.recentItems.push(...recent.map(command => this.toItem(command)));
81
- this.otherItems.push(...other.map(command => this.toItem(command)));
91
+ this.updateCommandContextElement();
92
+ this.withCommandContext(() => {
93
+ const { recent, other } = this.getCommands();
94
+ this.recentItems = recent.map(command => this.toItem(command));
95
+ this.otherItems = other.map(command => this.toItem(command));
96
+ });
82
97
  }
83
98
 
84
99
  getPicks(filter: string, token: CancellationToken): QuickPicks {
@@ -105,7 +120,8 @@ export class QuickCommandService implements QuickAccessContribution, QuickAccess
105
120
  toItem(command: Command): QuickPickItem {
106
121
  const label = (command.category) ? `${command.category}: ` + command.label! : command.label!;
107
122
  const iconClasses = this.getItemIconClasses(command);
108
- const activeElement = window.document.activeElement as HTMLElement;
123
+ const activeElement = window.document.activeElement;
124
+ const commandContextElement = this.commandContextElement ?? (activeElement instanceof HTMLElement ? activeElement : undefined);
109
125
 
110
126
  const originalLabel = command.originalLabel || command.label!;
111
127
  const originalCategory = command.originalCategory || command.category;
@@ -121,13 +137,24 @@ export class QuickCommandService implements QuickAccessContribution, QuickAccess
121
137
  alwaysShow: !!this.commandRegistry.getActiveHandler(command.id),
122
138
  keySequence: this.getKeybinding(command),
123
139
  execute: () => {
124
- activeElement.focus({ preventScroll: true });
140
+ commandContextElement?.focus({ preventScroll: true });
125
141
  this.commandRegistry.executeCommand(command.id);
126
142
  this.commandRegistry.addRecentCommand(command);
127
143
  }
128
144
  };
129
145
  }
130
146
 
147
+ protected updateCommandContextElement(): void {
148
+ // When the palette is opened directly, the picks are computed before the quick input is shown and focused.
149
+ const element = this.quickInputService?.previousFocusElement ?? window.document.activeElement;
150
+ this.commandContextElement = element instanceof HTMLElement ? element : undefined;
151
+ }
152
+
153
+ protected withCommandContext<T>(callback: () => T): T {
154
+ const element = this.commandContextElement;
155
+ return element?.isConnected ? this.contextKeyService.withContext(element, callback) : callback();
156
+ }
157
+
131
158
  private getKeybinding(command: Command): KeySequence | undefined {
132
159
  const keybindings = this.keybindingRegistry.getKeybindingsForCommand(command.id);
133
160
  if (!keybindings || keybindings.length === 0) {
@@ -60,7 +60,7 @@ export class QuickHelpService implements QuickAccessProvider, QuickAccessContrib
60
60
 
61
61
  for (const helpEntry of provider.helpEntries) {
62
62
  const prefix = helpEntry.prefix || provider.prefix;
63
- const label = prefix || '\u2026' /* ... */;
63
+ const label = prefix || '\u2026'; // ...
64
64
 
65
65
  (helpEntry.needsEditor ? editorProviders : globalProviders).push({
66
66
  label,
@@ -58,6 +58,17 @@ export function enableJSDOM(): () => void {
58
58
  }
59
59
  });
60
60
  (dom.window.document as any)['queryCommandSupported'] = function (): void { };
61
+ dom.window.matchMedia = () => ({
62
+ matches: false,
63
+ media: '',
64
+ // eslint-disable-next-line no-null/no-null
65
+ onchange: null,
66
+ addListener: () => undefined,
67
+ removeListener: () => undefined,
68
+ addEventListener: () => undefined,
69
+ removeEventListener: () => undefined,
70
+ dispatchEvent: () => false
71
+ });
61
72
 
62
73
  const disableJSDOM = (global as any)['_disableJSDOM'] = () => {
63
74
  let property: string | undefined;
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import * as assert from 'assert';
17
+ import assert from 'assert';
18
18
  import { Container } from 'inversify';
19
19
  import { createTreeContainer, isTreeServices } from './tree-container';
20
20
  import { TreeSearch } from './tree-search';