@theia/plugin-ext 1.37.0-next.8 → 1.37.0

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 (155) hide show
  1. package/lib/common/language-pack-service.d.ts +16 -0
  2. package/lib/common/language-pack-service.d.ts.map +1 -0
  3. package/lib/common/language-pack-service.js +21 -0
  4. package/lib/common/language-pack-service.js.map +1 -0
  5. package/lib/common/plugin-api-rpc-model.d.ts +6 -0
  6. package/lib/common/plugin-api-rpc-model.d.ts.map +1 -1
  7. package/lib/common/plugin-api-rpc-model.js +6 -1
  8. package/lib/common/plugin-api-rpc-model.js.map +1 -1
  9. package/lib/common/plugin-api-rpc.d.ts +22 -1
  10. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  11. package/lib/common/plugin-api-rpc.js +2 -1
  12. package/lib/common/plugin-api-rpc.js.map +1 -1
  13. package/lib/common/plugin-protocol.d.ts +2 -0
  14. package/lib/common/plugin-protocol.d.ts.map +1 -1
  15. package/lib/common/plugin-protocol.js.map +1 -1
  16. package/lib/hosted/browser/hosted-plugin.d.ts +6 -2
  17. package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
  18. package/lib/hosted/browser/hosted-plugin.js +26 -5
  19. package/lib/hosted/browser/hosted-plugin.js.map +1 -1
  20. package/lib/hosted/browser/worker/worker-main.js +4 -2
  21. package/lib/hosted/browser/worker/worker-main.js.map +1 -1
  22. package/lib/hosted/node/hosted-plugin-deployer-handler.js +2 -2
  23. package/lib/hosted/node/hosted-plugin-deployer-handler.js.map +1 -1
  24. package/lib/hosted/node/hosted-plugin-localization-service.d.ts +13 -1
  25. package/lib/hosted/node/hosted-plugin-localization-service.d.ts.map +1 -1
  26. package/lib/hosted/node/hosted-plugin-localization-service.js +122 -10
  27. package/lib/hosted/node/hosted-plugin-localization-service.js.map +1 -1
  28. package/lib/hosted/node/plugin-ext-hosted-backend-module.d.ts.map +1 -1
  29. package/lib/hosted/node/plugin-ext-hosted-backend-module.js +7 -0
  30. package/lib/hosted/node/plugin-ext-hosted-backend-module.js.map +1 -1
  31. package/lib/hosted/node/plugin-host-rpc.d.ts +2 -2
  32. package/lib/hosted/node/plugin-host-rpc.d.ts.map +1 -1
  33. package/lib/hosted/node/plugin-host-rpc.js +6 -4
  34. package/lib/hosted/node/plugin-host-rpc.js.map +1 -1
  35. package/lib/hosted/node/plugin-language-pack-service.d.ts +8 -0
  36. package/lib/hosted/node/plugin-language-pack-service.d.ts.map +1 -0
  37. package/lib/hosted/node/plugin-language-pack-service.js +54 -0
  38. package/lib/hosted/node/plugin-language-pack-service.js.map +1 -0
  39. package/lib/hosted/node/scanners/scanner-theia.d.ts.map +1 -1
  40. package/lib/hosted/node/scanners/scanner-theia.js +1 -0
  41. package/lib/hosted/node/scanners/scanner-theia.js.map +1 -1
  42. package/lib/main/browser/comments/comment-thread-widget.d.ts.map +1 -1
  43. package/lib/main/browser/comments/comment-thread-widget.js +5 -1
  44. package/lib/main/browser/comments/comment-thread-widget.js.map +1 -1
  45. package/lib/main/browser/comments/comments-main.d.ts +6 -1
  46. package/lib/main/browser/comments/comments-main.d.ts.map +1 -1
  47. package/lib/main/browser/comments/comments-main.js +15 -0
  48. package/lib/main/browser/comments/comments-main.js.map +1 -1
  49. package/lib/main/browser/localization-main.d.ts +9 -0
  50. package/lib/main/browser/localization-main.d.ts.map +1 -0
  51. package/lib/main/browser/localization-main.js +32 -0
  52. package/lib/main/browser/localization-main.js.map +1 -0
  53. package/lib/main/browser/main-context.d.ts.map +1 -1
  54. package/lib/main/browser/main-context.js +3 -0
  55. package/lib/main/browser/main-context.js.map +1 -1
  56. package/lib/main/browser/plugin-ext-frontend-module.d.ts.map +1 -1
  57. package/lib/main/browser/plugin-ext-frontend-module.js +5 -0
  58. package/lib/main/browser/plugin-ext-frontend-module.js.map +1 -1
  59. package/lib/main/browser/view/tree-view-widget.d.ts.map +1 -1
  60. package/lib/main/browser/view/tree-view-widget.js +10 -1
  61. package/lib/main/browser/view/tree-view-widget.js.map +1 -1
  62. package/lib/main/electron-browser/webview/electron-webview-widget-factory.d.ts +1 -0
  63. package/lib/main/electron-browser/webview/electron-webview-widget-factory.d.ts.map +1 -1
  64. package/lib/main/electron-browser/webview/electron-webview-widget-factory.js +4 -15
  65. package/lib/main/electron-browser/webview/electron-webview-widget-factory.js.map +1 -1
  66. package/lib/main/node/plugin-github-resolver.d.ts +3 -1
  67. package/lib/main/node/plugin-github-resolver.d.ts.map +1 -1
  68. package/lib/main/node/plugin-github-resolver.js +64 -71
  69. package/lib/main/node/plugin-github-resolver.js.map +1 -1
  70. package/lib/main/node/plugin-http-resolver.d.ts +2 -0
  71. package/lib/main/node/plugin-http-resolver.d.ts.map +1 -1
  72. package/lib/main/node/plugin-http-resolver.js +31 -31
  73. package/lib/main/node/plugin-http-resolver.js.map +1 -1
  74. package/lib/main/node/plugins-key-value-storage.js +1 -1
  75. package/lib/main/node/plugins-key-value-storage.js.map +1 -1
  76. package/lib/plugin/comments.d.ts +3 -0
  77. package/lib/plugin/comments.d.ts.map +1 -1
  78. package/lib/plugin/comments.js +24 -0
  79. package/lib/plugin/comments.js.map +1 -1
  80. package/lib/plugin/localization-ext.d.ts +17 -0
  81. package/lib/plugin/localization-ext.d.ts.map +1 -0
  82. package/lib/plugin/localization-ext.js +74 -0
  83. package/lib/plugin/localization-ext.js.map +1 -0
  84. package/lib/plugin/output-channel/log-output-channel.d.ts +24 -0
  85. package/lib/plugin/output-channel/log-output-channel.d.ts.map +1 -0
  86. package/lib/plugin/output-channel/log-output-channel.js +92 -0
  87. package/lib/plugin/output-channel/log-output-channel.js.map +1 -0
  88. package/lib/plugin/output-channel/output-channel-item.d.ts +3 -3
  89. package/lib/plugin/output-channel/output-channel-item.d.ts.map +1 -1
  90. package/lib/plugin/output-channel/output-channel-item.js.map +1 -1
  91. package/lib/plugin/output-channel-registry.d.ts +7 -2
  92. package/lib/plugin/output-channel-registry.d.ts.map +1 -1
  93. package/lib/plugin/output-channel-registry.js +15 -6
  94. package/lib/plugin/output-channel-registry.js.map +1 -1
  95. package/lib/plugin/plugin-context.d.ts +2 -1
  96. package/lib/plugin/plugin-context.d.ts.map +1 -1
  97. package/lib/plugin/plugin-context.js +26 -3
  98. package/lib/plugin/plugin-context.js.map +1 -1
  99. package/lib/plugin/plugin-manager.d.ts +3 -2
  100. package/lib/plugin/plugin-manager.d.ts.map +1 -1
  101. package/lib/plugin/plugin-manager.js +4 -1
  102. package/lib/plugin/plugin-manager.js.map +1 -1
  103. package/lib/plugin/preference-registry.d.ts +1 -1
  104. package/lib/plugin/preference-registry.js +1 -1
  105. package/lib/plugin/stubs/tests-api.d.ts +2 -1
  106. package/lib/plugin/stubs/tests-api.d.ts.map +1 -1
  107. package/lib/plugin/stubs/tests-api.js +2 -1
  108. package/lib/plugin/stubs/tests-api.js.map +1 -1
  109. package/lib/plugin/tree/tree-views.d.ts +2 -0
  110. package/lib/plugin/tree/tree-views.d.ts.map +1 -1
  111. package/lib/plugin/tree/tree-views.js +10 -3
  112. package/lib/plugin/tree/tree-views.js.map +1 -1
  113. package/lib/plugin/type-converters.d.ts.map +1 -1
  114. package/lib/plugin/type-converters.js +6 -3
  115. package/lib/plugin/type-converters.js.map +1 -1
  116. package/lib/plugin/types-impl.d.ts +8 -4
  117. package/lib/plugin/types-impl.d.ts.map +1 -1
  118. package/lib/plugin/types-impl.js +12 -7
  119. package/lib/plugin/types-impl.js.map +1 -1
  120. package/package.json +28 -30
  121. package/src/common/language-pack-service.ts +34 -0
  122. package/src/common/plugin-api-rpc-model.ts +7 -0
  123. package/src/common/plugin-api-rpc.ts +25 -2
  124. package/src/common/plugin-protocol.ts +2 -0
  125. package/src/hosted/browser/hosted-plugin.ts +27 -6
  126. package/src/hosted/browser/worker/worker-main.ts +5 -2
  127. package/src/hosted/node/hosted-plugin-deployer-handler.ts +2 -2
  128. package/src/hosted/node/hosted-plugin-localization-service.ts +132 -11
  129. package/src/hosted/node/plugin-ext-hosted-backend-module.ts +12 -0
  130. package/src/hosted/node/plugin-host-rpc.ts +8 -5
  131. package/src/hosted/node/plugin-language-pack-service.ts +43 -0
  132. package/src/hosted/node/scanners/scanner-theia.ts +1 -0
  133. package/src/main/browser/comments/comment-thread-widget.tsx +6 -1
  134. package/src/main/browser/comments/comments-main.ts +18 -1
  135. package/src/main/browser/localization-main.ts +34 -0
  136. package/src/main/browser/main-context.ts +4 -0
  137. package/src/main/browser/plugin-ext-frontend-module.ts +6 -0
  138. package/src/main/browser/view/tree-view-widget.tsx +11 -1
  139. package/src/main/electron-browser/webview/electron-webview-widget-factory.ts +4 -15
  140. package/src/main/node/plugin-github-resolver.ts +65 -81
  141. package/src/main/node/plugin-http-resolver.ts +29 -35
  142. package/src/main/node/plugins-key-value-storage.ts +1 -1
  143. package/src/plugin/comments.ts +32 -1
  144. package/src/plugin/localization-ext.ts +84 -0
  145. package/src/plugin/output-channel/log-output-channel.ts +108 -0
  146. package/src/plugin/output-channel/output-channel-item.ts +2 -2
  147. package/src/plugin/output-channel-registry.ts +20 -7
  148. package/src/plugin/plugin-context.ts +31 -3
  149. package/src/plugin/plugin-manager.ts +5 -1
  150. package/src/plugin/preference-registry.ts +1 -1
  151. package/src/plugin/stubs/tests-api.ts +3 -1
  152. package/src/plugin/tree/tree-views.ts +12 -3
  153. package/src/plugin/type-converters.ts +5 -3
  154. package/src/plugin/types-impl.ts +8 -3
  155. package/LICENSE +0 -642
@@ -632,13 +632,23 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
632
632
 
633
633
  handleDragEnd(node: TreeViewNode, event: React.DragEvent<HTMLElement>): void {
634
634
  this.applicationShell.clearAdditionalDraggedEditorUris();
635
+ this.model.proxy!.$dragEnd(this.id);
635
636
  }
636
637
 
637
638
  handleDragOver(event: React.DragEvent<HTMLElement>): void {
639
+ const hasFiles = (items: DataTransferItemList) => {
640
+ for (let i = 0; i < items.length; i++) {
641
+ if (items[i].kind === 'file') {
642
+ return true;
643
+ }
644
+ }
645
+ return false;
646
+ };
647
+
638
648
  if (event.dataTransfer) {
639
649
  const canDrop = event.dataTransfer.types.some(type => this.options.dropMimeTypes!.includes(type)) ||
640
650
  event.dataTransfer.types.includes(this.treeDragType) ||
641
- this.options.dropMimeTypes!.includes('files') && event.dataTransfer.files.length > 0;
651
+ this.options.dropMimeTypes!.includes('files') && hasFiles(event.dataTransfer.items);
642
652
  if (canDrop) {
643
653
  event.preventDefault();
644
654
  event.dataTransfer.dropEffect = 'move';
@@ -14,12 +14,11 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import * as electronRemote from '@theia/core/electron-shared/@electron/remote';
18
- import { ElectronSecurityToken } from '@theia/core/lib/electron-common/electron-token';
19
17
  import { WebviewWidgetFactory } from '../../browser/webview/webview-widget-factory';
20
18
  import { WebviewWidgetIdentifier, WebviewWidget } from '../../browser/webview/webview';
21
19
  import { CustomEditorWidgetFactory } from '../../browser/custom-editors/custom-editor-widget-factory';
22
20
  import { CustomEditorWidget } from '../../browser/custom-editors/custom-editor-widget';
21
+ import '@theia/core/lib/electron-common/electron-api';
23
22
 
24
23
  export class ElectronWebviewWidgetFactory extends WebviewWidgetFactory {
25
24
 
@@ -34,13 +33,8 @@ export class ElectronWebviewWidgetFactory extends WebviewWidgetFactory {
34
33
  *
35
34
  * @param endpoint cookie's target url
36
35
  */
37
- protected async attachElectronSecurityCookie(endpoint: string): Promise<void> {
38
- await electronRemote.session.defaultSession.cookies.set({
39
- url: endpoint,
40
- name: ElectronSecurityToken,
41
- value: JSON.stringify(this.container.get(ElectronSecurityToken)),
42
- httpOnly: true
43
- });
36
+ protected attachElectronSecurityCookie(endpoint: string): Promise<void> {
37
+ return window.electronTheiaCore.attachSecurityToken(endpoint);
44
38
  }
45
39
 
46
40
  }
@@ -59,12 +53,7 @@ export class ElectronCustomEditorWidgetFactory extends CustomEditorWidgetFactory
59
53
  * @param endpoint cookie's target url
60
54
  */
61
55
  protected async attachElectronSecurityCookie(endpoint: string): Promise<void> {
62
- await electronRemote.session.defaultSession.cookies.set({
63
- url: endpoint,
64
- name: ElectronSecurityToken,
65
- value: JSON.stringify(this.container.get(ElectronSecurityToken)),
66
- httpOnly: true
67
- });
56
+ return window.electronTheiaCore.attachSecurityToken(endpoint);
68
57
  }
69
58
 
70
59
  }
@@ -14,11 +14,11 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { injectable } from '@theia/core/shared/inversify';
18
- import * as fs from 'fs';
17
+ import { RequestContext, RequestService } from '@theia/core/shared/@theia/request';
18
+ import { inject, injectable } from '@theia/core/shared/inversify';
19
+ import { promises as fs, existsSync, mkdirSync } from 'fs';
19
20
  import * as os from 'os';
20
21
  import * as path from 'path';
21
- import * as request from 'request';
22
22
  import { PluginDeployerResolver, PluginDeployerResolverContext } from '../../common';
23
23
 
24
24
  /**
@@ -35,10 +35,13 @@ export class GithubPluginDeployerResolver implements PluginDeployerResolver {
35
35
 
36
36
  private unpackedFolder: string;
37
37
 
38
+ @inject(RequestService)
39
+ protected readonly request: RequestService;
40
+
38
41
  constructor() {
39
42
  this.unpackedFolder = path.resolve(os.tmpdir(), 'github-remote');
40
- if (!fs.existsSync(this.unpackedFolder)) {
41
- fs.mkdirSync(this.unpackedFolder);
43
+ if (!existsSync(this.unpackedFolder)) {
44
+ mkdirSync(this.unpackedFolder);
42
45
  }
43
46
  }
44
47
 
@@ -48,95 +51,76 @@ export class GithubPluginDeployerResolver implements PluginDeployerResolver {
48
51
  async resolve(pluginResolverContext: PluginDeployerResolverContext): Promise<void> {
49
52
 
50
53
  // download the file
51
- return new Promise<void>((resolve, reject) => {
52
- // extract data
53
- const extracted = /^github:(.*)\/(.*)\/(.*)$/gm.exec(pluginResolverContext.getOriginId());
54
- if (!extracted || extracted === null || extracted.length !== 4) {
55
- reject(new Error('Invalid extension' + pluginResolverContext.getOriginId()));
56
- return;
57
- }
54
+ // extract data
55
+ const extracted = /^github:(.*)\/(.*)\/(.*)$/gm.exec(pluginResolverContext.getOriginId());
56
+ if (!extracted || extracted === null || extracted.length !== 4) {
57
+ throw new Error('Invalid extension' + pluginResolverContext.getOriginId());
58
+ }
58
59
 
59
- const orgName = extracted[1];
60
- const repoName = extracted[2];
61
- const file = extracted[3];
62
-
63
- // get version if any
64
- const splitFile = file.split('@');
65
- let version;
66
- let filename: string;
67
- if (splitFile.length === 1) {
68
- filename = file;
69
- version = 'latest';
70
- } else {
71
- filename = splitFile[0];
72
- version = splitFile[1];
73
- }
74
- // latest version, need to get the redirect
75
- const url = GithubPluginDeployerResolver.GITHUB_ENDPOINT + orgName + '/' + repoName + '/releases/latest';
60
+ const orgName = extracted[1];
61
+ const repoName = extracted[2];
62
+ const file = extracted[3];
63
+
64
+ // get version if any
65
+ const splitFile = file.split('@');
66
+ let version;
67
+ let filename: string;
68
+ if (splitFile.length === 1) {
69
+ filename = file;
70
+ version = 'latest';
71
+ } else {
72
+ filename = splitFile[0];
73
+ version = splitFile[1];
74
+ }
75
+ // latest version, need to get the redirect
76
+ const url = GithubPluginDeployerResolver.GITHUB_ENDPOINT + orgName + '/' + repoName + '/releases/latest';
76
77
 
78
+ // if latest, resolve first the real version
79
+ if (version === 'latest') {
77
80
  // disable redirect to grab the release
78
- const options = {
79
- followRedirect: false
80
- };
81
- // if latest, resolve first the real version
82
- if (version === 'latest') {
83
- request.get(url, options).on('response', response => {
84
-
85
- // should have a redirect
86
- if (response.statusCode === 302) {
87
- const redirectLocation = response.headers.location;
88
- if (!redirectLocation) {
89
- reject(new Error('Invalid github link with latest not being found'));
90
- return;
91
- }
92
-
93
- // parse redirect link
94
- const taggedValueArray = /^https:\/\/.*tag\/(.*)/gm.exec(redirectLocation);
95
- if (!taggedValueArray || taggedValueArray.length !== 2) {
96
- reject(new Error('The redirect link for latest is invalid ' + redirectLocation));
97
- return;
98
- }
99
-
100
- // grab version of tag
101
- this.grabGithubFile(pluginResolverContext, orgName, repoName, filename, taggedValueArray[1], resolve, reject);
102
-
103
- }
104
- });
105
- } else {
106
- this.grabGithubFile(pluginResolverContext, orgName, repoName, filename, version, resolve, reject);
107
- }
108
-
109
- });
81
+ const followRedirects = 0;
82
+ const response = await this.request.request({ url, followRedirects });
83
+ // should have a redirect
84
+ if (response.res.statusCode === 302) {
85
+ const redirectLocation = response.res.headers.location;
86
+ if (!redirectLocation) {
87
+ throw new Error('Invalid github link with latest not being found');
88
+ }
89
+
90
+ // parse redirect link
91
+ const taggedValueArray = /^https:\/\/.*tag\/(.*)/gm.exec(redirectLocation);
92
+ if (!taggedValueArray || taggedValueArray.length !== 2) {
93
+ throw new Error('The redirect link for latest is invalid ' + redirectLocation);
94
+ }
95
+
96
+ // grab version of tag
97
+ return this.grabGithubFile(pluginResolverContext, orgName, repoName, filename, taggedValueArray[1]);
110
98
 
99
+ }
100
+ } else {
101
+ return this.grabGithubFile(pluginResolverContext, orgName, repoName, filename, version);
102
+ }
111
103
  }
112
104
 
113
105
  /*
114
106
  * Grab the github file specified by the plugin's ID
115
107
  */
116
- protected grabGithubFile(pluginResolverContext: PluginDeployerResolverContext, orgName: string, repoName: string, filename: string, version: string,
117
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
- resolve: (value?: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void {
119
-
108
+ protected async grabGithubFile(pluginResolverContext: PluginDeployerResolverContext, orgName: string, repoName: string, filename: string, version: string): Promise<void> {
120
109
  const unpackedPath = path.resolve(this.unpackedFolder, path.basename(version + filename));
121
- const finish = () => {
122
- pluginResolverContext.addPlugin(pluginResolverContext.getOriginId(), unpackedPath);
123
- resolve();
124
- };
125
-
126
- // use of cache. If file is already there use it directly
127
- if (fs.existsSync(unpackedPath)) {
128
- finish();
110
+ try {
111
+ await fs.access(unpackedPath);
112
+ // use of cache. If file is already there use it directly
129
113
  return;
130
- }
131
- const dest = fs.createWriteStream(unpackedPath);
114
+ } catch { }
132
115
 
133
- dest.addListener('finish', finish);
134
116
  const url = GithubPluginDeployerResolver.GITHUB_ENDPOINT + orgName + '/' + repoName + '/releases/download/' + version + '/' + filename;
135
- request.get(url)
136
- .on('error', err => {
137
- reject(err);
138
- }).pipe(dest);
139
-
117
+ const response = await this.request.request({ url });
118
+ if (RequestContext.isSuccess(response)) {
119
+ await fs.writeFile(unpackedPath, response.buffer);
120
+ pluginResolverContext.addPlugin(pluginResolverContext.getOriginId(), unpackedPath);
121
+ } else {
122
+ throw new Error(`Could not download the plugin from GitHub. URL: ${url}. HTTP status code: ${response.res.statusCode}`);
123
+ }
140
124
  }
141
125
 
142
126
  /**
@@ -14,13 +14,12 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { injectable } from '@theia/core/shared/inversify';
18
- import * as fs from 'fs';
17
+ import { RequestContext, RequestService } from '@theia/core/shared/@theia/request';
18
+ import { inject, injectable } from '@theia/core/shared/inversify';
19
+ import { promises as fs, existsSync, mkdirSync } from 'fs';
19
20
  import * as os from 'os';
20
21
  import * as path from 'path';
21
22
  import * as url from 'url';
22
- import * as request from 'request';
23
-
24
23
  import { PluginDeployerResolver, PluginDeployerResolverContext } from '../../common';
25
24
 
26
25
  /**
@@ -33,10 +32,13 @@ export class HttpPluginDeployerResolver implements PluginDeployerResolver {
33
32
 
34
33
  private unpackedFolder: string;
35
34
 
35
+ @inject(RequestService)
36
+ protected readonly request: RequestService;
37
+
36
38
  constructor() {
37
39
  this.unpackedFolder = path.resolve(os.tmpdir(), 'http-remote');
38
- if (!fs.existsSync(this.unpackedFolder)) {
39
- fs.mkdirSync(this.unpackedFolder);
40
+ if (!existsSync(this.unpackedFolder)) {
41
+ mkdirSync(this.unpackedFolder);
40
42
  }
41
43
  }
42
44
 
@@ -46,39 +48,31 @@ export class HttpPluginDeployerResolver implements PluginDeployerResolver {
46
48
  async resolve(pluginResolverContext: PluginDeployerResolverContext): Promise<void> {
47
49
 
48
50
  // download the file
49
- return new Promise<void>((resolve, reject) => {
50
-
51
- // keep filename of the url
52
- const urlPath = pluginResolverContext.getOriginId();
53
- const link = url.parse(urlPath);
54
- if (!link.pathname) {
55
- reject(new Error('invalid link URI' + urlPath));
56
- return;
57
- }
58
-
59
- const dirname = path.dirname(link.pathname);
60
- const basename = path.basename(link.pathname);
61
- const filename = dirname.replace(/\W/g, '_') + ('-') + basename;
62
- const unpackedPath = path.resolve(this.unpackedFolder, path.basename(filename));
51
+ // keep filename of the url
52
+ const urlPath = pluginResolverContext.getOriginId();
53
+ const link = url.parse(urlPath);
54
+ if (!link.pathname) {
55
+ throw new Error('invalid link URI' + urlPath);
56
+ }
63
57
 
64
- const finish = () => {
65
- pluginResolverContext.addPlugin(pluginResolverContext.getOriginId(), unpackedPath);
66
- resolve();
67
- };
58
+ const dirname = path.dirname(link.pathname);
59
+ const basename = path.basename(link.pathname);
60
+ const filename = dirname.replace(/\W/g, '_') + ('-') + basename;
61
+ const unpackedPath = path.resolve(this.unpackedFolder, path.basename(filename));
68
62
 
63
+ try {
64
+ await fs.access(unpackedPath);
69
65
  // use of cache. If file is already there use it directly
70
- if (fs.existsSync(unpackedPath)) {
71
- finish();
72
- return;
73
- }
74
- const dest = fs.createWriteStream(unpackedPath);
66
+ return;
67
+ } catch { }
75
68
 
76
- dest.addListener('finish', finish);
77
- request.get(pluginResolverContext.getOriginId())
78
- .on('error', err => {
79
- reject(err);
80
- }).pipe(dest);
81
- });
69
+ const response = await this.request.request({ url: pluginResolverContext.getOriginId() });
70
+ if (RequestContext.isSuccess(response)) {
71
+ await fs.writeFile(unpackedPath, response.buffer);
72
+ pluginResolverContext.addPlugin(pluginResolverContext.getOriginId(), unpackedPath);
73
+ } else {
74
+ throw new Error(`Could not download the plugin from ${pluginResolverContext.getOriginId()}. HTTP status code: ${response.res.statusCode}`);
75
+ }
82
76
 
83
77
  }
84
78
 
@@ -62,7 +62,7 @@ export class PluginsKeyValueStorage {
62
62
 
63
63
  const data = await this.readFromFile(dataPath);
64
64
 
65
- if (value === undefined || value === {}) {
65
+ if (value === undefined) {
66
66
  delete data[key];
67
67
  } else {
68
68
  data[key] = value;
@@ -18,10 +18,11 @@ import * as theia from '@theia/plugin';
18
18
  import { RPCProtocol } from '../common/rpc-protocol';
19
19
  import { CommandRegistryImpl } from './command-registry';
20
20
  import { UriComponents } from '../common/uri-components';
21
- import { CommentThreadCollapsibleState, URI } from './types-impl';
21
+ import { CommentThreadCollapsibleState, CommentThreadState, URI } from './types-impl';
22
22
  import {
23
23
  Range,
24
24
  Comment,
25
+ CommentThreadState as CommentThreadStateModel,
25
26
  CommentThreadCollapsibleState as CommentThreadCollapsibleStateModel,
26
27
  CommentOptions
27
28
  } from '../common/plugin-api-rpc-model';
@@ -185,6 +186,7 @@ type CommentThreadModification = Partial<{
185
186
  contextValue: string | undefined,
186
187
  comments: theia.Comment[],
187
188
  collapsibleState: theia.CommentThreadCollapsibleState
189
+ state: theia.CommentThreadState
188
190
  canReply: boolean;
189
191
  }>;
190
192
 
@@ -276,6 +278,20 @@ export class ExtHostCommentThread implements theia.CommentThread, theia.Disposab
276
278
  this._onDidUpdateCommentThread.fire();
277
279
  }
278
280
 
281
+ private _state?: theia.CommentThreadState;
282
+
283
+ get state(): theia.CommentThreadState {
284
+ return this._state!;
285
+ }
286
+
287
+ set state(newState: theia.CommentThreadState) {
288
+ if (this._state !== newState) {
289
+ this._state = newState;
290
+ this.modifications.state = newState;
291
+ this._onDidUpdateCommentThread.fire();
292
+ }
293
+ }
294
+
279
295
  private localDisposables: Disposable[];
280
296
 
281
297
  private _isDisposed: boolean;
@@ -357,6 +373,9 @@ export class ExtHostCommentThread implements theia.CommentThread, theia.Disposab
357
373
  if (modified('collapsibleState')) {
358
374
  formattedModifications.collapseState = convertToCollapsibleState(this.collapseState);
359
375
  }
376
+ if (modified('state')) {
377
+ formattedModifications.state = convertToState(this._state);
378
+ }
360
379
  if (modified('canReply')) {
361
380
  formattedModifications.canReply = this.canReply;
362
381
  }
@@ -516,3 +535,15 @@ function convertToCollapsibleState(kind: theia.CommentThreadCollapsibleState | u
516
535
  }
517
536
  return CommentThreadCollapsibleStateModel.Collapsed;
518
537
  }
538
+
539
+ function convertToState(kind: theia.CommentThreadState | undefined): CommentThreadStateModel {
540
+ if (kind !== undefined) {
541
+ switch (kind) {
542
+ case CommentThreadState.Resolved:
543
+ return CommentThreadStateModel.Resolved;
544
+ case CommentThreadState.Unresolved:
545
+ return CommentThreadStateModel.Unresolved;
546
+ }
547
+ }
548
+ return CommentThreadStateModel.Unresolved;
549
+ }
@@ -0,0 +1,84 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2023 TypeFox 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 WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ /* eslint-disable @typescript-eslint/no-explicit-any */
18
+
19
+ import { nls } from '@theia/core';
20
+ import { Localization } from '@theia/core/lib/common/i18n/localization';
21
+ import { LocalizationExt, LocalizationMain, Plugin, PLUGIN_RPC_CONTEXT, StringDetails } from '../common';
22
+ import { LanguagePackBundle } from '../common/language-pack-service';
23
+ import { RPCProtocol } from '../common/rpc-protocol';
24
+ import { URI } from './types-impl';
25
+
26
+ export class LocalizationExtImpl implements LocalizationExt {
27
+
28
+ private readonly _proxy: LocalizationMain;
29
+ private currentLanguage?: string;
30
+ private isDefaultLanguage = true;
31
+ private readonly bundleCache = new Map<string, LanguagePackBundle | undefined>();
32
+
33
+ constructor(rpc: RPCProtocol) {
34
+ this._proxy = rpc.getProxy(PLUGIN_RPC_CONTEXT.LOCALIZATION_MAIN);
35
+ }
36
+
37
+ translateMessage(pluginId: string, details: StringDetails): string {
38
+ const { message, args, comment } = details;
39
+ if (this.isDefaultLanguage) {
40
+ return Localization.format(message, (args ?? {}));
41
+ }
42
+
43
+ let key = message;
44
+ if (comment && comment.length > 0) {
45
+ key += `/${Array.isArray(comment) ? comment.join() : comment}`;
46
+ }
47
+ const str = this.bundleCache.get(pluginId)?.contents[key];
48
+ return Localization.format(str ?? message, (args ?? {}));
49
+ }
50
+
51
+ getBundle(pluginId: string): { [key: string]: string } | undefined {
52
+ return this.bundleCache.get(pluginId)?.contents;
53
+ }
54
+
55
+ getBundleUri(pluginId: string): URI | undefined {
56
+ const uri = this.bundleCache.get(pluginId)?.uri;
57
+ return uri ? URI.parse(uri) : undefined;
58
+ }
59
+
60
+ async initializeLocalizedMessages(plugin: Plugin, currentLanguage: string): Promise<void> {
61
+ this.currentLanguage ??= currentLanguage;
62
+ this.isDefaultLanguage = this.currentLanguage === nls.defaultLocale;
63
+
64
+ if (this.isDefaultLanguage) {
65
+ return;
66
+ }
67
+
68
+ if (this.bundleCache.has(plugin.model.id)) {
69
+ return;
70
+ }
71
+
72
+ let bundle: LanguagePackBundle | undefined;
73
+
74
+ try {
75
+ bundle = await this._proxy.$fetchBundle(plugin.model.id);
76
+ } catch (e) {
77
+ console.error(`Failed to load translations for ${plugin.model.id}: ${e.message}`);
78
+ return;
79
+ }
80
+
81
+ this.bundleCache.set(plugin.model.id, bundle);
82
+ }
83
+
84
+ }
@@ -0,0 +1,108 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2023 STMicroelectronics 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 WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ /* eslint-disable @typescript-eslint/no-explicit-any */
17
+
18
+ import { Emitter } from '@theia/core/shared/vscode-languageserver-protocol';
19
+ import * as theia from '@theia/plugin';
20
+
21
+ import { OutputChannelRegistryMain, PluginInfo } from '../../common/plugin-api-rpc';
22
+ import { OutputChannelImpl } from './output-channel-item';
23
+ import { LogLevel } from '../types-impl';
24
+ import { isArray, isObject } from '@theia/core';
25
+
26
+ export class LogOutputChannelImpl extends OutputChannelImpl implements theia.LogOutputChannel {
27
+
28
+ readonly onDidChangeLogLevelEmitter: Emitter<theia.LogLevel> = new Emitter<theia.LogLevel>();
29
+ readonly onDidChangeLogLevel: theia.Event<theia.LogLevel> = this.onDidChangeLogLevelEmitter.event;
30
+ public logLevel: theia.LogLevel;
31
+
32
+ constructor(name: string, proxy: OutputChannelRegistryMain, pluginInfo: PluginInfo) {
33
+ super(name, proxy, pluginInfo);
34
+ this.setLogLevel(LogLevel.Info);
35
+ }
36
+
37
+ setLogLevel(level: theia.LogLevel): void {
38
+ if (this.logLevel !== level) {
39
+ this.logLevel = level;
40
+ this.onDidChangeLogLevelEmitter.fire(this.logLevel);
41
+ }
42
+ }
43
+
44
+ getLogLevel(): theia.LogLevel {
45
+ return this.logLevel;
46
+ }
47
+
48
+ override append(value: string): void {
49
+ super.validate();
50
+ this.info(value);
51
+ }
52
+
53
+ override appendLine(value: string): void {
54
+ super.validate();
55
+ this.append(value + '\n');
56
+ }
57
+
58
+ override dispose(): void {
59
+ super.dispose();
60
+ this.onDidChangeLogLevelEmitter.dispose();
61
+ }
62
+
63
+ protected log(level: theia.LogLevel, message: string): void {
64
+ super.validate();
65
+ if (this.checkLogLevel(level)) {
66
+ const now = new Date();
67
+ const eol = message.endsWith('\n') ? '' : '\n';
68
+ const logMessage = `${now.toISOString()} [${LogLevel[level]}] ${message}${eol}`;
69
+ this.proxy.$append(this.name, logMessage, this.pluginInfo);
70
+ }
71
+ }
72
+
73
+ private checkLogLevel(level: theia.LogLevel): boolean {
74
+ return this.logLevel <= level;
75
+ }
76
+
77
+ trace(message: string, ...args: any[]): void {
78
+ this.log(LogLevel.Trace, this.format(message, args));
79
+ }
80
+
81
+ debug(message: string, ...args: any[]): void {
82
+ this.log(LogLevel.Debug, this.format(message, args));
83
+ }
84
+
85
+ info(message: string, ...args: any[]): void {
86
+ this.log(LogLevel.Info, this.format(message, args));
87
+ }
88
+
89
+ warn(message: string, ...args: any[]): void {
90
+ this.log(LogLevel.Warning, this.format(message, args));
91
+ }
92
+
93
+ error(errorMsg: string | Error, ...args: any[]): void {
94
+ if (errorMsg instanceof Error) {
95
+ this.log(LogLevel.Error, this.format(errorMsg.stack || errorMsg.message, args));
96
+ } else {
97
+ this.log(LogLevel.Error, this.format(errorMsg, args));
98
+ }
99
+ }
100
+
101
+ private format(message: string, args: any[]): string {
102
+ if (args.length > 0) {
103
+ return `${message} ${args.map((arg: any) => isObject(arg) || isArray(arg) ? JSON.stringify(arg) : arg).join(' ')}`;
104
+ }
105
+ return message;
106
+ }
107
+
108
+ }
@@ -20,7 +20,7 @@ export class OutputChannelImpl implements theia.OutputChannel {
20
20
 
21
21
  private disposed: boolean;
22
22
 
23
- constructor(readonly name: string, private proxy: OutputChannelRegistryMain, private readonly pluginInfo: PluginInfo) {
23
+ constructor(readonly name: string, protected readonly proxy: OutputChannelRegistryMain, protected readonly pluginInfo: PluginInfo) {
24
24
  }
25
25
 
26
26
  dispose(): void {
@@ -65,7 +65,7 @@ export class OutputChannelImpl implements theia.OutputChannel {
65
65
  this.proxy.$close(this.name);
66
66
  }
67
67
 
68
- private validate(): void {
68
+ protected validate(): void {
69
69
  if (this.disposed) {
70
70
  throw new Error('Channel has been closed');
71
71
  }