@theia/plugin-ext 1.73.0-next.9 → 1.73.1
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.
- package/lib/common/lm-tool-protocol.d.ts +58 -0
- package/lib/common/lm-tool-protocol.d.ts.map +1 -0
- package/lib/common/lm-tool-protocol.js +38 -0
- package/lib/common/lm-tool-protocol.js.map +1 -0
- package/lib/common/lm-tool-protocol.spec.d.ts +2 -0
- package/lib/common/lm-tool-protocol.spec.d.ts.map +1 -0
- package/lib/common/lm-tool-protocol.spec.js +80 -0
- package/lib/common/lm-tool-protocol.spec.js.map +1 -0
- package/lib/common/plugin-api-rpc-model.d.ts +4 -0
- package/lib/common/plugin-api-rpc-model.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc-model.js.map +1 -1
- package/lib/common/plugin-api-rpc.d.ts +6 -1
- package/lib/common/plugin-api-rpc.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc.js +4 -2
- package/lib/common/plugin-api-rpc.js.map +1 -1
- package/lib/common/plugin-protocol.d.ts +8 -0
- package/lib/common/plugin-protocol.d.ts.map +1 -1
- package/lib/common/plugin-protocol.js.map +1 -1
- package/lib/hosted/node/hosted-plugin-localization-service.d.ts +2 -1
- package/lib/hosted/node/hosted-plugin-localization-service.d.ts.map +1 -1
- package/lib/hosted/node/hosted-plugin-localization-service.js +6 -1
- package/lib/hosted/node/hosted-plugin-localization-service.js.map +1 -1
- package/lib/hosted/node/plugin-deployer-handler-impl.js +4 -3
- package/lib/hosted/node/plugin-deployer-handler-impl.js.map +1 -1
- package/lib/hosted/node/plugin-host-module.d.ts.map +1 -1
- package/lib/hosted/node/plugin-host-module.js +2 -0
- package/lib/hosted/node/plugin-host-module.js.map +1 -1
- package/lib/hosted/node/scanners/scanner-theia.d.ts +2 -0
- package/lib/hosted/node/scanners/scanner-theia.d.ts.map +1 -1
- package/lib/hosted/node/scanners/scanner-theia.js +55 -49
- package/lib/hosted/node/scanners/scanner-theia.js.map +1 -1
- package/lib/main/browser/comments/comment-thread-widget.d.ts +3 -3
- package/lib/main/browser/comments/comment-thread-widget.d.ts.map +1 -1
- package/lib/main/browser/comments/comment-thread-widget.js.map +1 -1
- package/lib/main/browser/custom-editors/custom-editor-opener.d.ts.map +1 -1
- package/lib/main/browser/custom-editors/custom-editor-opener.js +1 -0
- package/lib/main/browser/custom-editors/custom-editor-opener.js.map +1 -1
- package/lib/main/browser/custom-editors/custom-editor-widget.d.ts +1 -0
- package/lib/main/browser/custom-editors/custom-editor-widget.d.ts.map +1 -1
- package/lib/main/browser/custom-editors/custom-editor-widget.js +3 -0
- package/lib/main/browser/custom-editors/custom-editor-widget.js.map +1 -1
- package/lib/main/browser/custom-editors/custom-editors-main.d.ts.map +1 -1
- package/lib/main/browser/custom-editors/custom-editors-main.js +2 -0
- package/lib/main/browser/custom-editors/custom-editors-main.js.map +1 -1
- package/lib/main/browser/debug/debug-main.d.ts +1 -11
- package/lib/main/browser/debug/debug-main.d.ts.map +1 -1
- package/lib/main/browser/debug/debug-main.js +3 -24
- package/lib/main/browser/debug/debug-main.js.map +1 -1
- package/lib/main/browser/debug/plugin-debug-service.d.ts +2 -1
- package/lib/main/browser/debug/plugin-debug-service.d.ts.map +1 -1
- package/lib/main/browser/debug/plugin-debug-service.js +8 -3
- package/lib/main/browser/debug/plugin-debug-service.js.map +1 -1
- package/lib/main/browser/debug/plugin-debug-session-factory.d.ts +7 -44
- package/lib/main/browser/debug/plugin-debug-session-factory.d.ts.map +1 -1
- package/lib/main/browser/debug/plugin-debug-session-factory.js +29 -35
- package/lib/main/browser/debug/plugin-debug-session-factory.js.map +1 -1
- package/lib/main/browser/languages-main.d.ts +6 -1
- package/lib/main/browser/languages-main.d.ts.map +1 -1
- package/lib/main/browser/languages-main.js +39 -2
- package/lib/main/browser/languages-main.js.map +1 -1
- package/lib/main/browser/lm-main.js +2 -2
- package/lib/main/browser/lm-main.js.map +1 -1
- package/lib/main/browser/lm-tool-main.d.ts +14 -0
- package/lib/main/browser/lm-tool-main.d.ts.map +1 -0
- package/lib/main/browser/lm-tool-main.js +101 -0
- package/lib/main/browser/lm-tool-main.js.map +1 -0
- package/lib/main/browser/lm-tool-main.spec.d.ts +2 -0
- package/lib/main/browser/lm-tool-main.spec.d.ts.map +1 -0
- package/lib/main/browser/lm-tool-main.spec.js +100 -0
- package/lib/main/browser/lm-tool-main.spec.js.map +1 -0
- package/lib/main/browser/main-context.d.ts.map +1 -1
- package/lib/main/browser/main-context.js +3 -0
- package/lib/main/browser/main-context.js.map +1 -1
- package/lib/main/browser/main-file-system-event-service.d.ts +21 -4
- package/lib/main/browser/main-file-system-event-service.d.ts.map +1 -1
- package/lib/main/browser/main-file-system-event-service.js +47 -17
- package/lib/main/browser/main-file-system-event-service.js.map +1 -1
- package/lib/main/browser/main-file-system-event-service.spec.js +61 -26
- package/lib/main/browser/main-file-system-event-service.spec.js.map +1 -1
- package/lib/main/browser/notebooks/renderers/cell-output-webview.d.ts +2 -1
- package/lib/main/browser/notebooks/renderers/cell-output-webview.d.ts.map +1 -1
- package/lib/main/browser/notebooks/renderers/cell-output-webview.js +11 -5
- package/lib/main/browser/notebooks/renderers/cell-output-webview.js.map +1 -1
- package/lib/main/browser/plugin-contribution-handler.d.ts +2 -0
- package/lib/main/browser/plugin-contribution-handler.d.ts.map +1 -1
- package/lib/main/browser/plugin-contribution-handler.js +10 -4
- package/lib/main/browser/plugin-contribution-handler.js.map +1 -1
- package/lib/main/browser/view/plugin-view-registry.d.ts +1 -0
- package/lib/main/browser/view/plugin-view-registry.d.ts.map +1 -1
- package/lib/main/browser/view/plugin-view-registry.js +28 -3
- package/lib/main/browser/view/plugin-view-registry.js.map +1 -1
- package/lib/main/browser/view/plugin-view-registry.spec.js +40 -0
- package/lib/main/browser/view/plugin-view-registry.spec.js.map +1 -1
- package/lib/main/browser/webview/webview-resource-cache.d.ts +2 -0
- package/lib/main/browser/webview/webview-resource-cache.d.ts.map +1 -1
- package/lib/main/browser/webview/webview-resource-cache.js +7 -1
- package/lib/main/browser/webview/webview-resource-cache.js.map +1 -1
- package/lib/main/browser/webview/webview.d.ts +2 -1
- package/lib/main/browser/webview/webview.d.ts.map +1 -1
- package/lib/main/browser/webview/webview.js +7 -1
- package/lib/main/browser/webview/webview.js.map +1 -1
- package/lib/main/node/plugin-deployer-impl.js +2 -1
- package/lib/main/node/plugin-deployer-impl.js.map +1 -1
- package/lib/plugin/languages/diagnostics.d.ts +4 -1
- package/lib/plugin/languages/diagnostics.d.ts.map +1 -1
- package/lib/plugin/languages/diagnostics.js +22 -9
- package/lib/plugin/languages/diagnostics.js.map +1 -1
- package/lib/plugin/languages/multi-document-highlight.d.ts +14 -0
- package/lib/plugin/languages/multi-document-highlight.d.ts.map +1 -0
- package/lib/plugin/languages/multi-document-highlight.js +60 -0
- package/lib/plugin/languages/multi-document-highlight.js.map +1 -0
- package/lib/plugin/languages.d.ts +3 -1
- package/lib/plugin/languages.d.ts.map +1 -1
- package/lib/plugin/languages.js +11 -0
- package/lib/plugin/languages.js.map +1 -1
- package/lib/plugin/lm-tool-ext.d.ts +28 -0
- package/lib/plugin/lm-tool-ext.d.ts.map +1 -0
- package/lib/plugin/lm-tool-ext.js +171 -0
- package/lib/plugin/lm-tool-ext.js.map +1 -0
- package/lib/plugin/lm-tool-ext.spec.d.ts +2 -0
- package/lib/plugin/lm-tool-ext.spec.d.ts.map +1 -0
- package/lib/plugin/lm-tool-ext.spec.js +124 -0
- package/lib/plugin/lm-tool-ext.spec.js.map +1 -0
- package/lib/plugin/plugin-context.d.ts.map +1 -1
- package/lib/plugin/plugin-context.js +10 -11
- package/lib/plugin/plugin-context.js.map +1 -1
- package/lib/plugin/types-impl.d.ts +0 -9
- package/lib/plugin/types-impl.d.ts.map +1 -1
- package/lib/plugin/types-impl.js +22 -15
- package/lib/plugin/types-impl.js.map +1 -1
- package/package.json +32 -31
- package/src/common/lm-tool-protocol.spec.ts +89 -0
- package/src/common/lm-tool-protocol.ts +102 -0
- package/src/common/plugin-api-rpc-model.ts +5 -0
- package/src/common/plugin-api-rpc.ts +9 -2
- package/src/common/plugin-protocol.ts +9 -0
- package/src/hosted/node/hosted-plugin-localization-service.ts +6 -3
- package/src/hosted/node/plugin-deployer-handler-impl.ts +5 -5
- package/src/hosted/node/plugin-host-module.ts +2 -0
- package/src/hosted/node/scanners/scanner-theia.ts +54 -50
- package/src/main/browser/comments/comment-thread-widget.tsx +5 -5
- package/src/main/browser/custom-editors/custom-editor-opener.tsx +1 -0
- package/src/main/browser/custom-editors/custom-editor-widget.ts +4 -0
- package/src/main/browser/custom-editors/custom-editors-main.ts +2 -0
- package/src/main/browser/debug/debug-main.ts +3 -45
- package/src/main/browser/debug/plugin-debug-service.ts +7 -5
- package/src/main/browser/debug/plugin-debug-session-factory.ts +25 -71
- package/src/main/browser/languages-main.ts +49 -4
- package/src/main/browser/lm-main.ts +2 -2
- package/src/main/browser/lm-tool-main.spec.ts +126 -0
- package/src/main/browser/lm-tool-main.ts +116 -0
- package/src/main/browser/main-context.ts +4 -0
- package/src/main/browser/main-file-system-event-service.spec.ts +76 -29
- package/src/main/browser/main-file-system-event-service.ts +46 -16
- package/src/main/browser/notebooks/renderers/cell-output-webview.tsx +11 -7
- package/src/main/browser/plugin-contribution-handler.ts +8 -4
- package/src/main/browser/plugin-ext-widget.tsx +1 -1
- package/src/main/browser/view/plugin-view-registry.spec.ts +69 -1
- package/src/main/browser/view/plugin-view-registry.ts +30 -3
- package/src/main/browser/webview/webview-resource-cache.ts +6 -2
- package/src/main/browser/webview/webview.ts +6 -3
- package/src/main/node/plugin-deployer-impl.ts +2 -2
- package/src/plugin/languages/diagnostics.ts +28 -10
- package/src/plugin/languages/multi-document-highlight.ts +75 -0
- package/src/plugin/languages.ts +20 -0
- package/src/plugin/lm-tool-ext.spec.ts +152 -0
- package/src/plugin/lm-tool-ext.ts +197 -0
- package/src/plugin/plugin-context.ts +11 -11
- package/src/plugin/types-impl.ts +22 -15
|
@@ -14,53 +14,32 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
+
import { injectable, inject, interfaces } from '@theia/core/shared/inversify';
|
|
17
18
|
import { DefaultDebugSessionFactory } from '@theia/debug/lib/browser/debug-session-contribution';
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { BreakpointManager } from '@theia/debug/lib/browser/breakpoint/breakpoint-manager';
|
|
21
|
-
import { LabelProvider } from '@theia/core/lib/browser/label-provider';
|
|
22
|
-
import { MessageClient } from '@theia/core/lib/common/message-service-protocol';
|
|
23
|
-
import { OutputChannelManager } from '@theia/output/lib/browser/output-channel';
|
|
24
|
-
import { DebugPreferences } from '@theia/debug/lib/common/debug-preferences';
|
|
25
|
-
import { DebugConfigurationSessionOptions, TestRunReference } from '@theia/debug/lib/browser/debug-session-options';
|
|
26
|
-
import { DebugSession } from '@theia/debug/lib/browser/debug-session';
|
|
19
|
+
import { DebugConfigurationSessionOptions } from '@theia/debug/lib/browser/debug-session-options';
|
|
20
|
+
import { DebugSession, DebugSessionData } from '@theia/debug/lib/browser/debug-session';
|
|
27
21
|
import { DebugSessionConnection } from '@theia/debug/lib/browser/debug-session-connection';
|
|
28
22
|
import { TerminalWidgetOptions, TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
|
|
29
23
|
import { TerminalOptionsExt } from '../../../common/plugin-api-rpc';
|
|
30
|
-
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
31
|
-
import { DebugContribution } from '@theia/debug/lib/browser/debug-contribution';
|
|
32
|
-
import { ContributionProvider } from '@theia/core/lib/common/contribution-provider';
|
|
33
|
-
import { WorkspaceService } from '@theia/workspace/lib/browser';
|
|
34
24
|
import { PluginChannel } from '../../../common/connection';
|
|
35
|
-
import { TestService } from '@theia/test/lib/browser/test-service';
|
|
36
|
-
import { DebugSessionManager } from '@theia/debug/lib/browser/debug-session-manager';
|
|
37
|
-
import { CommandService } from '@theia/core';
|
|
38
25
|
|
|
26
|
+
export const PluginTerminalOptionsExt = Symbol('PluginTerminalOptionsExt');
|
|
27
|
+
|
|
28
|
+
@injectable()
|
|
39
29
|
export class PluginDebugSession extends DebugSession {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
protected override readonly terminalServer: TerminalService,
|
|
49
|
-
protected override readonly editorManager: EditorManager,
|
|
50
|
-
protected override readonly breakpoints: BreakpointManager,
|
|
51
|
-
protected override readonly labelProvider: LabelProvider,
|
|
52
|
-
protected override readonly messages: MessageClient,
|
|
53
|
-
protected override readonly fileService: FileService,
|
|
54
|
-
protected readonly terminalOptionsExt: TerminalOptionsExt | undefined,
|
|
55
|
-
protected override readonly debugContributionProvider: ContributionProvider<DebugContribution>,
|
|
56
|
-
protected override readonly workspaceService: WorkspaceService,
|
|
57
|
-
debugPreferences: DebugPreferences,
|
|
58
|
-
protected override readonly commandService: CommandService) {
|
|
59
|
-
super(id, options, parentSession, testService, testRun, sessionManager, connection, terminalServer, editorManager, breakpoints,
|
|
60
|
-
labelProvider, messages, fileService, debugContributionProvider,
|
|
61
|
-
workspaceService, debugPreferences, commandService);
|
|
30
|
+
|
|
31
|
+
static override createContainer(
|
|
32
|
+
parent: interfaces.Container, data: DebugSessionData, connection: DebugSessionConnection, terminalOptionsExt?: TerminalOptionsExt
|
|
33
|
+
): interfaces.Container {
|
|
34
|
+
const child = DebugSession.createContainer(parent, data, connection);
|
|
35
|
+
child.rebind(DebugSession).to(PluginDebugSession);
|
|
36
|
+
child.bind(PluginTerminalOptionsExt).toConstantValue(terminalOptionsExt);
|
|
37
|
+
return child;
|
|
62
38
|
}
|
|
63
39
|
|
|
40
|
+
@inject(PluginTerminalOptionsExt)
|
|
41
|
+
protected readonly terminalOptionsExt: TerminalOptionsExt | undefined;
|
|
42
|
+
|
|
64
43
|
protected override async doCreateTerminal(terminalWidgetOptions: TerminalWidgetOptions): Promise<TerminalWidget> {
|
|
65
44
|
terminalWidgetOptions = Object.assign({}, terminalWidgetOptions, this.terminalOptionsExt);
|
|
66
45
|
return super.doCreateTerminal(terminalWidgetOptions);
|
|
@@ -73,49 +52,24 @@ export class PluginDebugSession extends DebugSession {
|
|
|
73
52
|
*/
|
|
74
53
|
export class PluginDebugSessionFactory extends DefaultDebugSessionFactory {
|
|
75
54
|
constructor(
|
|
76
|
-
protected override readonly terminalService: TerminalService,
|
|
77
|
-
protected override readonly editorManager: EditorManager,
|
|
78
|
-
protected override readonly breakpoints: BreakpointManager,
|
|
79
|
-
protected override readonly labelProvider: LabelProvider,
|
|
80
|
-
protected override readonly messages: MessageClient,
|
|
81
|
-
protected override readonly outputChannelManager: OutputChannelManager,
|
|
82
|
-
protected override readonly debugPreferences: DebugPreferences,
|
|
83
55
|
protected readonly connectionFactory: (sessionId: string) => Promise<PluginChannel>,
|
|
84
|
-
protected override readonly fileService: FileService,
|
|
85
56
|
protected readonly terminalOptionsExt: TerminalOptionsExt | undefined,
|
|
86
|
-
|
|
87
|
-
protected override readonly testService: TestService,
|
|
88
|
-
protected override readonly workspaceService: WorkspaceService,
|
|
89
|
-
protected override readonly commandService: CommandService,
|
|
57
|
+
container: interfaces.Container,
|
|
90
58
|
) {
|
|
91
|
-
super();
|
|
59
|
+
super(container);
|
|
92
60
|
}
|
|
93
61
|
|
|
94
|
-
override
|
|
62
|
+
override createSession(sessionId: string, options: DebugConfigurationSessionOptions, parentSession?: DebugSession): DebugSession {
|
|
95
63
|
const connection = new DebugSessionConnection(
|
|
96
64
|
sessionId,
|
|
97
65
|
this.connectionFactory,
|
|
98
66
|
this.getTraceOutputChannel());
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
sessionId,
|
|
67
|
+
const data: DebugSessionData = {
|
|
68
|
+
id: sessionId,
|
|
102
69
|
options,
|
|
103
70
|
parentSession,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
connection,
|
|
108
|
-
this.terminalService,
|
|
109
|
-
this.editorManager,
|
|
110
|
-
this.breakpoints,
|
|
111
|
-
this.labelProvider,
|
|
112
|
-
this.messages,
|
|
113
|
-
this.fileService,
|
|
114
|
-
this.terminalOptionsExt,
|
|
115
|
-
this.debugContributionProvider,
|
|
116
|
-
this.workspaceService,
|
|
117
|
-
this.debugPreferences,
|
|
118
|
-
this.commandService
|
|
119
|
-
);
|
|
71
|
+
};
|
|
72
|
+
const child = PluginDebugSession.createContainer(this.container, data, connection, this.terminalOptionsExt);
|
|
73
|
+
return child.get(DebugSession);
|
|
120
74
|
}
|
|
121
75
|
}
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
IdentifiableInlineCompletions,
|
|
40
40
|
HoverWithId
|
|
41
41
|
} from '../../common/plugin-api-rpc';
|
|
42
|
-
import { injectable, inject } from '@theia/core/shared/inversify';
|
|
42
|
+
import { injectable, inject, named } from '@theia/core/shared/inversify';
|
|
43
43
|
import {
|
|
44
44
|
SerializedDocumentFilter, MarkerData, Range, RelatedInformation,
|
|
45
45
|
MarkerSeverity, DocumentLink, WorkspaceSymbolParams, CodeAction, CompletionDto,
|
|
@@ -80,12 +80,14 @@ import {
|
|
|
80
80
|
EvaluatableExpressionProvider,
|
|
81
81
|
InlineValue,
|
|
82
82
|
InlineValueContext,
|
|
83
|
-
InlineValuesProvider
|
|
83
|
+
InlineValuesProvider,
|
|
84
|
+
MultiDocumentHighlightProvider
|
|
84
85
|
} from '@theia/monaco-editor-core/esm/vs/editor/common/languages';
|
|
85
86
|
import { ITextModel } from '@theia/monaco-editor-core/esm/vs/editor/common/model';
|
|
86
87
|
import { CodeActionTriggerKind } from '../../plugin/types-impl';
|
|
87
88
|
import { IReadonlyVSDataTransfer } from '@theia/monaco-editor-core/esm/vs/base/common/dataTransfer';
|
|
88
89
|
import { FileUploadService } from '@theia/filesystem/lib/common/upload/file-upload';
|
|
90
|
+
import { ILogger } from '@theia/core';
|
|
89
91
|
|
|
90
92
|
@injectable()
|
|
91
93
|
export class LanguagesMainImpl implements LanguagesMain, Disposable {
|
|
@@ -108,6 +110,9 @@ export class LanguagesMainImpl implements LanguagesMain, Disposable {
|
|
|
108
110
|
@inject(FileUploadService)
|
|
109
111
|
protected readonly fileUploadService: FileUploadService;
|
|
110
112
|
|
|
113
|
+
@inject(ILogger) @named('plugin-ext:LanguagesMainImpl')
|
|
114
|
+
protected readonly logger: ILogger;
|
|
115
|
+
|
|
111
116
|
private readonly proxy: LanguagesExt;
|
|
112
117
|
private readonly services = new Map<number, Disposable>();
|
|
113
118
|
private readonly toDispose = new DisposableCollection();
|
|
@@ -349,7 +354,8 @@ export class LanguagesMainImpl implements LanguagesMain, Disposable {
|
|
|
349
354
|
|
|
350
355
|
protected createHoverProvider(handle: number): monaco.languages.HoverProvider {
|
|
351
356
|
return {
|
|
352
|
-
provideHover: (model, position, token) =>
|
|
357
|
+
provideHover: (model, position, token, context) =>
|
|
358
|
+
this.provideHover(handle, model, position, token, context as monaco.languages.HoverContext<HoverWithId> | undefined)
|
|
353
359
|
};
|
|
354
360
|
}
|
|
355
361
|
|
|
@@ -445,6 +451,45 @@ export class LanguagesMainImpl implements LanguagesMain, Disposable {
|
|
|
445
451
|
});
|
|
446
452
|
}
|
|
447
453
|
|
|
454
|
+
$registerMultiDocumentHighlightProvider(handle: number, _pluginInfo: PluginInfo, selector: SerializedDocumentFilter[]): void {
|
|
455
|
+
const languageSelector = this.toLanguageSelector(selector);
|
|
456
|
+
const multiDocumentHighlightProvider = this.createMultiDocumentHighlightProvider(handle, languageSelector);
|
|
457
|
+
this.register(handle,
|
|
458
|
+
StandaloneServices.get(ILanguageFeaturesService).multiDocumentHighlightProvider.register(languageSelector, multiDocumentHighlightProvider));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
protected createMultiDocumentHighlightProvider(handle: number, selector: LanguageSelector): MultiDocumentHighlightProvider {
|
|
462
|
+
return {
|
|
463
|
+
selector,
|
|
464
|
+
provideMultiDocumentHighlights: (model, position, otherModels, token) =>
|
|
465
|
+
// @monaco-uplift: cast due to ITextModel enum incompatibility between internal and standalone API types
|
|
466
|
+
this.provideMultiDocumentHighlights(handle, model as unknown as monaco.editor.ITextModel, position,
|
|
467
|
+
otherModels as unknown as monaco.editor.ITextModel[], token)
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
protected provideMultiDocumentHighlights(
|
|
472
|
+
handle: number, model: monaco.editor.ITextModel, position: monaco.Position,
|
|
473
|
+
otherModels: monaco.editor.ITextModel[], token: monaco.CancellationToken
|
|
474
|
+
): monaco.languages.ProviderResult<Map<monaco.Uri, monaco.languages.DocumentHighlight[]>> {
|
|
475
|
+
const otherResources = otherModels.map(m => m.uri);
|
|
476
|
+
return this.proxy.$provideMultiDocumentHighlights(handle, model.uri, position, otherResources, token).then(result => {
|
|
477
|
+
if (!result) {
|
|
478
|
+
return undefined;
|
|
479
|
+
}
|
|
480
|
+
const map = new Map<monaco.Uri, monaco.languages.DocumentHighlight[]>();
|
|
481
|
+
for (const entry of result) {
|
|
482
|
+
const uri = monaco.Uri.revive(entry.uri);
|
|
483
|
+
const highlights: monaco.languages.DocumentHighlight[] = entry.highlights.map(item => ({
|
|
484
|
+
...item,
|
|
485
|
+
kind: item.kind ?? monaco.languages.DocumentHighlightKind.Text
|
|
486
|
+
}));
|
|
487
|
+
map.set(uri, highlights);
|
|
488
|
+
}
|
|
489
|
+
return map;
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
448
493
|
$registerWorkspaceSymbolProvider(handle: number, pluginInfo: PluginInfo): void {
|
|
449
494
|
const workspaceSymbolProvider = this.createWorkspaceSymbolProvider(handle);
|
|
450
495
|
this.register(handle, this.monacoLanguages.registerWorkspaceSymbolProvider(workspaceSymbolProvider));
|
|
@@ -958,7 +1003,7 @@ export class LanguagesMainImpl implements LanguagesMain, Disposable {
|
|
|
958
1003
|
dispose: () => this.proxy.$releaseCodeActions(handle, actions.map(a => a.cacheId))
|
|
959
1004
|
};
|
|
960
1005
|
} catch (e) {
|
|
961
|
-
|
|
1006
|
+
this.logger.error(e);
|
|
962
1007
|
return undefined;
|
|
963
1008
|
}
|
|
964
1009
|
}
|
|
@@ -64,7 +64,7 @@ export class McpServerDefinitionRegistryMainImpl implements McpServerDefinitionR
|
|
|
64
64
|
try {
|
|
65
65
|
const definitions = await this.$getServerDefinitions(handle);
|
|
66
66
|
for (const definition of definitions) {
|
|
67
|
-
this.mcpServerManager.removeServer(definition.label);
|
|
67
|
+
await this.mcpServerManager.removeServer(definition.label);
|
|
68
68
|
}
|
|
69
69
|
} catch (error) {
|
|
70
70
|
console.error('Error getting server definitions for removal:', error);
|
|
@@ -107,7 +107,7 @@ export class McpServerDefinitionRegistryMainImpl implements McpServerDefinitionR
|
|
|
107
107
|
|
|
108
108
|
for (const definition of definitions) {
|
|
109
109
|
const mcpServerDescription = this.convertToMcpServerDescription(handle, definition);
|
|
110
|
-
this.mcpServerManager.addOrUpdateServer(mcpServerDescription);
|
|
110
|
+
await this.mcpServerManager.addOrUpdateServer(mcpServerDescription);
|
|
111
111
|
}
|
|
112
112
|
} catch (error) {
|
|
113
113
|
console.error('Error loading MCP server definitions:', error);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH 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 { LanguageModelToolsMainImpl } from './lm-tool-main';
|
|
19
|
+
import {
|
|
20
|
+
ToolResultTextPartDto,
|
|
21
|
+
ToolResultDataPartDto,
|
|
22
|
+
ToolResultPromptTsxPartDto,
|
|
23
|
+
ToolResultUnknownPartDto,
|
|
24
|
+
ToolResultPartDto,
|
|
25
|
+
uint8ArrayToBase64,
|
|
26
|
+
} from '../../common/lm-tool-protocol';
|
|
27
|
+
import { ToolCallContentResult } from '@theia/ai-core/lib/common/language-model';
|
|
28
|
+
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
|
|
29
|
+
|
|
30
|
+
// Access private methods for testing
|
|
31
|
+
interface LmToolMainInternals {
|
|
32
|
+
convertDtoToToolCallResult(part: ToolResultPartDto): ToolCallContentResult;
|
|
33
|
+
convertDataPart(base64: string, mimeType: string): ToolCallContentResult;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createInstance(): LmToolMainInternals {
|
|
37
|
+
const impl = Object.create(LanguageModelToolsMainImpl.prototype) as LanguageModelToolsMainImpl;
|
|
38
|
+
return impl as unknown as LmToolMainInternals;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe('LanguageModelToolsMainImpl - DTO to ToolCallContentResult conversion', () => {
|
|
42
|
+
let instance: LmToolMainInternals;
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
instance = createInstance();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('convertDtoToToolCallResult', () => {
|
|
49
|
+
it('should convert text part DTO to ToolCallTextResult', () => {
|
|
50
|
+
const part: ToolResultTextPartDto = { type: 'text', value: 'hello world' };
|
|
51
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
52
|
+
expect(result).to.deep.equal({ type: 'text', text: 'hello world' });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should convert prompt-tsx part DTO to ToolCallTextResult with JSON', () => {
|
|
56
|
+
const part: ToolResultPromptTsxPartDto = { type: 'prompt-tsx', value: { foo: 'bar' } };
|
|
57
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
58
|
+
expect(result).to.deep.equal({ type: 'text', text: '{"foo":"bar"}' });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should convert unknown part DTO to ToolCallTextResult', () => {
|
|
62
|
+
const part: ToolResultUnknownPartDto = { type: 'unknown', json: '{"custom":"data"}' };
|
|
63
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
64
|
+
expect(result).to.deep.equal({ type: 'text', text: '{"custom":"data"}' });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should convert data part with image mimeType to ToolCallImageResult', () => {
|
|
68
|
+
const base64 = btoa('fake-image-data');
|
|
69
|
+
const part: ToolResultDataPartDto = { type: 'data', base64, mimeType: 'image/png' };
|
|
70
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
71
|
+
expect(result).to.deep.equal({ type: 'image', base64data: base64, mimeType: 'image/png' });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should convert data part with audio mimeType to ToolCallAudioResult', () => {
|
|
75
|
+
const base64 = btoa('fake-audio-data');
|
|
76
|
+
const part: ToolResultDataPartDto = { type: 'data', base64, mimeType: 'audio/mp3' };
|
|
77
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
78
|
+
expect(result).to.deep.equal({ type: 'audio', data: base64, mimeType: 'audio/mp3' });
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should convert data part with text/plain mimeType to ToolCallTextResult', () => {
|
|
82
|
+
const base64 = btoa('plain text content');
|
|
83
|
+
const part: ToolResultDataPartDto = { type: 'data', base64, mimeType: 'text/plain' };
|
|
84
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
85
|
+
expect(result).to.deep.equal({ type: 'text', text: 'plain text content' });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should convert data part with application/json mimeType to ToolCallTextResult', () => {
|
|
89
|
+
const jsonString = '{"key":"value"}';
|
|
90
|
+
const base64 = btoa(jsonString);
|
|
91
|
+
const part: ToolResultDataPartDto = { type: 'data', base64, mimeType: 'application/json' };
|
|
92
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
93
|
+
expect(result).to.deep.equal({ type: 'text', text: jsonString });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should convert data part with text/x-json mimeType to ToolCallTextResult', () => {
|
|
97
|
+
const jsonString = '{"data":123}';
|
|
98
|
+
const base64 = btoa(jsonString);
|
|
99
|
+
const part: ToolResultDataPartDto = { type: 'data', base64, mimeType: 'text/x-json' };
|
|
100
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
101
|
+
expect(result).to.deep.equal({ type: 'text', text: jsonString });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should convert data part with image/jpeg mimeType to ToolCallImageResult', () => {
|
|
105
|
+
const base64 = btoa('jpeg-data');
|
|
106
|
+
const part: ToolResultDataPartDto = { type: 'data', base64, mimeType: 'image/jpeg' };
|
|
107
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
108
|
+
expect(result).to.deep.equal({ type: 'image', base64data: base64, mimeType: 'image/jpeg' });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should convert data part with audio/wav mimeType to ToolCallAudioResult', () => {
|
|
112
|
+
const base64 = btoa('wav-data');
|
|
113
|
+
const part: ToolResultDataPartDto = { type: 'data', base64, mimeType: 'audio/wav' };
|
|
114
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
115
|
+
expect(result).to.deep.equal({ type: 'audio', data: base64, mimeType: 'audio/wav' });
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should correctly decode UTF-8 text from base64 data part', () => {
|
|
119
|
+
const utf8Text = 'café 日本語';
|
|
120
|
+
const base64 = uint8ArrayToBase64(BinaryBuffer.fromString(utf8Text).buffer);
|
|
121
|
+
const part: ToolResultDataPartDto = { type: 'data', base64, mimeType: 'text/plain' };
|
|
122
|
+
const result = instance.convertDtoToToolCallResult(part);
|
|
123
|
+
expect(result).to.deep.equal({ type: 'text', text: utf8Text });
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource
|
|
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 { interfaces } from '@theia/core/shared/inversify';
|
|
18
|
+
import { RPCProtocol } from '../../common/rpc-protocol';
|
|
19
|
+
import {
|
|
20
|
+
LanguageModelToolsMain,
|
|
21
|
+
LanguageModelToolsExt,
|
|
22
|
+
LanguageModelToolDto,
|
|
23
|
+
ToolResultPartDto,
|
|
24
|
+
isToolInvocationError,
|
|
25
|
+
base64ToUint8Array,
|
|
26
|
+
} from '../../common/lm-tool-protocol';
|
|
27
|
+
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
|
|
28
|
+
import { MAIN_RPC_CONTEXT } from '../../common/plugin-api-rpc';
|
|
29
|
+
import { ToolInvocationRegistry } from '@theia/ai-core/lib/common';
|
|
30
|
+
import { ToolRequest, ToolRequestParameters, ToolInvocationContext, ToolCallContent, ToolCallContentResult, createToolCallError } from '@theia/ai-core/lib/common/language-model';
|
|
31
|
+
|
|
32
|
+
export class LanguageModelToolsMainImpl implements LanguageModelToolsMain {
|
|
33
|
+
private readonly proxy: LanguageModelToolsExt;
|
|
34
|
+
private readonly toolInvocationRegistry: ToolInvocationRegistry | undefined;
|
|
35
|
+
private readonly toolHandleToName = new Map<number, string>();
|
|
36
|
+
|
|
37
|
+
constructor(
|
|
38
|
+
rpc: RPCProtocol,
|
|
39
|
+
container: interfaces.Container
|
|
40
|
+
) {
|
|
41
|
+
this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.LM_TOOLS_EXT);
|
|
42
|
+
try {
|
|
43
|
+
this.toolInvocationRegistry = container.get(ToolInvocationRegistry);
|
|
44
|
+
} catch {
|
|
45
|
+
this.toolInvocationRegistry = undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async $registerTool(handle: number, name: string, metadata: LanguageModelToolDto, pluginId: string): Promise<void> {
|
|
50
|
+
if (!this.toolInvocationRegistry) {
|
|
51
|
+
console.warn('ToolInvocationRegistry not available - tool will not be registered');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (this.toolInvocationRegistry.getFunction(name)) {
|
|
55
|
+
throw new Error(`Tool '${name}' is already registered.`);
|
|
56
|
+
}
|
|
57
|
+
const parameters: ToolRequestParameters = ToolRequest.isToolRequestParameters(metadata.inputSchema)
|
|
58
|
+
? metadata.inputSchema as ToolRequestParameters
|
|
59
|
+
: { type: 'object', properties: {} };
|
|
60
|
+
// Note: metadata.tags is not forwarded to ToolRequest as ToolRequest has no tags field.
|
|
61
|
+
// Tags are exposed to extensions on the Ext side via lm.tools (LanguageModelToolInformation).
|
|
62
|
+
const toolRequest: ToolRequest = {
|
|
63
|
+
id: name,
|
|
64
|
+
name: name,
|
|
65
|
+
providerName: `plugin_lm_tools_${pluginId}`,
|
|
66
|
+
description: metadata.description,
|
|
67
|
+
parameters,
|
|
68
|
+
handler: async (argString: string, ctx?: ToolInvocationContext): Promise<ToolCallContent> => {
|
|
69
|
+
const result = await this.proxy.$invokeTool(handle, argString, ctx?.cancellationToken);
|
|
70
|
+
if (isToolInvocationError(result)) {
|
|
71
|
+
return createToolCallError(result.error);
|
|
72
|
+
}
|
|
73
|
+
const content: ToolCallContentResult[] = result.content.map(part => this.convertDtoToToolCallResult(part));
|
|
74
|
+
return { content };
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
this.toolHandleToName.set(handle, name);
|
|
78
|
+
this.toolInvocationRegistry.registerTool(toolRequest);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
$unregisterTool(handle: number): void {
|
|
82
|
+
if (!this.toolInvocationRegistry) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const name = this.toolHandleToName.get(handle);
|
|
86
|
+
if (name) {
|
|
87
|
+
this.toolInvocationRegistry.unregisterTool(name);
|
|
88
|
+
this.toolHandleToName.delete(handle);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private convertDtoToToolCallResult(part: ToolResultPartDto): ToolCallContentResult {
|
|
93
|
+
switch (part.type) {
|
|
94
|
+
case 'text':
|
|
95
|
+
return { type: 'text', text: part.value };
|
|
96
|
+
case 'data':
|
|
97
|
+
return this.convertDataPart(part.base64, part.mimeType);
|
|
98
|
+
case 'prompt-tsx':
|
|
99
|
+
return { type: 'text', text: JSON.stringify(part.value) };
|
|
100
|
+
case 'unknown':
|
|
101
|
+
return { type: 'text', text: part.json };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private convertDataPart(base64: string, mimeType: string): ToolCallContentResult {
|
|
106
|
+
if (mimeType.startsWith('image/')) {
|
|
107
|
+
return { type: 'image', base64data: base64, mimeType };
|
|
108
|
+
}
|
|
109
|
+
if (mimeType.startsWith('audio/')) {
|
|
110
|
+
return { type: 'audio', data: base64, mimeType };
|
|
111
|
+
}
|
|
112
|
+
// Text-like MIME types: decode base64 to string
|
|
113
|
+
const decoded = BinaryBuffer.wrap(base64ToUint8Array(base64)).toString();
|
|
114
|
+
return { type: 'text', text: decoded };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -67,6 +67,7 @@ import { TestingMainImpl } from './test-main';
|
|
|
67
67
|
import { UriMainImpl } from './uri-main';
|
|
68
68
|
import { LoggerMainImpl } from './logger-main';
|
|
69
69
|
import { McpServerDefinitionRegistryMainImpl } from './lm-main';
|
|
70
|
+
import { LanguageModelToolsMainImpl } from './lm-tool-main';
|
|
70
71
|
|
|
71
72
|
export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container): void {
|
|
72
73
|
const loggerMain = new LoggerMainImpl(container);
|
|
@@ -211,4 +212,7 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container
|
|
|
211
212
|
|
|
212
213
|
const mcpServerDefinitionRegistryMain = new McpServerDefinitionRegistryMainImpl(rpc, container);
|
|
213
214
|
rpc.set(PLUGIN_RPC_CONTEXT.MCP_SERVER_DEFINITION_REGISTRY_MAIN, mcpServerDefinitionRegistryMain);
|
|
215
|
+
|
|
216
|
+
const languageModelToolsMain = new LanguageModelToolsMainImpl(rpc, container);
|
|
217
|
+
rpc.set(PLUGIN_RPC_CONTEXT.LM_TOOLS_MAIN, languageModelToolsMain);
|
|
214
218
|
}
|
|
@@ -17,9 +17,12 @@
|
|
|
17
17
|
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
|
|
18
18
|
const disableJSDOM = enableJSDOM();
|
|
19
19
|
|
|
20
|
+
import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
|
|
21
|
+
FrontendApplicationConfigProvider.set({});
|
|
22
|
+
|
|
20
23
|
import * as assert from 'assert';
|
|
24
|
+
import { URI } from '@theia/core';
|
|
21
25
|
import { Disposable } from '@theia/core/lib/common/disposable';
|
|
22
|
-
import { WatchOptions } from '@theia/filesystem/lib/common/files';
|
|
23
26
|
import { UriComponents } from '../../common/uri-components';
|
|
24
27
|
import { MainFileSystemEventService } from './main-file-system-event-service';
|
|
25
28
|
|
|
@@ -27,52 +30,96 @@ disableJSDOM();
|
|
|
27
30
|
|
|
28
31
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
29
32
|
|
|
30
|
-
// A
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
33
|
+
// A language server (e.g. `redhat.java` / JDT-LS) registers a watcher rooted at the PARENT of the
|
|
34
|
+
// workspace folder - `RelativePattern(parentDir, folderName)` - purely to detect deletion of the
|
|
35
|
+
// workspace folder itself. The pattern has no globstar, so `ensureWatching` sends it as a
|
|
36
|
+
// NON-recursive `$watch` on `parentDir`. Theia's backend ignores the `recursive` flag and always
|
|
37
|
+
// watches recursively, so this turns into a recursive crawl of every sibling subtree under the
|
|
38
|
+
// parent - thousands of inodes the workspace does not own - which can exhaust the OS file-watch
|
|
39
|
+
// budget. `files.watcherExclude` cannot bound it because the root is outside the workspace.
|
|
36
40
|
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
41
|
+
// These tests pin the fix: a non-recursive watch rooted at a strict ancestor of a workspace root is
|
|
42
|
+
// not registered, while watches on/inside the workspace and explicit recursive requests are
|
|
43
|
+
// untouched.
|
|
44
|
+
describe('MainFileSystemEventService ancestor-of-workspace watch handling', () => {
|
|
40
45
|
|
|
41
46
|
function componentsFor(path: string): UriComponents {
|
|
42
47
|
return { scheme: 'file', authority: '', path, query: '', fragment: '' };
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
const watchCalls: WatchOptions[] = [];
|
|
47
|
-
|
|
50
|
+
function createService(rootUris: string[], watchCalls: UriComponents[]): MainFileSystemEventService {
|
|
48
51
|
const fileService: any = {
|
|
49
52
|
onDidFilesChange: () => Disposable.NULL,
|
|
50
53
|
onDidRunUserOperation: () => Disposable.NULL,
|
|
51
54
|
addFileOperationParticipant: () => Disposable.NULL,
|
|
52
|
-
watch: (
|
|
53
|
-
watchCalls.push(
|
|
55
|
+
watch: (resource: UriComponents) => {
|
|
56
|
+
watchCalls.push(resource);
|
|
54
57
|
return Disposable.NULL;
|
|
55
58
|
}
|
|
56
59
|
};
|
|
60
|
+
const workspaceService: any = { tryGetRoots: () => rootUris.map(uri => ({ resource: new URI(uri) })) };
|
|
61
|
+
const rpc: any = { getProxy: () => ({}) };
|
|
62
|
+
return new MainFileSystemEventService(rpc, {} as any, fileService, workspaceService);
|
|
63
|
+
}
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
: undefined
|
|
62
|
-
};
|
|
65
|
+
it('skips a non-recursive watch rooted at a strict ancestor of a workspace root', () => {
|
|
66
|
+
const watchCalls: UriComponents[] = [];
|
|
67
|
+
const service = createService(['file:///projects/my-app'], watchCalls);
|
|
63
68
|
|
|
64
|
-
|
|
69
|
+
service.$watch(1, componentsFor('/projects'), { recursive: false, excludes: [] });
|
|
70
|
+
|
|
71
|
+
assert.strictEqual(watchCalls.length, 0, 'ancestor-of-workspace watch must not be registered');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('still registers a non-recursive watch on the workspace root itself', () => {
|
|
75
|
+
const watchCalls: UriComponents[] = [];
|
|
76
|
+
const service = createService(['file:///projects/my-app'], watchCalls);
|
|
77
|
+
|
|
78
|
+
service.$watch(1, componentsFor('/projects/my-app'), { recursive: false, excludes: [] });
|
|
79
|
+
|
|
80
|
+
assert.strictEqual(watchCalls.length, 1);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('still registers a non-recursive watch on an outer root that is itself the parent of another root', () => {
|
|
84
|
+
const watchCalls: UriComponents[] = [];
|
|
85
|
+
// Multi-root workspace where `/projects` is a root AND the parent of the `/projects/my-app` root.
|
|
86
|
+
// The outer root is explicitly opened by the user, so its watch must not be dropped as an
|
|
87
|
+
// "ancestor of the workspace".
|
|
88
|
+
const service = createService(['file:///projects', 'file:///projects/my-app'], watchCalls);
|
|
89
|
+
|
|
90
|
+
service.$watch(1, componentsFor('/projects'), { recursive: false, excludes: [] });
|
|
91
|
+
|
|
92
|
+
assert.strictEqual(watchCalls.length, 1, 'a folder that is itself a workspace root must be watched, even if it is an ancestor of another root');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('still registers a non-recursive watch inside the workspace', () => {
|
|
96
|
+
const watchCalls: UriComponents[] = [];
|
|
97
|
+
const service = createService(['file:///projects/my-app'], watchCalls);
|
|
98
|
+
|
|
99
|
+
service.$watch(1, componentsFor('/projects/my-app/src'), { recursive: false, excludes: [] });
|
|
100
|
+
|
|
101
|
+
assert.strictEqual(watchCalls.length, 1);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('does not skip an explicit recursive watch on an ancestor (honored as requested)', () => {
|
|
105
|
+
const watchCalls: UriComponents[] = [];
|
|
106
|
+
const service = createService(['file:///projects/my-app'], watchCalls);
|
|
107
|
+
|
|
108
|
+
service.$watch(1, componentsFor('/projects'), { recursive: true, excludes: [] });
|
|
109
|
+
|
|
110
|
+
assert.strictEqual(watchCalls.length, 1);
|
|
111
|
+
});
|
|
65
112
|
|
|
66
|
-
|
|
113
|
+
it('frees the session for a skipped watch so $unwatch and re-watch do not throw', () => {
|
|
114
|
+
const watchCalls: UriComponents[] = [];
|
|
115
|
+
const service = createService(['file:///projects/my-app'], watchCalls);
|
|
67
116
|
|
|
68
|
-
|
|
69
|
-
service.$
|
|
117
|
+
service.$watch(1, componentsFor('/projects'), { recursive: false, excludes: [] });
|
|
118
|
+
service.$unwatch(1);
|
|
119
|
+
// Re-using the same session id must not throw "already a watch request".
|
|
120
|
+
service.$watch(1, componentsFor('/projects'), { recursive: false, excludes: [] });
|
|
70
121
|
|
|
71
|
-
assert.strictEqual(watchCalls.length,
|
|
72
|
-
const excludes = watchCalls[0].excludes;
|
|
73
|
-
assert.ok(excludes.includes('**/node_modules/**'), 'enabled watcherExclude pattern should be applied');
|
|
74
|
-
assert.ok(excludes.includes('**/.git/objects/**'), 'enabled watcherExclude pattern should be applied');
|
|
75
|
-
assert.ok(!excludes.includes('**/disabled-exclude/**'), 'patterns set to `false` must not be applied');
|
|
122
|
+
assert.strictEqual(watchCalls.length, 0);
|
|
76
123
|
});
|
|
77
124
|
|
|
78
125
|
});
|