;
- @inject(MarkdownRenderer)
- private renderer: MarkdownRenderer;
-
@inject(ChatAgentService)
protected chatAgentService: ChatAgentService;
@@ -336,16 +331,7 @@ export class ChatViewTreeWidget extends TreeWidget {
}
private renderChatRequest(node: RequestNode): React.ReactNode {
- const text = node.request.request.displayText ?? node.request.request.text;
- const markdownString = new MarkdownStringImpl(text, { supportHtml: true, isTrusted: true });
- return (
-
- { this.renderer.render(markdownString).element}
- >}
-
- );
+ return ;
}
private renderChatResponse(node: ResponseNode): React.ReactNode {
@@ -389,6 +375,13 @@ export class ChatViewTreeWidget extends TreeWidget {
}
}
+const ChatRequestRender = ({ node }: { node: RequestNode }) => {
+ const text = node.request.request.displayText ?? node.request.request.text;
+ const ref = useMarkdownRendering(text);
+
+ return ;
+};
+
const ProgressMessage = (c: ChatProgressMessage) => (
{c.content}
diff --git a/packages/ai-chat/package.json b/packages/ai-chat/package.json
index 907a6b05712c6..bc6843dc6fe42 100644
--- a/packages/ai-chat/package.json
+++ b/packages/ai-chat/package.json
@@ -1,13 +1,13 @@
{
"name": "@theia/ai-chat",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - AI Chat Extension",
"dependencies": {
- "@theia/ai-core": "1.53.0",
- "@theia/ai-history": "1.53.0",
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/ai-core": "1.54.0",
+ "@theia/ai-history": "1.54.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/workspace": "1.54.0",
"minimatch": "^5.1.0",
"tslib": "^2.6.2"
},
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/ai-chat/src/browser/ai-chat-frontend-module.ts b/packages/ai-chat/src/browser/ai-chat-frontend-module.ts
index d4ed71579b514..c2231c64734aa 100644
--- a/packages/ai-chat/src/browser/ai-chat-frontend-module.ts
+++ b/packages/ai-chat/src/browser/ai-chat-frontend-module.ts
@@ -33,6 +33,7 @@ import { UniversalChatAgent } from '../common/universal-chat-agent';
import { aiChatPreferences } from './ai-chat-preferences';
import { ChatAgentsVariableContribution } from '../common/chat-agents-variable-contribution';
import { FrontendChatServiceImpl } from './frontend-chat-service';
+import { DefaultResponseContentMatcherProvider, DefaultResponseContentFactory, ResponseContentMatcherProvider } from '../common/response-content-matcher';
export default new ContainerModule(bind => {
bindContributionProvider(bind, Agent);
@@ -42,6 +43,11 @@ export default new ContainerModule(bind => {
bind(ChatAgentService).toService(ChatAgentServiceImpl);
bind(DefaultChatAgentId).toConstantValue({ id: OrchestratorChatAgentId });
+ bindContributionProvider(bind, ResponseContentMatcherProvider);
+ bind(DefaultResponseContentMatcherProvider).toSelf().inSingletonScope();
+ bind(ResponseContentMatcherProvider).toService(DefaultResponseContentMatcherProvider);
+ bind(DefaultResponseContentFactory).toSelf().inSingletonScope();
+
bind(AIVariableContribution).to(ChatAgentsVariableContribution).inSingletonScope();
bind(ChatRequestParserImpl).toSelf().inSingletonScope();
diff --git a/packages/ai-chat/src/common/chat-agents.ts b/packages/ai-chat/src/common/chat-agents.ts
index ee279125855be..ce6bbd741a17c 100644
--- a/packages/ai-chat/src/common/chat-agents.ts
+++ b/packages/ai-chat/src/common/chat-agents.ts
@@ -25,6 +25,7 @@ import {
LanguageModel,
LanguageModelRequirement,
LanguageModelResponse,
+ LanguageModelStreamResponse,
PromptService,
ResolvedPromptTemplate,
ToolRequest,
@@ -37,19 +38,20 @@ import {
LanguageModelStreamResponsePart,
MessageActor,
} from '@theia/ai-core/lib/common';
-import { CancellationToken, CancellationTokenSource, ILogger, isArray } from '@theia/core';
-import { inject, injectable } from '@theia/core/shared/inversify';
+import { CancellationToken, CancellationTokenSource, ContributionProvider, ILogger, isArray } from '@theia/core';
+import { inject, injectable, named, postConstruct } from '@theia/core/shared/inversify';
import { ChatAgentService } from './chat-agent-service';
import {
ChatModel,
ChatRequestModel,
ChatRequestModelImpl,
ChatResponseContent,
- CodeChatResponseContentImpl,
ErrorChatResponseContentImpl,
MarkdownChatResponseContentImpl,
ToolCallChatResponseContentImpl
} from './chat-model';
+import { findFirstMatch, parseContents } from './parse-contents';
+import { DefaultResponseContentFactory, ResponseContentMatcher, ResponseContentMatcherProvider } from './response-content-matcher';
/**
* A conversation consists of a sequence of ChatMessages.
@@ -121,6 +123,14 @@ export abstract class AbstractChatAgent {
@inject(ILogger) protected logger: ILogger;
@inject(CommunicationRecordingService) protected recordingService: CommunicationRecordingService;
@inject(PromptService) protected promptService: PromptService;
+
+ @inject(ContributionProvider) @named(ResponseContentMatcherProvider)
+ protected contentMatcherProviders: ContributionProvider;
+ protected contentMatchers: ResponseContentMatcher[] = [];
+
+ @inject(DefaultResponseContentFactory)
+ protected defaultContentFactory: DefaultResponseContentFactory;
+
constructor(
public id: string,
public languageModelRequirements: LanguageModelRequirement[],
@@ -130,6 +140,11 @@ export abstract class AbstractChatAgent {
public tags: String[] = ['Chat']) {
}
+ @postConstruct()
+ init(): void {
+ this.contentMatchers = this.contentMatcherProviders.getContributions().flatMap(provider => provider.matchers);
+ }
+
async invoke(request: ChatRequestModelImpl): Promise {
try {
const languageModel = await this.getLanguageModel(this.defaultLanguageModelPurpose);
@@ -189,6 +204,14 @@ export abstract class AbstractChatAgent {
}
}
+ protected parseContents(text: string): ChatResponseContent[] {
+ return parseContents(
+ text,
+ this.contentMatchers,
+ this.defaultContentFactory?.create.bind(this.defaultContentFactory)
+ );
+ };
+
protected handleError(request: ChatRequestModelImpl, error: Error): void {
request.response.response.addContent(new ErrorChatResponseContentImpl(error));
request.response.error(error);
@@ -281,9 +304,8 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
protected override async addContentsToResponse(languageModelResponse: LanguageModelResponse, request: ChatRequestModelImpl): Promise {
if (isLanguageModelTextResponse(languageModelResponse)) {
- request.response.response.addContent(
- new MarkdownChatResponseContentImpl(languageModelResponse.text)
- );
+ const contents = this.parseContents(languageModelResponse.text);
+ request.response.response.addContents(contents);
request.response.complete();
this.recordingService.recordResponse({
agentId: this.id,
@@ -295,57 +317,7 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
return;
}
if (isLanguageModelStreamResponse(languageModelResponse)) {
- for await (const token of languageModelResponse.stream) {
- const newContents = this.parse(token, request.response.response.content);
- if (isArray(newContents)) {
- newContents.forEach(newContent => request.response.response.addContent(newContent));
- } else {
- request.response.response.addContent(newContents);
- }
-
- const lastContent = request.response.response.content.pop();
- if (lastContent === undefined) {
- return;
- }
- const text = lastContent.asString?.();
- if (text === undefined) {
- return;
- }
- let curSearchIndex = 0;
- const result: ChatResponseContent[] = [];
- while (curSearchIndex < text.length) {
- // find start of code block: ```[language]\n[\n]```
- const codeStartIndex = text.indexOf('```', curSearchIndex);
- if (codeStartIndex === -1) {
- break;
- }
-
- // find language specifier if present
- const newLineIndex = text.indexOf('\n', codeStartIndex + 3);
- const language = codeStartIndex + 3 < newLineIndex ? text.substring(codeStartIndex + 3, newLineIndex) : undefined;
-
- // find end of code block
- const codeEndIndex = text.indexOf('```', codeStartIndex + 3);
- if (codeEndIndex === -1) {
- break;
- }
-
- // add text before code block as markdown content
- result.push(new MarkdownChatResponseContentImpl(text.substring(curSearchIndex, codeStartIndex)));
- // add code block as code content
- const codeText = text.substring(newLineIndex + 1, codeEndIndex).trimEnd();
- result.push(new CodeChatResponseContentImpl(codeText, language));
- curSearchIndex = codeEndIndex + 3;
- }
-
- if (result.length > 0) {
- result.forEach(r => {
- request.response.response.addContent(r);
- });
- } else {
- request.response.response.addContent(lastContent);
- }
- }
+ await this.addStreamResponse(languageModelResponse, request);
request.response.complete();
this.recordingService.recordResponse({
agentId: this.id,
@@ -366,11 +338,38 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
);
}
- private parse(token: LanguageModelStreamResponsePart, previousContent: ChatResponseContent[]): ChatResponseContent | ChatResponseContent[] {
+ protected async addStreamResponse(languageModelResponse: LanguageModelStreamResponse, request: ChatRequestModelImpl): Promise {
+ for await (const token of languageModelResponse.stream) {
+ const newContents = this.parse(token, request.response.response.content);
+ if (isArray(newContents)) {
+ request.response.response.addContents(newContents);
+ } else {
+ request.response.response.addContent(newContents);
+ }
+
+ const lastContent = request.response.response.content.pop();
+ if (lastContent === undefined) {
+ return;
+ }
+ const text = lastContent.asString?.();
+ if (text === undefined) {
+ return;
+ }
+
+ const result: ChatResponseContent[] = findFirstMatch(this.contentMatchers, text) ? this.parseContents(text) : [];
+ if (result.length > 0) {
+ request.response.response.addContents(result);
+ } else {
+ request.response.response.addContent(lastContent);
+ }
+ }
+ }
+
+ protected parse(token: LanguageModelStreamResponsePart, previousContent: ChatResponseContent[]): ChatResponseContent | ChatResponseContent[] {
const content = token.content;
// eslint-disable-next-line no-null/no-null
if (content !== undefined && content !== null) {
- return new MarkdownChatResponseContentImpl(content);
+ return this.defaultContentFactory.create(content);
}
const toolCalls = token.tool_calls;
if (toolCalls !== undefined) {
@@ -378,7 +377,7 @@ export abstract class AbstractStreamParsingChatAgent extends AbstractChatAgent {
new ToolCallChatResponseContentImpl(toolCall.id, toolCall.function?.name, toolCall.function?.arguments, toolCall.finished, toolCall.result));
return toolCallContents;
}
- return new MarkdownChatResponseContentImpl('');
+ return this.defaultContentFactory.create('');
}
}
diff --git a/packages/ai-chat/src/common/chat-model.ts b/packages/ai-chat/src/common/chat-model.ts
index a71c273f04110..c485c69c7c4c8 100644
--- a/packages/ai-chat/src/common/chat-model.ts
+++ b/packages/ai-chat/src/common/chat-model.ts
@@ -374,7 +374,7 @@ export class ChatRequestModelImpl implements ChatRequestModel {
}
export class ErrorChatResponseContentImpl implements ErrorChatResponseContent {
- kind: 'error' = 'error';
+ readonly kind = 'error';
protected _error: Error;
constructor(error: Error) {
this._error = error;
@@ -388,7 +388,7 @@ export class ErrorChatResponseContentImpl implements ErrorChatResponseContent {
}
export class TextChatResponseContentImpl implements TextChatResponseContent {
- kind: 'text' = 'text';
+ readonly kind = 'text';
protected _content: string;
constructor(content: string) {
@@ -410,7 +410,7 @@ export class TextChatResponseContentImpl implements TextChatResponseContent {
}
export class MarkdownChatResponseContentImpl implements MarkdownChatResponseContent {
- kind: 'markdownContent' = 'markdownContent';
+ readonly kind = 'markdownContent';
protected _content: MarkdownStringImpl = new MarkdownStringImpl();
constructor(content: string) {
@@ -432,7 +432,7 @@ export class MarkdownChatResponseContentImpl implements MarkdownChatResponseCont
}
export class InformationalChatResponseContentImpl implements InformationalChatResponseContent {
- kind: 'informational' = 'informational';
+ readonly kind = 'informational';
protected _content: MarkdownStringImpl;
constructor(content: string) {
@@ -454,7 +454,7 @@ export class InformationalChatResponseContentImpl implements InformationalChatRe
}
export class CodeChatResponseContentImpl implements CodeChatResponseContent {
- kind: 'code' = 'code';
+ readonly kind = 'code';
protected _code: string;
protected _language?: string;
protected _location?: Location;
@@ -488,7 +488,7 @@ export class CodeChatResponseContentImpl implements CodeChatResponseContent {
}
export class ToolCallChatResponseContentImpl implements ToolCallChatResponseContent {
- kind: 'toolCall' = 'toolCall';
+ readonly kind = 'toolCall';
protected _id?: string;
protected _name?: string;
protected _arguments?: string;
@@ -546,7 +546,7 @@ export const COMMAND_CHAT_RESPONSE_COMMAND: Command = {
id: 'ai-chat.command-chat-response.generic'
};
export class CommandChatResponseContentImpl implements CommandChatResponseContent {
- kind: 'command' = 'command';
+ readonly kind = 'command';
constructor(public command?: Command, public customCallback?: CustomCallback, protected args?: unknown[]) {
}
@@ -561,7 +561,7 @@ export class CommandChatResponseContentImpl implements CommandChatResponseConten
}
export class HorizontalLayoutChatResponseContentImpl implements HorizontalLayoutChatResponseContent {
- kind: 'horizontal' = 'horizontal';
+ readonly kind = 'horizontal';
protected _content: ChatResponseContent[];
constructor(content: ChatResponseContent[] = []) {
@@ -601,10 +601,20 @@ class ChatResponseImpl implements ChatResponse {
return this._content;
}
+ addContents(contents: ChatResponseContent[]): void {
+ contents.forEach(c => this.doAddContent(c));
+ this._onDidChangeEmitter.fire();
+ }
+
addContent(nextContent: ChatResponseContent): void {
// TODO: Support more complex merges affecting different content than the last, e.g. via some kind of ProcessorRegistry
// TODO: Support more of the built-in VS Code behavior, see
// https://github.com/microsoft/vscode/blob/a2cab7255c0df424027be05d58e1b7b941f4ea60/src/vs/workbench/contrib/chat/common/chatModel.ts#L188-L244
+ this.doAddContent(nextContent);
+ this._onDidChangeEmitter.fire();
+ }
+
+ protected doAddContent(nextContent: ChatResponseContent): void {
if (ToolCallChatResponseContent.is(nextContent) && nextContent.id !== undefined) {
const fittingTool = this._content.find(c => ToolCallChatResponseContent.is(c) && c.id === nextContent.id);
if (fittingTool !== undefined) {
@@ -613,10 +623,9 @@ class ChatResponseImpl implements ChatResponse {
this._content.push(nextContent);
}
} else {
- const lastElement =
- this._content.length > 0
- ? this._content[this._content.length - 1]
- : undefined;
+ const lastElement = this._content.length > 0
+ ? this._content[this._content.length - 1]
+ : undefined;
if (lastElement?.kind === nextContent.kind && ChatResponseContent.hasMerge(lastElement)) {
const mergeSuccess = lastElement.merge(nextContent);
if (!mergeSuccess) {
@@ -627,7 +636,6 @@ class ChatResponseImpl implements ChatResponse {
}
}
this._updateResponseRepresentation();
- this._onDidChangeEmitter.fire();
}
protected _updateResponseRepresentation(): void {
diff --git a/packages/ai-chat/src/common/parse-contents.spec.ts b/packages/ai-chat/src/common/parse-contents.spec.ts
new file mode 100644
index 0000000000000..c0a009f8cb814
--- /dev/null
+++ b/packages/ai-chat/src/common/parse-contents.spec.ts
@@ -0,0 +1,142 @@
+// *****************************************************************************
+// Copyright (C) 2024 EclipseSource GmbH.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0.
+//
+// This Source Code may also be made available under the following Secondary
+// Licenses when the conditions for such availability set forth in the Eclipse
+// Public License v. 2.0 are satisfied: GNU General Public License, version 2
+// with the GNU Classpath Exception which is available at
+// https://www.gnu.org/software/classpath/license.html.
+//
+// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
+// *****************************************************************************
+
+import { expect } from 'chai';
+import { ChatResponseContent, CodeChatResponseContentImpl, MarkdownChatResponseContentImpl } from './chat-model';
+import { parseContents } from './parse-contents';
+import { CodeContentMatcher, ResponseContentMatcher } from './response-content-matcher';
+
+export class CommandChatResponseContentImpl implements ChatResponseContent {
+ constructor(public readonly command: string) { }
+ kind = 'command';
+}
+
+export const CommandContentMatcher: ResponseContentMatcher = {
+ start: /^$/m,
+ end: /^<\/command>$/m,
+ contentFactory: (content: string) => {
+ const code = content.replace(/^\n|<\/command>$/g, '');
+ return new CommandChatResponseContentImpl(code.trim());
+ }
+};
+
+describe('parseContents', () => {
+ it('should parse code content', () => {
+ const text = '```typescript\nconsole.log("Hello World");\n```';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript')]);
+ });
+
+ it('should parse markdown content', () => {
+ const text = 'Hello **World**';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('Hello **World**')]);
+ });
+
+ it('should parse multiple content blocks', () => {
+ const text = '```typescript\nconsole.log("Hello World");\n```\nHello **World**';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([
+ new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
+ new MarkdownChatResponseContentImpl('\nHello **World**')
+ ]);
+ });
+
+ it('should parse multiple content blocks with different languages', () => {
+ const text = '```typescript\nconsole.log("Hello World");\n```\n```python\nprint("Hello World")\n```';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([
+ new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
+ new CodeChatResponseContentImpl('print("Hello World")', 'python')
+ ]);
+ });
+
+ it('should parse multiple content blocks with different languages and markdown', () => {
+ const text = '```typescript\nconsole.log("Hello World");\n```\nHello **World**\n```python\nprint("Hello World")\n```';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([
+ new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
+ new MarkdownChatResponseContentImpl('\nHello **World**\n'),
+ new CodeChatResponseContentImpl('print("Hello World")', 'python')
+ ]);
+ });
+
+ it('should parse content blocks with empty content', () => {
+ const text = '```typescript\n```\nHello **World**\n```python\nprint("Hello World")\n```';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([
+ new CodeChatResponseContentImpl('', 'typescript'),
+ new MarkdownChatResponseContentImpl('\nHello **World**\n'),
+ new CodeChatResponseContentImpl('print("Hello World")', 'python')
+ ]);
+ });
+
+ it('should parse content with markdown, code, and markdown', () => {
+ const text = 'Hello **World**\n```typescript\nconsole.log("Hello World");\n```\nGoodbye **World**';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([
+ new MarkdownChatResponseContentImpl('Hello **World**\n'),
+ new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
+ new MarkdownChatResponseContentImpl('\nGoodbye **World**')
+ ]);
+ });
+
+ it('should handle text with no special content', () => {
+ const text = 'Just some plain text.';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('Just some plain text.')]);
+ });
+
+ it('should handle text with only start code block', () => {
+ const text = '```typescript\nconsole.log("Hello World");';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('```typescript\nconsole.log("Hello World");')]);
+ });
+
+ it('should handle text with only end code block', () => {
+ const text = 'console.log("Hello World");\n```';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([new MarkdownChatResponseContentImpl('console.log("Hello World");\n```')]);
+ });
+
+ it('should handle text with unmatched code block', () => {
+ const text = '```typescript\nconsole.log("Hello World");\n```\n```python\nprint("Hello World")';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([
+ new CodeChatResponseContentImpl('console.log("Hello World");', 'typescript'),
+ new MarkdownChatResponseContentImpl('\n```python\nprint("Hello World")')
+ ]);
+ });
+
+ it('should parse code block without newline after language', () => {
+ const text = '```typescript console.log("Hello World");```';
+ const result = parseContents(text);
+ expect(result).to.deep.equal([
+ new MarkdownChatResponseContentImpl('```typescript console.log("Hello World");```')
+ ]);
+ });
+
+ it('should parse with matches of multiple different matchers and default', () => {
+ const text = '\nMY_SPECIAL_COMMAND\n\nHello **World**\n```python\nprint("Hello World")\n```\n\nMY_SPECIAL_COMMAND2\n';
+ const result = parseContents(text, [CodeContentMatcher, CommandContentMatcher]);
+ expect(result).to.deep.equal([
+ new CommandChatResponseContentImpl('MY_SPECIAL_COMMAND'),
+ new MarkdownChatResponseContentImpl('\nHello **World**\n'),
+ new CodeChatResponseContentImpl('print("Hello World")', 'python'),
+ new CommandChatResponseContentImpl('MY_SPECIAL_COMMAND2'),
+ ]);
+ });
+});
diff --git a/packages/ai-chat/src/common/parse-contents.ts b/packages/ai-chat/src/common/parse-contents.ts
new file mode 100644
index 0000000000000..16f405495ce20
--- /dev/null
+++ b/packages/ai-chat/src/common/parse-contents.ts
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 EclipseSource GmbH.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
+ * with the GNU Classpath Exception which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
+ */
+import { ChatResponseContent } from './chat-model';
+import { CodeContentMatcher, MarkdownContentFactory, ResponseContentFactory, ResponseContentMatcher } from './response-content-matcher';
+
+interface Match {
+ matcher: ResponseContentMatcher;
+ index: number;
+ content: string;
+}
+
+export function parseContents(
+ text: string,
+ contentMatchers: ResponseContentMatcher[] = [CodeContentMatcher],
+ defaultContentFactory: ResponseContentFactory = MarkdownContentFactory
+): ChatResponseContent[] {
+ const result: ChatResponseContent[] = [];
+
+ let currentIndex = 0;
+ while (currentIndex < text.length) {
+ const remainingText = text.substring(currentIndex);
+ const match = findFirstMatch(contentMatchers, remainingText);
+ if (!match) {
+ // Add the remaining text as default content
+ if (remainingText.length > 0) {
+ result.push(defaultContentFactory(remainingText));
+ }
+ break;
+ }
+ // We have a match
+ // 1. Add preceding text as default content
+ if (match.index > 0) {
+ const precedingContent = remainingText.substring(0, match.index);
+ if (precedingContent.trim().length > 0) {
+ result.push(defaultContentFactory(precedingContent));
+ }
+ }
+ // 2. Add the matched content object
+ result.push(match.matcher.contentFactory(match.content));
+ // Update currentIndex to the end of the end of the match
+ // And continue with the search after the end of the match
+ currentIndex += match.index + match.content.length;
+ }
+
+ return result;
+}
+
+export function findFirstMatch(contentMatchers: ResponseContentMatcher[], text: string): Match | undefined {
+ let firstMatch: { matcher: ResponseContentMatcher, index: number, content: string } | undefined;
+ for (const matcher of contentMatchers) {
+ const startMatch = matcher.start.exec(text);
+ if (!startMatch) {
+ // No start match found, try next matcher.
+ continue;
+ }
+ const endOfStartMatch = startMatch.index + startMatch[0].length;
+ if (endOfStartMatch >= text.length) {
+ // There is no text after the start match.
+ // No need to search for the end match yet, try next matcher.
+ continue;
+ }
+ const remainingTextAfterStartMatch = text.substring(endOfStartMatch);
+ const endMatch = matcher.end.exec(remainingTextAfterStartMatch);
+ if (!endMatch) {
+ // No end match found, try next matcher.
+ continue;
+ }
+ // Found start and end match.
+ // Record the full match, if it is the earliest found so far.
+ const index = startMatch.index;
+ const contentEnd = index + startMatch[0].length + endMatch.index + endMatch[0].length;
+ const content = text.substring(index, contentEnd);
+ if (!firstMatch || index < firstMatch.index) {
+ firstMatch = { matcher, index, content };
+ }
+ }
+ return firstMatch;
+}
+
diff --git a/packages/ai-chat/src/common/response-content-matcher.ts b/packages/ai-chat/src/common/response-content-matcher.ts
new file mode 100644
index 0000000000000..3fb785e603c5f
--- /dev/null
+++ b/packages/ai-chat/src/common/response-content-matcher.ts
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2024 EclipseSource GmbH.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the Eclipse
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
+ * with the GNU Classpath Exception which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
+ */
+import {
+ ChatResponseContent,
+ CodeChatResponseContentImpl,
+ MarkdownChatResponseContentImpl
+} from './chat-model';
+import { injectable } from '@theia/core/shared/inversify';
+
+export type ResponseContentFactory = (content: string) => ChatResponseContent;
+
+export const MarkdownContentFactory: ResponseContentFactory = (content: string) =>
+ new MarkdownChatResponseContentImpl(content);
+
+/**
+ * Default response content factory used if no other `ResponseContentMatcher` applies.
+ * By default, this factory creates a markdown content object.
+ *
+ * @see MarkdownChatResponseContentImpl
+ */
+@injectable()
+export class DefaultResponseContentFactory {
+ create(content: string): ChatResponseContent {
+ return MarkdownContentFactory(content);
+ }
+}
+
+/**
+ * Clients can contribute response content matchers to parse a chat response into specific
+ * `ChatResponseContent` instances.
+ */
+export interface ResponseContentMatcher {
+ /** Regular expression for finding the start delimiter. */
+ start: RegExp;
+ /** Regular expression for finding the start delimiter. */
+ end: RegExp;
+ /**
+ * The factory creating a response content from the matching content,
+ * from start index to end index of the match (including delimiters).
+ */
+ contentFactory: ResponseContentFactory;
+}
+
+export const CodeContentMatcher: ResponseContentMatcher = {
+ start: /^```.*?$/m,
+ end: /^```$/m,
+ contentFactory: (content: string) => {
+ const language = content.match(/^```(\w+)/)?.[1] || '';
+ const code = content.replace(/^```(\w+)\n|```$/g, '');
+ return new CodeChatResponseContentImpl(code.trim(), language);
+ }
+};
+
+/**
+ * Clients can contribute response content matchers to parse the response content.
+ *
+ * The default chat user interface will collect all contributed matchers and use them
+ * to parse the response into structured content parts (e.g. code blocks, markdown blocks),
+ * which are then rendered with a `ChatResponsePartRenderer` registered for the respective
+ * content part type.
+ *
+ * ### Example
+ * ```ts
+ * bind(ResponseContentMatcherProvider).to(MyResponseContentMatcherProvider);
+ * ...
+ * @injectable()
+ * export class MyResponseContentMatcherProvider implements ResponseContentMatcherProvider {
+ * readonly matchers: ResponseContentMatcher[] = [{
+ * start: /^$/m,
+ * end: /^$/m,
+ * contentFactory: (content: string) => {
+ * const command = content.replace(/^\n|<\/command>$/g, '');
+ * return new MyChatResponseContentImpl(command.trim());
+ * }
+ * }];
+ * }
+ * ```
+ *
+ * @see ResponseContentMatcher
+ */
+export const ResponseContentMatcherProvider = Symbol('ResponseContentMatcherProvider');
+export interface ResponseContentMatcherProvider {
+ readonly matchers: ResponseContentMatcher[];
+}
+
+@injectable()
+export class DefaultResponseContentMatcherProvider implements ResponseContentMatcherProvider {
+ readonly matchers: ResponseContentMatcher[] = [CodeContentMatcher];
+}
diff --git a/packages/ai-code-completion/package.json b/packages/ai-code-completion/package.json
index 8ab9c57a3de79..8cf5e1a630163 100644
--- a/packages/ai-code-completion/package.json
+++ b/packages/ai-code-completion/package.json
@@ -1,14 +1,14 @@
{
"name": "@theia/ai-code-completion",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - AI Core",
"dependencies": {
- "@theia/ai-core": "1.53.0",
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
+ "@theia/ai-core": "1.54.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/output": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/output": "1.54.0",
+ "@theia/workspace": "1.54.0",
"minimatch": "^5.1.0",
"tslib": "^2.6.2"
},
@@ -46,7 +46,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/ai-core/package.json b/packages/ai-core/package.json
index 294fbcb871fc2..e40cc0906d1a3 100644
--- a/packages/ai-core/package.json
+++ b/packages/ai-core/package.json
@@ -1,16 +1,16 @@
{
"name": "@theia/ai-core",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - AI Core",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/output": "1.53.0",
- "@theia/variable-resolver": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/output": "1.54.0",
+ "@theia/variable-resolver": "1.54.0",
+ "@theia/workspace": "1.54.0",
"minimatch": "^5.1.0",
"tslib": "^2.6.2"
},
@@ -50,7 +50,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/ai-core/src/browser/ai-configuration/language-model-renderer.tsx b/packages/ai-core/src/browser/ai-configuration/language-model-renderer.tsx
index f41a8acfd84bd..1305168f65f59 100644
--- a/packages/ai-core/src/browser/ai-configuration/language-model-renderer.tsx
+++ b/packages/ai-core/src/browser/ai-configuration/language-model-renderer.tsx
@@ -31,7 +31,7 @@ export const LanguageModelRenderer: React.FC = (
const findLanguageModelRequirement = async (purpose: string): Promise => {
const requirementSetting = await aiSettingsService.getAgentSettings(agent.id);
- return requirementSetting?.languageModelRequirements.find(e => e.purpose === purpose);
+ return requirementSetting?.languageModelRequirements?.find(e => e.purpose === purpose);
};
const [lmRequirementMap, setLmRequirementMap] = React.useState>({});
diff --git a/packages/ai-core/src/browser/frontend-language-model-registry.ts b/packages/ai-core/src/browser/frontend-language-model-registry.ts
index 045d066b60970..90b80a0688451 100644
--- a/packages/ai-core/src/browser/frontend-language-model-registry.ts
+++ b/packages/ai-core/src/browser/frontend-language-model-registry.ts
@@ -288,7 +288,7 @@ export class FrontendLanguageModelRegistryImpl
override async selectLanguageModels(request: LanguageModelSelector): Promise {
await this.initialized;
- const userSettings = (await this.settingsService.getAgentSettings(request.agent))?.languageModelRequirements.find(req => req.purpose === request.purpose);
+ const userSettings = (await this.settingsService.getAgentSettings(request.agent))?.languageModelRequirements?.find(req => req.purpose === request.purpose);
if (userSettings?.identifier) {
const model = await this.getLanguageModel(userSettings.identifier);
if (model) {
diff --git a/packages/ai-core/src/common/settings-service.ts b/packages/ai-core/src/common/settings-service.ts
index 2c8f204b96643..007daec366250 100644
--- a/packages/ai-core/src/common/settings-service.ts
+++ b/packages/ai-core/src/common/settings-service.ts
@@ -28,6 +28,6 @@ export interface AISettingsService {
}
export type AISettings = Record;
export interface AgentSettings {
- languageModelRequirements: LanguageModelRequirement[];
- enable: boolean;
+ languageModelRequirements?: LanguageModelRequirement[];
+ enable?: boolean;
}
diff --git a/packages/ai-history/package.json b/packages/ai-history/package.json
index 0eb2b6f471cc2..f4c4cd224670d 100644
--- a/packages/ai-history/package.json
+++ b/packages/ai-history/package.json
@@ -1,13 +1,13 @@
{
"name": "@theia/ai-history",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - AI communication history",
"dependencies": {
- "@theia/ai-core": "1.53.0",
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/output": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/ai-core": "1.54.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/output": "1.54.0",
+ "@theia/workspace": "1.54.0",
"minimatch": "^5.1.0",
"tslib": "^2.6.2"
},
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/ai-ollama/package.json b/packages/ai-ollama/package.json
index 779515df07d0b..b2a5d74346abb 100644
--- a/packages/ai-ollama/package.json
+++ b/packages/ai-ollama/package.json
@@ -1,15 +1,15 @@
{
"name": "@theia/ai-ollama",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Ollama Integration",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/workspace": "1.54.0",
"minimatch": "^5.1.0",
"tslib": "^2.6.2",
"ollama": "^0.5.8",
- "@theia/ai-core": "1.53.0"
+ "@theia/ai-core": "1.54.0"
},
"publishConfig": {
"access": "public"
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/ai-openai/package.json b/packages/ai-openai/package.json
index 1a0d2f69e8859..3ac4dd9ab057e 100644
--- a/packages/ai-openai/package.json
+++ b/packages/ai-openai/package.json
@@ -1,15 +1,15 @@
{
"name": "@theia/ai-openai",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - OpenAI Integration",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/workspace": "1.54.0",
"minimatch": "^5.1.0",
"tslib": "^2.6.2",
"openai": "^4.55.7",
- "@theia/ai-core": "1.53.0"
+ "@theia/ai-core": "1.54.0"
},
"publishConfig": {
"access": "public"
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/ai-openai/src/node/openai-language-model.ts b/packages/ai-openai/src/node/openai-language-model.ts
index e7edc59b0fb23..7692a21f8a9e4 100644
--- a/packages/ai-openai/src/node/openai-language-model.ts
+++ b/packages/ai-openai/src/node/openai-language-model.ts
@@ -134,9 +134,12 @@ export class OpenAiModel implements LanguageModel {
}
protected supportsStructuredOutput(): boolean {
- // currently only the lastest 4o and 4o-mini models support structured output
- // see https://platform.openai.com/docs/guides/structured-outputs
- return this.model === 'gpt-4o-2024-08-06' || this.model === 'gpt-4o-mini';
+ // see https://platform.openai.com/docs/models/gpt-4o
+ return [
+ 'gpt-4o',
+ 'gpt-4o-2024-08-06',
+ 'gpt-4o-mini'
+ ].includes(this.model);
}
protected async handleStructuredOutputRequest(openai: OpenAI, request: LanguageModelRequest): Promise {
diff --git a/packages/ai-terminal/package.json b/packages/ai-terminal/package.json
index f32d1794bf62b..acf37e6632656 100644
--- a/packages/ai-terminal/package.json
+++ b/packages/ai-terminal/package.json
@@ -1,12 +1,12 @@
{
"name": "@theia/ai-terminal",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - AI Terminal Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/ai-core": "1.53.0",
- "@theia/ai-chat": "1.53.0",
- "@theia/terminal": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/ai-core": "1.54.0",
+ "@theia/ai-chat": "1.54.0",
+ "@theia/terminal": "1.54.0",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.2"
},
@@ -43,7 +43,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/ai-terminal/src/browser/ai-terminal-agent.ts b/packages/ai-terminal/src/browser/ai-terminal-agent.ts
index f68f73eeb3424..98d083d7bee76 100644
--- a/packages/ai-terminal/src/browser/ai-terminal-agent.ts
+++ b/packages/ai-terminal/src/browser/ai-terminal-agent.ts
@@ -16,12 +16,13 @@
import {
Agent,
+ CommunicationRecordingService,
getJsonOfResponse,
isLanguageModelParsedResponse,
LanguageModelRegistry, LanguageModelRequirement,
PromptService
} from '@theia/ai-core/lib/common';
-import { ILogger } from '@theia/core';
+import { generateUuid, ILogger } from '@theia/core';
import { inject, injectable } from '@theia/core/shared/inversify';
import { z } from 'zod';
import zodToJsonSchema from 'zod-to-json-schema';
@@ -33,6 +34,8 @@ type Commands = z.infer;
@injectable()
export class AiTerminalAgent implements Agent {
+ @inject(CommunicationRecordingService)
+ protected recordingService: CommunicationRecordingService;
id = 'Terminal Assistant';
name = 'Terminal Assistant';
@@ -153,6 +156,18 @@ recent-terminal-contents:
return [];
}
+ // since we do not actually hold complete conversions, the request/response pair is considered a session
+ const sessionId = generateUuid();
+ const requestId = generateUuid();
+ this.recordingService.recordRequest({
+ agentId: this.id,
+ sessionId,
+ timestamp: Date.now(),
+ requestId,
+ request: systemPrompt,
+ messages: [userPrompt],
+ });
+
try {
const result = await lm.request({
messages: [
@@ -181,12 +196,28 @@ recent-terminal-contents:
// model returned structured output
const parsedResult = Commands.safeParse(result.parsed);
if (parsedResult.success) {
+ const responseTextfromParsed = JSON.stringify(parsedResult.data.commands);
+ this.recordingService.recordResponse({
+ agentId: this.id,
+ sessionId,
+ timestamp: Date.now(),
+ requestId,
+ response: responseTextfromParsed,
+ });
return parsedResult.data.commands;
}
}
// fall back to agent-based parsing of result
const jsonResult = await getJsonOfResponse(result);
+ const responseTextFromJSON = JSON.stringify(jsonResult);
+ this.recordingService.recordResponse({
+ agentId: this.id,
+ sessionId,
+ timestamp: Date.now(),
+ requestId,
+ response: responseTextFromJSON
+ });
const parsedJsonResult = Commands.safeParse(jsonResult);
if (parsedJsonResult.success) {
return parsedJsonResult.data.commands;
diff --git a/packages/ai-workspace-agent/package.json b/packages/ai-workspace-agent/package.json
index 65a50a7f12990..d992fb740a4cc 100644
--- a/packages/ai-workspace-agent/package.json
+++ b/packages/ai-workspace-agent/package.json
@@ -1,6 +1,6 @@
{
"name": "@theia/ai-workspace-agent",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "AI Workspace Agent Extension",
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
"repository": {
@@ -15,20 +15,20 @@
"theia-extension"
],
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/workspace": "1.53.0",
- "@theia/navigator": "1.53.0",
- "@theia/terminal": "1.53.0",
- "@theia/ai-core": "1.53.0",
- "@theia/ai-chat": "1.53.0"
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/workspace": "1.54.0",
+ "@theia/navigator": "1.54.0",
+ "@theia/terminal": "1.54.0",
+ "@theia/ai-core": "1.54.0",
+ "@theia/ai-chat": "1.54.0"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
- "@theia/cli": "1.53.0",
- "@theia/test": "1.53.0"
+ "@theia/cli": "1.54.0",
+ "@theia/test": "1.54.0"
},
"theiaExtensions": [
{
diff --git a/packages/bulk-edit/package.json b/packages/bulk-edit/package.json
index 312ef80cc23a8..c0352dc098be6 100644
--- a/packages/bulk-edit/package.json
+++ b/packages/bulk-edit/package.json
@@ -1,14 +1,14 @@
{
"name": "@theia/bulk-edit",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Bulk Edit Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/workspace": "1.53.0",
+ "@theia/workspace": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -44,7 +44,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/callhierarchy/package.json b/packages/callhierarchy/package.json
index cde8b9af18d1d..ebad7bf16c619 100644
--- a/packages/callhierarchy/package.json
+++ b/packages/callhierarchy/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/callhierarchy",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Call Hierarchy Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
"ts-md5": "^1.2.2",
"tslib": "^2.6.2"
},
@@ -41,7 +41,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/collaboration/package.json b/packages/collaboration/package.json
index ef39af5fad751..76a4a88e72794 100644
--- a/packages/collaboration/package.json
+++ b/packages/collaboration/package.json
@@ -1,14 +1,14 @@
{
"name": "@theia/collaboration",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Collaboration Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/workspace": "1.53.0",
+ "@theia/workspace": "1.54.0",
"open-collaboration-protocol": "0.2.0",
"open-collaboration-yjs": "0.2.0",
"socket.io-client": "^4.5.3",
@@ -49,7 +49,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/console/package.json b/packages/console/package.json
index 6b0055c2b2fb5..a0a68be4de510 100644
--- a/packages/console/package.json
+++ b/packages/console/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/console",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Console Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
"anser": "^2.0.1",
"tslib": "^2.6.2"
@@ -42,7 +42,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/core/README.md b/packages/core/README.md
index 2483bb3abbaa4..438d5b4d9ead9 100644
--- a/packages/core/README.md
+++ b/packages/core/README.md
@@ -84,12 +84,12 @@ export class SomeClass {
- `@phosphor/signaling` (from [`@phosphor/signaling@1`](https://www.npmjs.com/package/@phosphor/signaling))
- `@phosphor/virtualdom` (from [`@phosphor/virtualdom@1`](https://www.npmjs.com/package/@phosphor/virtualdom))
- `@phosphor/widgets` (from [`@phosphor/widgets@1`](https://www.npmjs.com/package/@phosphor/widgets))
- - `@theia/application-package` (from [`@theia/application-package@1.53.0`](https://www.npmjs.com/package/@theia/application-package/v/1.53.0))
- - `@theia/application-package/lib/api` (from [`@theia/application-package@1.53.0`](https://www.npmjs.com/package/@theia/application-package/v/1.53.0))
- - `@theia/application-package/lib/environment` (from [`@theia/application-package@1.53.0`](https://www.npmjs.com/package/@theia/application-package/v/1.53.0))
- - `@theia/request` (from [`@theia/request@1.53.0`](https://www.npmjs.com/package/@theia/request/v/1.53.0))
- - `@theia/request/lib/proxy` (from [`@theia/request@1.53.0`](https://www.npmjs.com/package/@theia/request/v/1.53.0))
- - `@theia/request/lib/node-request-service` (from [`@theia/request@1.53.0`](https://www.npmjs.com/package/@theia/request/v/1.53.0))
+ - `@theia/application-package` (from [`@theia/application-package@1.54.0`](https://www.npmjs.com/package/@theia/application-package/v/1.54.0))
+ - `@theia/application-package/lib/api` (from [`@theia/application-package@1.54.0`](https://www.npmjs.com/package/@theia/application-package/v/1.54.0))
+ - `@theia/application-package/lib/environment` (from [`@theia/application-package@1.54.0`](https://www.npmjs.com/package/@theia/application-package/v/1.54.0))
+ - `@theia/request` (from [`@theia/request@1.54.0`](https://www.npmjs.com/package/@theia/request/v/1.54.0))
+ - `@theia/request/lib/proxy` (from [`@theia/request@1.54.0`](https://www.npmjs.com/package/@theia/request/v/1.54.0))
+ - `@theia/request/lib/node-request-service` (from [`@theia/request@1.54.0`](https://www.npmjs.com/package/@theia/request/v/1.54.0))
- `fs-extra` (from [`fs-extra@^4.0.2`](https://www.npmjs.com/package/fs-extra))
- `fuzzy` (from [`fuzzy@^0.1.3`](https://www.npmjs.com/package/fuzzy))
- `inversify` (from [`inversify@^6.0.1`](https://www.npmjs.com/package/inversify))
diff --git a/packages/core/i18n/nls.cs.json b/packages/core/i18n/nls.cs.json
index 5168d1dd92a9a..4d8ba688a5bc8 100644
--- a/packages/core/i18n/nls.cs.json
+++ b/packages/core/i18n/nls.cs.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "Otevřete zobrazení konfigurace AI",
+ "aiHistory:open": "Otevřít zobrazení Historie AI",
"debug.breakpoint.editCondition": "Upravit stav...",
"notebook.cell.changeToCode": "Změna buňky na kód",
"notebook.cell.changeToMarkdown": "Změna buňky na Mardown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Zrušení všech testovacích běhů",
+ "stackFrameAt": "na adrese",
"testRunDefaultName": "{0} spustit {1}",
"testRuns": "Testovací běhy"
},
diff --git a/packages/core/i18n/nls.de.json b/packages/core/i18n/nls.de.json
index c032b6c735f39..99e7919a92af1 100644
--- a/packages/core/i18n/nls.de.json
+++ b/packages/core/i18n/nls.de.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "AI-Konfigurationsansicht öffnen",
+ "aiHistory:open": "AI-Historienansicht öffnen",
"debug.breakpoint.editCondition": "Edit Bedingung...",
"notebook.cell.changeToCode": "Zelle in Code ändern",
"notebook.cell.changeToMarkdown": "Zelle in Mardown ändern",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Alle Testläufe abbrechen",
+ "stackFrameAt": "unter",
"testRunDefaultName": "{0} laufen. {1}",
"testRuns": "Testläufe"
},
diff --git a/packages/core/i18n/nls.es.json b/packages/core/i18n/nls.es.json
index 8931ed3df2226..bdc2b7c783ed9 100644
--- a/packages/core/i18n/nls.es.json
+++ b/packages/core/i18n/nls.es.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "Abrir la vista Configuración AI",
+ "aiHistory:open": "Abrir la vista Historial de IA",
"debug.breakpoint.editCondition": "Editar condición...",
"notebook.cell.changeToCode": "Cambiar celda por código",
"notebook.cell.changeToMarkdown": "Cambiar Celda a Mardown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Cancelar todas las pruebas",
+ "stackFrameAt": "en",
"testRunDefaultName": "{0} ejecute {1}",
"testRuns": "Pruebas"
},
diff --git a/packages/core/i18n/nls.fr.json b/packages/core/i18n/nls.fr.json
index 45accd898c9b0..b6685cda6431e 100644
--- a/packages/core/i18n/nls.fr.json
+++ b/packages/core/i18n/nls.fr.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "Ouvrir la vue Configuration AI",
+ "aiHistory:open": "Ouvrir la vue de l'historique de l'IA",
"debug.breakpoint.editCondition": "Edit Condition...",
"notebook.cell.changeToCode": "Changer la cellule en code",
"notebook.cell.changeToMarkdown": "Changer la cellule en Mardown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Annuler tous les essais",
+ "stackFrameAt": "à",
"testRunDefaultName": "{0} courir {1}",
"testRuns": "Essais"
},
diff --git a/packages/core/i18n/nls.hu.json b/packages/core/i18n/nls.hu.json
index c059404ecd184..c91fe4d959b39 100644
--- a/packages/core/i18n/nls.hu.json
+++ b/packages/core/i18n/nls.hu.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "AI konfigurációs nézet megnyitása",
+ "aiHistory:open": "AI előzmények nézet megnyitása",
"debug.breakpoint.editCondition": "Szerkesztési feltétel...",
"notebook.cell.changeToCode": "Cellát kódra váltani",
"notebook.cell.changeToMarkdown": "Cellát átváltoztatni Mardown-ra",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Minden tesztfuttatás törlése",
+ "stackFrameAt": "a címen.",
"testRunDefaultName": "{0} fuss {1}",
"testRuns": "Tesztfutások"
},
diff --git a/packages/core/i18n/nls.it.json b/packages/core/i18n/nls.it.json
index 46ff1f2ae77fb..41589e74f0a4c 100644
--- a/packages/core/i18n/nls.it.json
+++ b/packages/core/i18n/nls.it.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "Aprire la vista Configurazione AI",
+ "aiHistory:open": "Aprire la vista Cronologia AI",
"debug.breakpoint.editCondition": "Modifica della condizione...",
"notebook.cell.changeToCode": "Cambia cella in codice",
"notebook.cell.changeToMarkdown": "Cambiare la cella in Mardown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Annullamento di tutte le esecuzioni di test",
+ "stackFrameAt": "a",
"testRunDefaultName": "{0} corsa {1}",
"testRuns": "Esecuzioni di prova"
},
diff --git a/packages/core/i18n/nls.ja.json b/packages/core/i18n/nls.ja.json
index 1d823f74c0c86..ddcbf18d4c7a2 100644
--- a/packages/core/i18n/nls.ja.json
+++ b/packages/core/i18n/nls.ja.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "AI設定ビューを開く",
+ "aiHistory:open": "AI履歴ビューを開く",
"debug.breakpoint.editCondition": "編集条件...",
"notebook.cell.changeToCode": "セルをコードに変更",
"notebook.cell.changeToMarkdown": "セルをマーダウンに変更",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "すべてのテスト実行をキャンセルする",
+ "stackFrameAt": "で",
"testRunDefaultName": "{0} 走る{1}",
"testRuns": "テスト走行"
},
diff --git a/packages/core/i18n/nls.json b/packages/core/i18n/nls.json
index e797ed9a60e8a..e20a2fba22fcc 100644
--- a/packages/core/i18n/nls.json
+++ b/packages/core/i18n/nls.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "Open AI Configuration view",
+ "aiHistory:open": "Open AI History view",
"debug.breakpoint.editCondition": "Edit Condition...",
"notebook.cell.changeToCode": "Change Cell to Code",
"notebook.cell.changeToMarkdown": "Change Cell to Markdown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Cancel All Test Runs",
+ "stackFrameAt": "at",
"testRunDefaultName": "{0} run {1}",
"testRuns": "Test Runs"
},
diff --git a/packages/core/i18n/nls.ko.json b/packages/core/i18n/nls.ko.json
index c35b5f4e7a0d9..38710bd357012 100644
--- a/packages/core/i18n/nls.ko.json
+++ b/packages/core/i18n/nls.ko.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "AI 구성 보기 열기",
+ "aiHistory:open": "AI 기록 보기 열기",
"debug.breakpoint.editCondition": "조건 편집...",
"notebook.cell.changeToCode": "셀을 코드로 변경",
"notebook.cell.changeToMarkdown": "셀을 마크다운으로 변경",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "모든 테스트 실행 취소",
+ "stackFrameAt": "에서",
"testRunDefaultName": "{0} 실행 {1}",
"testRuns": "테스트 실행"
},
diff --git a/packages/core/i18n/nls.pl.json b/packages/core/i18n/nls.pl.json
index 8955829d6df56..189aa3f86f263 100644
--- a/packages/core/i18n/nls.pl.json
+++ b/packages/core/i18n/nls.pl.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "Otwórz widok konfiguracji AI",
+ "aiHistory:open": "Otwórz widok historii AI",
"debug.breakpoint.editCondition": "Warunek edycji...",
"notebook.cell.changeToCode": "Zmień komórkę na kod",
"notebook.cell.changeToMarkdown": "Zmień komórkę na Mardown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Anulowanie wszystkich testów",
+ "stackFrameAt": "na",
"testRunDefaultName": "{0} bieg {1}",
"testRuns": "Przebiegi testowe"
},
diff --git a/packages/core/i18n/nls.pt-br.json b/packages/core/i18n/nls.pt-br.json
index 10793ca773fd0..2fba038a91fe7 100644
--- a/packages/core/i18n/nls.pt-br.json
+++ b/packages/core/i18n/nls.pt-br.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "Abrir a visualização de Configuração de IA",
+ "aiHistory:open": "Abrir a visualização do histórico de IA",
"debug.breakpoint.editCondition": "Editar condição...",
"notebook.cell.changeToCode": "Alterar célula para código",
"notebook.cell.changeToMarkdown": "Mudança de célula para Mardown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Cancelar todas as execuções de teste",
+ "stackFrameAt": "em",
"testRunDefaultName": "{0} executar {1}",
"testRuns": "Execuções de teste"
},
diff --git a/packages/core/i18n/nls.ru.json b/packages/core/i18n/nls.ru.json
index 18e1d8d01d3fa..26efaa004ac7e 100644
--- a/packages/core/i18n/nls.ru.json
+++ b/packages/core/i18n/nls.ru.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "Откройте представление конфигурации AI",
+ "aiHistory:open": "Откройте представление истории ИИ",
"debug.breakpoint.editCondition": "Изменить состояние...",
"notebook.cell.changeToCode": "Измените ячейку на код",
"notebook.cell.changeToMarkdown": "Измените ячейку на Мардаун",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Отмена всех тестовых запусков",
+ "stackFrameAt": "на",
"testRunDefaultName": "{0} запустить {1}",
"testRuns": "Тестовые испытания"
},
diff --git a/packages/core/i18n/nls.tr.json b/packages/core/i18n/nls.tr.json
index 87ebc516eaeed..d855292211eb6 100644
--- a/packages/core/i18n/nls.tr.json
+++ b/packages/core/i18n/nls.tr.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "AI Yapılandırma görünümünü açın",
+ "aiHistory:open": "Yapay Zeka Geçmişi görünümünü açın",
"debug.breakpoint.editCondition": "Düzenleme Durumu...",
"notebook.cell.changeToCode": "Hücreyi Kod Olarak Değiştir",
"notebook.cell.changeToMarkdown": "Hücreyi Markdown Olarak Değiştirme",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "Tüm Test Çalışmalarını İptal Et",
+ "stackFrameAt": "at",
"testRunDefaultName": "{0} koşmak {1}",
"testRuns": "Test Çalışmaları"
},
diff --git a/packages/core/i18n/nls.zh-cn.json b/packages/core/i18n/nls.zh-cn.json
index 3c356b419855d..43694260cfc3f 100644
--- a/packages/core/i18n/nls.zh-cn.json
+++ b/packages/core/i18n/nls.zh-cn.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "打开 AI 配置视图",
+ "aiHistory:open": "打开人工智能历史视图",
"debug.breakpoint.editCondition": "编辑条件...",
"notebook.cell.changeToCode": "将单元格更改为代码",
"notebook.cell.changeToMarkdown": "将 Cell 改为 Mardown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "取消所有测试运行",
+ "stackFrameAt": "于",
"testRunDefaultName": "{0} 运行{1}",
"testRuns": "测试运行"
},
diff --git a/packages/core/i18n/nls.zh-tw.json b/packages/core/i18n/nls.zh-tw.json
index b3f4b4f67c936..ede1123f822d0 100644
--- a/packages/core/i18n/nls.zh-tw.json
+++ b/packages/core/i18n/nls.zh-tw.json
@@ -1,4 +1,6 @@
{
+ "aiConfiguration:open": "開啟 AI 設定檢視",
+ "aiHistory:open": "開啟 AI 歷史檢視",
"debug.breakpoint.editCondition": "編輯條件...",
"notebook.cell.changeToCode": "變更儲存格為代碼",
"notebook.cell.changeToMarkdown": "變更儲存格為 Markdown",
@@ -499,6 +501,7 @@
},
"test": {
"cancelAllTestRuns": "取消所有測試執行",
+ "stackFrameAt": "於",
"testRunDefaultName": "{0} 跑{1}",
"testRuns": "測試運行"
},
diff --git a/packages/core/package.json b/packages/core/package.json
index b941db18927e3..d86b2ab085578 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@theia/core",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia is a cloud & desktop IDE framework implemented in TypeScript.",
"main": "lib/common/index.js",
"typings": "lib/common/index.d.ts",
@@ -16,8 +16,8 @@
"@phosphor/signaling": "1",
"@phosphor/virtualdom": "1",
"@phosphor/widgets": "1",
- "@theia/application-package": "1.53.0",
- "@theia/request": "1.53.0",
+ "@theia/application-package": "1.54.0",
+ "@theia/request": "1.54.0",
"@types/body-parser": "^1.16.4",
"@types/cookie": "^0.3.3",
"@types/dompurify": "^2.2.2",
@@ -210,8 +210,8 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
- "@theia/re-exports": "1.53.0",
+ "@theia/ext-scripts": "1.54.0",
+ "@theia/re-exports": "1.54.0",
"minimist": "^1.2.0",
"nodejs-file-downloader": "4.13.0"
},
diff --git a/packages/core/src/browser/frontend-application-module.ts b/packages/core/src/browser/frontend-application-module.ts
index 51131f9b1ce93..ea29eff0ebf87 100644
--- a/packages/core/src/browser/frontend-application-module.ts
+++ b/packages/core/src/browser/frontend-application-module.ts
@@ -144,6 +144,7 @@ import { bindTreePreferences } from './tree';
import { OpenWithService } from './open-with-service';
import { ViewColumnService } from './shell/view-column-service';
import { DomInputUndoRedoHandler, UndoRedoHandler, UndoRedoHandlerService } from './undo-redo-handler';
+import { WidgetStatusBarContribution, WidgetStatusBarService } from './widget-status-bar-service';
export { bindResourceProvider, bindMessageService, bindPreferenceService };
@@ -471,4 +472,8 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is
bindContributionProvider(bind, UndoRedoHandler);
bind(DomInputUndoRedoHandler).toSelf().inSingletonScope();
bind(UndoRedoHandler).toService(DomInputUndoRedoHandler);
+
+ bind(WidgetStatusBarService).toSelf().inSingletonScope();
+ bind(FrontendApplicationContribution).toService(WidgetStatusBarService);
+ bindContributionProvider(bind, WidgetStatusBarContribution);
});
diff --git a/packages/core/src/browser/index.ts b/packages/core/src/browser/index.ts
index ecc1ccc4da2f8..02cae0fbdf1f4 100644
--- a/packages/core/src/browser/index.ts
+++ b/packages/core/src/browser/index.ts
@@ -48,3 +48,4 @@ export * from './styling-service';
export * from './hover-service';
export * from './saveable-service';
export * from './undo-redo-handler';
+export * from './widget-status-bar-service';
diff --git a/packages/core/src/browser/open-with-service.ts b/packages/core/src/browser/open-with-service.ts
index 1e347ca88301b..56eb7c4d54a93 100644
--- a/packages/core/src/browser/open-with-service.ts
+++ b/packages/core/src/browser/open-with-service.ts
@@ -77,6 +77,10 @@ export class OpenWithService {
protected readonly handlers: OpenWithHandler[] = [];
registerHandler(handler: OpenWithHandler): Disposable {
+ if (this.handlers.some(h => h.id === handler.id)) {
+ console.warn('Duplicate OpenWithHandler registration: ' + handler.id);
+ return Disposable.NULL;
+ }
this.handlers.push(handler);
return Disposable.create(() => {
const index = this.handlers.indexOf(handler);
diff --git a/packages/core/src/browser/style/tabs.css b/packages/core/src/browser/style/tabs.css
index d81927dca9e90..661030977fa90 100644
--- a/packages/core/src/browser/style/tabs.css
+++ b/packages/core/src/browser/style/tabs.css
@@ -9,10 +9,7 @@
--theia-private-horizontal-tab-scrollbar-height: 5px;
--theia-tabbar-toolbar-z-index: 1001;
--theia-toolbar-active-transform-scale: 1.272019649;
- --theia-horizontal-toolbar-height: calc(
- var(--theia-private-horizontal-tab-height) +
- var(--theia-private-horizontal-tab-scrollbar-rail-height) / 2
- );
+ --theia-horizontal-toolbar-height: calc(var(--theia-private-horizontal-tab-height) + var(--theia-private-horizontal-tab-scrollbar-rail-height) / 2);
--theia-dragover-tab-border-width: 2px;
}
@@ -75,9 +72,7 @@
border-left: var(--theia-border-width) solid var(--theia-editorGroup-border);
}
-#theia-main-content-panel
- .p-DockPanel-handle[data-orientation="vertical"]
- + .p-TabBar {
+#theia-main-content-panel .p-DockPanel-handle[data-orientation="vertical"]+.p-TabBar {
border-top: var(--theia-border-width) solid var(--theia-editorGroup-border);
}
@@ -142,11 +137,9 @@
-webkit-appearance: none;
-moz-appearance: none;
- background-image: linear-gradient(
- 45deg,
+ background-image: linear-gradient(45deg,
transparent 50%,
- var(--theia-icon-foreground) 50%
- ),
+ var(--theia-icon-foreground) 50%),
linear-gradient(135deg, var(--theia-icon-foreground) 50%, transparent 50%);
background-position: calc(100% - 6px) 8px, calc(100% - 2px) 8px, 100% 0;
background-size: 4px 5px;
@@ -225,12 +218,8 @@
visibility: hidden;
}
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.p-mod-closable
- > .p-TabBar-tabCloseIcon,
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.theia-mod-pinned
- > .p-TabBar-tabCloseIcon {
+.p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-closable>.p-TabBar-tabCloseIcon,
+.p-TabBar.theia-app-centers .p-TabBar-tab.theia-mod-pinned>.p-TabBar-tabCloseIcon {
padding: 2px;
margin-top: 2px;
margin-left: 4px;
@@ -248,31 +237,19 @@
-ms-user-select: none;
}
-.p-TabBar.theia-app-centers.dynamic-tabs
- .p-TabBar-tab.p-mod-closable
- > .p-TabBar-tabCloseIcon,
-.p-TabBar.theia-app-centers.dynamic-tabs
- .p-TabBar-tab.theia-mod-pinned
- > .p-TabBar-tabCloseIcon {
+.p-TabBar.theia-app-centers.dynamic-tabs .p-TabBar-tab.p-mod-closable>.p-TabBar-tabCloseIcon,
+.p-TabBar.theia-app-centers.dynamic-tabs .p-TabBar-tab.theia-mod-pinned>.p-TabBar-tabCloseIcon {
/* hide close icon for dynamic tabs strategy*/
display: none;
}
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.p-mod-current
- > .p-TabBar-tabCloseIcon,
-.p-TabBar.theia-app-centers
- .p-TabBar-tab:hover.p-mod-closable
- > .p-TabBar-tabCloseIcon,
-.p-TabBar.theia-app-centers
- .p-TabBar-tab:hover.theia-mod-pinned
- > .p-TabBar-tabCloseIcon {
+.p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-current>.p-TabBar-tabCloseIcon,
+.p-TabBar.theia-app-centers .p-TabBar-tab:hover.p-mod-closable>.p-TabBar-tabCloseIcon,
+.p-TabBar.theia-app-centers .p-TabBar-tab:hover.theia-mod-pinned>.p-TabBar-tabCloseIcon {
display: inline-block;
}
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.p-mod-closable
- > .p-TabBar-tabCloseIcon:hover {
+.p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-closable>.p-TabBar-tabCloseIcon:hover {
border-radius: 5px;
background-color: rgba(50%, 50%, 50%, 0.2);
}
@@ -282,33 +259,21 @@
padding-right: 4px;
}
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.p-mod-closable:not(.theia-mod-dirty):hover
- > .p-TabBar-tabCloseIcon:before,
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.p-mod-closable:not(.theia-mod-dirty).p-TabBar-tab.p-mod-current
- > .p-TabBar-tabCloseIcon:before,
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.p-mod-closable.theia-mod-dirty
- > .p-TabBar-tabCloseIcon:hover:before {
+.p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-closable:not(.theia-mod-dirty):hover>.p-TabBar-tabCloseIcon:before,
+.p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-closable:not(.theia-mod-dirty).p-TabBar-tab.p-mod-current>.p-TabBar-tabCloseIcon:before,
+.p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-closable.theia-mod-dirty>.p-TabBar-tabCloseIcon:hover:before {
content: "\ea76";
}
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.p-mod-closable.theia-mod-dirty
- > .p-TabBar-tabCloseIcon:before {
+.p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-closable.theia-mod-dirty>.p-TabBar-tabCloseIcon:before {
content: "\ea71";
}
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.theia-mod-pinned
- > .p-TabBar-tabCloseIcon:before {
+.p-TabBar.theia-app-centers .p-TabBar-tab.theia-mod-pinned>.p-TabBar-tabCloseIcon:before {
content: "\eba0";
}
-.p-TabBar.theia-app-centers
- .p-TabBar-tab.theia-mod-pinned.theia-mod-dirty
- > .p-TabBar-tabCloseIcon:before {
+.p-TabBar.theia-app-centers .p-TabBar-tab.theia-mod-pinned.theia-mod-dirty>.p-TabBar-tabCloseIcon:before {
content: "\ebb2";
}
@@ -351,72 +316,35 @@
| Perfect scrollbar
|----------------------------------------------------------------------------*/
-.p-TabBar[data-orientation="horizontal"]
- .p-TabBar-content-container
- > .ps__rail-x {
+.p-TabBar[data-orientation="horizontal"] .p-TabBar-content-container>.ps__rail-x {
height: var(--theia-private-horizontal-tab-scrollbar-rail-height);
z-index: 1000;
}
-.p-TabBar[data-orientation="horizontal"]
- .p-TabBar-content-container
- > .ps__rail-x
- > .ps__thumb-x {
+.p-TabBar[data-orientation="horizontal"] .p-TabBar-content-container>.ps__rail-x>.ps__thumb-x {
height: var(--theia-private-horizontal-tab-scrollbar-height) !important;
- bottom: calc(
- (
- var(--theia-private-horizontal-tab-scrollbar-rail-height) -
- var(--theia-private-horizontal-tab-scrollbar-height)
- ) / 2
- );
-}
-
-.p-TabBar[data-orientation="horizontal"]
- .p-TabBar-content-container
- > .ps__rail-x:hover,
-.p-TabBar[data-orientation="horizontal"]
- .p-TabBar-content-container
- > .ps__rail-x:focus {
+ bottom: calc((var(--theia-private-horizontal-tab-scrollbar-rail-height) - var(--theia-private-horizontal-tab-scrollbar-height)) / 2);
+}
+
+.p-TabBar[data-orientation="horizontal"] .p-TabBar-content-container>.ps__rail-x:hover,
+.p-TabBar[data-orientation="horizontal"] .p-TabBar-content-container>.ps__rail-x:focus {
height: var(--theia-private-horizontal-tab-scrollbar-rail-height) !important;
}
-.p-TabBar[data-orientation="horizontal"]
- .p-TabBar-content-container
- > .ps__rail-x:hover
- > .ps__thumb-x,
-.p-TabBar[data-orientation="horizontal"]
- .p-TabBar-content-container
- > .ps__rail-x:focus
- > .ps__thumb-x {
- height: calc(
- var(--theia-private-horizontal-tab-scrollbar-height) / 2
- ) !important;
- bottom: calc(
- (
- var(--theia-private-horizontal-tab-scrollbar-rail-height) -
- var(--theia-private-horizontal-tab-scrollbar-height)
- ) / 2
- );
-}
-
-.p-TabBar[data-orientation="vertical"]
- .p-TabBar-content-container
- > .ps__rail-y {
+.p-TabBar[data-orientation="horizontal"] .p-TabBar-content-container>.ps__rail-x:hover>.ps__thumb-x,
+.p-TabBar[data-orientation="horizontal"] .p-TabBar-content-container>.ps__rail-x:focus>.ps__thumb-x {
+ height: calc(var(--theia-private-horizontal-tab-scrollbar-height) / 2) !important;
+ bottom: calc((var(--theia-private-horizontal-tab-scrollbar-rail-height) - var(--theia-private-horizontal-tab-scrollbar-height)) / 2);
+}
+
+.p-TabBar[data-orientation="vertical"] .p-TabBar-content-container>.ps__rail-y {
width: var(--theia-private-horizontal-tab-scrollbar-rail-height);
z-index: 1000;
}
-.p-TabBar[data-orientation="vertical"]
- .p-TabBar-content-container
- > .ps__rail-y
- > .ps__thumb-y {
+.p-TabBar[data-orientation="vertical"] .p-TabBar-content-container>.ps__rail-y>.ps__thumb-y {
width: var(--theia-private-horizontal-tab-scrollbar-height) !important;
- right: calc(
- (
- var(--theia-private-horizontal-tab-scrollbar-rail-height) -
- var(--theia-private-horizontal-tab-scrollbar-height)
- ) / 2
- );
+ right: calc((var(--theia-private-horizontal-tab-scrollbar-rail-height) - var(--theia-private-horizontal-tab-scrollbar-height)) / 2);
}
.p-TabBar[data-orientation="vertical"] .p-TabBar-content-container {
@@ -447,9 +375,8 @@
|----------------------------------------------------------------------------*/
.p-TabBar-toolbar {
- z-index: var(
- --theia-tabbar-toolbar-z-index
- ); /* Due to the scrollbar (`z-index: 1000;`) it has a greater `z-index`. */
+ z-index: var(--theia-tabbar-toolbar-z-index);
+ /* Due to the scrollbar (`z-index: 1000;`) it has a greater `z-index`. */
display: flex;
flex-direction: row-reverse;
padding: 4px;
@@ -460,7 +387,8 @@
.p-TabBar-content-container {
display: flex;
flex: 1;
- position: relative; /* This is necessary for perfect-scrollbar */
+ position: relative;
+ /* This is necessary for perfect-scrollbar */
}
.p-TabBar-toolbar .item {
@@ -473,7 +401,7 @@
}
.p-TabBar-toolbar .item>div {
- height: 100%;
+ height: 100%;
}
.p-TabBar-toolbar .item.enabled {
@@ -491,14 +419,14 @@
background-color: var(--theia-inputOption-activeBackground);
}
-.p-TabBar-toolbar .item > div {
- line-height: calc(var(--theia-icon-size)+2px);
- height: calc(var(--theia-icon-size)+2px);
+.p-TabBar-toolbar .item>div {
+ line-height: calc(var(--theia-icon-size) + 2px);
+ height: calc(var(--theia-icon-size) + 2px);
background-repeat: no-repeat;
line-height: 18px;
}
-.p-TabBar-toolbar .item > div.no-icon {
+.p-TabBar-toolbar .item>div.no-icon {
/* Make room for a text label instead of an icon. */
width: 100%;
}
@@ -532,9 +460,7 @@
vertical-align: bottom;
}
-#theia-main-content-panel
- .p-TabBar:not(.theia-tabBar-active)
- .p-TabBar-toolbar {
+#theia-main-content-panel .p-TabBar:not(.theia-tabBar-active) .p-TabBar-toolbar {
display: none;
}
@@ -543,9 +469,7 @@
}
.p-TabBar.theia-tabBar-multirow[data-orientation="horizontal"] {
- min-height: calc(
- var(--theia-breadcrumbs-height) + var(--theia-horizontal-toolbar-height)
- );
+ min-height: calc(var(--theia-breadcrumbs-height) + var(--theia-horizontal-toolbar-height));
flex-direction: column;
}
@@ -569,19 +493,14 @@
flex-direction: column;
}
-.p-TabBar.theia-app-centers[data-orientation="horizontal"].dynamic-tabs
- .p-TabBar-tabLabel {
+.p-TabBar.theia-app-centers[data-orientation="horizontal"].dynamic-tabs .p-TabBar-tabLabel {
/* fade out text with dynamic tabs strategy */
- mask-image: linear-gradient(
- to left,
- rgba(0, 0, 0, 0.3),
- rgba(0, 0, 0, 1) 15px
- );
- -webkit-mask-image: linear-gradient(
- to left,
- rgba(0, 0, 0, 0.3),
- rgba(0, 0, 0, 1) 15px
- );
+ mask-image: linear-gradient(to left,
+ rgba(0, 0, 0, 0.3),
+ rgba(0, 0, 0, 1) 15px);
+ -webkit-mask-image: linear-gradient(to left,
+ rgba(0, 0, 0, 0.3),
+ rgba(0, 0, 0, 1) 15px);
flex: 1;
}
@@ -625,13 +544,11 @@
/*-----------------------------------------------------------------------------
| Open tabs dropdown
|----------------------------------------------------------------------------*/
-.theia-tabBar-open-tabs
- > .theia-select-component
- .theia-select-component-label {
+.theia-tabBar-open-tabs>.theia-select-component .theia-select-component-label {
display: none;
}
-.theia-tabBar-open-tabs > .theia-select-component {
+.theia-tabBar-open-tabs>.theia-select-component {
min-width: auto;
height: 100%;
}
@@ -644,4 +561,4 @@
.theia-tabBar-open-tabs.p-mod-hidden {
display: none;
-}
+}
\ No newline at end of file
diff --git a/packages/core/src/browser/widget-status-bar-service.ts b/packages/core/src/browser/widget-status-bar-service.ts
new file mode 100644
index 0000000000000..d705880d90546
--- /dev/null
+++ b/packages/core/src/browser/widget-status-bar-service.ts
@@ -0,0 +1,84 @@
+// *****************************************************************************
+// Copyright (C) 2024 TypeFox and others.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0.
+//
+// This Source Code may also be made available under the following Secondary
+// Licenses when the conditions for such availability set forth in the Eclipse
+// Public License v. 2.0 are satisfied: GNU General Public License, version 2
+// with the GNU Classpath Exception which is available at
+// https://www.gnu.org/software/classpath/license.html.
+//
+// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
+// *****************************************************************************
+
+import { inject, injectable, named } from 'inversify';
+import { Widget } from './widgets';
+import { StatusBar } from './status-bar';
+import { FrontendApplicationContribution } from './frontend-application-contribution';
+import { ContributionProvider } from '../common';
+import { FrontendApplication } from './frontend-application';
+
+export const WidgetStatusBarContribution = Symbol('WidgetStatusBarContribution');
+
+export interface WidgetStatusBarContribution {
+ canHandle(widget: Widget): widget is T;
+ activate(statusBar: StatusBar, widget: T): void;
+ deactivate(statusBar: StatusBar): void;
+}
+
+/**
+ * Creates an empty {@link WidgetStatusBarContribution} that does nothing.
+ * Useful for widgets that are not handled by any other contribution, for example:
+ * * Settings widget
+ * * Welcome widget
+ * * Webview widget
+ *
+ * @param prototype Prototype to identify the kind of the widget.
+ * @returns An empty {@link WidgetStatusBarContribution}.
+ */
+export function noopWidgetStatusBarContribution(prototype: Function): WidgetStatusBarContribution {
+ return {
+ canHandle(widget: Widget): widget is Widget {
+ return widget instanceof prototype;
+ },
+ activate: () => { },
+ deactivate: () => { }
+ };
+}
+
+@injectable()
+export class WidgetStatusBarService implements FrontendApplicationContribution {
+
+ @inject(ContributionProvider) @named(WidgetStatusBarContribution)
+ protected readonly contributionProvider: ContributionProvider>;
+
+ @inject(StatusBar)
+ protected readonly statusBar: StatusBar;
+
+ onStart(app: FrontendApplication): void {
+ app.shell.onDidChangeCurrentWidget(event => {
+ if (event.newValue) {
+ this.show(event.newValue);
+ }
+ });
+ }
+
+ protected show(widget: Widget): void {
+ const contributions = this.contributionProvider.getContributions();
+ // If any contribution can handle the widget, activate it
+ // If none can, keep everything as is
+ if (contributions.some(contribution => contribution.canHandle(widget))) {
+ for (const contribution of contributions) {
+ // Deactivate all contributions
+ contribution.deactivate(this.statusBar);
+ if (contribution.canHandle(widget)) {
+ // Selectively re-activate them
+ contribution.activate(this.statusBar, widget);
+ }
+ }
+ }
+ }
+}
diff --git a/packages/core/src/browser/widgets/split-widget.ts b/packages/core/src/browser/widgets/split-widget.ts
index 0c1e5dd3d4269..ff54f218a7483 100644
--- a/packages/core/src/browser/widgets/split-widget.ts
+++ b/packages/core/src/browser/widgets/split-widget.ts
@@ -14,12 +14,11 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
-import { Emitter } from 'vscode-languageserver-protocol';
import { ApplicationShell, StatefulWidget } from '../shell';
import { BaseWidget, Message, PanelLayout, SplitPanel, Widget } from './widget';
import { CompositeSaveable, Saveable, SaveableSource } from '../saveable';
import { Navigatable } from '../navigatable-types';
-import { URI } from '../../common';
+import { Emitter, URI } from '../../common';
/**
* A widget containing a number of panes in a split layout.
diff --git a/packages/debug/package.json b/packages/debug/package.json
index 20c5f05cf0f2a..bb7dcb3e6d939 100644
--- a/packages/debug/package.json
+++ b/packages/debug/package.json
@@ -1,22 +1,22 @@
{
"name": "@theia/debug",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Debug Extension",
"dependencies": {
- "@theia/console": "1.53.0",
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/markers": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/console": "1.54.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/markers": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/output": "1.53.0",
- "@theia/process": "1.53.0",
- "@theia/task": "1.53.0",
- "@theia/test": "1.53.0",
- "@theia/terminal": "1.53.0",
- "@theia/variable-resolver": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/output": "1.54.0",
+ "@theia/process": "1.54.0",
+ "@theia/task": "1.54.0",
+ "@theia/test": "1.54.0",
+ "@theia/terminal": "1.54.0",
+ "@theia/variable-resolver": "1.54.0",
+ "@theia/workspace": "1.54.0",
"@vscode/debugprotocol": "^1.51.0",
"fast-deep-equal": "^3.1.3",
"jsonc-parser": "^2.2.0",
@@ -59,7 +59,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/dev-container/package.json b/packages/dev-container/package.json
index 32f233826ae62..8c50696c150f6 100644
--- a/packages/dev-container/package.json
+++ b/packages/dev-container/package.json
@@ -1,12 +1,12 @@
{
"name": "@theia/dev-container",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Editor Preview Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/output": "1.53.0",
- "@theia/remote": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/output": "1.54.0",
+ "@theia/remote": "1.54.0",
+ "@theia/workspace": "1.54.0",
"dockerode": "^4.0.2",
"jsonc-parser": "^2.2.0",
"uuid": "^8.0.0"
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
+ "@theia/ext-scripts": "1.54.0",
"@types/dockerode": "^3.3.23"
},
"nyc": {
diff --git a/packages/editor-preview/package.json b/packages/editor-preview/package.json
index 7f55c86cd94fc..9c572f902b63e 100644
--- a/packages/editor-preview/package.json
+++ b/packages/editor-preview/package.json
@@ -1,11 +1,11 @@
{
"name": "@theia/editor-preview",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Editor Preview Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/navigator": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/navigator": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -41,7 +41,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/editor-preview/src/browser/editor-preview-tree-decorator.ts b/packages/editor-preview/src/browser/editor-preview-tree-decorator.ts
index 21c6671cee3ca..c5908ef105624 100644
--- a/packages/editor-preview/src/browser/editor-preview-tree-decorator.ts
+++ b/packages/editor-preview/src/browser/editor-preview-tree-decorator.ts
@@ -30,11 +30,10 @@ import {
import { Disposable } from '@theia/core/lib/common';
import { OpenEditorNode } from '@theia/navigator/lib/browser/open-editors-widget/navigator-open-editors-tree-model';
import { EditorPreviewWidget } from './editor-preview-widget';
-import { EditorPreviewManager } from './editor-preview-manager';
@injectable()
export class EditorPreviewTreeDecorator implements TreeDecorator, FrontendApplicationContribution {
- @inject(EditorPreviewManager) protected readonly editorPreviewManager: EditorPreviewManager;
+
@inject(ApplicationShell) protected readonly shell: ApplicationShell;
readonly id = 'theia-open-editors-file-decorator';
diff --git a/packages/editor/package.json b/packages/editor/package.json
index c0a330246a020..32d1e2d9d1f7b 100644
--- a/packages/editor/package.json
+++ b/packages/editor/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/editor",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Editor Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/variable-resolver": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/variable-resolver": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -41,7 +41,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/editor/src/browser/editor-contribution.ts b/packages/editor/src/browser/editor-contribution.ts
index a51191531fdf4..00dca84019da8 100644
--- a/packages/editor/src/browser/editor-contribution.ts
+++ b/packages/editor/src/browser/editor-contribution.ts
@@ -20,7 +20,9 @@ import { injectable, inject, optional } from '@theia/core/shared/inversify';
import { StatusBarAlignment, StatusBar } from '@theia/core/lib/browser/status-bar/status-bar';
import {
FrontendApplicationContribution, DiffUris, DockLayout,
- QuickInputService, KeybindingRegistry, KeybindingContribution, SHELL_TABBAR_CONTEXT_SPLIT, ApplicationShell
+ QuickInputService, KeybindingRegistry, KeybindingContribution, SHELL_TABBAR_CONTEXT_SPLIT, ApplicationShell,
+ WidgetStatusBarContribution,
+ Widget
} from '@theia/core/lib/browser';
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
import { CommandHandler, DisposableCollection, MenuContribution, MenuModelRegistry } from '@theia/core';
@@ -33,9 +35,9 @@ import { EditorWidget } from './editor-widget';
import { EditorLanguageStatusService } from './language-status/editor-language-status-service';
@injectable()
-export class EditorContribution implements FrontendApplicationContribution, CommandContribution, KeybindingContribution, MenuContribution {
+export class EditorContribution implements FrontendApplicationContribution,
+ CommandContribution, KeybindingContribution, MenuContribution, WidgetStatusBarContribution {
- @inject(StatusBar) protected readonly statusBar: StatusBar;
@inject(EditorManager) protected readonly editorManager: EditorManager;
@inject(EditorLanguageStatusService) protected readonly languageStatusService: EditorLanguageStatusService;
@inject(ApplicationShell) protected readonly shell: ApplicationShell;
@@ -48,9 +50,6 @@ export class EditorContribution implements FrontendApplicationContribution, Comm
onStart(): void {
this.initEditorContextKeys();
-
- this.updateStatusBar();
- this.editorManager.onCurrentEditorChanged(() => this.updateStatusBar());
}
protected initEditorContextKeys(): void {
@@ -72,33 +71,41 @@ export class EditorContribution implements FrontendApplicationContribution, Comm
}
protected readonly toDisposeOnCurrentEditorChanged = new DisposableCollection();
- protected updateStatusBar(): void {
+
+ canHandle(widget: Widget): widget is EditorWidget {
+ return widget instanceof EditorWidget;
+ }
+
+ activate(statusBar: StatusBar, widget: EditorWidget): void {
this.toDisposeOnCurrentEditorChanged.dispose();
+ const editor = widget.editor;
+ this.updateLanguageStatus(statusBar, editor);
+ this.updateEncodingStatus(statusBar, editor);
+ this.setCursorPositionStatus(statusBar, editor);
+ this.toDisposeOnCurrentEditorChanged.pushAll([
+ editor.onLanguageChanged(() => this.updateLanguageStatus(statusBar, editor)),
+ editor.onEncodingChanged(() => this.updateEncodingStatus(statusBar, editor)),
+ editor.onCursorPositionChanged(() => this.setCursorPositionStatus(statusBar, editor))
+ ]);
+ }
- const widget = this.editorManager.currentEditor;
- const editor = widget && widget.editor;
- this.updateLanguageStatus(editor);
- this.updateEncodingStatus(editor);
- this.setCursorPositionStatus(editor);
- if (editor) {
- this.toDisposeOnCurrentEditorChanged.pushAll([
- editor.onLanguageChanged(() => this.updateLanguageStatus(editor)),
- editor.onEncodingChanged(() => this.updateEncodingStatus(editor)),
- editor.onCursorPositionChanged(() => this.setCursorPositionStatus(editor))
- ]);
- }
+ deactivate(statusBar: StatusBar): void {
+ this.toDisposeOnCurrentEditorChanged.dispose();
+ this.updateLanguageStatus(statusBar, undefined);
+ this.updateEncodingStatus(statusBar, undefined);
+ this.setCursorPositionStatus(statusBar, undefined);
}
- protected updateLanguageStatus(editor: TextEditor | undefined): void {
+ protected updateLanguageStatus(statusBar: StatusBar, editor: TextEditor | undefined): void {
this.languageStatusService.updateLanguageStatus(editor);
}
- protected updateEncodingStatus(editor: TextEditor | undefined): void {
+ protected updateEncodingStatus(statusBar: StatusBar, editor: TextEditor | undefined): void {
if (!editor) {
- this.statusBar.removeElement('editor-status-encoding');
+ statusBar.removeElement('editor-status-encoding');
return;
}
- this.statusBar.setElement('editor-status-encoding', {
+ statusBar.setElement('editor-status-encoding', {
text: SUPPORTED_ENCODINGS[editor.getEncoding()].labelShort,
alignment: StatusBarAlignment.RIGHT,
priority: 10,
@@ -107,13 +114,13 @@ export class EditorContribution implements FrontendApplicationContribution, Comm
});
}
- protected setCursorPositionStatus(editor: TextEditor | undefined): void {
+ protected setCursorPositionStatus(statusBar: StatusBar, editor: TextEditor | undefined): void {
if (!editor) {
- this.statusBar.removeElement('editor-status-cursor-position');
+ statusBar.removeElement('editor-status-cursor-position');
return;
}
const { cursor } = editor;
- this.statusBar.setElement('editor-status-cursor-position', {
+ statusBar.setElement('editor-status-cursor-position', {
text: nls.localizeByDefault('Ln {0}, Col {1}', cursor.line + 1, editor.getVisibleColumn(cursor)),
alignment: StatusBarAlignment.RIGHT,
priority: 100,
diff --git a/packages/editor/src/browser/editor-frontend-module.ts b/packages/editor/src/browser/editor-frontend-module.ts
index e4a089ae90b2a..d5142fa29fa9e 100644
--- a/packages/editor/src/browser/editor-frontend-module.ts
+++ b/packages/editor/src/browser/editor-frontend-module.ts
@@ -19,7 +19,7 @@ import '../../src/browser/language-status/editor-language-status.css';
import { ContainerModule } from '@theia/core/shared/inversify';
import { CommandContribution, MenuContribution } from '@theia/core/lib/common';
-import { OpenHandler, WidgetFactory, FrontendApplicationContribution, KeybindingContribution } from '@theia/core/lib/browser';
+import { OpenHandler, WidgetFactory, FrontendApplicationContribution, KeybindingContribution, WidgetStatusBarContribution } from '@theia/core/lib/browser';
import { VariableContribution } from '@theia/variable-resolver/lib/browser';
import { EditorManager, EditorAccess, ActiveEditorAccess, CurrentEditorAccess } from './editor-manager';
import { EditorContribution } from './editor-contribution';
@@ -59,7 +59,6 @@ export default new ContainerModule(bind => {
bind(KeybindingContribution).toService(EditorKeybindingContribution);
bind(EditorContribution).toSelf().inSingletonScope();
- bind(FrontendApplicationContribution).toService(EditorContribution);
bind(EditorLanguageStatusService).toSelf().inSingletonScope();
bind(EditorLineNumberContribution).toSelf().inSingletonScope();
@@ -73,7 +72,13 @@ export default new ContainerModule(bind => {
bind(VariableContribution).to(EditorVariableContribution).inSingletonScope();
- [CommandContribution, KeybindingContribution, MenuContribution].forEach(serviceIdentifier => {
+ [
+ FrontendApplicationContribution,
+ WidgetStatusBarContribution,
+ CommandContribution,
+ KeybindingContribution,
+ MenuContribution
+ ].forEach(serviceIdentifier => {
bind(serviceIdentifier).toService(EditorContribution);
});
bind(QuickEditorService).toSelf().inSingletonScope();
diff --git a/packages/electron/package.json b/packages/electron/package.json
index e6ec7699f5883..23e63797d9c8e 100644
--- a/packages/electron/package.json
+++ b/packages/electron/package.json
@@ -1,6 +1,6 @@
{
"name": "@theia/electron",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Electron utility package",
"dependencies": {
"electron-store": "^8.0.0",
@@ -8,8 +8,8 @@
"native-keymap": "^2.2.1"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
- "@theia/re-exports": "1.53.0"
+ "@theia/ext-scripts": "1.54.0",
+ "@theia/re-exports": "1.54.0"
},
"peerDependencies": {
"electron": "^30.1.2"
diff --git a/packages/external-terminal/package.json b/packages/external-terminal/package.json
index e0348b0654fed..e15aedbc83909 100644
--- a/packages/external-terminal/package.json
+++ b/packages/external-terminal/package.json
@@ -1,11 +1,11 @@
{
"name": "@theia/external-terminal",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - External Terminal Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/workspace": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -42,7 +42,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/file-search/package.json b/packages/file-search/package.json
index 4c5ba9e5d522e..79861c8efdc55 100644
--- a/packages/file-search/package.json
+++ b/packages/file-search/package.json
@@ -1,13 +1,13 @@
{
"name": "@theia/file-search",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - File Search Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/process": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/process": "1.54.0",
+ "@theia/workspace": "1.54.0",
"@vscode/ripgrep": "^1.14.2",
"tslib": "^2.6.2"
},
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/filesystem/package.json b/packages/filesystem/package.json
index 7c1a60322c673..bcdd37c09bc2f 100644
--- a/packages/filesystem/package.json
+++ b/packages/filesystem/package.json
@@ -1,9 +1,9 @@
{
"name": "@theia/filesystem",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - FileSystem Extension",
"dependencies": {
- "@theia/core": "1.53.0",
+ "@theia/core": "1.54.0",
"@types/body-parser": "^1.17.0",
"@types/multer": "^1.4.7",
"@types/rimraf": "^2.0.2",
@@ -73,7 +73,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/getting-started/package.json b/packages/getting-started/package.json
index 644cfca695224..cb666bfd2dc5f 100644
--- a/packages/getting-started/package.json
+++ b/packages/getting-started/package.json
@@ -1,14 +1,14 @@
{
"name": "@theia/getting-started",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - GettingStarted Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/keymaps": "1.53.0",
- "@theia/preview": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/keymaps": "1.54.0",
+ "@theia/preview": "1.54.0",
+ "@theia/workspace": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/getting-started/src/browser/getting-started-frontend-module.ts b/packages/getting-started/src/browser/getting-started-frontend-module.ts
index fbcc828646f02..d029dd7a2236c 100644
--- a/packages/getting-started/src/browser/getting-started-frontend-module.ts
+++ b/packages/getting-started/src/browser/getting-started-frontend-module.ts
@@ -17,13 +17,14 @@
import { GettingStartedContribution } from './getting-started-contribution';
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
import { GettingStartedWidget } from './getting-started-widget';
-import { WidgetFactory, FrontendApplicationContribution, bindViewContribution } from '@theia/core/lib/browser';
+import { WidgetFactory, FrontendApplicationContribution, bindViewContribution, noopWidgetStatusBarContribution, WidgetStatusBarContribution } from '@theia/core/lib/browser';
import { bindGettingStartedPreferences } from './getting-started-preferences';
import '../../src/browser/style/index.css';
export default new ContainerModule((bind: interfaces.Bind) => {
bindViewContribution(bind, GettingStartedContribution);
bind(FrontendApplicationContribution).toService(GettingStartedContribution);
+ bind(WidgetStatusBarContribution).toConstantValue(noopWidgetStatusBarContribution(GettingStartedWidget));
bind(GettingStartedWidget).toSelf();
bind(WidgetFactory).toDynamicValue(context => ({
id: GettingStartedWidget.ID,
diff --git a/packages/git/package.json b/packages/git/package.json
index eb69eba9b6383..a5e1b776c1ec3 100644
--- a/packages/git/package.json
+++ b/packages/git/package.json
@@ -1,16 +1,16 @@
{
"name": "@theia/git",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Git Integration",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/navigator": "1.53.0",
- "@theia/scm": "1.53.0",
- "@theia/scm-extra": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/navigator": "1.54.0",
+ "@theia/scm": "1.54.0",
+ "@theia/scm-extra": "1.54.0",
+ "@theia/workspace": "1.54.0",
"@types/diff": "^5.2.1",
"@types/p-queue": "^2.3.1",
"diff": "^5.2.0",
@@ -67,7 +67,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
+ "@theia/ext-scripts": "1.54.0",
"@types/luxon": "^2.3.2",
"upath": "^1.0.2"
},
diff --git a/packages/keymaps/package.json b/packages/keymaps/package.json
index 425fe663b24fd..5a0bbff683274 100644
--- a/packages/keymaps/package.json
+++ b/packages/keymaps/package.json
@@ -1,18 +1,18 @@
{
"name": "@theia/keymaps",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Custom Keymaps Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/preferences": "1.53.0",
- "@theia/userstorage": "1.53.0",
+ "@theia/preferences": "1.54.0",
+ "@theia/userstorage": "1.54.0",
"jsonc-parser": "^2.2.0",
"tslib": "^2.6.2"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"publishConfig": {
"access": "public"
diff --git a/packages/keymaps/src/browser/keymaps-frontend-module.ts b/packages/keymaps/src/browser/keymaps-frontend-module.ts
index 2056444246231..5a2c1476bc357 100644
--- a/packages/keymaps/src/browser/keymaps-frontend-module.ts
+++ b/packages/keymaps/src/browser/keymaps-frontend-module.ts
@@ -22,7 +22,7 @@ import { KeymapsFrontendContribution } from './keymaps-frontend-contribution';
import { CommandContribution, MenuContribution } from '@theia/core/lib/common';
import { KeybindingContribution } from '@theia/core/lib/browser/keybinding';
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
-import { WidgetFactory } from '@theia/core/lib/browser';
+import { noopWidgetStatusBarContribution, WidgetFactory, WidgetStatusBarContribution } from '@theia/core/lib/browser';
import { KeybindingWidget } from './keybindings-widget';
import { KeybindingSchemaUpdater } from './keybinding-schema-updater';
import { JsonSchemaContribution } from '@theia/core/lib/browser/json-schema-store';
@@ -41,4 +41,5 @@ export default new ContainerModule(bind => {
})).inSingletonScope();
bind(KeybindingSchemaUpdater).toSelf().inSingletonScope();
bind(JsonSchemaContribution).toService(KeybindingSchemaUpdater);
+ bind(WidgetStatusBarContribution).toConstantValue(noopWidgetStatusBarContribution(KeybindingWidget));
});
diff --git a/packages/markers/package.json b/packages/markers/package.json
index 97d1a36c62c8a..47aba430ee260 100644
--- a/packages/markers/package.json
+++ b/packages/markers/package.json
@@ -1,11 +1,11 @@
{
"name": "@theia/markers",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Markers Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/workspace": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -41,7 +41,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/memory-inspector/package.json b/packages/memory-inspector/package.json
index ff3b247c27495..a505a90f24873 100644
--- a/packages/memory-inspector/package.json
+++ b/packages/memory-inspector/package.json
@@ -1,6 +1,6 @@
{
"name": "@theia/memory-inspector",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Memory Inspector",
"keywords": [
"theia-extension"
@@ -27,8 +27,8 @@
"watch": "theiaext watch"
},
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/debug": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/debug": "1.54.0",
"@vscode/debugprotocol": "^1.51.0",
"long": "^4.0.0",
"tslib": "^2.6.2"
diff --git a/packages/messages/package.json b/packages/messages/package.json
index 56cfe7f700f30..d0526320a5100 100644
--- a/packages/messages/package.json
+++ b/packages/messages/package.json
@@ -1,9 +1,9 @@
{
"name": "@theia/messages",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Messages Extension",
"dependencies": {
- "@theia/core": "1.53.0",
+ "@theia/core": "1.54.0",
"react-perfect-scrollbar": "^1.5.3",
"ts-md5": "^1.2.2",
"tslib": "^2.6.2"
@@ -41,7 +41,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/metrics/package.json b/packages/metrics/package.json
index 422ede4ef0702..ffa673db971e4 100644
--- a/packages/metrics/package.json
+++ b/packages/metrics/package.json
@@ -1,9 +1,9 @@
{
"name": "@theia/metrics",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Metrics Extension",
"dependencies": {
- "@theia/core": "1.53.0",
+ "@theia/core": "1.54.0",
"prom-client": "^10.2.0",
"tslib": "^2.6.2"
},
@@ -44,7 +44,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/mini-browser/package.json b/packages/mini-browser/package.json
index 405aab53fc71c..2dbc4baf27487 100644
--- a/packages/mini-browser/package.json
+++ b/packages/mini-browser/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/mini-browser",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Mini-Browser Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
"@types/mime-types": "^2.1.0",
"mime-types": "^2.1.18",
"pdfobject": "^2.0.201604172",
@@ -49,7 +49,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/monaco/package.json b/packages/monaco/package.json
index 626ab8cb50145..7e65c3cd66811 100644
--- a/packages/monaco/package.json
+++ b/packages/monaco/package.json
@@ -1,15 +1,15 @@
{
"name": "@theia/monaco",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Monaco Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/markers": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/markers": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/outline-view": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/outline-view": "1.54.0",
+ "@theia/workspace": "1.54.0",
"fast-plist": "^0.1.2",
"idb": "^4.0.5",
"jsonc-parser": "^2.2.0",
@@ -52,7 +52,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/monaco/src/browser/monaco-frontend-module.ts b/packages/monaco/src/browser/monaco-frontend-module.ts
index 0bd3a74f2500c..e7d727453bb07 100644
--- a/packages/monaco/src/browser/monaco-frontend-module.ts
+++ b/packages/monaco/src/browser/monaco-frontend-module.ts
@@ -21,7 +21,8 @@ import {
FrontendApplicationContribution, KeybindingContribution,
PreferenceService, PreferenceSchemaProvider, createPreferenceProxy,
PreferenceScope, PreferenceChange, OVERRIDE_PROPERTY_PATTERN, QuickInputService, StylingParticipant, WebSocketConnectionProvider,
- UndoRedoHandler
+ UndoRedoHandler,
+ WidgetStatusBarContribution
} from '@theia/core/lib/browser';
import { TextEditorProvider, DiffNavigatorProvider, TextEditor } from '@theia/editor/lib/browser';
import { MonacoEditorProvider, MonacoEditorFactory } from './monaco-editor-provider';
@@ -135,7 +136,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(FrontendApplicationContribution).toService(MonacoFormattingConflictsContribution);
bind(MonacoStatusBarContribution).toSelf().inSingletonScope();
- bind(FrontendApplicationContribution).toService(MonacoStatusBarContribution);
+ bind(WidgetStatusBarContribution).toService(MonacoStatusBarContribution);
bind(MonacoCommandRegistry).toSelf().inSingletonScope();
bind(MonacoEditorCommandHandlers).toSelf().inSingletonScope();
diff --git a/packages/monaco/src/browser/monaco-status-bar-contribution.ts b/packages/monaco/src/browser/monaco-status-bar-contribution.ts
index fae85805e9f1a..c7ac733d29987 100644
--- a/packages/monaco/src/browser/monaco-status-bar-contribution.ts
+++ b/packages/monaco/src/browser/monaco-status-bar-contribution.ts
@@ -14,93 +14,90 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
-import { injectable, inject } from '@theia/core/shared/inversify';
+import { injectable } from '@theia/core/shared/inversify';
import { DisposableCollection, nls } from '@theia/core';
-import { FrontendApplicationContribution, FrontendApplication, StatusBar, StatusBarAlignment } from '@theia/core/lib/browser';
-import { EditorCommands, EditorManager, EditorWidget } from '@theia/editor/lib/browser';
+import { StatusBar, StatusBarAlignment, Widget, WidgetStatusBarContribution } from '@theia/core/lib/browser';
+import { EditorCommands, EditorWidget } from '@theia/editor/lib/browser';
import { MonacoEditor } from './monaco-editor';
import * as monaco from '@theia/monaco-editor-core';
+export const EDITOR_STATUS_TABBING_CONFIG = 'editor-status-tabbing-config';
+export const EDITOR_STATUS_EOL = 'editor-status-eol';
+
@injectable()
-export class MonacoStatusBarContribution implements FrontendApplicationContribution {
+export class MonacoStatusBarContribution implements WidgetStatusBarContribution {
protected readonly toDispose = new DisposableCollection();
- constructor(
- @inject(EditorManager) protected readonly editorManager: EditorManager,
- @inject(StatusBar) protected readonly statusBar: StatusBar
- ) { }
-
- onStart(app: FrontendApplication): void {
- this.updateStatusBar();
- this.editorManager.onCurrentEditorChanged(() => this.updateStatusBar());
+ canHandle(widget: Widget): widget is EditorWidget {
+ if (widget instanceof EditorWidget) {
+ return Boolean(this.getModel(widget));
+ }
+ return false;
}
- protected updateStatusBar(): void {
- const editor = this.editorManager.currentEditor;
+ activate(statusBar: StatusBar, editor: EditorWidget): void {
+ this.toDispose.dispose();
const editorModel = this.getModel(editor);
- if (editor && editorModel) {
- this.setConfigTabSizeWidget();
- this.setLineEndingWidget();
-
- this.toDispose.dispose();
+ if (editorModel) {
+ this.setConfigTabSizeWidget(statusBar, editorModel);
+ this.setLineEndingWidget(statusBar, editorModel);
this.toDispose.push(editorModel.onDidChangeOptions(() => {
- this.setConfigTabSizeWidget();
- this.setLineEndingWidget();
+ this.setConfigTabSizeWidget(statusBar, editorModel);
+ this.setLineEndingWidget(statusBar, editorModel);
}));
let previous = editorModel.getEOL();
this.toDispose.push(editorModel.onDidChangeContent(e => {
if (previous !== e.eol) {
previous = e.eol;
- this.setLineEndingWidget();
+ this.setLineEndingWidget(statusBar, editorModel);
}
}));
} else {
- this.removeConfigTabSizeWidget();
- this.removeLineEndingWidget();
+ this.deactivate(statusBar);
}
}
- protected setConfigTabSizeWidget(): void {
- const editor = this.editorManager.currentEditor;
- const editorModel = this.getModel(editor);
- if (editor && editorModel) {
- const modelOptions = editorModel.getOptions();
- const tabSize = modelOptions.tabSize;
- const indentSize = modelOptions.indentSize;
- const spaceOrTabSizeMessage = modelOptions.insertSpaces
- ? nls.localizeByDefault('Spaces: {0}', indentSize)
- : nls.localizeByDefault('Tab Size: {0}', tabSize);
- this.statusBar.setElement('editor-status-tabbing-config', {
- text: spaceOrTabSizeMessage,
- alignment: StatusBarAlignment.RIGHT,
- priority: 10,
- command: EditorCommands.CONFIG_INDENTATION.id,
- tooltip: nls.localizeByDefault('Select Indentation')
- });
- }
+ deactivate(statusBar: StatusBar): void {
+ this.toDispose.dispose();
+ this.removeConfigTabSizeWidget(statusBar);
+ this.removeLineEndingWidget(statusBar);
}
- protected removeConfigTabSizeWidget(): void {
- this.statusBar.removeElement('editor-status-tabbing-config');
+
+ protected setConfigTabSizeWidget(statusBar: StatusBar, model: monaco.editor.ITextModel): void {
+ const modelOptions = model.getOptions();
+ const tabSize = modelOptions.tabSize;
+ const indentSize = modelOptions.indentSize;
+ const spaceOrTabSizeMessage = modelOptions.insertSpaces
+ ? nls.localizeByDefault('Spaces: {0}', indentSize)
+ : nls.localizeByDefault('Tab Size: {0}', tabSize);
+ statusBar.setElement(EDITOR_STATUS_TABBING_CONFIG, {
+ text: spaceOrTabSizeMessage,
+ alignment: StatusBarAlignment.RIGHT,
+ priority: 10,
+ command: EditorCommands.CONFIG_INDENTATION.id,
+ tooltip: nls.localizeByDefault('Select Indentation')
+ });
}
- protected setLineEndingWidget(): void {
- const editor = this.editorManager.currentEditor;
- const editorModel = this.getModel(editor);
- if (editor && editorModel) {
- const eol = editorModel.getEOL();
- const text = eol === '\n' ? 'LF' : 'CRLF';
- this.statusBar.setElement('editor-status-eol', {
- text: `${text}`,
- alignment: StatusBarAlignment.RIGHT,
- priority: 11,
- command: EditorCommands.CONFIG_EOL.id,
- tooltip: nls.localizeByDefault('Select End of Line Sequence')
- });
- }
+ protected removeConfigTabSizeWidget(statusBar: StatusBar): void {
+ statusBar.removeElement(EDITOR_STATUS_TABBING_CONFIG);
}
- protected removeLineEndingWidget(): void {
- this.statusBar.removeElement('editor-status-eol');
+
+ protected setLineEndingWidget(statusBar: StatusBar, model: monaco.editor.ITextModel): void {
+ const eol = model.getEOL();
+ const text = eol === '\n' ? 'LF' : 'CRLF';
+ statusBar.setElement(EDITOR_STATUS_EOL, {
+ text: `${text}`,
+ alignment: StatusBarAlignment.RIGHT,
+ priority: 11,
+ command: EditorCommands.CONFIG_EOL.id,
+ tooltip: nls.localizeByDefault('Select End of Line Sequence')
+ });
+ }
+
+ protected removeLineEndingWidget(statusBar: StatusBar): void {
+ statusBar.removeElement(EDITOR_STATUS_EOL);
}
protected getModel(editor: EditorWidget | undefined): monaco.editor.ITextModel | undefined {
diff --git a/packages/navigator/package.json b/packages/navigator/package.json
index e20b6b9692b2a..9abadafa4f317 100644
--- a/packages/navigator/package.json
+++ b/packages/navigator/package.json
@@ -1,11 +1,11 @@
{
"name": "@theia/navigator",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Navigator Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/workspace": "1.54.0",
"minimatch": "^5.1.0",
"tslib": "^2.6.2"
},
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/notebook/package.json b/packages/notebook/package.json
index c62ef82bb0701..cc15cf13ac99f 100644
--- a/packages/notebook/package.json
+++ b/packages/notebook/package.json
@@ -1,14 +1,14 @@
{
"name": "@theia/notebook",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Notebook Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/outline-view": "1.53.0",
+ "@theia/outline-view": "1.54.0",
"advanced-mark.js": "^2.6.0",
"react-perfect-scrollbar": "^1.5.8",
"tslib": "^2.6.2"
@@ -46,7 +46,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
+ "@theia/ext-scripts": "1.54.0",
"@types/markdown-it": "^12.2.3",
"@types/vscode-notebook-renderer": "^1.72.0"
},
diff --git a/packages/notebook/src/browser/contributions/notebook-status-bar-contribution.ts b/packages/notebook/src/browser/contributions/notebook-status-bar-contribution.ts
index 05ded847b5bb3..740970baf76ca 100644
--- a/packages/notebook/src/browser/contributions/notebook-status-bar-contribution.ts
+++ b/packages/notebook/src/browser/contributions/notebook-status-bar-contribution.ts
@@ -14,10 +14,9 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
-import { inject, injectable } from '@theia/core/shared/inversify';
-import { FrontendApplicationContribution, StatusBar, StatusBarAlignment } from '@theia/core/lib/browser';
+import { injectable } from '@theia/core/shared/inversify';
+import { StatusBar, StatusBarAlignment, Widget, WidgetStatusBarContribution } from '@theia/core/lib/browser';
import { Disposable } from '@theia/core/lib/common';
-import { NotebookEditorWidgetService } from '../service/notebook-editor-widget-service';
import { NotebookEditorWidget } from '../notebook-editor-widget';
import { nls } from '@theia/core';
import { NotebookCommands } from './notebook-actions-contribution';
@@ -25,53 +24,43 @@ import { NotebookCommands } from './notebook-actions-contribution';
export const NOTEBOOK_CELL_SELECTION_STATUS_BAR_ID = 'notebook-cell-selection-position';
@injectable()
-export class NotebookStatusBarContribution implements FrontendApplicationContribution {
+export class NotebookStatusBarContribution implements WidgetStatusBarContribution {
- @inject(StatusBar) protected readonly statusBar: StatusBar;
- @inject(NotebookEditorWidgetService) protected readonly editorWidgetService: NotebookEditorWidgetService;
+ protected onDeactivate: Disposable | undefined;
- protected currentCellSelectionListener: Disposable | undefined;
- protected lastFocusedEditor: NotebookEditorWidget | undefined;
+ canHandle(widget: Widget): widget is NotebookEditorWidget {
+ return widget instanceof NotebookEditorWidget;
+ }
- onStart(): void {
- this.editorWidgetService.onDidChangeFocusedEditor(editor => {
- this.currentCellSelectionListener?.dispose();
- this.currentCellSelectionListener = editor?.model?.onDidChangeSelectedCell(() =>
- this.updateStatusbar(editor)
- );
- editor?.onDidDispose(() => {
- this.lastFocusedEditor = undefined;
- this.updateStatusbar();
+ activate(statusBar: StatusBar, widget: NotebookEditorWidget): void {
+ widget.ready.then(model => {
+ this.onDeactivate = model.onDidChangeSelectedCell(() => {
+ this.updateStatusbar(statusBar, widget);
});
- this.updateStatusbar(editor);
- this.lastFocusedEditor = editor;
});
- if (this.editorWidgetService.focusedEditor) {
- this.updateStatusbar();
- }
+ this.updateStatusbar(statusBar, widget);
}
- protected async updateStatusbar(editor?: NotebookEditorWidget): Promise {
- if ((!editor && !this.lastFocusedEditor?.isVisible) || editor?.model?.cells.length === 0) {
- this.statusBar.removeElement(NOTEBOOK_CELL_SELECTION_STATUS_BAR_ID);
- return;
- }
+ deactivate(statusBar: StatusBar): void {
+ this.onDeactivate?.dispose();
+ this.updateStatusbar(statusBar);
+ }
- await editor?.ready;
- if (!editor?.model) {
+ protected async updateStatusbar(statusBar: StatusBar, editor?: NotebookEditorWidget): Promise {
+ const model = await editor?.ready;
+ if (!model || model.cells.length === 0 || !model.selectedCell) {
+ statusBar.removeElement(NOTEBOOK_CELL_SELECTION_STATUS_BAR_ID);
return;
}
- const selectedCellIndex = editor.model.selectedCell ? editor.model.cells.indexOf(editor.model.selectedCell) + 1 : '';
+ const selectedCellIndex = model.cells.indexOf(model.selectedCell) + 1;
- this.statusBar.setElement(NOTEBOOK_CELL_SELECTION_STATUS_BAR_ID, {
- text: nls.localizeByDefault('Cell {0} of {1}', selectedCellIndex, editor.model.cells.length),
+ statusBar.setElement(NOTEBOOK_CELL_SELECTION_STATUS_BAR_ID, {
+ text: nls.localizeByDefault('Cell {0} of {1}', selectedCellIndex, model.cells.length),
alignment: StatusBarAlignment.RIGHT,
priority: 100,
command: NotebookCommands.CENTER_ACTIVE_CELL.id,
arguments: [editor]
});
-
}
-
}
diff --git a/packages/notebook/src/browser/notebook-editor-widget.tsx b/packages/notebook/src/browser/notebook-editor-widget.tsx
index a936a270825a4..3451d76615e8d 100644
--- a/packages/notebook/src/browser/notebook-editor-widget.tsx
+++ b/packages/notebook/src/browser/notebook-editor-widget.tsx
@@ -212,7 +212,7 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
protected override onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
- this.node.focus();
+ (this.node.getElementsByClassName('theia-notebook-main-container')[0] as HTMLDivElement)?.focus();
}
getResourceUri(): URI | undefined {
@@ -271,7 +271,7 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
;
} else {
- return
+ return
;
}
diff --git a/packages/notebook/src/browser/notebook-frontend-module.ts b/packages/notebook/src/browser/notebook-frontend-module.ts
index 839d16908a17d..b5158315668b2 100644
--- a/packages/notebook/src/browser/notebook-frontend-module.ts
+++ b/packages/notebook/src/browser/notebook-frontend-module.ts
@@ -16,7 +16,9 @@
import '../../src/browser/style/index.css';
import { ContainerModule } from '@theia/core/shared/inversify';
-import { FrontendApplicationContribution, KeybindingContribution, LabelProviderContribution, OpenHandler, UndoRedoHandler, WidgetFactory } from '@theia/core/lib/browser';
+import {
+ FrontendApplicationContribution, KeybindingContribution, LabelProviderContribution, OpenHandler, UndoRedoHandler, WidgetFactory, WidgetStatusBarContribution
+} from '@theia/core/lib/browser';
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
import { NotebookOpenHandler } from './notebook-open-handler';
import { CommandContribution, MenuContribution, ResourceResolver, } from '@theia/core';
@@ -117,5 +119,5 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(UndoRedoHandler).toService(NotebookUndoRedoHandler);
bind(NotebookStatusBarContribution).toSelf().inSingletonScope();
- bind(FrontendApplicationContribution).toService(NotebookStatusBarContribution);
+ bind(WidgetStatusBarContribution).toService(NotebookStatusBarContribution);
});
diff --git a/packages/outline-view/package.json b/packages/outline-view/package.json
index b843df4db85ab..d7ce97cab677c 100644
--- a/packages/outline-view/package.json
+++ b/packages/outline-view/package.json
@@ -1,9 +1,9 @@
{
"name": "@theia/outline-view",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Outline View Extension",
"dependencies": {
- "@theia/core": "1.53.0",
+ "@theia/core": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -39,7 +39,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/output/package.json b/packages/output/package.json
index 3844098b6f9fc..ef2c8059bcf49 100644
--- a/packages/output/package.json
+++ b/packages/output/package.json
@@ -1,11 +1,11 @@
{
"name": "@theia/output",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Output Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
"@types/p-queue": "^2.3.1",
"p-queue": "^2.4.2",
@@ -44,7 +44,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/plugin-dev/package.json b/packages/plugin-dev/package.json
index 64e3d429d2b0c..eff7071bcf6d1 100644
--- a/packages/plugin-dev/package.json
+++ b/packages/plugin-dev/package.json
@@ -1,16 +1,16 @@
{
"name": "@theia/plugin-dev",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Plugin Development Extension",
"main": "lib/common/index.js",
"typings": "lib/common/index.d.ts",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/debug": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/output": "1.53.0",
- "@theia/plugin-ext": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/debug": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/output": "1.54.0",
+ "@theia/plugin-ext": "1.54.0",
+ "@theia/workspace": "1.54.0",
"ps-tree": "^1.2.0",
"tslib": "^2.6.2"
},
@@ -49,7 +49,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/plugin-ext-headless/package.json b/packages/plugin-ext-headless/package.json
index 0a37cd93a205d..52ac90e82f9d8 100644
--- a/packages/plugin-ext-headless/package.json
+++ b/packages/plugin-ext-headless/package.json
@@ -1,13 +1,13 @@
{
"name": "@theia/plugin-ext-headless",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Headless (Backend-only) Plugin Extension",
"main": "lib/common/index.js",
"typings": "lib/common/index.d.ts",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/plugin-ext": "1.53.0",
- "@theia/terminal": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/plugin-ext": "1.54.0",
+ "@theia/terminal": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -44,7 +44,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
+ "@theia/ext-scripts": "1.54.0",
"@types/decompress": "^4.2.2",
"@types/escape-html": "^0.0.20",
"@types/lodash.clonedeep": "^4.5.3",
diff --git a/packages/plugin-ext-vscode/package.json b/packages/plugin-ext-vscode/package.json
index 2e8ce00a71ea7..b58d98b27c46e 100644
--- a/packages/plugin-ext-vscode/package.json
+++ b/packages/plugin-ext-vscode/package.json
@@ -1,22 +1,22 @@
{
"name": "@theia/plugin-ext-vscode",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Plugin Extension for VsCode",
"dependencies": {
- "@theia/callhierarchy": "1.53.0",
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/callhierarchy": "1.54.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/navigator": "1.53.0",
- "@theia/outline-view": "1.53.0",
- "@theia/plugin": "1.53.0",
- "@theia/plugin-ext": "1.53.0",
- "@theia/terminal": "1.53.0",
- "@theia/typehierarchy": "1.53.0",
- "@theia/userstorage": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/navigator": "1.54.0",
+ "@theia/outline-view": "1.54.0",
+ "@theia/plugin": "1.54.0",
+ "@theia/plugin-ext": "1.54.0",
+ "@theia/terminal": "1.54.0",
+ "@theia/typehierarchy": "1.54.0",
+ "@theia/userstorage": "1.54.0",
+ "@theia/workspace": "1.54.0",
"decompress": "^4.2.1",
"filenamify": "^4.1.0",
"tslib": "^2.6.2"
@@ -55,7 +55,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/plugin-ext/package.json b/packages/plugin-ext/package.json
index 129124f12c7d1..3143dc53e15be 100644
--- a/packages/plugin-ext/package.json
+++ b/packages/plugin-ext/package.json
@@ -1,37 +1,37 @@
{
"name": "@theia/plugin-ext",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Plugin Extension",
"main": "lib/common/index.js",
"typings": "lib/common/index.d.ts",
"dependencies": {
- "@theia/bulk-edit": "1.53.0",
- "@theia/callhierarchy": "1.53.0",
- "@theia/console": "1.53.0",
- "@theia/core": "1.53.0",
- "@theia/debug": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/editor-preview": "1.53.0",
- "@theia/file-search": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/markers": "1.53.0",
- "@theia/messages": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/bulk-edit": "1.54.0",
+ "@theia/callhierarchy": "1.54.0",
+ "@theia/console": "1.54.0",
+ "@theia/core": "1.54.0",
+ "@theia/debug": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/editor-preview": "1.54.0",
+ "@theia/file-search": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/markers": "1.54.0",
+ "@theia/messages": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/navigator": "1.53.0",
- "@theia/notebook": "1.53.0",
- "@theia/output": "1.53.0",
- "@theia/plugin": "1.53.0",
- "@theia/preferences": "1.53.0",
- "@theia/scm": "1.53.0",
- "@theia/search-in-workspace": "1.53.0",
- "@theia/task": "1.53.0",
- "@theia/terminal": "1.53.0",
- "@theia/test": "1.53.0",
- "@theia/timeline": "1.53.0",
- "@theia/typehierarchy": "1.53.0",
- "@theia/variable-resolver": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/navigator": "1.54.0",
+ "@theia/notebook": "1.54.0",
+ "@theia/output": "1.54.0",
+ "@theia/plugin": "1.54.0",
+ "@theia/preferences": "1.54.0",
+ "@theia/scm": "1.54.0",
+ "@theia/search-in-workspace": "1.54.0",
+ "@theia/task": "1.54.0",
+ "@theia/terminal": "1.54.0",
+ "@theia/test": "1.54.0",
+ "@theia/timeline": "1.54.0",
+ "@theia/typehierarchy": "1.54.0",
+ "@theia/variable-resolver": "1.54.0",
+ "@theia/workspace": "1.54.0",
"@types/mime": "^2.0.1",
"@vscode/debugprotocol": "^1.51.0",
"@vscode/proxy-agent": "^0.13.2",
@@ -88,7 +88,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
+ "@theia/ext-scripts": "1.54.0",
"@types/decompress": "^4.2.2",
"@types/escape-html": "^0.0.20",
"@types/lodash.clonedeep": "^4.5.3",
diff --git a/packages/plugin-ext/src/common/plugin-api-rpc-model.ts b/packages/plugin-ext/src/common/plugin-api-rpc-model.ts
index 7a4ecdae2f2b4..de2450bff21bb 100644
--- a/packages/plugin-ext/src/common/plugin-api-rpc-model.ts
+++ b/packages/plugin-ext/src/common/plugin-api-rpc-model.ts
@@ -72,6 +72,17 @@ export interface Range {
readonly endColumn: number;
}
+export interface Position {
+ /**
+ * line number (starts at 1)
+ */
+ readonly lineNumber: number,
+ /**
+ * column (starts at 1)
+ */
+ readonly column: number
+}
+
export { MarkdownStringDTO as MarkdownString };
export interface SerializedDocumentFilter {
diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts
index 4c06174642f4f..7c21c72086927 100644
--- a/packages/plugin-ext/src/common/plugin-api-rpc.ts
+++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts
@@ -805,9 +805,9 @@ export interface RegisterTreeDataProviderOptions {
}
export interface TreeViewRevealOptions {
- select: boolean
- focus: boolean
- expand: boolean | number
+ readonly select: boolean
+ readonly focus: boolean
+ readonly expand: boolean | number
}
export interface TreeViewsMain {
diff --git a/packages/plugin-ext/src/common/test-types.ts b/packages/plugin-ext/src/common/test-types.ts
index af87290c87672..56c2ec4015262 100644
--- a/packages/plugin-ext/src/common/test-types.ts
+++ b/packages/plugin-ext/src/common/test-types.ts
@@ -27,6 +27,7 @@ import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
import { UriComponents } from './uri-components';
import { Location, Range } from './plugin-api-rpc-model';
import { isObject } from '@theia/core';
+import * as languageProtocol from '@theia/core/shared/vscode-languageserver-protocol';
export enum TestRunProfileKind {
Run = 1,
@@ -74,17 +75,30 @@ export interface TestFailureDTO extends TestStateChangeDTO {
readonly duration?: number;
}
+export namespace TestFailureDTO {
+ export function is(ref: unknown): ref is TestFailureDTO {
+ return isObject
(ref)
+ && (ref.state === TestExecutionState.Failed || ref.state === TestExecutionState.Errored);
+ }
+}
export interface TestSuccessDTO extends TestStateChangeDTO {
readonly state: TestExecutionState.Passed;
readonly duration?: number;
}
+export interface TestMessageStackFrameDTO {
+ uri?: languageProtocol.DocumentUri;
+ position?: languageProtocol.Position;
+ label: string;
+}
+
export interface TestMessageDTO {
readonly expected?: string;
readonly actual?: string;
- readonly location?: Location;
+ readonly location?: languageProtocol.Location;
readonly message: string | MarkdownString;
readonly contextValue?: string;
+ readonly stackTrace?: TestMessageStackFrameDTO[];
}
export interface TestItemDTO {
diff --git a/packages/plugin-ext/src/main/browser/menus/plugin-menu-command-adapter.ts b/packages/plugin-ext/src/main/browser/menus/plugin-menu-command-adapter.ts
index 9e79ae892cd96..2f1dc3c7e49ab 100644
--- a/packages/plugin-ext/src/main/browser/menus/plugin-menu-command-adapter.ts
+++ b/packages/plugin-ext/src/main/browser/menus/plugin-menu-command-adapter.ts
@@ -32,7 +32,6 @@ import { TreeViewWidget } from '../view/tree-view-widget';
import { CodeEditorWidgetUtil, codeToTheiaMappings, ContributionPoint } from './vscode-theia-menu-mappings';
import { TAB_BAR_TOOLBAR_CONTEXT_MENU } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { TestItem, TestMessage } from '@theia/test/lib/browser/test-service';
-import { fromLocation } from '../hierarchy/hierarchy-types-converters';
export type ArgumentAdapter = (...args: unknown[]) => unknown[];
@@ -315,7 +314,8 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
actual: testMessage.actual,
expected: testMessage.expected,
contextValue: testMessage.contextValue,
- location: testMessage.location ? fromLocation(testMessage.location) : undefined
+ location: testMessage.location,
+ stackTrace: testMessage.stackTrace
};
return [TestMessageArg.create(testItemReference, testMessageDTO)];
}
diff --git a/packages/plugin-ext/src/main/browser/plugin-ext-frontend-module.ts b/packages/plugin-ext/src/main/browser/plugin-ext-frontend-module.ts
index a8510268870f3..5e592c30c397b 100644
--- a/packages/plugin-ext/src/main/browser/plugin-ext-frontend-module.ts
+++ b/packages/plugin-ext/src/main/browser/plugin-ext-frontend-module.ts
@@ -22,7 +22,9 @@ import { ContainerModule } from '@theia/core/shared/inversify';
import {
FrontendApplicationContribution, WidgetFactory, bindViewContribution,
ViewContainerIdentifier, ViewContainer, createTreeContainer, TreeWidget, LabelProviderContribution, LabelProvider,
- UndoRedoHandler, DiffUris, Navigatable, SplitWidget
+ UndoRedoHandler, DiffUris, Navigatable, SplitWidget,
+ noopWidgetStatusBarContribution,
+ WidgetStatusBarContribution
} from '@theia/core/lib/browser';
import { MaybePromise, CommandContribution, ResourceResolver, bindContributionProvider, URI, generateUuid } from '@theia/core/lib/common';
import { WebSocketConnectionProvider } from '@theia/core/lib/browser/messaging';
@@ -191,6 +193,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(WebviewSecondaryWindowSupport).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(WebviewSecondaryWindowSupport);
bind(FrontendApplicationContribution).toService(WebviewContextKeys);
+ bind(WidgetStatusBarContribution).toConstantValue(noopWidgetStatusBarContribution(WebviewWidget));
bind(PluginCustomEditorRegistry).toSelf().inSingletonScope();
bind(CustomEditorService).toSelf().inSingletonScope();
diff --git a/packages/plugin-ext/src/main/browser/test-main.ts b/packages/plugin-ext/src/main/browser/test-main.ts
index cd50fd4813ddf..3662373142758 100644
--- a/packages/plugin-ext/src/main/browser/test-main.ts
+++ b/packages/plugin-ext/src/main/browser/test-main.ts
@@ -27,7 +27,10 @@ import { CancellationToken, Disposable, Event, URI } from '@theia/core';
import { MAIN_RPC_CONTEXT, TestControllerUpdate, TestingExt, TestingMain } from '../../common';
import { RPCProtocol } from '../../common/rpc-protocol';
import { interfaces } from '@theia/core/shared/inversify';
-import { TestExecutionState, TestItemDTO, TestItemReference, TestOutputDTO, TestRunDTO, TestRunProfileDTO, TestStateChangeDTO } from '../../common/test-types';
+import {
+ TestExecutionState, TestItemDTO, TestItemReference, TestOutputDTO,
+ TestRunDTO, TestRunProfileDTO, TestStateChangeDTO
+} from '../../common/test-types';
import { TestRunProfileKind } from '../../plugin/types-impl';
import { CommandRegistryMainImpl } from './command-registry-main';
diff --git a/packages/plugin-ext/src/plugin/file-system-ext-impl.ts b/packages/plugin-ext/src/plugin/file-system-ext-impl.ts
index 9eb59c06cc12c..b54be1a8dc093 100644
--- a/packages/plugin-ext/src/plugin/file-system-ext-impl.ts
+++ b/packages/plugin-ext/src/plugin/file-system-ext-impl.ts
@@ -40,8 +40,9 @@ import { State, StateMachine, LinkComputer, Edge } from '../common/link-computer
import { commonPrefixLength } from '@theia/core/lib/common/strings';
import { CharCode } from '@theia/core/lib/common/char-code';
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
-import { Emitter } from '@theia/core/shared/vscode-languageserver-protocol';
import { MarkdownString } from '../common/plugin-api-rpc-model';
+import { Emitter } from '@theia/core/lib/common';
+import { createAPIObject } from './plugin-context';
type IDisposable = vscode.Disposable;
@@ -137,8 +138,11 @@ export class FsLinkProvider {
}
class ConsumerFileSystem implements vscode.FileSystem {
+ apiObject: vscode.FileSystem;
- constructor(private _proxy: FileSystemMain, private _capabilities: Map) { }
+ constructor(private _proxy: FileSystemMain, private _capabilities: Map) {
+ this.apiObject = createAPIObject(this);
+ }
stat(uri: vscode.Uri): Promise {
return this._proxy.$stat(uri).catch(ConsumerFileSystem._handleError);
@@ -210,7 +214,7 @@ export class FileSystemExtImpl implements FileSystemExt {
private _handlePool: number = 0;
- readonly fileSystem: vscode.FileSystem;
+ readonly fileSystem: ConsumerFileSystem;
constructor(rpc: RPCProtocol) {
this._proxy = rpc.getProxy(PLUGIN_RPC_CONTEXT.FILE_SYSTEM_MAIN);
diff --git a/packages/plugin-ext/src/plugin/plugin-context.ts b/packages/plugin-ext/src/plugin/plugin-context.ts
index bb19d777fb058..61688deddeecf 100644
--- a/packages/plugin-ext/src/plugin/plugin-context.ts
+++ b/packages/plugin-ext/src/plugin/plugin-context.ts
@@ -187,6 +187,7 @@ import {
TestTag,
TestRunRequest,
TestMessage,
+ TestMessageStackFrame,
ExtensionKind,
InlineCompletionItem,
InlineCompletionList,
@@ -278,6 +279,21 @@ import { NotebookEditorsExtImpl } from './notebook/notebook-editors';
import { TestingExtImpl } from './tests';
import { UriExtImpl } from './uri-ext';
+export function createAPIObject(rawObject: T): T {
+ return new Proxy(rawObject, {
+ get(target, p, receiver) {
+ const isOwnProperty = !!Object.getOwnPropertyDescriptor(target, p);
+ const val = Reflect.get(target, p);
+ if (!isOwnProperty && typeof val === 'function') {
+ // bind functions that are inherited from the prototype to the object itself.
+ // This should handle the case of events.
+ return val.bind(target);
+ }
+ return val;
+ },
+ }) as T;
+}
+
export function createAPIFactory(
rpc: RPCProtocol,
pluginManager: PluginManager,
@@ -495,7 +511,8 @@ export function createAPIFactory(
return quickOpenExt.showQuickPick(plugin, items, options, token);
},
createQuickPick(): theia.QuickPick {
- return quickOpenExt.createQuickPick(plugin);
+
+ return createAPIObject(quickOpenExt.createQuickPick(plugin));
},
showWorkspaceFolderPick(options?: theia.WorkspaceFolderPickOptions): PromiseLike {
return workspaceExt.pickWorkspaceFolder(options);
@@ -534,9 +551,12 @@ export function createAPIFactory(
priority = priorityOrAlignment;
}
+ // TODO: here
return statusBarMessageRegistryExt.createStatusBarItem(alignment, priority, id);
},
createOutputChannel(name: string, options?: { log: true }): any {
+
+ // TODO: here
return !options
? outputChannelRegistryExt.createOutputChannel(name, pluginToPluginInfo(plugin))
: outputChannelRegistryExt.createOutputChannel(name, pluginToPluginInfo(plugin), options);
@@ -545,7 +565,7 @@ export function createAPIFactory(
title: string,
showOptions: theia.ViewColumn | theia.WebviewPanelShowOptions,
options: theia.WebviewPanelOptions & theia.WebviewOptions = {}): theia.WebviewPanel {
- return webviewExt.createWebview(viewType, title, showOptions, options, plugin);
+ return createAPIObject(webviewExt.createWebview(viewType, title, showOptions, options, plugin));
},
registerWebviewPanelSerializer(viewType: string, serializer: theia.WebviewPanelSerializer): theia.Disposable {
return webviewExt.registerWebviewPanelSerializer(viewType, serializer, plugin);
@@ -573,19 +593,19 @@ export function createAPIFactory(
createTerminal(nameOrOptions: theia.TerminalOptions | theia.ExtensionTerminalOptions | theia.ExtensionTerminalOptions | (string | undefined),
shellPath?: string,
shellArgs?: string[] | string): theia.Terminal {
- return terminalExt.createTerminal(plugin, nameOrOptions, shellPath, shellArgs);
+ return createAPIObject(terminalExt.createTerminal(plugin, nameOrOptions, shellPath, shellArgs));
},
onDidChangeTerminalState,
onDidCloseTerminal,
onDidOpenTerminal,
createTextEditorDecorationType(options: theia.DecorationRenderOptions): theia.TextEditorDecorationType {
- return editors.createTextEditorDecorationType(options);
+ return createAPIObject(editors.createTextEditorDecorationType(options));
},
registerTreeDataProvider(viewId: string, treeDataProvider: theia.TreeDataProvider): Disposable {
return treeViewsExt.registerTreeDataProvider(plugin, viewId, treeDataProvider);
},
createTreeView(viewId: string, options: theia.TreeViewOptions): theia.TreeView {
- return treeViewsExt.createTreeView(plugin, viewId, options);
+ return createAPIObject(treeViewsExt.createTreeView(plugin, viewId, options));
},
withScmProgress(task: (progress: theia.Progress) => Thenable) {
const options: ProgressOptions = { location: ProgressLocation.SourceControl };
@@ -604,7 +624,7 @@ export function createAPIFactory(
return uriExt.registerUriHandler(handler, pluginToPluginInfo(plugin));
},
createInputBox(): theia.InputBox {
- return quickOpenExt.createInputBox(plugin);
+ return createAPIObject(quickOpenExt.createInputBox(plugin));
},
registerTerminalLinkProvider(provider: theia.TerminalLinkProvider): theia.Disposable {
return terminalExt.registerTerminalLinkProvider(provider);
@@ -652,7 +672,7 @@ export function createAPIFactory(
const workspace: typeof theia.workspace = {
get fs(): theia.FileSystem {
- return fileSystemExt.fileSystem;
+ return fileSystemExt.fileSystem.apiObject;
},
get rootPath(): string | undefined {
@@ -755,7 +775,7 @@ export function createAPIFactory(
return notebooksExt.getNotebookDocument(uri).apiNotebook;
},
createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): theia.FileSystemWatcher =>
- extHostFileSystemEvent.createFileSystemWatcher(fromGlobPattern(pattern), ignoreCreate, ignoreChange, ignoreDelete),
+ createAPIObject(extHostFileSystemEvent.createFileSystemWatcher(fromGlobPattern(pattern), ignoreCreate, ignoreChange, ignoreDelete)),
findFiles(include: theia.GlobPattern, exclude?: theia.GlobPattern | null, maxResults?: number, token?: CancellationToken): PromiseLike {
return workspaceExt.findFiles(include, exclude, maxResults, token);
},
@@ -848,7 +868,7 @@ export function createAPIFactory(
return telemetryExt.onDidChangeTelemetryEnabled;
},
createTelemetryLogger(sender: theia.TelemetrySender, options?: theia.TelemetryLoggerOptions): theia.TelemetryLogger {
- return telemetryExt.createTelemetryLogger(sender, options);
+ return createAPIObject(telemetryExt.createTelemetryLogger(sender, options));
},
get remoteName(): string | undefined { return envExt.remoteName; },
get machineId(): string { return envExt.machineId; },
@@ -923,7 +943,7 @@ export function createAPIFactory(
return languagesExt.getDiagnostics(resource);
},
createDiagnosticCollection(name?: string): theia.DiagnosticCollection {
- return languagesExt.createDiagnosticCollection(name);
+ return createAPIObject(languagesExt.createDiagnosticCollection(name));
},
setLanguageConfiguration(language: string, configuration: theia.LanguageConfiguration): theia.Disposable {
return languagesExt.setLanguageConfiguration(language, configuration);
@@ -1060,7 +1080,7 @@ export function createAPIFactory(
const tests: typeof theia.tests = {
createTestController(id, label: string) {
- return testingExt.createTestController(id, label);
+ return createAPIObject(testingExt.createTestController(id, label));
}
};
/* End of Tests API */
@@ -1172,6 +1192,7 @@ export function createAPIFactory(
},
get taskExecutions(): ReadonlyArray {
+ // TODO: here
return tasksExt.taskExecutions;
},
onDidStartTask(listener, thisArg?, disposables?) {
@@ -1192,19 +1213,19 @@ export function createAPIFactory(
get inputBox(): theia.SourceControlInputBox {
const inputBox = scmExt.getLastInputBox(plugin);
if (inputBox) {
- return inputBox;
+ return inputBox.apiObject;
} else {
throw new Error('Input box not found!');
}
},
createSourceControl(id: string, label: string, rootUri?: URI): theia.SourceControl {
- return scmExt.createSourceControl(plugin, id, label, rootUri);
+ return createAPIObject(scmExt.createSourceControl(plugin, id, label, rootUri));
}
};
const comments: typeof theia.comments = {
createCommentController(id: string, label: string): theia.CommentController {
- return commentsExt.createCommentController(plugin, id, label);
+ return createAPIObject(commentsExt.createCommentController(plugin, id, label));
}
};
@@ -1463,6 +1484,7 @@ export function createAPIFactory(
TestTag,
TestRunRequest,
TestMessage,
+ TestMessageStackFrame,
ExtensionKind,
InlineCompletionItem,
InlineCompletionList,
diff --git a/packages/plugin-ext/src/plugin/scm.ts b/packages/plugin-ext/src/plugin/scm.ts
index 4703ab3626f14..f34556cee2ae8 100644
--- a/packages/plugin-ext/src/plugin/scm.ts
+++ b/packages/plugin-ext/src/plugin/scm.ts
@@ -39,6 +39,7 @@ import { URI, ThemeIcon } from './types-impl';
import { ScmCommandArg } from '../common/plugin-api-rpc';
import { sep } from '@theia/core/lib/common/paths';
import { PluginIconPath } from './plugin-icon-path';
+import { createAPIObject } from './plugin-context';
type ProviderHandle = number;
type GroupHandle = number;
type ResourceStateHandle = number;
@@ -290,6 +291,7 @@ interface ValidateInput {
export class ScmInputBoxImpl implements theia.SourceControlInputBox {
private _value: string = '';
+ apiObject: theia.SourceControlInputBox;
get value(): string {
return this._value;
@@ -354,7 +356,7 @@ export class ScmInputBoxImpl implements theia.SourceControlInputBox {
}
constructor(private plugin: Plugin, private proxy: ScmMain, private sourceControlHandle: number) {
- // noop
+ this.apiObject = createAPIObject(this);
}
onInputBoxValueChange(value: string): void {
@@ -543,8 +545,7 @@ class SourceControlImpl implements theia.SourceControl {
return this._rootUri;
}
- private _inputBox: ScmInputBoxImpl;
- get inputBox(): ScmInputBoxImpl { return this._inputBox; }
+ readonly inputBox: ScmInputBoxImpl;
private _count: number | undefined = undefined;
@@ -642,7 +643,7 @@ class SourceControlImpl implements theia.SourceControl {
private _label: string,
private _rootUri?: theia.Uri
) {
- this._inputBox = new ScmInputBoxImpl(plugin, this.proxy, this.handle);
+ this.inputBox = new ScmInputBoxImpl(plugin, this.proxy, this.handle);
this.proxy.$registerSourceControl(this.handle, _id, _label, _rootUri);
}
diff --git a/packages/plugin-ext/src/plugin/tests.ts b/packages/plugin-ext/src/plugin/tests.ts
index 101532e86b2ed..514bcbbe4fabc 100644
--- a/packages/plugin-ext/src/plugin/tests.ts
+++ b/packages/plugin-ext/src/plugin/tests.ts
@@ -40,10 +40,12 @@ import { TestItemImpl, TestItemCollection } from './test-item';
import { AccumulatingTreeDeltaEmitter, TreeDelta } from '@theia/test/lib/common/tree-delta';
import {
TestItemDTO, TestOutputDTO, TestExecutionState, TestRunProfileDTO,
- TestRunProfileKind, TestRunRequestDTO, TestStateChangeDTO, TestItemReference, TestMessageArg, TestMessageDTO
+ TestRunProfileKind, TestRunRequestDTO, TestStateChangeDTO, TestItemReference, TestMessageArg, TestMessageDTO,
+ TestMessageStackFrameDTO
} from '../common/test-types';
+import * as protocol from '@theia/core/shared/vscode-languageserver-protocol';
import { ChangeBatcher, observableProperty } from '@theia/test/lib/common/collections';
-import { TestRunRequest } from './types-impl';
+import { Location, Position, Range, TestRunRequest, URI } from './types-impl';
import { MarkdownString } from '../common/plugin-api-rpc-model';
type RefreshHandler = (token: theia.CancellationToken) => void | theia.Thenable;
@@ -374,7 +376,36 @@ export class TestingExtImpl implements TestingExt {
actualOutput: testMessage.actual,
expectedOutput: testMessage.expected,
contextValue: testMessage.contextValue,
- location: testMessage.location ? Convert.toLocation(testMessage.location) : undefined
+ location: this.toLocation(testMessage.location),
+ stackTrace: testMessage.stackTrace ? testMessage.stackTrace.map(frame => this.toStackFrame(frame)) : undefined
+ };
+ }
+
+ toLocation(location: protocol.Location | undefined): Location | undefined {
+ if (!location) {
+ return undefined;
+ }
+ return new Location(URI.parse(location.uri), this.toRange(location.range));
+ }
+
+ toRange(range: protocol.Range): Range {
+ return new Range(this.toPosition(range.start), this.toPosition(range.end));
+ }
+
+ toPosition(position: protocol.Position): Position;
+ toPosition(position: protocol.Position | undefined): Position | undefined;
+ toPosition(position: protocol.Position | undefined): Position | undefined {
+ if (!position) {
+ return undefined;
+ }
+ return new Position(position.line, position.character);
+ }
+
+ toStackFrame(stackFrame: TestMessageStackFrameDTO): theia.TestMessageStackFrame {
+ return {
+ label: stackFrame.label,
+ position: this.toPosition(stackFrame.position),
+ uri: stackFrame.uri ? URI.parse(stackFrame.uri) : undefined
};
}
diff --git a/packages/plugin-ext/src/plugin/type-converters.ts b/packages/plugin-ext/src/plugin/type-converters.ts
index 7419d07e9da07..c25ac586a7b78 100644
--- a/packages/plugin-ext/src/plugin/type-converters.ts
+++ b/packages/plugin-ext/src/plugin/type-converters.ts
@@ -34,7 +34,7 @@ import { BinaryBuffer } from '@theia/core/lib/common/buffer';
import { CellRange, isTextStreamMime } from '@theia/notebook/lib/common';
import { MarkdownString as MarkdownStringDTO } from '@theia/core/lib/common/markdown-rendering';
-import { TestItemDTO, TestMessageDTO } from '../common/test-types';
+import { TestItemDTO, TestMessageDTO, TestMessageStackFrameDTO } from '../common/test-types';
import { PluginIconPath } from './plugin-icon-path';
const SIDE_GROUP = -2;
@@ -134,12 +134,21 @@ export function fromRange(range: theia.Range | undefined): model.Range | undefin
endColumn: end.character + 1
};
}
-
-export function fromPosition(position: types.Position | theia.Position): Position {
+export function fromPosition(position: types.Position | theia.Position): Position;
+export function fromPosition(position: types.Position | theia.Position | undefined): Position | undefined;
+export function fromPosition(position: types.Position | theia.Position | undefined): Position | undefined {
+ if (!position) {
+ return undefined;
+ }
return { lineNumber: position.line + 1, column: position.character + 1 };
}
-export function toPosition(position: Position): types.Position {
+export function toPosition(position: Position): types.Position;
+export function toPosition(position: Position | undefined): types.Position | undefined;
+export function toPosition(position: Position | undefined): types.Position | undefined {
+ if (!position) {
+ return undefined;
+ }
return new types.Position(position.lineNumber - 1, position.column - 1);
}
@@ -474,6 +483,18 @@ export function fromLocation(location: theia.Location | undefined): model.Locati
};
}
+export function fromLocationToLanguageServerLocation(location: theia.Location): lstypes.Location;
+export function fromLocationToLanguageServerLocation(location: theia.Location | undefined): lstypes.Location | undefined;
+export function fromLocationToLanguageServerLocation(location: theia.Location | undefined): lstypes.Location | undefined {
+ if (!location) {
+ return undefined;
+ }
+ return {
+ uri: location.uri.toString(),
+ range: location.range
+ };
+}
+
export function fromTextDocumentShowOptions(options: theia.TextDocumentShowOptions): model.TextDocumentShowOptions {
if (options.selection) {
return {
@@ -1697,15 +1718,26 @@ export namespace TestMessage {
return message.map(msg => TestMessage.from(msg)[0]);
}
return [{
- location: fromLocation(message.location),
+ location: fromLocationToLanguageServerLocation(message.location),
message: fromMarkdown(message.message)!,
expected: message.expectedOutput,
actual: message.actualOutput,
- contextValue: message.contextValue
+ contextValue: message.contextValue,
+ stackTrace: message.stackTrace && message.stackTrace.map(frame => TestMessageStackFrame.from(frame))
}];
}
}
+export namespace TestMessageStackFrame {
+ export function from(stackTrace: theia.TestMessageStackFrame): TestMessageStackFrameDTO {
+ return {
+ label: stackTrace.label,
+ position: stackTrace.position,
+ uri: stackTrace?.uri?.toString()
+ };
+ }
+}
+
export namespace TestItem {
export function from(test: theia.TestItem): TestItemDTO {
return TestItem.fromPartial(test);
diff --git a/packages/plugin-ext/src/plugin/types-impl.ts b/packages/plugin-ext/src/plugin/types-impl.ts
index 1aee501f2e810..d7a0734259657 100644
--- a/packages/plugin-ext/src/plugin/types-impl.ts
+++ b/packages/plugin-ext/src/plugin/types-impl.ts
@@ -3036,7 +3036,7 @@ export class DebugThread implements theia.DebugThread {
}
export class DebugStackFrame implements theia.DebugStackFrame {
- constructor(readonly session: theia.DebugSession, readonly threadId: number, readonly frameId: number) { }
+ constructor(readonly session: theia.DebugSession, readonly threadId: number, readonly frameId: number) { }
}
@es5ClassCompat
@@ -3350,6 +3350,7 @@ export class TestMessage implements theia.TestMessage {
public actualOutput?: string;
public location?: theia.Location;
public contextValue?: string;
+ public stackTrace?: theia.TestMessageStackFrame[] | undefined;
public static diff(message: string | theia.MarkdownString, expected: string, actual: string): theia.TestMessage {
const msg = new TestMessage(message);
@@ -3366,6 +3367,14 @@ export class TestCoverageCount {
constructor(public covered: number, public total: number) { }
}
+export class TestMessageStackFrame implements theia.TestMessageStackFrame {
+ constructor(
+ public label: string,
+ public uri?: theia.Uri,
+ public position?: Position
+ ) { }
+}
+
@es5ClassCompat
export class FileCoverage {
diff --git a/packages/plugin-metrics/package.json b/packages/plugin-metrics/package.json
index e94657de4a0d5..4852c50738780 100644
--- a/packages/plugin-metrics/package.json
+++ b/packages/plugin-metrics/package.json
@@ -1,13 +1,13 @@
{
"name": "@theia/plugin-metrics",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Plugin Metrics",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/metrics": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/metrics": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/plugin": "1.53.0",
- "@theia/plugin-ext": "1.53.0",
+ "@theia/plugin": "1.54.0",
+ "@theia/plugin-ext": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -44,7 +44,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/plugin/package.json b/packages/plugin/package.json
index 7acbf0e09fd9e..b9c572034c9e6 100644
--- a/packages/plugin/package.json
+++ b/packages/plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@theia/plugin",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Plugin API",
"types": "./src/theia.d.ts",
"publishConfig": {
@@ -27,7 +27,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts
index 6caa690fdacf1..fe8d5f6200d28 100644
--- a/packages/plugin/src/theia.d.ts
+++ b/packages/plugin/src/theia.d.ts
@@ -6728,13 +6728,31 @@ export module '@theia/plugin' {
badge: ViewBadge | undefined;
/**
- * Reveal an element. By default revealed element is selected.
+ * Reveals the given element in the tree view.
+ * If the tree view is not visible then the tree view is shown and element is revealed.
*
+ * By default revealed element is selected.
* In order to not to select, set the option `select` to `false`.
+ * In order to focus, set the option `focus` to `true`.
+ * In order to expand the revealed element, set the option `expand` to `true`. To expand recursively set `expand` to the number of levels to expand.
*
- * **NOTE:** {@link TreeDataProvider TreeDataProvider} is required to implement {@link TreeDataProvider.getParent getParent} method to access this API.
+ * * *NOTE:* In VS Code, you can expand only to 3 levels maximum. This is not the case in Theia, there are no limits to expansion level.
+ * * *NOTE:* The {@link TreeDataProvider} that the `TreeView` {@link window.createTreeView is registered with} with must implement {@link TreeDataProvider.getParent getParent} method to access this API.
*/
- reveal(element: T, options?: { select?: boolean; focus?: boolean; expand?: boolean | number }): Thenable;
+ reveal(element: T, options?: {
+ /**
+ * If true, then the element will be selected.
+ */
+ readonly select?: boolean;
+ /**
+ * If true, then the element will be focused.
+ */
+ readonly focus?: boolean;
+ /**
+ * If true, then the element will be expanded. If a number is passed, then up to that number of levels of children will be expanded
+ */
+ readonly expand?: boolean | number;
+ }): Thenable;
}
/**
@@ -16966,6 +16984,34 @@ export module '@theia/plugin' {
error: string | MarkdownString | undefined;
}
+ /**
+ * A stack frame found in the {@link TestMessage.stackTrace}.
+ */
+ export class TestMessageStackFrame {
+ /**
+ * The location of this stack frame. This should be provided as a URI if the
+ * location of the call frame can be accessed by the editor.
+ */
+ uri?: Uri;
+
+ /**
+ * Position of the stack frame within the file.
+ */
+ position?: Position;
+
+ /**
+ * The name of the stack frame, typically a method or function name.
+ */
+ label: string;
+
+ /**
+ * @param label The name of the stack frame
+ * @param file The file URI of the stack frame
+ * @param position The position of the stack frame within the file
+ */
+ constructor(label: string, uri?: Uri, position?: Position);
+ }
+
/**
* Message associated with the test state. Can be linked to a specific
* source range -- useful for assertion failures, for example.
@@ -17022,6 +17068,11 @@ export module '@theia/plugin' {
*/
contextValue?: string;
+ /**
+ * The stack trace associated with the message or failure.
+ */
+ stackTrace?: TestMessageStackFrame[];
+
/**
* Creates a new TestMessage that will present as a diff in the editor.
* @param message Message to display to the user.
diff --git a/packages/preferences/package.json b/packages/preferences/package.json
index 7963265e81868..83f970627b727 100644
--- a/packages/preferences/package.json
+++ b/packages/preferences/package.json
@@ -1,15 +1,15 @@
{
"name": "@theia/preferences",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Preferences Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/userstorage": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/userstorage": "1.54.0",
+ "@theia/workspace": "1.54.0",
"async-mutex": "^0.3.1",
"fast-deep-equal": "^3.1.3",
"jsonc-parser": "^2.2.0",
@@ -50,7 +50,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/preferences/src/browser/preference-frontend-module.ts b/packages/preferences/src/browser/preference-frontend-module.ts
index ef7d553bcee84..d55f47e63d60b 100644
--- a/packages/preferences/src/browser/preference-frontend-module.ts
+++ b/packages/preferences/src/browser/preference-frontend-module.ts
@@ -17,7 +17,7 @@
import '../../src/browser/style/index.css';
import './preferences-monaco-contribution';
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
-import { bindViewContribution, FrontendApplicationContribution, OpenHandler } from '@theia/core/lib/browser';
+import { bindViewContribution, FrontendApplicationContribution, noopWidgetStatusBarContribution, OpenHandler, WidgetStatusBarContribution } from '@theia/core/lib/browser';
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { PreferenceTreeGenerator } from './util/preference-tree-generator';
import { bindPreferenceProviders } from './preference-bindings';
@@ -33,6 +33,7 @@ import { CliPreferences, CliPreferencesPath } from '../common/cli-preferences';
import { ServiceConnectionProvider } from '@theia/core/lib/browser/messaging/service-connection-provider';
import { PreferenceFrontendContribution } from './preference-frontend-contribution';
import { PreferenceLayoutProvider } from './util/preference-layout';
+import { PreferencesWidget } from './views/preference-widget';
export function bindPreferences(bind: interfaces.Bind, unbind: interfaces.Unbind): void {
bindPreferenceProviders(bind, unbind);
@@ -59,6 +60,8 @@ export function bindPreferences(bind: interfaces.Bind, unbind: interfaces.Unbind
bind(CliPreferences).toDynamicValue(ctx => ServiceConnectionProvider.createProxy(ctx.container, CliPreferencesPath)).inSingletonScope();
bind(PreferenceFrontendContribution).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(PreferenceFrontendContribution);
+
+ bind(WidgetStatusBarContribution).toConstantValue(noopWidgetStatusBarContribution(PreferencesWidget));
}
export default new ContainerModule((bind, unbind, isBound, rebind) => {
diff --git a/packages/preview/package.json b/packages/preview/package.json
index 3b346f27ec6ce..0fae6f0b68c67 100644
--- a/packages/preview/package.json
+++ b/packages/preview/package.json
@@ -1,12 +1,12 @@
{
"name": "@theia/preview",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Preview Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/mini-browser": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/mini-browser": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@types/highlight.js": "^10.1.0",
"@types/markdown-it-anchor": "^4.0.1",
"highlight.js": "10.4.1",
@@ -46,7 +46,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/process/package.json b/packages/process/package.json
index e1626aa212009..bef30552ed384 100644
--- a/packages/process/package.json
+++ b/packages/process/package.json
@@ -1,9 +1,9 @@
{
"name": "@theia/process",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia process support.",
"dependencies": {
- "@theia/core": "1.53.0",
+ "@theia/core": "1.54.0",
"node-pty": "0.11.0-beta24",
"string-argv": "^0.1.1",
"tslib": "^2.6.2"
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/property-view/package.json b/packages/property-view/package.json
index 46cc02f53cd1a..515ea5bbd4ad9 100644
--- a/packages/property-view/package.json
+++ b/packages/property-view/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/property-view",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Property View Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -40,7 +40,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/remote/package.json b/packages/remote/package.json
index 4993914bbbd03..71377a15a35d4 100644
--- a/packages/remote/package.json
+++ b/packages/remote/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/remote",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Remote",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
"archiver": "^5.3.1",
"decompress": "^4.2.1",
"decompress-tar": "^4.0.0",
@@ -52,7 +52,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
+ "@theia/ext-scripts": "1.54.0",
"@types/archiver": "^5.3.2",
"@types/decompress": "^4.2.4",
"@types/express-http-proxy": "^1.6.3",
diff --git a/packages/scm-extra/package.json b/packages/scm-extra/package.json
index 0a83d3c53fa75..227b1f92580cd 100644
--- a/packages/scm-extra/package.json
+++ b/packages/scm-extra/package.json
@@ -1,13 +1,13 @@
{
"name": "@theia/scm-extra",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Source control extras Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/navigator": "1.53.0",
- "@theia/scm": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/navigator": "1.54.0",
+ "@theia/scm": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -43,7 +43,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/scm/package.json b/packages/scm/package.json
index 4a5bfd979221a..87b52c2704627 100644
--- a/packages/scm/package.json
+++ b/packages/scm/package.json
@@ -1,12 +1,12 @@
{
"name": "@theia/scm",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Source control Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
"@types/diff": "^5.2.1",
"diff": "^5.2.0",
@@ -49,7 +49,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/search-in-workspace/package.json b/packages/search-in-workspace/package.json
index ba4cde4e6bfc6..2b8e007c68d19 100644
--- a/packages/search-in-workspace/package.json
+++ b/packages/search-in-workspace/package.json
@@ -1,14 +1,14 @@
{
"name": "@theia/search-in-workspace",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Search in workspace",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/navigator": "1.53.0",
- "@theia/process": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/navigator": "1.54.0",
+ "@theia/process": "1.54.0",
+ "@theia/workspace": "1.54.0",
"@vscode/ripgrep": "^1.14.2",
"minimatch": "^5.1.0",
"react-autosize-textarea": "^7.0.0",
@@ -48,6 +48,6 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
}
}
diff --git a/packages/secondary-window/package.json b/packages/secondary-window/package.json
index 237203d85b302..1513249fc66f7 100644
--- a/packages/secondary-window/package.json
+++ b/packages/secondary-window/package.json
@@ -1,9 +1,9 @@
{
"name": "@theia/secondary-window",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Secondary Window Extension",
"dependencies": {
- "@theia/core": "1.53.0",
+ "@theia/core": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -39,6 +39,6 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
}
}
diff --git a/packages/task/package.json b/packages/task/package.json
index 507ff9d0724b3..5d2cc954395e8 100644
--- a/packages/task/package.json
+++ b/packages/task/package.json
@@ -1,19 +1,19 @@
{
"name": "@theia/task",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Task extension. This extension adds support for executing raw or terminal processes in the backend.",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/markers": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/markers": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/process": "1.53.0",
- "@theia/terminal": "1.53.0",
- "@theia/userstorage": "1.53.0",
- "@theia/variable-resolver": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/process": "1.54.0",
+ "@theia/terminal": "1.54.0",
+ "@theia/userstorage": "1.54.0",
+ "@theia/variable-resolver": "1.54.0",
+ "@theia/workspace": "1.54.0",
"async-mutex": "^0.3.1",
"jsonc-parser": "^2.2.0",
"p-debounce": "^2.1.0",
@@ -53,7 +53,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/terminal/package.json b/packages/terminal/package.json
index bf9c8a435a54d..7dd3431211d6e 100644
--- a/packages/terminal/package.json
+++ b/packages/terminal/package.json
@@ -1,15 +1,15 @@
{
"name": "@theia/terminal",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Terminal Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/file-search": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/process": "1.53.0",
- "@theia/variable-resolver": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/file-search": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/process": "1.54.0",
+ "@theia/variable-resolver": "1.54.0",
+ "@theia/workspace": "1.54.0",
"tslib": "^2.6.2",
"xterm": "^5.3.0",
"xterm-addon-fit": "^0.8.0",
@@ -50,7 +50,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/test/package.json b/packages/test/package.json
index e30f799f7ac30..74637739d8f82 100644
--- a/packages/test/package.json
+++ b/packages/test/package.json
@@ -1,13 +1,13 @@
{
"name": "@theia/test",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Test Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/navigator": "1.53.0",
- "@theia/terminal": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/navigator": "1.54.0",
+ "@theia/terminal": "1.54.0",
"xterm": "^4.16.0",
"xterm-addon-fit": "^0.5.0"
},
@@ -44,7 +44,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/test/src/browser/style/index.css b/packages/test/src/browser/style/index.css
index f919706ee4318..c880f8c433ac4 100644
--- a/packages/test/src/browser/style/index.css
+++ b/packages/test/src/browser/style/index.css
@@ -18,25 +18,29 @@
}
.theia-test-view .passed,
-.theia-test-result-view .passed {
+.theia-test-run-view .passed {
color: var(--theia-successBackground);
}
.theia-test-view .failed,
-.theia-test-result-view .failed {
+.theia-test-run-view .failed {
color: var(--theia-editorError-foreground);
}
.theia-test-view .errored,
-.theia-test-result-view .errored {
+.theia-test-run-view .errored {
color: var(--theia-editorError-foreground);
}
.theia-test-view .queued,
-.theia-test-result-view .queued {
+.theia-test-run-view .queued {
color: var(--theia-editorWarning-foreground);
}
+.theia-test-result-view .debug-frame {
+ white-space: pre;
+}
+
.theia-test-view .theia-TreeNode:not(:hover):not(.theia-mod-selected) .theia-test-tree-inline-action {
display: none;
}
\ No newline at end of file
diff --git a/packages/test/src/browser/test-service.ts b/packages/test/src/browser/test-service.ts
index 210ca558c58c7..c2fb29f2744d0 100644
--- a/packages/test/src/browser/test-service.ts
+++ b/packages/test/src/browser/test-service.ts
@@ -15,7 +15,7 @@
// *****************************************************************************
import { CancellationToken, ContributionProvider, Disposable, Emitter, Event, QuickPickService, isObject, nls } from '@theia/core/lib/common';
-import { CancellationTokenSource, Location, Range } from '@theia/core/shared/vscode-languageserver-protocol';
+import { CancellationTokenSource, Location, Range, Position, DocumentUri } from '@theia/core/shared/vscode-languageserver-protocol';
import { CollectionDelta, TreeDelta } from '../common/tree-delta';
import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
import URI from '@theia/core/lib/common/uri';
@@ -56,9 +56,16 @@ export enum TestExecutionState {
export interface TestMessage {
readonly expected?: string;
readonly actual?: string;
- readonly location: Location;
+ readonly location?: Location;
readonly message: string | MarkdownString;
readonly contextValue?: string;
+ readonly stackTrace?: TestMessageStackFrame[];
+}
+
+export interface TestMessageStackFrame {
+ readonly label: string,
+ readonly uri?: DocumentUri,
+ readonly position?: Position,
}
export namespace TestMessage {
@@ -367,7 +374,7 @@ export class DefaultTestService implements TestService {
selectDefaultProfile(): void {
this.pickProfileKind().then(kind => {
- const profiles = this.getControllers().flatMap(c => c.testRunProfiles).filter(profile => profile.kind === kind);
+ const profiles = this.getControllers().flatMap(c => c.testRunProfiles).filter(profile => profile.kind === kind);
this.pickProfile(profiles, nls.localizeByDefault('Pick a test profile to use')).then(activeProfile => {
if (activeProfile) {
// only change the default for the controller containing selected profile for default and its profiles with same kind
diff --git a/packages/test/src/browser/view/test-result-widget.ts b/packages/test/src/browser/view/test-result-widget.ts
index 4df73d7914e97..a1f154acc9f50 100644
--- a/packages/test/src/browser/view/test-result-widget.ts
+++ b/packages/test/src/browser/view/test-result-widget.ts
@@ -14,14 +14,17 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
-import { BaseWidget, Message, codicon } from '@theia/core/lib/browser';
+import { BaseWidget, LabelProvider, Message, OpenerService, codicon } from '@theia/core/lib/browser';
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
import { TestOutputUIModel } from './test-output-ui-model';
import { DisposableCollection, nls } from '@theia/core';
-import { TestFailure, TestMessage } from '../test-service';
+import { TestFailure, TestMessage, TestMessageStackFrame } from '../test-service';
import { MarkdownRenderer } from '@theia/core/lib/browser/markdown-rendering/markdown-renderer';
import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
-
+import { URI } from '@theia/core/lib/common/uri';
+import { FileService } from '@theia/filesystem/lib/browser/file-service';
+import { NavigationLocationService } from '@theia/editor/lib/browser/navigation/navigation-location-service';
+import { NavigationLocation, Position } from '@theia/editor/lib/browser/navigation/navigation-location';
@injectable()
export class TestResultWidget extends BaseWidget {
@@ -29,6 +32,10 @@ export class TestResultWidget extends BaseWidget {
@inject(TestOutputUIModel) uiModel: TestOutputUIModel;
@inject(MarkdownRenderer) markdownRenderer: MarkdownRenderer;
+ @inject(OpenerService) openerService: OpenerService;
+ @inject(FileService) fileService: FileService;
+ @inject(NavigationLocationService) navigationService: NavigationLocationService;
+ @inject(LabelProvider) protected readonly labelProvider: LabelProvider;
protected toDisposeOnRender = new DisposableCollection();
protected input: TestMessage[] = [];
@@ -36,6 +43,7 @@ export class TestResultWidget extends BaseWidget {
constructor() {
super();
+ this.addClass('theia-test-result-view');
this.id = TestResultWidget.ID;
this.title.label = nls.localizeByDefault('Test Results');
this.title.caption = nls.localizeByDefault('Test Results');
@@ -83,6 +91,48 @@ export class TestResultWidget extends BaseWidget {
} else {
this.content.append(this.node.ownerDocument.createTextNode(message.message));
}
+ if (message.stackTrace) {
+ const stackTraceElement = this.node.ownerDocument.createElement('div');
+ message.stackTrace.map(frame => this.renderFrame(frame, stackTraceElement));
+ this.content.append(stackTraceElement);
+ }
+ });
+ }
+
+ renderFrame(stackFrame: TestMessageStackFrame, stackTraceElement: HTMLElement): void {
+ const frameElement = stackTraceElement.ownerDocument.createElement('div');
+ frameElement.classList.add('debug-frame');
+ frameElement.append(` ${nls.localize('theia/test/stackFrameAt', 'at')} ${stackFrame.label}`);
+
+ // Add URI information as clickable links
+ if (stackFrame.uri) {
+ frameElement.append(' (');
+ const uri = new URI(stackFrame.uri);
+
+ const link = this.node.ownerDocument.createElement('a');
+ let content = `${this.labelProvider.getName(uri)}`;
+ if (stackFrame.position) {
+ // Display Position as a 1-based position, similar to Monaco ones.
+ const monacoPosition = {
+ lineNumber: stackFrame.position.line + 1,
+ column: stackFrame.position.character + 1
+ };
+ content += `:${monacoPosition.lineNumber}:${monacoPosition.column}`;
+ }
+ link.textContent = content;
+ link.href = `${uri}`;
+ link.onclick = () => this.openUriInWorkspace(uri, stackFrame.position);
+ frameElement.append(link);
+ frameElement.append(')');
+ }
+ stackTraceElement.append(frameElement);
+ }
+
+ async openUriInWorkspace(uri: URI, position?: Position): Promise {
+ this.fileService.resolve(uri).then(stat => {
+ if (stat.isFile) {
+ this.navigationService.reveal(NavigationLocation.create(uri, position ?? { line: 0, character: 0 }));
+ }
});
}
diff --git a/packages/test/src/browser/view/test-run-widget.tsx b/packages/test/src/browser/view/test-run-widget.tsx
index c45a6454be7e8..02001bd4347cf 100644
--- a/packages/test/src/browser/view/test-run-widget.tsx
+++ b/packages/test/src/browser/view/test-run-widget.tsx
@@ -198,7 +198,7 @@ export class TestRunTreeWidget extends TreeWidget {
@postConstruct()
protected override init(): void {
super.init();
- this.addClass('theia-test-result-view');
+ this.addClass('theia-test-run-view');
this.model.onSelectionChanged(() => {
const node = this.model.selectedNodes[0];
if (node instanceof TestRunNode) {
diff --git a/packages/timeline/package.json b/packages/timeline/package.json
index d508da7c10aaf..f778a8d5978f9 100644
--- a/packages/timeline/package.json
+++ b/packages/timeline/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/timeline",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Timeline Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/navigator": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/navigator": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -40,7 +40,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/toolbar/package.json b/packages/toolbar/package.json
index da728cf0315f3..7c0abda7c4399 100644
--- a/packages/toolbar/package.json
+++ b/packages/toolbar/package.json
@@ -1,6 +1,6 @@
{
"name": "@theia/toolbar",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Toolbar",
"keywords": [
"theia-extension"
@@ -27,15 +27,15 @@
"watch": "theiaext watch"
},
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
- "@theia/file-search": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/monaco": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
+ "@theia/file-search": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/monaco": "1.54.0",
"@theia/monaco-editor-core": "1.83.101",
- "@theia/search-in-workspace": "1.53.0",
- "@theia/userstorage": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/search-in-workspace": "1.54.0",
+ "@theia/userstorage": "1.54.0",
+ "@theia/workspace": "1.54.0",
"ajv": "^6.5.3",
"jsonc-parser": "^2.2.0",
"perfect-scrollbar": "^1.3.0",
diff --git a/packages/typehierarchy/package.json b/packages/typehierarchy/package.json
index d9965c61e42d0..0802b6ccd5530 100644
--- a/packages/typehierarchy/package.json
+++ b/packages/typehierarchy/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/typehierarchy",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Type Hierarchy Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/editor": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/editor": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -40,7 +40,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/userstorage/package.json b/packages/userstorage/package.json
index 0b7cee4c41d76..f43f417ae21e4 100644
--- a/packages/userstorage/package.json
+++ b/packages/userstorage/package.json
@@ -1,10 +1,10 @@
{
"name": "@theia/userstorage",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - User Storage Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -40,7 +40,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/variable-resolver/package.json b/packages/variable-resolver/package.json
index ba8fbdafbd7cb..5cdb301cebdf6 100644
--- a/packages/variable-resolver/package.json
+++ b/packages/variable-resolver/package.json
@@ -1,9 +1,9 @@
{
"name": "@theia/variable-resolver",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Variable Resolver Extension",
"dependencies": {
- "@theia/core": "1.53.0",
+ "@theia/core": "1.54.0",
"tslib": "^2.6.2"
},
"publishConfig": {
@@ -45,7 +45,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/packages/vsx-registry/package.json b/packages/vsx-registry/package.json
index 86656ef7f8dac..3eabc882978ee 100644
--- a/packages/vsx-registry/package.json
+++ b/packages/vsx-registry/package.json
@@ -1,16 +1,16 @@
{
"name": "@theia/vsx-registry",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - VSX Registry",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/navigator": "1.53.0",
- "@theia/ovsx-client": "1.53.0",
- "@theia/plugin-ext": "1.53.0",
- "@theia/plugin-ext-vscode": "1.53.0",
- "@theia/preferences": "1.53.0",
- "@theia/workspace": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/navigator": "1.54.0",
+ "@theia/ovsx-client": "1.54.0",
+ "@theia/plugin-ext": "1.54.0",
+ "@theia/plugin-ext-vscode": "1.54.0",
+ "@theia/preferences": "1.54.0",
+ "@theia/workspace": "1.54.0",
"limiter": "^2.1.0",
"luxon": "^2.4.0",
"p-debounce": "^2.1.0",
@@ -55,7 +55,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0",
+ "@theia/ext-scripts": "1.54.0",
"@types/luxon": "^2.3.2"
},
"nyc": {
diff --git a/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts b/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts
index 2bb0b34eec0c9..19736daf75b62 100644
--- a/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts
+++ b/packages/vsx-registry/src/browser/vsx-registry-frontend-module.ts
@@ -18,7 +18,9 @@ import '../../src/browser/style/index.css';
import { ContainerModule } from '@theia/core/shared/inversify';
import {
- WidgetFactory, bindViewContribution, FrontendApplicationContribution, ViewContainerIdentifier, OpenHandler, WidgetManager, WebSocketConnectionProvider
+ WidgetFactory, bindViewContribution, FrontendApplicationContribution, ViewContainerIdentifier, OpenHandler, WidgetManager, WebSocketConnectionProvider,
+ WidgetStatusBarContribution,
+ noopWidgetStatusBarContribution
} from '@theia/core/lib/browser';
import { VSXExtensionsViewContainer } from './vsx-extensions-view-container';
import { VSXExtensionsContribution } from './vsx-extensions-contribution';
@@ -64,6 +66,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
})).inSingletonScope();
bind(VSXExtensionEditorManager).toSelf().inSingletonScope();
bind(OpenHandler).toService(VSXExtensionEditorManager);
+ bind(WidgetStatusBarContribution).toConstantValue(noopWidgetStatusBarContribution(VSXExtensionEditor));
bind(WidgetFactory).toDynamicValue(({ container }) => ({
id: VSXExtensionsWidget.ID,
diff --git a/packages/workspace/package.json b/packages/workspace/package.json
index 85340e1e18638..4480fb4d92c12 100644
--- a/packages/workspace/package.json
+++ b/packages/workspace/package.json
@@ -1,11 +1,11 @@
{
"name": "@theia/workspace",
- "version": "1.53.0",
+ "version": "1.54.0",
"description": "Theia - Workspace Extension",
"dependencies": {
- "@theia/core": "1.53.0",
- "@theia/filesystem": "1.53.0",
- "@theia/variable-resolver": "1.53.0",
+ "@theia/core": "1.54.0",
+ "@theia/filesystem": "1.54.0",
+ "@theia/variable-resolver": "1.54.0",
"jsonc-parser": "^2.2.0",
"tslib": "^2.6.2",
"valid-filename": "^2.0.1"
@@ -47,7 +47,7 @@
"watch": "theiaext watch"
},
"devDependencies": {
- "@theia/ext-scripts": "1.53.0"
+ "@theia/ext-scripts": "1.54.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
diff --git a/sample-plugins/sample-namespace/plugin-a/package.json b/sample-plugins/sample-namespace/plugin-a/package.json
index 6979f04fb5433..8b1af99d4c01f 100644
--- a/sample-plugins/sample-namespace/plugin-a/package.json
+++ b/sample-plugins/sample-namespace/plugin-a/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "plugin-a",
- "version": "1.53.0",
+ "version": "1.54.0",
"main": "extension.js",
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
"repository": {
diff --git a/sample-plugins/sample-namespace/plugin-b/package.json b/sample-plugins/sample-namespace/plugin-b/package.json
index 4cb8ea0bd7577..6f195fb4b3569 100644
--- a/sample-plugins/sample-namespace/plugin-b/package.json
+++ b/sample-plugins/sample-namespace/plugin-b/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "plugin-b",
- "version": "1.53.0",
+ "version": "1.54.0",
"main": "extension.js",
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
"repository": {
diff --git a/sample-plugins/sample-namespace/plugin-gotd/package.json b/sample-plugins/sample-namespace/plugin-gotd/package.json
index eee86aed9b23a..0eae6cb2417db 100644
--- a/sample-plugins/sample-namespace/plugin-gotd/package.json
+++ b/sample-plugins/sample-namespace/plugin-gotd/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "plugin-gotd",
- "version": "1.53.0",
+ "version": "1.54.0",
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
"repository": {
"type": "git",
@@ -15,7 +15,7 @@
"*"
],
"devDependencies": {
- "@theia/api-provider-sample": "1.53.0"
+ "@theia/api-provider-sample": "1.54.0"
},
"scripts": {
"prepare": "yarn -s package",