mirror of
https://github.com/microsoft/vscode.git
synced 2026-08-13 01:04:23 +01:00
Merge branch 'main' into fix-205353
This commit is contained in:
Generated
+1
-1
@@ -109,7 +109,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "inno_updater"
|
||||
version = "0.10.1"
|
||||
version = "0.11.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "inno_updater"
|
||||
version = "0.10.1"
|
||||
version = "0.11.0"
|
||||
authors = ["Microsoft <monacotools@microsoft.com>"]
|
||||
build = "build.rs"
|
||||
|
||||
|
||||
@@ -1519,7 +1519,7 @@ begin
|
||||
|
||||
StopTunnelServiceIfNeeded();
|
||||
|
||||
Exec(ExpandConstant('{app}\tools\inno_updater.exe'), ExpandConstant('"{app}\{#ExeBasename}.exe" ' + BoolToStr(LockFileExists())), '', SW_SHOW, ewWaitUntilTerminated, UpdateResultCode);
|
||||
Exec(ExpandConstant('{app}\tools\inno_updater.exe'), ExpandConstant('"{app}\{#ExeBasename}.exe" ' + BoolToStr(LockFileExists()) + ' "{cm:UpdatingVisualStudioCode}"'), '', SW_SHOW, ewWaitUntilTerminated, UpdateResultCode);
|
||||
end;
|
||||
|
||||
if ShouldRestartTunnelService then
|
||||
|
||||
@@ -6,4 +6,5 @@ AddToPath=Zu PATH hinzuf
|
||||
RunAfter=%1 nach der Installation ausführen
|
||||
Other=Andere:
|
||||
SourceFile=%1-Quelldatei
|
||||
OpenWithCodeContextMenu=Mit %1 öffnen
|
||||
OpenWithCodeContextMenu=Mit %1 öffnen
|
||||
UpdatingVisualStudioCode=Visual Studio Code wird aktualisiert...
|
||||
@@ -14,3 +14,4 @@ RunAfter=Run %1 after installation
|
||||
Other=Other:
|
||||
SourceFile=%1 Source File
|
||||
OpenWithCodeContextMenu=Open w&ith %1
|
||||
UpdatingVisualStudioCode=Updating Visual Studio Code...
|
||||
|
||||
@@ -7,3 +7,4 @@ RunAfter=Ejecutar %1 despu
|
||||
Other=Otros:
|
||||
SourceFile=Archivo de origen %1
|
||||
OpenWithCodeContextMenu=Abrir &con %1
|
||||
UpdatingVisualStudioCode=Actualizando Visual Studio Code...
|
||||
@@ -6,4 +6,5 @@ AddToPath=Ajouter
|
||||
RunAfter=Exécuter %1 après l'installation
|
||||
Other=Autre :
|
||||
SourceFile=Fichier source %1
|
||||
OpenWithCodeContextMenu=Ouvrir avec %1
|
||||
OpenWithCodeContextMenu=Ouvrir avec %1
|
||||
UpdatingVisualStudioCode=Mise à jour de Visual Studio Code...
|
||||
@@ -6,4 +6,5 @@ AddToPath=Hozz
|
||||
RunAfter=%1 indítása a telepítés után
|
||||
Other=Egyéb:
|
||||
SourceFile=%1 forrásfájl
|
||||
OpenWithCodeContextMenu=Megnyitás a következővel: %1
|
||||
OpenWithCodeContextMenu=Megnyitás a következővel: %1
|
||||
UpdatingVisualStudioCode=A Visual Studio Code frissítése...
|
||||
@@ -6,4 +6,5 @@ AddToPath=Aggiungi a PATH (disponibile dopo il riavvio)
|
||||
RunAfter=Esegui %1 dopo l'installazione
|
||||
Other=Altro:
|
||||
SourceFile=File di origine %1
|
||||
OpenWithCodeContextMenu=Apri con %1
|
||||
OpenWithCodeContextMenu=Apri con %1
|
||||
UpdatingVisualStudioCode=Aggiornamento di Visual Studio Code...
|
||||
@@ -6,4 +6,5 @@ AddToPath=PATH
|
||||
RunAfter=インストール後に %1 を実行する
|
||||
Other=その他:
|
||||
SourceFile=%1 ソース ファイル
|
||||
OpenWithCodeContextMenu=%1 で開く
|
||||
OpenWithCodeContextMenu=%1 で開く
|
||||
UpdatingVisualStudioCode=Visual Studio Code を更新しています...
|
||||
@@ -6,4 +6,5 @@ AddToPath=PATH
|
||||
RunAfter=설치 후 %1 실행
|
||||
Other=기타:
|
||||
SourceFile=%1 원본 파일
|
||||
OpenWithCodeContextMenu=%1(으)로 열기
|
||||
OpenWithCodeContextMenu=%1(으)로 열기
|
||||
UpdatingVisualStudioCode=Visual Studio Code 업데이트 중...
|
||||
@@ -6,4 +6,5 @@ AddToPath=Adicione em PATH (dispon
|
||||
RunAfter=Executar %1 após a instalação
|
||||
Other=Outros:
|
||||
SourceFile=Arquivo Fonte %1
|
||||
OpenWithCodeContextMenu=Abrir com %1
|
||||
OpenWithCodeContextMenu=Abrir com %1
|
||||
UpdatingVisualStudioCode=Atualizando o Visual Studio Code...
|
||||
@@ -6,4 +6,5 @@ AddToPath=
|
||||
RunAfter=Запустить %1 после установки
|
||||
Other=Другое:
|
||||
SourceFile=Исходный файл %1
|
||||
OpenWithCodeContextMenu=Открыть с помощью %1
|
||||
OpenWithCodeContextMenu=Открыть с помощью %1
|
||||
UpdatingVisualStudioCode=Обновление Visual Studio Code...
|
||||
@@ -6,4 +6,5 @@ AddToPath=PATH'e ekle (yeniden ba
|
||||
RunAfter=Kurulumdan sonra %1 uygulamasını çalıştır.
|
||||
Other=Diğer:
|
||||
SourceFile=%1 Kaynak Dosyası
|
||||
OpenWithCodeContextMenu=%1 İle Aç
|
||||
OpenWithCodeContextMenu=%1 İle Aç
|
||||
UpdatingVisualStudioCode=Visual Studio Code güncelleniyor...
|
||||
@@ -6,4 +6,5 @@ AddToPath=
|
||||
RunAfter=安装后运行 %1
|
||||
Other=其他:
|
||||
SourceFile=%1 源文件
|
||||
OpenWithCodeContextMenu=通过 %1 打开
|
||||
OpenWithCodeContextMenu=通过 %1 打开
|
||||
UpdatingVisualStudioCode=正在更新 Visual Studio Code...
|
||||
@@ -6,4 +6,5 @@ AddToPath=
|
||||
RunAfter=安裝後執行 %1
|
||||
Other=其他:
|
||||
SourceFile=%1 來源檔案
|
||||
OpenWithCodeContextMenu=以 %1 開啟
|
||||
OpenWithCodeContextMenu=以 %1 開啟
|
||||
UpdatingVisualStudioCode=正在更新 Visual Studio Code...
|
||||
Binary file not shown.
@@ -589,5 +589,15 @@
|
||||
"prependLicenseText": [
|
||||
"Copyright (c) heap.js authors"
|
||||
]
|
||||
},
|
||||
{
|
||||
// Reason: mono-repo where the individual packages are also dual-licensed under MIT and Apache-2.0
|
||||
"name": "system-configuration",
|
||||
"fullLicenseTextUri": "https://github.com/mullvad/system-configuration-rs/blob/main/system-configuration/LICENSE-MIT"
|
||||
},
|
||||
{
|
||||
// Reason: mono-repo where the individual packages are also dual-licensed under MIT and Apache-2.0
|
||||
"name": "system-configuration-sys",
|
||||
"fullLicenseTextUri": "https://github.com/mullvad/system-configuration-rs/blob/main/system-configuration-sys/LICENSE-MIT"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"css.lint.emptyRules.desc": "Do not use empty rulesets.",
|
||||
"css.lint.float.desc": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.",
|
||||
"css.lint.fontFaceProperties.desc": "`@font-face` rule must define `src` and `font-family` properties.",
|
||||
"css.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers.",
|
||||
"css.lint.hexColorLength.desc": "Hex colors must consist of 3, 4, 6 or 8 hex numbers.",
|
||||
"css.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.",
|
||||
"css.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older.",
|
||||
"css.lint.important.desc": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.",
|
||||
@@ -47,7 +47,7 @@
|
||||
"less.lint.emptyRules.desc": "Do not use empty rulesets.",
|
||||
"less.lint.float.desc": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.",
|
||||
"less.lint.fontFaceProperties.desc": "`@font-face` rule must define `src` and `font-family` properties.",
|
||||
"less.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers.",
|
||||
"less.lint.hexColorLength.desc": "Hex colors must consist of 3, 4, 6 or 8 hex numbers.",
|
||||
"less.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.",
|
||||
"less.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older.",
|
||||
"less.lint.important.desc": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.",
|
||||
@@ -81,7 +81,7 @@
|
||||
"scss.lint.emptyRules.desc": "Do not use empty rulesets.",
|
||||
"scss.lint.float.desc": "Avoid using `float`. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes.",
|
||||
"scss.lint.fontFaceProperties.desc": "`@font-face` rule must define `src` and `font-family` properties.",
|
||||
"scss.lint.hexColorLength.desc": "Hex colors must consist of three or six hex numbers.",
|
||||
"scss.lint.hexColorLength.desc": "Hex colors must consist of 3, 4, 6 or 8 hex numbers.",
|
||||
"scss.lint.idSelector.desc": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML.",
|
||||
"scss.lint.ieHack.desc": "IE hacks are only necessary when supporting IE7 and older.",
|
||||
"scss.lint.important.desc": "Avoid using `!important`. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored.",
|
||||
|
||||
@@ -2759,13 +2759,8 @@
|
||||
"default": false
|
||||
},
|
||||
"git.inputValidation": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"always",
|
||||
"warn",
|
||||
"off"
|
||||
],
|
||||
"default": "off",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%config.inputValidation%"
|
||||
},
|
||||
"git.inputValidationLength": {
|
||||
@@ -2781,11 +2776,6 @@
|
||||
"default": 50,
|
||||
"markdownDescription": "%config.inputValidationSubjectLength%"
|
||||
},
|
||||
"git.experimental.inputValidation": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%config.inputValidation%"
|
||||
},
|
||||
"git.detectSubmodules": {
|
||||
"type": "boolean",
|
||||
"scope": "resource",
|
||||
@@ -3208,46 +3198,6 @@
|
||||
"highContrast": "#8db9e2",
|
||||
"highContrastLight": "#1258a7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.incomingAddedForegroundColor",
|
||||
"description": "%colors.incomingAdded%",
|
||||
"defaults": {
|
||||
"light": "#587c0c",
|
||||
"dark": "#81b88b",
|
||||
"highContrast": "#1b5225",
|
||||
"highContrastLight": "#374e06"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.incomingDeletedForegroundColor",
|
||||
"description": "%colors.incomingDeleted%",
|
||||
"defaults": {
|
||||
"light": "#ad0707",
|
||||
"dark": "#c74e39",
|
||||
"highContrast": "#c74e39",
|
||||
"highContrastLight": "#ad0707"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.incomingRenamedForegroundColor",
|
||||
"description": "%colors.incomingRenamed%",
|
||||
"defaults": {
|
||||
"light": "#007100",
|
||||
"dark": "#73C991",
|
||||
"highContrast": "#73C991",
|
||||
"highContrastLight": "#007100"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gitDecoration.incomingModifiedForegroundColor",
|
||||
"description": "%colors.incomingModified%",
|
||||
"defaults": {
|
||||
"light": "#895503",
|
||||
"dark": "#E2C08D",
|
||||
"highContrast": "#E2C08D",
|
||||
"highContrastLight": "#895503"
|
||||
}
|
||||
}
|
||||
],
|
||||
"configurationDefaults": {
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
"config.openAfterClone.prompt": "Always prompt for action.",
|
||||
"config.showInlineOpenFileAction": "Controls whether to show an inline Open File action in the Git changes view.",
|
||||
"config.showPushSuccessNotification": "Controls whether to show a notification when a push is successful.",
|
||||
"config.inputValidation": "Controls when to show commit message input validation.",
|
||||
"config.inputValidation": "Controls whether to show commit message input validation diagnostics.",
|
||||
"config.inputValidationLength": "Controls the commit message length threshold for showing a warning.",
|
||||
"config.inputValidationSubjectLength": "Controls the commit message subject length threshold for showing a warning. Unset it to inherit the value of `#git.inputValidationLength#`.",
|
||||
"config.detectSubmodules": "Controls whether to automatically detect Git submodules.",
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window, workspace, Uri, Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, ThemeColor, l10n } from 'vscode';
|
||||
import { window, workspace, Uri, Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, ThemeColor } from 'vscode';
|
||||
import * as path from 'path';
|
||||
import { Repository, GitResourceGroup } from './repository';
|
||||
import { Model } from './model';
|
||||
import { debounce } from './decorators';
|
||||
import { filterEvent, dispose, anyEvent, fireEvent, PromiseSource, combinedDisposable } from './util';
|
||||
import { Change, GitErrorCodes, Status } from './api/git';
|
||||
import { GitErrorCodes, Status } from './api/git';
|
||||
|
||||
class GitIgnoreDecorationProvider implements FileDecorationProvider {
|
||||
|
||||
@@ -153,100 +153,100 @@ class GitDecorationProvider implements FileDecorationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
class GitIncomingChangesFileDecorationProvider implements FileDecorationProvider {
|
||||
// class GitIncomingChangesFileDecorationProvider implements FileDecorationProvider {
|
||||
|
||||
private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
|
||||
readonly onDidChangeFileDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
|
||||
// private readonly _onDidChangeDecorations = new EventEmitter<Uri[]>();
|
||||
// readonly onDidChangeFileDecorations: Event<Uri[]> = this._onDidChangeDecorations.event;
|
||||
|
||||
private decorations = new Map<string, FileDecoration>();
|
||||
private readonly disposables: Disposable[] = [];
|
||||
// private decorations = new Map<string, FileDecoration>();
|
||||
// private readonly disposables: Disposable[] = [];
|
||||
|
||||
constructor(private readonly repository: Repository) {
|
||||
this.disposables.push(window.registerFileDecorationProvider(this));
|
||||
repository.historyProvider.onDidChangeCurrentHistoryItemGroup(this.onDidChangeCurrentHistoryItemGroup, this, this.disposables);
|
||||
}
|
||||
// constructor(private readonly repository: Repository) {
|
||||
// this.disposables.push(window.registerFileDecorationProvider(this));
|
||||
// repository.historyProvider.onDidChangeCurrentHistoryItemGroup(this.onDidChangeCurrentHistoryItemGroup, this, this.disposables);
|
||||
// }
|
||||
|
||||
private async onDidChangeCurrentHistoryItemGroup(): Promise<void> {
|
||||
const newDecorations = new Map<string, FileDecoration>();
|
||||
await this.collectIncomingChangesFileDecorations(newDecorations);
|
||||
const uris = new Set([...this.decorations.keys()].concat([...newDecorations.keys()]));
|
||||
// private async onDidChangeCurrentHistoryItemGroup(): Promise<void> {
|
||||
// const newDecorations = new Map<string, FileDecoration>();
|
||||
// await this.collectIncomingChangesFileDecorations(newDecorations);
|
||||
// const uris = new Set([...this.decorations.keys()].concat([...newDecorations.keys()]));
|
||||
|
||||
this.decorations = newDecorations;
|
||||
this._onDidChangeDecorations.fire([...uris.values()].map(value => Uri.parse(value, true)));
|
||||
}
|
||||
// this.decorations = newDecorations;
|
||||
// this._onDidChangeDecorations.fire([...uris.values()].map(value => Uri.parse(value, true)));
|
||||
// }
|
||||
|
||||
private async collectIncomingChangesFileDecorations(bucket: Map<string, FileDecoration>): Promise<void> {
|
||||
for (const change of await this.getIncomingChanges()) {
|
||||
switch (change.status) {
|
||||
case Status.INDEX_ADDED:
|
||||
bucket.set(change.uri.toString(), {
|
||||
badge: '↓A',
|
||||
color: new ThemeColor('gitDecoration.incomingAddedForegroundColor'),
|
||||
tooltip: l10n.t('Incoming Changes (added)'),
|
||||
});
|
||||
break;
|
||||
case Status.DELETED:
|
||||
bucket.set(change.uri.toString(), {
|
||||
badge: '↓D',
|
||||
color: new ThemeColor('gitDecoration.incomingDeletedForegroundColor'),
|
||||
tooltip: l10n.t('Incoming Changes (deleted)'),
|
||||
});
|
||||
break;
|
||||
case Status.INDEX_RENAMED:
|
||||
bucket.set(change.originalUri.toString(), {
|
||||
badge: '↓R',
|
||||
color: new ThemeColor('gitDecoration.incomingRenamedForegroundColor'),
|
||||
tooltip: l10n.t('Incoming Changes (renamed)'),
|
||||
});
|
||||
break;
|
||||
case Status.MODIFIED:
|
||||
bucket.set(change.uri.toString(), {
|
||||
badge: '↓M',
|
||||
color: new ThemeColor('gitDecoration.incomingModifiedForegroundColor'),
|
||||
tooltip: l10n.t('Incoming Changes (modified)'),
|
||||
});
|
||||
break;
|
||||
default: {
|
||||
bucket.set(change.uri.toString(), {
|
||||
badge: '↓~',
|
||||
color: new ThemeColor('gitDecoration.incomingModifiedForegroundColor'),
|
||||
tooltip: l10n.t('Incoming Changes'),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// private async collectIncomingChangesFileDecorations(bucket: Map<string, FileDecoration>): Promise<void> {
|
||||
// for (const change of await this.getIncomingChanges()) {
|
||||
// switch (change.status) {
|
||||
// case Status.INDEX_ADDED:
|
||||
// bucket.set(change.uri.toString(), {
|
||||
// badge: '↓A',
|
||||
// color: new ThemeColor('gitDecoration.incomingAddedForegroundColor'),
|
||||
// tooltip: l10n.t('Incoming Changes (added)'),
|
||||
// });
|
||||
// break;
|
||||
// case Status.DELETED:
|
||||
// bucket.set(change.uri.toString(), {
|
||||
// badge: '↓D',
|
||||
// color: new ThemeColor('gitDecoration.incomingDeletedForegroundColor'),
|
||||
// tooltip: l10n.t('Incoming Changes (deleted)'),
|
||||
// });
|
||||
// break;
|
||||
// case Status.INDEX_RENAMED:
|
||||
// bucket.set(change.originalUri.toString(), {
|
||||
// badge: '↓R',
|
||||
// color: new ThemeColor('gitDecoration.incomingRenamedForegroundColor'),
|
||||
// tooltip: l10n.t('Incoming Changes (renamed)'),
|
||||
// });
|
||||
// break;
|
||||
// case Status.MODIFIED:
|
||||
// bucket.set(change.uri.toString(), {
|
||||
// badge: '↓M',
|
||||
// color: new ThemeColor('gitDecoration.incomingModifiedForegroundColor'),
|
||||
// tooltip: l10n.t('Incoming Changes (modified)'),
|
||||
// });
|
||||
// break;
|
||||
// default: {
|
||||
// bucket.set(change.uri.toString(), {
|
||||
// badge: '↓~',
|
||||
// color: new ThemeColor('gitDecoration.incomingModifiedForegroundColor'),
|
||||
// tooltip: l10n.t('Incoming Changes'),
|
||||
// });
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private async getIncomingChanges(): Promise<Change[]> {
|
||||
try {
|
||||
const historyProvider = this.repository.historyProvider;
|
||||
const currentHistoryItemGroup = historyProvider.currentHistoryItemGroup;
|
||||
// private async getIncomingChanges(): Promise<Change[]> {
|
||||
// try {
|
||||
// const historyProvider = this.repository.historyProvider;
|
||||
// const currentHistoryItemGroup = historyProvider.currentHistoryItemGroup;
|
||||
|
||||
if (!currentHistoryItemGroup?.base) {
|
||||
return [];
|
||||
}
|
||||
// if (!currentHistoryItemGroup?.base) {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
const ancestor = await historyProvider.resolveHistoryItemGroupCommonAncestor(currentHistoryItemGroup.id, currentHistoryItemGroup.base.id);
|
||||
if (!ancestor) {
|
||||
return [];
|
||||
}
|
||||
// const ancestor = await historyProvider.resolveHistoryItemGroupCommonAncestor(currentHistoryItemGroup.id, currentHistoryItemGroup.base.id);
|
||||
// if (!ancestor) {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
const changes = await this.repository.diffBetween(ancestor.id, currentHistoryItemGroup.base.id);
|
||||
return changes;
|
||||
} catch (err) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
// const changes = await this.repository.diffBetween(ancestor.id, currentHistoryItemGroup.base.id);
|
||||
// return changes;
|
||||
// } catch (err) {
|
||||
// return [];
|
||||
// }
|
||||
// }
|
||||
|
||||
provideFileDecoration(uri: Uri): FileDecoration | undefined {
|
||||
return this.decorations.get(uri.toString());
|
||||
}
|
||||
// provideFileDecoration(uri: Uri): FileDecoration | undefined {
|
||||
// return this.decorations.get(uri.toString());
|
||||
// }
|
||||
|
||||
dispose(): void {
|
||||
dispose(this.disposables);
|
||||
}
|
||||
}
|
||||
// dispose(): void {
|
||||
// dispose(this.disposables);
|
||||
// }
|
||||
// }
|
||||
|
||||
export class GitDecorations {
|
||||
|
||||
@@ -287,7 +287,7 @@ export class GitDecorations {
|
||||
private onDidOpenRepository(repository: Repository): void {
|
||||
const providers = combinedDisposable([
|
||||
new GitDecorationProvider(repository),
|
||||
new GitIncomingChangesFileDecorationProvider(repository)
|
||||
// new GitIncomingChangesFileDecorationProvider(repository)
|
||||
]);
|
||||
|
||||
this.providers.set(repository, providers);
|
||||
|
||||
@@ -21,14 +21,38 @@ export class GitCommitInputBoxDiagnosticsManager {
|
||||
constructor(private readonly model: Model) {
|
||||
this.diagnostics = languages.createDiagnosticCollection();
|
||||
|
||||
mapEvent(filterEvent(workspace.onDidChangeTextDocument, e => e.document.uri.scheme === 'vscode-scm'), e => e.document)(this.onDidChangeTextDocument, this, this.disposables);
|
||||
filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.experimental.inputValidation'))(this.onDidChangeConfiguration, this, this.disposables);
|
||||
this.migrateInputValidationSettings()
|
||||
.then(() => {
|
||||
mapEvent(filterEvent(workspace.onDidChangeTextDocument, e => e.document.uri.scheme === 'vscode-scm'), e => e.document)(this.onDidChangeTextDocument, this, this.disposables);
|
||||
filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.inputValidation'))(this.onDidChangeConfiguration, this, this.disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public getDiagnostics(uri: Uri): ReadonlyArray<Diagnostic> {
|
||||
return this.diagnostics.get(uri) ?? [];
|
||||
}
|
||||
|
||||
private async migrateInputValidationSettings(): Promise<void> {
|
||||
try {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const inputValidation = config.inspect<'always' | 'warn' | 'off' | boolean>('inputValidation');
|
||||
|
||||
if (inputValidation === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Workspace setting
|
||||
if (typeof inputValidation.workspaceValue === 'string') {
|
||||
await config.update('inputValidation', inputValidation.workspaceValue !== 'off', false);
|
||||
}
|
||||
|
||||
// User setting
|
||||
if (typeof inputValidation.globalValue === 'string') {
|
||||
await config.update('inputValidation', inputValidation.workspaceValue !== 'off', true);
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
private onDidChangeConfiguration(): void {
|
||||
for (const repository of this.model.repositories) {
|
||||
this.onDidChangeTextDocument(repository.inputBox.document);
|
||||
@@ -37,7 +61,7 @@ export class GitCommitInputBoxDiagnosticsManager {
|
||||
|
||||
private onDidChangeTextDocument(document: TextDocument): void {
|
||||
const config = workspace.getConfiguration('git');
|
||||
const inputValidation = config.get<boolean>('experimental.inputValidation', false) === true;
|
||||
const inputValidation = config.get<boolean>('inputValidation', false);
|
||||
if (!inputValidation) {
|
||||
this.diagnostics.set(document.uri, undefined);
|
||||
return;
|
||||
|
||||
@@ -975,10 +975,9 @@ export class Repository implements Disposable {
|
||||
this.setCountBadge();
|
||||
}
|
||||
|
||||
validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined {
|
||||
let tooManyChangesWarning: SourceControlInputBoxValidation | undefined;
|
||||
validateInput(text: string, _: number): SourceControlInputBoxValidation | undefined {
|
||||
if (this.isRepositoryHuge) {
|
||||
tooManyChangesWarning = {
|
||||
return {
|
||||
message: l10n.t('Too many changes were detected. Only the first {0} changes will be shown below.', this.isRepositoryHuge.limit),
|
||||
type: SourceControlInputBoxValidationType.Warning
|
||||
};
|
||||
@@ -993,59 +992,7 @@ export class Repository implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
const config = workspace.getConfiguration('git');
|
||||
const setting = config.get<'always' | 'warn' | 'off'>('inputValidation');
|
||||
|
||||
if (setting === 'off') {
|
||||
return tooManyChangesWarning;
|
||||
}
|
||||
|
||||
if (/^\s+$/.test(text)) {
|
||||
return {
|
||||
message: l10n.t('Current commit message only contains whitespace characters'),
|
||||
type: SourceControlInputBoxValidationType.Warning
|
||||
};
|
||||
}
|
||||
|
||||
let lineNumber = 0;
|
||||
let start = 0;
|
||||
let match: RegExpExecArray | null;
|
||||
const regex = /\r?\n/g;
|
||||
|
||||
while ((match = regex.exec(text)) && position > match.index) {
|
||||
start = match.index + match[0].length;
|
||||
lineNumber++;
|
||||
}
|
||||
|
||||
const end = match ? match.index : text.length;
|
||||
|
||||
const line = text.substring(start, end);
|
||||
|
||||
let threshold = config.get<number>('inputValidationLength', 50);
|
||||
|
||||
if (lineNumber === 0) {
|
||||
const inputValidationSubjectLength = config.get<number | null>('inputValidationSubjectLength', null);
|
||||
|
||||
if (inputValidationSubjectLength !== null) {
|
||||
threshold = inputValidationSubjectLength;
|
||||
}
|
||||
}
|
||||
|
||||
if (line.length <= threshold) {
|
||||
if (setting !== 'always') {
|
||||
return tooManyChangesWarning;
|
||||
}
|
||||
|
||||
return {
|
||||
message: l10n.t('{0} characters left in current line', threshold - line.length),
|
||||
type: SourceControlInputBoxValidationType.Information
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
message: l10n.t('{0} characters over {1} in current line', line.length - threshold, threshold),
|
||||
type: SourceControlInputBoxValidationType.Warning
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"chatParticipant",
|
||||
"languageModels",
|
||||
"defaultChatParticipant",
|
||||
"chatVariableResolver",
|
||||
"contribViewsRemote",
|
||||
"contribStatusBarItems",
|
||||
"createFileSystemWatcher",
|
||||
|
||||
@@ -74,7 +74,7 @@ suite('chat', () => {
|
||||
});
|
||||
|
||||
test('participant and variable', async () => {
|
||||
disposables.push(chat.registerVariable('myVar', 'My variable', {
|
||||
disposables.push(chat.registerChatVariableResolver('myVar', 'My variable', {
|
||||
resolve(_name, _context, _token) {
|
||||
return [{ level: ChatVariableLevel.Full, value: 'myValue' }];
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.87.0",
|
||||
"distro": "af73a537ea203329debad3df7ca7b42b4799473f",
|
||||
"distro": "b314654a31bdba8cd2b0c7548e931916d03416bf",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
||||
@@ -226,12 +226,17 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
|
||||
const title = this.getTooltip() ?? '';
|
||||
this.updateAriaLabel();
|
||||
|
||||
if (!this.customHover) {
|
||||
const hoverDelegate = this.options.hoverDelegate ?? getDefaultHoverDelegate('element');
|
||||
this.customHover = setupCustomHover(hoverDelegate, this.element, title);
|
||||
this._store.add(this.customHover);
|
||||
if (this.options.hoverDelegate?.showNativeHover) {
|
||||
/* While custom hover is not supported with context view */
|
||||
this.element.title = title;
|
||||
} else {
|
||||
this.customHover.update(title);
|
||||
if (!this.customHover) {
|
||||
const hoverDelegate = this.options.hoverDelegate ?? getDefaultHoverDelegate('element');
|
||||
this.customHover = setupCustomHover(hoverDelegate, this.element, title);
|
||||
this._store.add(this.customHover);
|
||||
} else {
|
||||
this.customHover.update(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -591,11 +591,13 @@ export const Codicon = {
|
||||
gitStash: register('git-stash', 0xec26),
|
||||
gitStashApply: register('git-stash-apply', 0xec27),
|
||||
gitStashPop: register('git-stash-pop', 0xec28),
|
||||
coverage: register('coverage', 0xec2e),
|
||||
runAllCoverage: register('run-all-coverage', 0xec2d),
|
||||
runCoverage: register('run-all-coverage', 0xec2c),
|
||||
coverage: register('coverage', 0xec2e),
|
||||
githubProject: register('github-project', 0xec2f),
|
||||
|
||||
// derived icons, that could become separate icons
|
||||
// TODO: These mappings should go in the vscode-codicons mapping file
|
||||
|
||||
dialogError: register('dialog-error', 'error'),
|
||||
dialogWarning: register('dialog-warning', 'warning'),
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { env } from 'vs/base/common/process';
|
||||
|
||||
// Define the enumeration for Desktop Environments
|
||||
enum DesktopEnvironment {
|
||||
UNKNOWN = 'UNKNOWN',
|
||||
CINNAMON = 'CINNAMON',
|
||||
DEEPIN = 'DEEPIN',
|
||||
GNOME = 'GNOME',
|
||||
KDE3 = 'KDE3',
|
||||
KDE4 = 'KDE4',
|
||||
KDE5 = 'KDE5',
|
||||
KDE6 = 'KDE6',
|
||||
PANTHEON = 'PANTHEON',
|
||||
UNITY = 'UNITY',
|
||||
XFCE = 'XFCE',
|
||||
UKUI = 'UKUI',
|
||||
LXQT = 'LXQT',
|
||||
}
|
||||
|
||||
const kXdgCurrentDesktopEnvVar = 'XDG_CURRENT_DESKTOP';
|
||||
const kKDESessionEnvVar = 'KDE_SESSION_VERSION';
|
||||
|
||||
export function getDesktopEnvironment(): DesktopEnvironment {
|
||||
const xdgCurrentDesktop = env[kXdgCurrentDesktopEnvVar];
|
||||
if (xdgCurrentDesktop) {
|
||||
const values = xdgCurrentDesktop.split(':').map(value => value.trim()).filter(value => value.length > 0);
|
||||
for (const value of values) {
|
||||
switch (value) {
|
||||
case 'Unity': {
|
||||
const desktopSessionUnity = env['DESKTOP_SESSION'];
|
||||
if (desktopSessionUnity && desktopSessionUnity.includes('gnome-fallback')) {
|
||||
return DesktopEnvironment.GNOME;
|
||||
}
|
||||
|
||||
return DesktopEnvironment.UNITY;
|
||||
}
|
||||
case 'Deepin':
|
||||
return DesktopEnvironment.DEEPIN;
|
||||
case 'GNOME':
|
||||
return DesktopEnvironment.GNOME;
|
||||
case 'X-Cinnamon':
|
||||
return DesktopEnvironment.CINNAMON;
|
||||
case 'KDE': {
|
||||
const kdeSession = env[kKDESessionEnvVar];
|
||||
if (kdeSession === '5') { return DesktopEnvironment.KDE5; }
|
||||
if (kdeSession === '6') { return DesktopEnvironment.KDE6; }
|
||||
return DesktopEnvironment.KDE4;
|
||||
}
|
||||
case 'Pantheon':
|
||||
return DesktopEnvironment.PANTHEON;
|
||||
case 'XFCE':
|
||||
return DesktopEnvironment.XFCE;
|
||||
case 'UKUI':
|
||||
return DesktopEnvironment.UKUI;
|
||||
case 'LXQt':
|
||||
return DesktopEnvironment.LXQT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const desktopSession = env['DESKTOP_SESSION'];
|
||||
if (desktopSession) {
|
||||
switch (desktopSession) {
|
||||
case 'deepin':
|
||||
return DesktopEnvironment.DEEPIN;
|
||||
case 'gnome':
|
||||
case 'mate':
|
||||
return DesktopEnvironment.GNOME;
|
||||
case 'kde4':
|
||||
case 'kde-plasma':
|
||||
return DesktopEnvironment.KDE4;
|
||||
case 'kde':
|
||||
if (kKDESessionEnvVar in env) {
|
||||
return DesktopEnvironment.KDE4;
|
||||
}
|
||||
return DesktopEnvironment.KDE3;
|
||||
case 'xfce':
|
||||
case 'xubuntu':
|
||||
return DesktopEnvironment.XFCE;
|
||||
case 'ukui':
|
||||
return DesktopEnvironment.UKUI;
|
||||
}
|
||||
}
|
||||
|
||||
if ('GNOME_DESKTOP_SESSION_ID' in env) {
|
||||
return DesktopEnvironment.GNOME;
|
||||
}
|
||||
if ('KDE_FULL_SESSION' in env) {
|
||||
if (kKDESessionEnvVar in env) {
|
||||
return DesktopEnvironment.KDE4;
|
||||
}
|
||||
return DesktopEnvironment.KDE3;
|
||||
}
|
||||
|
||||
return DesktopEnvironment.UNKNOWN;
|
||||
}
|
||||
@@ -116,6 +116,8 @@ import { RemoteConnectionType } from 'vs/platform/remote/common/remoteAuthorityR
|
||||
import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory';
|
||||
import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import { SharedProcessRawConnection, SharedProcessLifecycle } from 'vs/platform/sharedProcess/common/sharedProcess';
|
||||
import { getOSReleaseInfo } from 'vs/base/node/osReleaseInfo';
|
||||
import { getDesktopEnvironment } from 'vs/base/common/desktopEnvironmentInfo';
|
||||
|
||||
class SharedProcessMain extends Disposable implements IClientConnectionFilter {
|
||||
|
||||
@@ -172,6 +174,9 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
|
||||
// Report Profiles Info
|
||||
this.reportProfilesInfo(telemetryService, userDataProfilesService);
|
||||
this._register(userDataProfilesService.onDidChangeProfiles(() => this.reportProfilesInfo(telemetryService, userDataProfilesService)));
|
||||
|
||||
// Report Client OS/DE Info
|
||||
this.reportClientOSInfo(telemetryService, logService);
|
||||
});
|
||||
|
||||
// Instantiate Contributions
|
||||
@@ -458,6 +463,35 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
|
||||
});
|
||||
}
|
||||
|
||||
private async reportClientOSInfo(telemetryService: ITelemetryService, logService: ILogService): Promise<void> {
|
||||
if (isLinux) {
|
||||
const releaseInfo = await getOSReleaseInfo(logService.error.bind(logService));
|
||||
const desktopEnvironment = getDesktopEnvironment();
|
||||
if (releaseInfo) {
|
||||
type ClientPlatformInfoClassification = {
|
||||
platformId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'A string identifying the operating system without any version information.' };
|
||||
platformVersionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'A string identifying the operating system version excluding any name information or release code.' };
|
||||
platformIdLike: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'A string identifying the operating system the current OS derivate is closely related to.' };
|
||||
desktopEnvironment: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'A string identifying the desktop environment the user is using.' };
|
||||
owner: 'benibenj';
|
||||
comment: 'Provides insight into the distro and desktop environment information on Linux.';
|
||||
};
|
||||
type ClientPlatformInfoEvent = {
|
||||
platformId: string;
|
||||
platformVersionId: string | undefined;
|
||||
platformIdLike: string | undefined;
|
||||
desktopEnvironment: string | undefined;
|
||||
};
|
||||
telemetryService.publicLog2<ClientPlatformInfoEvent, ClientPlatformInfoClassification>('clientPlatformInfo', {
|
||||
platformId: releaseInfo.id,
|
||||
platformVersionId: releaseInfo.version_id,
|
||||
platformIdLike: releaseInfo.id_like,
|
||||
desktopEnvironment: desktopEnvironment
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handledClientConnection(e: MessageEvent): boolean {
|
||||
|
||||
// This filter on message port messages will look for
|
||||
|
||||
@@ -315,7 +315,7 @@ class RenameController implements IEditorContribution {
|
||||
}
|
||||
|
||||
cancelRenameInput(): void {
|
||||
this._renameInputField.cancelInput(true);
|
||||
this._renameInputField.cancelInput(true, 'cancelRenameInput command');
|
||||
}
|
||||
|
||||
focusNextRenameSuggestion(): void {
|
||||
|
||||
@@ -25,6 +25,7 @@ import { NewSymbolName, NewSymbolNameTag, ProviderResult } from 'vs/editor/commo
|
||||
import { localize } from 'vs/nls';
|
||||
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { defaultListStyles } from 'vs/platform/theme/browser/defaultStyles';
|
||||
import {
|
||||
editorWidgetBackground,
|
||||
@@ -72,6 +73,7 @@ export class RenameInputField implements IContentWidget {
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
) {
|
||||
this._visibleContextKey = CONTEXT_RENAME_INPUT_VISIBLE.bindTo(contextKeyService);
|
||||
this._focusedContextKey = CONTEXT_RENAME_INPUT_FOCUSED.bindTo(contextKeyService);
|
||||
@@ -105,15 +107,15 @@ export class RenameInputField implements IContentWidget {
|
||||
this._input.className = 'rename-input';
|
||||
this._input.type = 'text';
|
||||
this._input.setAttribute('aria-label', localize('renameAriaLabel', "Rename input. Type new name and press Enter to commit."));
|
||||
// TODO@ulugbekna: is using addDisposableListener's right way to do it?
|
||||
this._disposables.add(addDisposableListener(this._input, 'focus', () => { this._focusedContextKey.set(true); }));
|
||||
this._disposables.add(addDisposableListener(this._input, 'blur', () => { this._focusedContextKey.reset(); }));
|
||||
this._domNode.appendChild(this._input);
|
||||
|
||||
this._candidatesView = new CandidatesView(this._domNode, {
|
||||
fontInfo: this._editor.getOption(EditorOption.fontInfo),
|
||||
onSelectionChange: () => this.acceptInput(false) // we don't allow preview with mouse click for now
|
||||
});
|
||||
this._candidatesView = this._disposables.add(
|
||||
new CandidatesView(this._domNode, {
|
||||
fontInfo: this._editor.getOption(EditorOption.fontInfo),
|
||||
onSelectionChange: () => this.acceptInput(false) // we don't allow preview with mouse click for now
|
||||
}));
|
||||
|
||||
this._label = document.createElement('div');
|
||||
this._label.className = 'rename-label';
|
||||
@@ -177,9 +179,10 @@ export class RenameInputField implements IContentWidget {
|
||||
|
||||
const bodyBox = getClientArea(this.getDomNode().ownerDocument.body);
|
||||
const editorBox = getDomNodePagePosition(this._editor.getDomNode());
|
||||
const cursorBox = this._editor.getScrolledVisiblePosition(this._position!);
|
||||
|
||||
this._nPxAvailableAbove = cursorBox.top + editorBox.top;
|
||||
const cursorBoxTop = this._getTopForPosition();
|
||||
|
||||
this._nPxAvailableAbove = cursorBoxTop + editorBox.top;
|
||||
this._nPxAvailableBelow = bodyBox.height - this._nPxAvailableAbove;
|
||||
|
||||
const lineHeight = this._editor.getOption(EditorOption.lineHeight);
|
||||
@@ -199,16 +202,16 @@ export class RenameInputField implements IContentWidget {
|
||||
const [accept, preview] = this._acceptKeybindings;
|
||||
this._label!.innerText = localize({ key: 'label', comment: ['placeholders are keybindings, e.g "F2 to Rename, Shift+F2 to Preview"'] }, "{0} to Rename, {1} to Preview", this._keybindingService.lookupKeybinding(accept)?.getLabel(), this._keybindingService.lookupKeybinding(preview)?.getLabel());
|
||||
|
||||
this._domNode!.style.minWidth = `250px`; // to prevent from widening when candidates come in
|
||||
this._domNode!.style.maxWidth = `400px`; // TODO@ulugbekna: what if we have a very long name?
|
||||
this._domNode!.style.minWidth = `200px`; // to prevent from widening when candidates come in
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
afterRender(position: ContentWidgetPositionPreference | null): void {
|
||||
this._trace('invoking afterRender, position: ', position ? 'not null' : 'null');
|
||||
if (position === null) {
|
||||
// cancel rename when input widget isn't rendered anymore
|
||||
this.cancelInput(true);
|
||||
this.cancelInput(true, 'afterRender (because position is null)');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -241,10 +244,12 @@ export class RenameInputField implements IContentWidget {
|
||||
private _currentCancelInput?: (focusEditor: boolean) => void;
|
||||
|
||||
acceptInput(wantsPreview: boolean): void {
|
||||
this._trace(`invoking acceptInput`);
|
||||
this._currentAcceptInput?.(wantsPreview);
|
||||
}
|
||||
|
||||
cancelInput(focusEditor: boolean): void {
|
||||
cancelInput(focusEditor: boolean, caller: string): void {
|
||||
this._trace(`invoking cancelInput, caller: ${caller}, _currentCancelInput: ${this._currentAcceptInput ? 'not undefined' : 'undefined'}`);
|
||||
this._currentCancelInput?.(focusEditor);
|
||||
}
|
||||
|
||||
@@ -280,6 +285,7 @@ export class RenameInputField implements IContentWidget {
|
||||
return new Promise<RenameInputFieldResult | boolean>(resolve => {
|
||||
|
||||
this._currentCancelInput = (focusEditor) => {
|
||||
this._trace('invoking _currentCancelInput');
|
||||
this._currentAcceptInput = undefined;
|
||||
this._currentCancelInput = undefined;
|
||||
this._candidatesView?.clearCandidates();
|
||||
@@ -288,12 +294,14 @@ export class RenameInputField implements IContentWidget {
|
||||
};
|
||||
|
||||
this._currentAcceptInput = (wantsPreview) => {
|
||||
this._trace('invoking _currentAcceptInput');
|
||||
assertType(this._input !== undefined);
|
||||
assertType(this._candidatesView !== undefined);
|
||||
|
||||
const candidateName = this._candidatesView.focusedCandidate;
|
||||
if ((candidateName === undefined && this._input.value === value) || this._input.value.trim().length === 0) {
|
||||
this.cancelInput(true);
|
||||
const newName = this._candidatesView.focusedCandidate ?? this._input.value;
|
||||
|
||||
if (newName === value || newName.trim().length === 0 /* is just whitespace */) {
|
||||
this.cancelInput(true, '_currentAcceptInput (because newName === value || newName.trim().length === 0)');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -302,14 +310,14 @@ export class RenameInputField implements IContentWidget {
|
||||
this._candidatesView.clearCandidates();
|
||||
|
||||
resolve({
|
||||
newName: candidateName ?? this._input.value,
|
||||
newName,
|
||||
wantsPreview: supportPreview && wantsPreview
|
||||
});
|
||||
};
|
||||
|
||||
disposeOnDone.add(cts.token.onCancellationRequested(() => this.cancelInput(true)));
|
||||
disposeOnDone.add(cts.token.onCancellationRequested(() => this.cancelInput(true, 'cts.token.onCancellationRequested')));
|
||||
if (!_sticky) {
|
||||
disposeOnDone.add(this._editor.onDidBlurEditorWidget(() => this.cancelInput(!this._domNode?.ownerDocument.hasFocus())));
|
||||
disposeOnDone.add(this._editor.onDidBlurEditorWidget(() => this.cancelInput(!this._domNode?.ownerDocument.hasFocus(), 'editor.onDidBlurEditorWidget')));
|
||||
}
|
||||
|
||||
this._show();
|
||||
@@ -321,6 +329,7 @@ export class RenameInputField implements IContentWidget {
|
||||
}
|
||||
|
||||
private _show(): void {
|
||||
this._trace('invoking _show');
|
||||
this._editor.revealLineInCenterIfOutsideViewport(this._position!.lineNumber, ScrollType.Smooth);
|
||||
this._visible = true;
|
||||
this._visibleContextKey.set(true);
|
||||
@@ -335,9 +344,13 @@ export class RenameInputField implements IContentWidget {
|
||||
}
|
||||
|
||||
private async _updateRenameCandidates(candidates: ProviderResult<NewSymbolName[]>[], currentName: string, token: CancellationToken) {
|
||||
const trace = (...args: any[]) => this._trace('_updateRenameCandidates', ...args);
|
||||
|
||||
trace('start');
|
||||
const namesListResults = await raceCancellation(Promise.allSettled(candidates), token);
|
||||
|
||||
if (namesListResults === undefined) {
|
||||
trace('returning early - received updateRenameCandidates results - undefined');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -346,30 +359,54 @@ export class RenameInputField implements IContentWidget {
|
||||
? namesListResult.value
|
||||
: []
|
||||
);
|
||||
trace(`received updateRenameCandidates results - total (unfiltered) ${newNames.length} candidates.`);
|
||||
|
||||
// deduplicate and filter out the current value
|
||||
const distinctNames = arrays.distinct(newNames, v => v.newSymbolName);
|
||||
trace(`distinct candidates - ${distinctNames.length} candidates.`);
|
||||
|
||||
const validDistinctNames = distinctNames.filter(({ newSymbolName }) => newSymbolName.trim().length > 0 && newSymbolName !== this._input?.value && newSymbolName !== currentName);
|
||||
trace(`valid distinct candidates - ${newNames.length} candidates.`);
|
||||
|
||||
if (validDistinctNames.length < 1) {
|
||||
trace('returning early - no valid distinct candidates');
|
||||
return;
|
||||
}
|
||||
|
||||
// show the candidates
|
||||
trace('setting candidates');
|
||||
this._candidatesView!.setCandidates(validDistinctNames);
|
||||
|
||||
// ask editor to re-layout given that the widget is now of a different size after rendering rename candidates
|
||||
trace('asking editor to re-layout');
|
||||
this._editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
private _hide(): void {
|
||||
this._trace('invoked _hide');
|
||||
this._visible = false;
|
||||
this._visibleContextKey.reset();
|
||||
this._editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
private _getTopForPosition(): number {
|
||||
const visibleRanges = this._editor.getVisibleRanges();
|
||||
let firstLineInViewport: number;
|
||||
if (visibleRanges.length > 0) {
|
||||
firstLineInViewport = visibleRanges[0].startLineNumber;
|
||||
} else {
|
||||
this._logService.warn('RenameInputField#_getTopForPosition: this should not happen - visibleRanges is empty');
|
||||
firstLineInViewport = Math.max(1, this._position!.lineNumber - 5); // @ulugbekna: fallback to current line minus 5
|
||||
}
|
||||
return this._editor.getTopForLineNumber(this._position!.lineNumber) - this._editor.getTopForLineNumber(firstLineInViewport);
|
||||
}
|
||||
|
||||
private _trace(...args: any[]) {
|
||||
this._logService.trace('RenameInputField', ...args);
|
||||
}
|
||||
}
|
||||
|
||||
export class CandidatesView {
|
||||
class CandidatesView {
|
||||
|
||||
private readonly _listWidget: List<NewSymbolName>;
|
||||
private readonly _listContainer: HTMLDivElement;
|
||||
@@ -377,8 +414,12 @@ export class CandidatesView {
|
||||
private _lineHeight: number;
|
||||
private _availableHeight: number;
|
||||
|
||||
private _disposables: DisposableStore;
|
||||
|
||||
constructor(parent: HTMLElement, opts: { fontInfo: FontInfo; onSelectionChange: () => void }) {
|
||||
|
||||
this._disposables = new DisposableStore();
|
||||
|
||||
this._availableHeight = 0;
|
||||
|
||||
this._lineHeight = opts.fontInfo.lineHeight;
|
||||
@@ -397,7 +438,7 @@ export class CandidatesView {
|
||||
}
|
||||
|
||||
getHeight(element: NewSymbolName): number {
|
||||
return that.candidateViewHeight;
|
||||
return that._candidateViewHeight;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -429,18 +470,22 @@ export class CandidatesView {
|
||||
}
|
||||
);
|
||||
|
||||
this._listWidget.onDidChangeSelection(e => {
|
||||
this._disposables.add(this._listWidget.onDidChangeSelection(e => {
|
||||
if (e.elements.length > 0) {
|
||||
opts.onSelectionChange();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
this._disposables.add(this._listWidget.onDidBlur(e => {
|
||||
this._listWidget.setFocus([]);
|
||||
}));
|
||||
|
||||
this._listWidget.style(defaultListStyles);
|
||||
}
|
||||
|
||||
public get candidateViewHeight(): number {
|
||||
const { totalHeight } = CandidateView.getLayoutInfo({ lineHeight: this._lineHeight });
|
||||
return totalHeight;
|
||||
dispose() {
|
||||
this._listWidget.dispose();
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
// height - max height allowed by parent element
|
||||
@@ -451,18 +496,12 @@ export class CandidatesView {
|
||||
}
|
||||
}
|
||||
|
||||
private _pickListHeight(nCandidates: number) {
|
||||
const heightToFitAllCandidates = this.candidateViewHeight * nCandidates;
|
||||
const height = Math.min(heightToFitAllCandidates, this._availableHeight, this.candidateViewHeight * 7 /* max # of candidates we want to show at once */);
|
||||
return height;
|
||||
}
|
||||
|
||||
public setCandidates(candidates: NewSymbolName[]): void {
|
||||
const height = this._pickListHeight(candidates.length);
|
||||
|
||||
this._listWidget.splice(0, 0, candidates);
|
||||
|
||||
this._listWidget.layout(height);
|
||||
this._listWidget.layout(height, this._pickListWidth(candidates));
|
||||
|
||||
this._listContainer.style.height = `${height}px`;
|
||||
}
|
||||
@@ -525,9 +564,25 @@ export class CandidatesView {
|
||||
}
|
||||
return focusedIx > 0;
|
||||
}
|
||||
|
||||
private get _candidateViewHeight(): number {
|
||||
const { totalHeight } = CandidateView.getLayoutInfo({ lineHeight: this._lineHeight });
|
||||
return totalHeight;
|
||||
}
|
||||
|
||||
private _pickListHeight(nCandidates: number) {
|
||||
const heightToFitAllCandidates = this._candidateViewHeight * nCandidates;
|
||||
const height = Math.min(heightToFitAllCandidates, this._availableHeight, this._candidateViewHeight * 7 /* max # of candidates we want to show at once */);
|
||||
return height;
|
||||
}
|
||||
|
||||
private _pickListWidth(candidates: NewSymbolName[]): number {
|
||||
return Math.max(...candidates.map(c => c.newSymbolName.length)) * 7 /* approximate # of pixes taken by a single character */;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class CandidateView { // TODO@ulugbekna: remove export
|
||||
class CandidateView {
|
||||
|
||||
// TODO@ulugbekna: accessibility
|
||||
|
||||
|
||||
@@ -238,7 +238,6 @@ export class WorkbenchHoverDelegate extends Disposable implements IHoverDelegate
|
||||
private lastHoverHideTime = Number.MAX_VALUE;
|
||||
private timeLimit = 200;
|
||||
|
||||
|
||||
private _delay: number;
|
||||
get delay(): number {
|
||||
if (this.instantHover && Date.now() - this.lastHoverHideTime < this.timeLimit) {
|
||||
|
||||
@@ -459,8 +459,8 @@ export class IssueMainService implements IIssueMainService {
|
||||
const replyChannel = `vscode:triggerReporterMenu`;
|
||||
const cts = new CancellationTokenSource();
|
||||
window.sendWhenReady(replyChannel, cts.token, { replyChannel, extensionId, extensionName });
|
||||
const result = await raceTimeout(new Promise(resolve => validatedIpcMain.once('vscode:triggerReporterMenuResponse:${extensionId}', (_: unknown, data: IssueReporterData | undefined) => resolve(data))), 5000, () => {
|
||||
this.logService.error('Error: Extension ${extensionId} timed out waiting for menu response');
|
||||
const result = await raceTimeout(new Promise(resolve => validatedIpcMain.once(`vscode:triggerReporterMenuResponse:${extensionId}`, (_: unknown, data: IssueReporterData | undefined) => resolve(data))), 5000, () => {
|
||||
this.logService.error(`Error: Extension ${extensionId} timed out waiting for menu response`);
|
||||
cts.cancel();
|
||||
});
|
||||
return result as IssueReporterData | undefined;
|
||||
|
||||
@@ -1409,8 +1409,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension, 'chatProvider');
|
||||
return extHostChatProvider.registerLanguageModel(extension, id, provider, metadata);
|
||||
},
|
||||
registerVariable(name: string, description: string, resolver: vscode.ChatVariableResolver) {
|
||||
checkProposedApiEnabled(extension, 'chatParticipant');
|
||||
registerChatVariableResolver(name: string, description: string, resolver: vscode.ChatVariableResolver) {
|
||||
checkProposedApiEnabled(extension, 'chatVariableResolver');
|
||||
return extHostChatVariables.registerVariableResolver(extension, name, description, resolver);
|
||||
},
|
||||
registerMappedEditsProvider(selector: vscode.DocumentSelector, provider: vscode.MappedEditsProvider) {
|
||||
@@ -1671,7 +1671,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
RelatedInformationType: extHostTypes.RelatedInformationType,
|
||||
SpeechToTextStatus: extHostTypes.SpeechToTextStatus,
|
||||
KeywordRecognitionStatus: extHostTypes.KeywordRecognitionStatus,
|
||||
ChatResponseTextPart: extHostTypes.ChatResponseTextPart,
|
||||
ChatResponseMarkdownPart: extHostTypes.ChatResponseMarkdownPart,
|
||||
ChatResponseFileTreePart: extHostTypes.ChatResponseFileTreePart,
|
||||
ChatResponseAnchorPart: extHostTypes.ChatResponseAnchorPart,
|
||||
|
||||
@@ -9,12 +9,13 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { DisposableMap, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ExtHostChatAgentsShape2, IChatAgentCompletionItem, IChatAgentHistoryEntryDto, IMainContext, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
@@ -233,7 +234,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||
res.push(new extHostTypes.ChatRequestTurn(h.request.message, h.request.command, h.request.variables.variables.map(typeConvert.ChatAgentResolvedVariable.to), { extensionId: '', participant: h.request.agentId }));
|
||||
|
||||
// RESPONSE turn
|
||||
const parts = coalesce(h.response.map(r => typeConvert.ChatResponsePart.from(r, this.commands.converter)));
|
||||
const parts = coalesce(h.response.map(r => typeConvert.ChatResponsePart.fromContent(r, this.commands.converter)));
|
||||
res.push(new extHostTypes.ChatResponseTurn(parts, result, { extensionId: '', participant: h.request.agentId }, h.request.command));
|
||||
}
|
||||
|
||||
@@ -261,6 +262,16 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||
|
||||
const ehResult = typeConvert.ChatAgentResult.to(result);
|
||||
return (await agent.provideFollowups(ehResult, token))
|
||||
.filter(f => {
|
||||
// The followup must refer to a participant that exists from the same extension
|
||||
const isValid = !f.participant || Iterable.some(
|
||||
this._agents.values(),
|
||||
a => a.id === f.participant && ExtensionIdentifier.equals(a.extension.identifier, agent.extension.identifier));
|
||||
if (!isValid) {
|
||||
this._logService.warn(`[@${agent.id}] ChatFollowup refers to an invalid participant: ${f.participant}`);
|
||||
}
|
||||
return isValid;
|
||||
})
|
||||
.map(f => typeConvert.ChatFollowup.from(f, request));
|
||||
}
|
||||
|
||||
@@ -340,6 +351,7 @@ class ExtHostChatAgent {
|
||||
private _iconPath: vscode.Uri | { light: vscode.Uri; dark: vscode.Uri } | vscode.ThemeIcon | undefined;
|
||||
private _isDefault: boolean | undefined;
|
||||
private _helpTextPrefix: string | vscode.MarkdownString | undefined;
|
||||
private _helpTextVariablesPrefix: string | vscode.MarkdownString | undefined;
|
||||
private _helpTextPostfix: string | vscode.MarkdownString | undefined;
|
||||
private _sampleRequest?: string;
|
||||
private _isSecondary: boolean | undefined;
|
||||
@@ -390,7 +402,7 @@ class ExtHostChatAgent {
|
||||
|
||||
return {
|
||||
name: c.name,
|
||||
description: c.description,
|
||||
description: c.description ?? '',
|
||||
followupPlaceholder: c.isSticky2?.placeholder,
|
||||
isSticky: c.isSticky2?.isSticky ?? c.isSticky,
|
||||
sampleRequest: c.sampleRequest
|
||||
@@ -470,6 +482,7 @@ class ExtHostChatAgent {
|
||||
isDefault: this._isDefault,
|
||||
isSecondary: this._isSecondary,
|
||||
helpTextPrefix: (!this._helpTextPrefix || typeof this._helpTextPrefix === 'string') ? this._helpTextPrefix : typeConvert.MarkdownString.from(this._helpTextPrefix),
|
||||
helpTextVariablesPrefix: (!this._helpTextVariablesPrefix || typeof this._helpTextVariablesPrefix === 'string') ? this._helpTextVariablesPrefix : typeConvert.MarkdownString.from(this._helpTextVariablesPrefix),
|
||||
helpTextPostfix: (!this._helpTextPostfix || typeof this._helpTextPostfix === 'string') ? this._helpTextPostfix : typeConvert.MarkdownString.from(this._helpTextPostfix),
|
||||
sampleRequest: this._sampleRequest,
|
||||
supportIssueReporting: this._supportIssueReporting,
|
||||
@@ -548,6 +561,19 @@ class ExtHostChatAgent {
|
||||
that._helpTextPrefix = v;
|
||||
updateMetadataSoon();
|
||||
},
|
||||
get helpTextVariablesPrefix() {
|
||||
checkProposedApiEnabled(that.extension, 'defaultChatParticipant');
|
||||
return that._helpTextVariablesPrefix;
|
||||
},
|
||||
set helpTextVariablesPrefix(v) {
|
||||
checkProposedApiEnabled(that.extension, 'defaultChatParticipant');
|
||||
if (!that._isDefault) {
|
||||
throw new Error('helpTextVariablesPrefix is only available on the default chat agent');
|
||||
}
|
||||
|
||||
that._helpTextVariablesPrefix = v;
|
||||
updateMetadataSoon();
|
||||
},
|
||||
get helpTextPostfix() {
|
||||
checkProposedApiEnabled(that.extension, 'defaultChatParticipant');
|
||||
return that._helpTextPostfix;
|
||||
|
||||
@@ -2201,18 +2201,16 @@ export namespace ChatFollowup {
|
||||
agentId: followup.participant ?? request?.agentId ?? '',
|
||||
subCommand: followup.command ?? request?.command,
|
||||
message: followup.prompt,
|
||||
title: followup.title,
|
||||
tooltip: followup.tooltip,
|
||||
title: followup.label
|
||||
};
|
||||
}
|
||||
|
||||
export function to(followup: IChatFollowup): vscode.ChatFollowup {
|
||||
return {
|
||||
prompt: followup.message,
|
||||
title: followup.title,
|
||||
label: followup.title,
|
||||
participant: followup.agentId,
|
||||
command: followup.subCommand,
|
||||
tooltip: followup.tooltip,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2332,18 +2330,6 @@ export namespace InteractiveEditorResponseFeedbackKind {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace ChatResponseTextPart {
|
||||
export function to(part: vscode.ChatResponseTextPart): Dto<IChatMarkdownContent> {
|
||||
return {
|
||||
kind: 'markdownContent',
|
||||
content: MarkdownString.from(new types.MarkdownString().appendText(part.value))
|
||||
};
|
||||
}
|
||||
export function from(part: Dto<IChatMarkdownContent>): vscode.ChatResponseTextPart {
|
||||
return new types.ChatResponseTextPart(part.content.value);
|
||||
}
|
||||
}
|
||||
|
||||
export namespace ChatResponseMarkdownPart {
|
||||
export function to(part: vscode.ChatResponseMarkdownPart): Dto<IChatMarkdownContent> {
|
||||
return {
|
||||
@@ -2477,14 +2463,27 @@ export namespace ChatResponsePart {
|
||||
}
|
||||
|
||||
export function from(part: extHostProtocol.IChatProgressDto, commandsConverter: CommandsConverter): vscode.ChatResponsePart | undefined {
|
||||
switch (part.kind) {
|
||||
case 'reference': return ChatResponseReferencePart.from(part);
|
||||
case 'markdownContent':
|
||||
case 'inlineReference':
|
||||
case 'progressMessage':
|
||||
case 'treeData':
|
||||
case 'command':
|
||||
return fromContent(part, commandsConverter);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function fromContent(part: extHostProtocol.IChatContentProgressDto, commandsConverter: CommandsConverter): vscode.ChatResponseMarkdownPart | vscode.ChatResponseFileTreePart | vscode.ChatResponseAnchorPart | vscode.ChatResponseCommandButtonPart | undefined {
|
||||
switch (part.kind) {
|
||||
case 'markdownContent': return ChatResponseMarkdownPart.from(part);
|
||||
case 'inlineReference': return ChatResponseAnchorPart.from(part);
|
||||
case 'reference': return ChatResponseReferencePart.from(part);
|
||||
case 'progressMessage': return ChatResponseProgressPart.from(part);
|
||||
case 'progressMessage': return undefined;
|
||||
case 'treeData': return ChatResponseFilesPart.from(part);
|
||||
case 'command': return ChatResponseCommandButtonPart.from(part, commandsConverter);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4205,14 +4205,6 @@ export enum ChatResultFeedbackKind {
|
||||
Helpful = 1,
|
||||
}
|
||||
|
||||
|
||||
export class ChatResponseTextPart {
|
||||
value: string;
|
||||
constructor(value: string) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
export class ChatResponseMarkdownPart {
|
||||
value: vscode.MarkdownString;
|
||||
constructor(value: string | vscode.MarkdownString) {
|
||||
@@ -4272,7 +4264,7 @@ export class ChatRequestTurn implements vscode.ChatRequestTurn {
|
||||
export class ChatResponseTurn implements vscode.ChatResponseTurn {
|
||||
|
||||
constructor(
|
||||
readonly response: ReadonlyArray<ChatResponseTextPart | ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart>,
|
||||
readonly response: ReadonlyArray<ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart>,
|
||||
readonly result: vscode.ChatResult,
|
||||
readonly participant: { extensionId: string; participant: string },
|
||||
readonly command?: string
|
||||
|
||||
@@ -206,8 +206,7 @@ export class BreadcrumbsControl {
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IBreadcrumbsService breadcrumbsService: IBreadcrumbsService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IBreadcrumbsService breadcrumbsService: IBreadcrumbsService
|
||||
) {
|
||||
this.domNode = document.createElement('div');
|
||||
this.domNode.classList.add('breadcrumbs-control');
|
||||
|
||||
@@ -366,10 +366,9 @@ class EditorStatus extends Disposable {
|
||||
}
|
||||
|
||||
private registerCommands(): void {
|
||||
CommandsRegistry.registerCommand({ id: 'changeEditorIndentation', handler: () => this.showIndentationPicker() });
|
||||
CommandsRegistry.registerCommand({ id: `changeEditorIndentation${this.targetWindowId}`, handler: () => this.showIndentationPicker() });
|
||||
}
|
||||
|
||||
|
||||
private async showIndentationPicker(): Promise<unknown> {
|
||||
const activeTextEditorControl = getCodeEditor(this.editorService.activeTextEditorControl);
|
||||
if (!activeTextEditorControl) {
|
||||
@@ -483,7 +482,7 @@ class EditorStatus extends Disposable {
|
||||
text,
|
||||
ariaLabel: text,
|
||||
tooltip: localize('selectIndentation', "Select Indentation"),
|
||||
command: 'changeEditorIndentation'
|
||||
command: `changeEditorIndentation${this.targetWindowId}`
|
||||
};
|
||||
|
||||
this.updateElement(this.indentationElement, props, 'status.editor.indentation', StatusbarAlignment.RIGHT, 100.4);
|
||||
|
||||
@@ -386,11 +386,13 @@
|
||||
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.sticky.dirty > .tab-actions .action-label:not(:hover)::before,
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sticky.dirty > .tab-actions .action-label:not(:hover)::before {
|
||||
content: "\ebb2"; /* use `pinned-dirty` icon unicode for sticky-dirty indication */
|
||||
font-family: 'codicon';
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover)::before,
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover)::before {
|
||||
content: "\ea71"; /* use `circle-filled` icon unicode for dirty indication */
|
||||
font-family: 'codicon';
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active > .tab-actions .action-label,
|
||||
|
||||
@@ -195,6 +195,10 @@ export class TextDiffEditor extends AbstractTextEditor<IDiffEditorViewState> imp
|
||||
|
||||
control.restoreViewState(editorViewState);
|
||||
|
||||
if (options?.revealIfVisible) {
|
||||
control.revealFirstDiff();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,8 +136,14 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer {
|
||||
private leftItemsContainer: HTMLElement | undefined;
|
||||
private rightItemsContainer: HTMLElement | undefined;
|
||||
|
||||
|
||||
private readonly hoverDelegate: WorkbenchHoverDelegate;
|
||||
private readonly hoverDelegate = this._register(this.instantiationService.createInstance(WorkbenchHoverDelegate, 'element', true, (_, focus?: boolean) => (
|
||||
{
|
||||
persistence: {
|
||||
hideOnKeyDown: true,
|
||||
sticky: focus
|
||||
}
|
||||
}
|
||||
)));
|
||||
|
||||
private readonly compactEntriesDisposable = this._register(new MutableDisposable<DisposableStore>());
|
||||
private readonly styleOverrides = new Set<IStatusbarStyleOverride>();
|
||||
@@ -149,20 +155,11 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer {
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super(id, { hasTitle: false }, themeService, storageService, layoutService);
|
||||
|
||||
this.hoverDelegate = this._register(instantiationService.createInstance(WorkbenchHoverDelegate, 'element', true, (_, focus?: boolean) => (
|
||||
{
|
||||
persistence: {
|
||||
hideOnKeyDown: true,
|
||||
sticky: focus
|
||||
}
|
||||
}
|
||||
)));
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ import { registerChatFileTreeActions } from 'vs/workbench/contrib/chat/browser/a
|
||||
import { QuickChatService } from 'vs/workbench/contrib/chat/browser/chatQuick';
|
||||
import { ChatAgentService, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { ChatVariablesService } from 'vs/workbench/contrib/chat/browser/chatVariables';
|
||||
import { chatAgentLeader, chatSubcommandLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IVoiceChatService, VoiceChatService } from 'vs/workbench/contrib/chat/common/voiceChat';
|
||||
|
||||
@@ -228,6 +228,7 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
|
||||
@IChatSlashCommandService slashCommandService: IChatSlashCommandService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IChatAgentService chatAgentService: IChatAgentService,
|
||||
@IChatVariablesService chatVariablesService: IChatVariablesService,
|
||||
) {
|
||||
super();
|
||||
this._store.add(slashCommandService.registerSlashCommand({
|
||||
@@ -246,6 +247,8 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
|
||||
}, async (prompt, progress) => {
|
||||
const defaultAgent = chatAgentService.getDefaultAgent();
|
||||
const agents = chatAgentService.getAgents();
|
||||
|
||||
// Report prefix
|
||||
if (defaultAgent?.metadata.helpTextPrefix) {
|
||||
if (isMarkdownString(defaultAgent.metadata.helpTextPrefix)) {
|
||||
progress.report({ content: defaultAgent.metadata.helpTextPrefix, kind: 'markdownContent' });
|
||||
@@ -255,6 +258,7 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
|
||||
progress.report({ content: '\n\n', kind: 'content' });
|
||||
}
|
||||
|
||||
// Report agent list
|
||||
const agentText = (await Promise.all(agents
|
||||
.filter(a => a.id !== defaultAgent?.id)
|
||||
.map(async a => {
|
||||
@@ -272,6 +276,23 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
|
||||
return (agentLine + '\n' + commandText).trim();
|
||||
}))).join('\n');
|
||||
progress.report({ content: new MarkdownString(agentText, { isTrusted: { enabledCommands: [SubmitAction.ID] } }), kind: 'markdownContent' });
|
||||
|
||||
// Report variables
|
||||
if (defaultAgent?.metadata.helpTextVariablesPrefix) {
|
||||
progress.report({ content: '\n\n', kind: 'content' });
|
||||
if (isMarkdownString(defaultAgent.metadata.helpTextVariablesPrefix)) {
|
||||
progress.report({ content: defaultAgent.metadata.helpTextVariablesPrefix, kind: 'markdownContent' });
|
||||
} else {
|
||||
progress.report({ content: defaultAgent.metadata.helpTextVariablesPrefix, kind: 'content' });
|
||||
}
|
||||
|
||||
const variableText = Array.from(chatVariablesService.getVariables())
|
||||
.map(v => `* \`${chatVariableLeader}${v.name}\` - ${v.description}`)
|
||||
.join('\n');
|
||||
progress.report({ content: '\n' + variableText, kind: 'content' });
|
||||
}
|
||||
|
||||
// Report help text ending
|
||||
if (defaultAgent?.metadata.helpTextPostfix) {
|
||||
progress.report({ content: '\n\n', kind: 'content' });
|
||||
if (isMarkdownString(defaultAgent.metadata.helpTextPostfix)) {
|
||||
|
||||
@@ -1270,14 +1270,14 @@ class ContentReferencesListRenderer implements IListRenderer<IChatContentReferen
|
||||
templateData.label.element.style.display = 'flex';
|
||||
const uri = 'uri' in element.reference ? element.reference.uri : element.reference;
|
||||
if (matchesSomeScheme(uri, Schemas.mailto, Schemas.http, Schemas.https)) {
|
||||
templateData.label.setResource({ resource: uri, name: uri.toString() }, { icon: Codicon.globe });
|
||||
} else {
|
||||
templateData.label.setFile(uri, {
|
||||
fileKind: FileKind.FILE,
|
||||
// Should not have this live-updating data on a historical reference
|
||||
fileDecorations: { badges: false, colors: false },
|
||||
range: 'range' in element.reference ? element.reference.range : undefined
|
||||
});
|
||||
} else {
|
||||
templateData.label.setResource({ resource: uri, name: uri.toString() }, { icon: Codicon.globe });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ export interface IChatAgentMetadata {
|
||||
description?: string;
|
||||
isDefault?: boolean; // The agent invoked when no agent is specified
|
||||
helpTextPrefix?: string | IMarkdownString;
|
||||
helpTextVariablesPrefix?: string | IMarkdownString;
|
||||
helpTextPostfix?: string | IMarkdownString;
|
||||
isSecondary?: boolean; // Invoked by ctrl/cmd+enter
|
||||
fullName?: string;
|
||||
|
||||
@@ -38,10 +38,12 @@
|
||||
|
||||
.open-editors .monaco-list .monaco-list-row.dirty:not(:hover) > .monaco-action-bar .codicon-pinned::before {
|
||||
content: "\ebb2"; /* use `pinned-dirty` icon unicode for sticky-dirty indication */
|
||||
font-family: 'codicon';
|
||||
}
|
||||
|
||||
.open-editors .monaco-list .monaco-list-row.dirty:not(:hover) > .monaco-action-bar .codicon-close::before {
|
||||
content: "\ea71"; /* use `circle-filled` icon unicode for dirty indication */
|
||||
font-family: 'codicon';
|
||||
}
|
||||
|
||||
.open-editors .monaco-list .monaco-list-row > .monaco-action-bar .action-close-all-files,
|
||||
|
||||
@@ -33,6 +33,7 @@ import { Categories } from 'vs/platform/action/common/actionCommonCategories';
|
||||
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { nativeHoverDelegate } from 'vs/platform/hover/browser/hover';
|
||||
|
||||
class LanguageStatusViewModel {
|
||||
|
||||
@@ -327,7 +328,7 @@ class LanguageStatus {
|
||||
}
|
||||
|
||||
// -- pin
|
||||
const actionBar = new ActionBar(right, {});
|
||||
const actionBar = new ActionBar(right, { hoverDelegate: nativeHoverDelegate });
|
||||
store.add(actionBar);
|
||||
let action: Action;
|
||||
if (!isPinned) {
|
||||
|
||||
@@ -14,7 +14,8 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
|
||||
const codeSettingRegex = /^<span (codesetting|codefeature)="([^\s"\:]+)(?::([^\s"]+))?">/;
|
||||
const codeSettingRegex = /^<code (codesetting)="([^\s"\:]+)(?::([^\s"]+))?">/;
|
||||
const codeFeatureRegex = /^<span (codefeature)="([^\s"\:]+)(?::([^\s"]+))?">/;
|
||||
|
||||
export class SimpleSettingRenderer {
|
||||
private _defaultSettings: DefaultSettings;
|
||||
@@ -40,7 +41,7 @@ export class SimpleSettingRenderer {
|
||||
|
||||
getHtmlRenderer(): (html: string) => string {
|
||||
return (html): string => {
|
||||
const match = codeSettingRegex.exec(html);
|
||||
const match = codeSettingRegex.exec(html) ?? codeFeatureRegex.exec(html);
|
||||
if (match && match.length === 4) {
|
||||
const settingId = match[2];
|
||||
const rendered = this.render(settingId, match[3], match[1] === 'codefeature');
|
||||
@@ -165,7 +166,10 @@ export class SimpleSettingRenderer {
|
||||
private renderSetting(setting: ISetting, newValue: string | undefined): string | undefined {
|
||||
const href = this.settingToUriString(setting.key, newValue);
|
||||
const title = nls.localize('changeSettingTitle', "Try feature");
|
||||
return `<span><a href="${href}" class="codesetting" title="${title}" aria-role="button"><svg width="14" height="14" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M9.1 4.4L8.6 2H7.4l-.5 2.4-.7.3-2-1.3-.9.8 1.3 2-.2.7-2.4.5v1.2l2.4.5.3.8-1.3 2 .8.8 2-1.3.8.3.4 2.3h1.2l.5-2.4.8-.3 2 1.3.8-.8-1.3-2 .3-.8 2.3-.4V7.4l-2.4-.5-.3-.8 1.3-2-.8-.8-2 1.3-.7-.2zM9.4 1l.5 2.4L12 2.1l2 2-1.4 2.1 2.4.4v2.8l-2.4.5L14 12l-2 2-2.1-1.4-.5 2.4H6.6l-.5-2.4L4 13.9l-2-2 1.4-2.1L1 9.4V6.6l2.4-.5L2.1 4l2-2 2.1 1.4.4-2.4h2.8zm.6 7c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zM8 9c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z"/></svg></a>`;
|
||||
return `<code tabindex="0"><a href="${href}" class="codesetting" title="${title}" aria-role="button"><svg width="14" height="14" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M9.1 4.4L8.6 2H7.4l-.5 2.4-.7.3-2-1.3-.9.8 1.3 2-.2.7-2.4.5v1.2l2.4.5.3.8-1.3 2 .8.8 2-1.3.8.3.4 2.3h1.2l.5-2.4.8-.3 2 1.3.8-.8-1.3-2 .3-.8 2.3-.4V7.4l-2.4-.5-.3-.8 1.3-2-.8-.8-2 1.3-.7-.2zM9.4 1l.5 2.4L12 2.1l2 2-1.4 2.1 2.4.4v2.8l-2.4.5L14 12l-2 2-2.1-1.4-.5 2.4H6.6l-.5-2.4L4 13.9l-2-2 1.4-2.1L1 9.4V6.6l2.4-.5L2.1 4l2-2 2.1 1.4.4-2.4h2.8zm.6 7c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zM8 9c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z"/></svg>
|
||||
<span class="separator"></span>
|
||||
<span class="setting-name">${setting.key}</span>
|
||||
</a></code><code>`;
|
||||
}
|
||||
|
||||
private renderFeature(setting: ISetting, newValue: string): string | undefined {
|
||||
|
||||
@@ -70,10 +70,13 @@ suite('Markdown Setting Renderer Test', () => {
|
||||
|
||||
test('render code setting button with value', () => {
|
||||
const htmlRenderer = settingRenderer.getHtmlRenderer();
|
||||
const htmlNoValue = '<span codesetting="example.booleanSetting">';
|
||||
const htmlNoValue = '<code codesetting="example.booleanSetting">';
|
||||
const renderedHtmlNoValue = htmlRenderer(htmlNoValue);
|
||||
assert.strictEqual(renderedHtmlNoValue,
|
||||
`<span><a href="code-setting://example.booleanSetting" class="codesetting" title="Try feature" aria-role="button"><svg width="14" height="14" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M9.1 4.4L8.6 2H7.4l-.5 2.4-.7.3-2-1.3-.9.8 1.3 2-.2.7-2.4.5v1.2l2.4.5.3.8-1.3 2 .8.8 2-1.3.8.3.4 2.3h1.2l.5-2.4.8-.3 2 1.3.8-.8-1.3-2 .3-.8 2.3-.4V7.4l-2.4-.5-.3-.8 1.3-2-.8-.8-2 1.3-.7-.2zM9.4 1l.5 2.4L12 2.1l2 2-1.4 2.1 2.4.4v2.8l-2.4.5L14 12l-2 2-2.1-1.4-.5 2.4H6.6l-.5-2.4L4 13.9l-2-2 1.4-2.1L1 9.4V6.6l2.4-.5L2.1 4l2-2 2.1 1.4.4-2.4h2.8zm.6 7c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zM8 9c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z"/></svg></a>`);
|
||||
`<code tabindex="0"><a href="code-setting://example.booleanSetting" class="codesetting" title="Try feature" aria-role="button"><svg width="14" height="14" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M9.1 4.4L8.6 2H7.4l-.5 2.4-.7.3-2-1.3-.9.8 1.3 2-.2.7-2.4.5v1.2l2.4.5.3.8-1.3 2 .8.8 2-1.3.8.3.4 2.3h1.2l.5-2.4.8-.3 2 1.3.8-.8-1.3-2 .3-.8 2.3-.4V7.4l-2.4-.5-.3-.8 1.3-2-.8-.8-2 1.3-.7-.2zM9.4 1l.5 2.4L12 2.1l2 2-1.4 2.1 2.4.4v2.8l-2.4.5L14 12l-2 2-2.1-1.4-.5 2.4H6.6l-.5-2.4L4 13.9l-2-2 1.4-2.1L1 9.4V6.6l2.4-.5L2.1 4l2-2 2.1 1.4.4-2.4h2.8zm.6 7c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zM8 9c.6 0 1-.4 1-1s-.4-1-1-1-1 .4-1 1 .4 1 1 1z"/></svg>
|
||||
<span class="separator"></span>
|
||||
<span class="setting-name">example.booleanSetting</span>
|
||||
</a></code><code>`);
|
||||
});
|
||||
|
||||
test('actions with no value', () => {
|
||||
|
||||
@@ -92,7 +92,10 @@ export class MultiDiffEditorInput extends EditorInput implements ILanguageSuppor
|
||||
/** @description Updates name */
|
||||
const resources = this._resources.read(reader) ?? [];
|
||||
const label = this.label ?? localize('name', "Multi Diff Editor");
|
||||
this._name = label + localize('files', " ({0} files)", resources?.length ?? 0);
|
||||
this._name = label + localize({
|
||||
key: 'files',
|
||||
comment: ['the number of files being shown']
|
||||
}, " ({0} files)", resources?.length ?? 0);
|
||||
this._onDidChangeLabel.fire();
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { SimpleSettingRenderer } from 'vs/workbench/contrib/markdown/browser/markdownSettingRenderer';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
|
||||
export class ReleaseNotesManager {
|
||||
private readonly _simpleSettingRenderer: SimpleSettingRenderer;
|
||||
@@ -44,6 +45,7 @@ export class ReleaseNotesManager {
|
||||
private readonly disposables = new DisposableStore();
|
||||
|
||||
public constructor(
|
||||
private readonly _useCurrentFile: boolean,
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@ILanguageService private readonly _languageService: ILanguageService,
|
||||
@@ -52,6 +54,7 @@ export class ReleaseNotesManager {
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@@ -196,7 +199,7 @@ export class ReleaseNotesManager {
|
||||
const fetchReleaseNotes = async () => {
|
||||
let text;
|
||||
try {
|
||||
text = await asTextOrError(await this._requestService.request({ url }, CancellationToken.None));
|
||||
text = this._useCurrentFile ? this._codeEditorService.getActiveCodeEditor()?.getModel()?.getValue() : await asTextOrError(await this._requestService.request({ url }, CancellationToken.None));
|
||||
} catch {
|
||||
throw new Error('Failed to fetch release notes');
|
||||
}
|
||||
@@ -258,48 +261,91 @@ export class ReleaseNotesManager {
|
||||
${DEFAULT_MARKDOWN_STYLES}
|
||||
${css}
|
||||
|
||||
/* codesetting */
|
||||
|
||||
code:has(.codesetting)+code {
|
||||
display: none;
|
||||
}
|
||||
|
||||
code:has(.codesetting) {
|
||||
background-color: var(--vscode-textPreformat-background);
|
||||
color: var(--vscode-textPreformat-foreground);
|
||||
padding-left: 1px;
|
||||
margin-right: 3px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
code:has(.codesetting):focus {
|
||||
border: 1px solid var(--vscode-button-border, transparent);
|
||||
}
|
||||
|
||||
.codesetting {
|
||||
color: var(--vscode-button-foreground);
|
||||
background-color: var(--vscode-button-background);
|
||||
width: fit-content;
|
||||
color: var(--vscode-textPreformat-foreground);
|
||||
padding: 0px 1px 1px 0px;
|
||||
font-size: 12px;
|
||||
font-size: 0px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
outline-offset: 2px !important;
|
||||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--vscode-button-border, transparent);
|
||||
line-height: 9px;
|
||||
outline: 1px solid transparent;
|
||||
display: inline-block;
|
||||
margin-top: 3px;
|
||||
margin-bottom: -4px !important;
|
||||
}
|
||||
.codesetting:hover {
|
||||
background-color: var(--vscode-button-hoverBackground);
|
||||
text-decoration: none !important;
|
||||
color: var(--vscode-button-hoverForeground) !important;
|
||||
}
|
||||
.codesetting:focus {
|
||||
outline: 0 !important;
|
||||
text-decoration: none !important;
|
||||
color: var(--vscode-button-hoverForeground) !important;
|
||||
border: 1px solid var(--vscode-button-border, transparent);
|
||||
display: inline;
|
||||
margin-right: 3px;
|
||||
}
|
||||
.codesetting svg {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--vscode-button-secondaryBorder, transparent);
|
||||
outline: 1px solid transparent;
|
||||
line-height: 9px;
|
||||
margin-bottom: -5px;
|
||||
padding-left: 0px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
padding-right: 2px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
text-rendering: auto;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
.codesetting .setting-name {
|
||||
font-size: 13px;
|
||||
padding-left: 2px;
|
||||
padding-right: 3px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
margin-left: -5px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
.codesetting:hover {
|
||||
color: var(--vscode-textPreformat-foreground) !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
code:has(.codesetting):hover {
|
||||
filter: brightness(140%);
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.codesetting:focus {
|
||||
outline: 0 !important;
|
||||
text-decoration: none !important;
|
||||
color: var(--vscode-button-hoverForeground) !important;
|
||||
}
|
||||
.codesetting .separator {
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
margin-bottom: -3px;
|
||||
display: inline-block;
|
||||
background-color: var(--vscode-editor-background);
|
||||
font-size: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* codefeature */
|
||||
|
||||
.codefeature-container {
|
||||
display: flex;
|
||||
@@ -357,66 +403,6 @@ export class ReleaseNotesManager {
|
||||
content: "${nls.localize('enableFeature', "Enable this feature")}";
|
||||
}
|
||||
|
||||
.codefeature-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.codefeature {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 58px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.codefeature-container input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--vscode-disabledForeground);
|
||||
transition: .4s;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.toggle:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: var(--vscode-editor-foreground);
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
input:checked+.codefeature > .toggle:before {
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
||||
input:checked+.codefeature > .toggle {
|
||||
background-color: var(--vscode-button-background);
|
||||
}
|
||||
|
||||
.codefeature-container:has(input) .title {
|
||||
line-height: 30px;
|
||||
padding-left: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.codefeature-container:has(input:checked) .title:after {
|
||||
content: "${nls.localize('disableFeature', "Disable this feature")}";
|
||||
}
|
||||
.codefeature-container:has(input:not(:checked)) .title:after {
|
||||
content: "${nls.localize('enableFeature', "Enable this feature")}";
|
||||
}
|
||||
|
||||
header { display: flex; align-items: center; padding-top: 1em; }
|
||||
</style>
|
||||
</head>
|
||||
@@ -486,6 +472,15 @@ export class ReleaseNotesManager {
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('keypress', event => {
|
||||
if (event.keyCode === 13) {
|
||||
if (event.target.children.length > 0 && event.target.children[0].href) {
|
||||
const clientRect = event.target.getBoundingClientRect();
|
||||
vscode.postMessage({ type: 'clickSetting', value: { uri: event.target.children[0].href, x: clientRect.right , y: clientRect.bottom }});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('change', event => {
|
||||
vscode.postMessage({ type: 'showReleaseNotes', value: input.checked }, '*');
|
||||
});
|
||||
@@ -525,4 +520,3 @@ export class ReleaseNotesManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update';
|
||||
import { ShowCurrentReleaseNotesActionId, ShowCurrentReleaseNotesFromCurrentFileActionId } from 'vs/workbench/contrib/update/common/update';
|
||||
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
@@ -59,7 +59,7 @@ export class ShowCurrentReleaseNotesAction extends Action2 {
|
||||
const openerService = accessor.get(IOpenerService);
|
||||
|
||||
try {
|
||||
await showReleaseNotesInEditor(instantiationService, productService.version);
|
||||
await showReleaseNotesInEditor(instantiationService, productService.version, false);
|
||||
} catch (err) {
|
||||
if (productService.releaseNotesUrl) {
|
||||
await openerService.open(URI.parse(productService.releaseNotesUrl));
|
||||
@@ -70,7 +70,35 @@ export class ShowCurrentReleaseNotesAction extends Action2 {
|
||||
}
|
||||
}
|
||||
|
||||
export class ShowCurrentReleaseNotesFromCurrentFileAction extends Action2 {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: ShowCurrentReleaseNotesFromCurrentFileActionId,
|
||||
title: {
|
||||
...localize2('showReleaseNotesCurrentFile', "Open Current File as Release Notes"),
|
||||
mnemonicTitle: localize({ key: 'mshowReleaseNotes', comment: ['&& denotes a mnemonic'] }, "Show &&Release Notes"),
|
||||
},
|
||||
category: localize2('developerCategory', "Developer"),
|
||||
f1: true,
|
||||
precondition: RELEASE_NOTES_URL
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
const productService = accessor.get(IProductService);
|
||||
|
||||
try {
|
||||
await showReleaseNotesInEditor(instantiationService, productService.version, true);
|
||||
} catch (err) {
|
||||
throw new Error(localize('releaseNotesFromFileNone', "Cannot open the current file as Release Notes"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAction2(ShowCurrentReleaseNotesAction);
|
||||
registerAction2(ShowCurrentReleaseNotesFromCurrentFileAction);
|
||||
|
||||
// Update
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ export const DOWNLOAD_URL = new RawContextKey<string>('downloadUrl', '');
|
||||
|
||||
let releaseNotesManager: ReleaseNotesManager | undefined = undefined;
|
||||
|
||||
export function showReleaseNotesInEditor(instantiationService: IInstantiationService, version: string) {
|
||||
export function showReleaseNotesInEditor(instantiationService: IInstantiationService, version: string, useCurrentFile: boolean) {
|
||||
if (!releaseNotesManager) {
|
||||
releaseNotesManager = instantiationService.createInstance(ReleaseNotesManager);
|
||||
releaseNotesManager = instantiationService.createInstance(ReleaseNotesManager, useCurrentFile);
|
||||
}
|
||||
|
||||
return releaseNotesManager.show(version);
|
||||
@@ -61,7 +61,7 @@ async function openLatestReleaseNotesInBrowser(accessor: ServicesAccessor) {
|
||||
async function showReleaseNotes(accessor: ServicesAccessor, version: string) {
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
try {
|
||||
await showReleaseNotesInEditor(instantiationService, version);
|
||||
await showReleaseNotesInEditor(instantiationService, version, false);
|
||||
} catch (err) {
|
||||
try {
|
||||
await instantiationService.invokeFunction(openLatestReleaseNotesInBrowser);
|
||||
@@ -135,7 +135,7 @@ export class ProductContribution implements IWorkbenchContribution {
|
||||
|
||||
// was there a major/minor update? if so, open release notes
|
||||
if (shouldShowReleaseNotes && !environmentService.skipReleaseNotes && releaseNotesUrl && lastVersion && currentVersion && isMajorMinorUpdate(lastVersion, currentVersion)) {
|
||||
showReleaseNotesInEditor(instantiationService, productService.version)
|
||||
showReleaseNotesInEditor(instantiationService, productService.version, false)
|
||||
.then(undefined, () => {
|
||||
notificationService.prompt(
|
||||
severity.Info,
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const ShowCurrentReleaseNotesActionId = 'update.showCurrentReleaseNotes';
|
||||
export const ShowCurrentReleaseNotesFromCurrentFileActionId = 'developer.showCurrentFileAsReleaseNotes';
|
||||
|
||||
@@ -79,6 +79,7 @@ import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { getWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { DynamicWorkbenchSecurityConfiguration } from 'vs/workbench/common/configuration';
|
||||
import { nativeHoverDelegate } from 'vs/platform/hover/browser/hover';
|
||||
|
||||
export class NativeWindow extends BaseWindow {
|
||||
|
||||
@@ -1163,7 +1164,7 @@ class ZoomStatusEntry extends Disposable {
|
||||
this.zoomLevelLabel = zoomLevelLabel;
|
||||
disposables.add(toDisposable(() => this.zoomLevelLabel = undefined));
|
||||
|
||||
const actionBarLeft = disposables.add(new ActionBar(left));
|
||||
const actionBarLeft = disposables.add(new ActionBar(left, { hoverDelegate: nativeHoverDelegate }));
|
||||
actionBarLeft.push(zoomOutAction, { icon: true, label: false, keybinding: this.keybindingService.lookupKeybinding(zoomOutAction.id)?.getLabel() });
|
||||
actionBarLeft.push(this.zoomLevelLabel, { icon: false, label: true });
|
||||
actionBarLeft.push(zoomInAction, { icon: true, label: false, keybinding: this.keybindingService.lookupKeybinding(zoomInAction.id)?.getLabel() });
|
||||
@@ -1172,7 +1173,7 @@ class ZoomStatusEntry extends Disposable {
|
||||
right.classList.add('zoom-status-right');
|
||||
container.appendChild(right);
|
||||
|
||||
const actionBarRight = disposables.add(new ActionBar(right));
|
||||
const actionBarRight = disposables.add(new ActionBar(right, { hoverDelegate: nativeHoverDelegate }));
|
||||
|
||||
actionBarRight.push(zoomResetAction, { icon: false, label: true });
|
||||
actionBarRight.push(zoomSettingsAction, { icon: true, label: false, keybinding: this.keybindingService.lookupKeybinding(zoomSettingsAction.id)?.getLabel() });
|
||||
|
||||
@@ -15,6 +15,7 @@ export const allApiProposals = Object.freeze({
|
||||
chatParticipantAdditions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts',
|
||||
chatProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatProvider.d.ts',
|
||||
chatTab: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatTab.d.ts',
|
||||
chatVariableResolver: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatVariableResolver.d.ts',
|
||||
codeActionAI: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.codeActionAI.d.ts',
|
||||
codeActionRanges: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.codeActionRanges.d.ts',
|
||||
codiconDecoration: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.codiconDecoration.d.ts',
|
||||
|
||||
@@ -85,7 +85,7 @@ export class NativeIssueService implements IWorkbenchIssueService {
|
||||
}
|
||||
}
|
||||
const result = [this._providers.has(extensionId.toLowerCase()), this._handlers.has(extensionId.toLowerCase())];
|
||||
ipcRenderer.send('vscode:triggerReporterStatusResponse', result);
|
||||
ipcRenderer.send(`vscode:triggerReporterStatusResponse`, result);
|
||||
});
|
||||
ipcRenderer.on('vscode:triggerReporterMenu', async (event, arg) => {
|
||||
const extensionId = arg.extensionId;
|
||||
@@ -108,7 +108,7 @@ export class NativeIssueService implements IWorkbenchIssueService {
|
||||
|
||||
if (!this.extensionIdentifierSet.has(extensionId)) {
|
||||
// send undefined to indicate no action was taken
|
||||
ipcRenderer.send('vscode:triggerReporterMenuResponse:${extensionId}', undefined);
|
||||
ipcRenderer.send(`vscode:triggerReporterMenuResponse:${extensionId}`, undefined);
|
||||
}
|
||||
menu.dispose();
|
||||
});
|
||||
@@ -186,7 +186,7 @@ export class NativeIssueService implements IWorkbenchIssueService {
|
||||
}, dataOverrides);
|
||||
|
||||
if (issueReporterData.extensionId && this.extensionIdentifierSet.has(issueReporterData.extensionId)) {
|
||||
ipcRenderer.send('vscode:triggerReporterMenuResponse:${issueReporterData.extensionId}', issueReporterData);
|
||||
ipcRenderer.send(`vscode:triggerReporterMenuResponse:${issueReporterData.extensionId}`, issueReporterData);
|
||||
this.extensionIdentifierSet.delete(new ExtensionIdentifier(issueReporterData.extensionId));
|
||||
}
|
||||
return this.issueMainService.openReporter(issueReporterData);
|
||||
|
||||
+43
-73
@@ -5,13 +5,15 @@
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
// TODO@API name: Turn?
|
||||
/**
|
||||
* Represents a user request in chat history.
|
||||
*/
|
||||
export class ChatRequestTurn {
|
||||
|
||||
/**
|
||||
* The prompt as entered by the user.
|
||||
*
|
||||
* Information about variables used in this request are is stored in {@link ChatRequest.variables}.
|
||||
* Information about variables used in this request is stored in {@link ChatRequestTurn.variables}.
|
||||
*
|
||||
* *Note* that the {@link ChatParticipant.name name} of the participant and the {@link ChatCommand.name command}
|
||||
* are not part of the prompt.
|
||||
@@ -36,13 +38,15 @@ declare module 'vscode' {
|
||||
private constructor(prompt: string, command: string | undefined, variables: ChatResolvedVariable[], participant: { extensionId: string; participant: string });
|
||||
}
|
||||
|
||||
// TODO@API name: Turn?
|
||||
/**
|
||||
* Represents a chat participant's response in chat history.
|
||||
*/
|
||||
export class ChatResponseTurn {
|
||||
|
||||
/**
|
||||
* The content that was received from the chat participant. Only the progress parts that represent actual content (not metadata) are represented.
|
||||
* The content that was received from the chat participant. Only the stream parts that represent actual content (not metadata) are represented.
|
||||
*/
|
||||
readonly response: ReadonlyArray<ChatResponseTextPart | ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart>;
|
||||
readonly response: ReadonlyArray<ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart>;
|
||||
|
||||
/**
|
||||
* The result that was received from the chat participant.
|
||||
@@ -50,13 +54,16 @@ declare module 'vscode' {
|
||||
readonly result: ChatResult;
|
||||
|
||||
/**
|
||||
* The name of the chat participant and contributing extension to which this request was directed.
|
||||
* The name of the chat participant and contributing extension that this response came from.
|
||||
*/
|
||||
readonly participant: { readonly extensionId: string; readonly participant: string };
|
||||
|
||||
/**
|
||||
* The name of the command that this response came from.
|
||||
*/
|
||||
readonly command?: string;
|
||||
|
||||
private constructor(response: ReadonlyArray<ChatResponseTextPart | ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart>, result: ChatResult, participant: { extensionId: string; participant: string });
|
||||
private constructor(response: ReadonlyArray<ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart>, result: ChatResult, participant: { extensionId: string; participant: string });
|
||||
}
|
||||
|
||||
export interface ChatContext {
|
||||
@@ -100,7 +107,7 @@ declare module 'vscode' {
|
||||
errorDetails?: ChatErrorDetails;
|
||||
|
||||
/**
|
||||
* Arbitrary metadata for this result. Can be anything but must be JSON-stringifyable.
|
||||
* Arbitrary metadata for this result. Can be anything, but must be JSON-stringifyable.
|
||||
*/
|
||||
readonly metadata?: { readonly [key: string]: any };
|
||||
}
|
||||
@@ -125,7 +132,8 @@ declare module 'vscode' {
|
||||
*/
|
||||
export interface ChatResultFeedback {
|
||||
/**
|
||||
* This instance of ChatResult has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance.
|
||||
* The ChatResult that the user is providing feedback for.
|
||||
* This instance has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance.
|
||||
*/
|
||||
readonly result: ChatResult;
|
||||
|
||||
@@ -160,8 +168,11 @@ declare module 'vscode' {
|
||||
readonly isSticky?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A ChatCommandProvider returns {@link ChatCommands commands} that can be invoked on a chat participant using `/`. For example, `@participant /command`.
|
||||
* These can be used as shortcuts to let the user explicitly invoke different functionalities provided by the participant.
|
||||
*/
|
||||
export interface ChatCommandProvider {
|
||||
|
||||
/**
|
||||
* Returns a list of commands that its participant is capable of handling. A command
|
||||
* can be selected by the user and will then be passed to the {@link ChatRequestHandler handler}
|
||||
@@ -177,7 +188,7 @@ declare module 'vscode' {
|
||||
}
|
||||
|
||||
/**
|
||||
* A followup question suggested by the model.
|
||||
* A followup question suggested by the participant.
|
||||
*/
|
||||
export interface ChatFollowup {
|
||||
/**
|
||||
@@ -185,9 +196,14 @@ declare module 'vscode' {
|
||||
*/
|
||||
prompt: string;
|
||||
|
||||
/**
|
||||
* A title to show the user. The prompt will be shown by default, when this is unspecified.
|
||||
*/
|
||||
label?: string;
|
||||
|
||||
/**
|
||||
* By default, the followup goes to the same participant/command. But this property can be set to invoke a different participant.
|
||||
* TODO@API do extensions need to specify the extensionID of the participant here as well?
|
||||
* Followups can only invoke a participant that was contributed by the same extension.
|
||||
*/
|
||||
participant?: string;
|
||||
|
||||
@@ -195,17 +211,6 @@ declare module 'vscode' {
|
||||
* By default, the followup goes to the same participant/command. But this property can be set to invoke a different command.
|
||||
*/
|
||||
command?: string;
|
||||
|
||||
/**
|
||||
* A tooltip to show when hovering over the followup.
|
||||
*/
|
||||
tooltip?: string;
|
||||
|
||||
/**
|
||||
* A title to show the user, when it is different than the message.
|
||||
*/
|
||||
// TODO@API title vs tooltip?
|
||||
title?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,8 +218,8 @@ declare module 'vscode' {
|
||||
*/
|
||||
export interface ChatFollowupProvider {
|
||||
/**
|
||||
*
|
||||
* @param result The same instance of the result object that was returned by the chat participant, and it can be extended with arbitrary properties if needed.
|
||||
* Provide followups for the given result.
|
||||
* @param result This instance has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance.
|
||||
* @param token A cancellation token.
|
||||
*/
|
||||
provideFollowups(result: ChatResult, token: CancellationToken): ProviderResult<ChatFollowup[]>;
|
||||
@@ -225,9 +230,11 @@ declare module 'vscode' {
|
||||
*/
|
||||
export type ChatRequestHandler = (request: ChatRequest, context: ChatContext, response: ChatResponseStream, token: CancellationToken) => ProviderResult<ChatResult>;
|
||||
|
||||
|
||||
/**
|
||||
* A chat participant can be invoked by the user in a chat session, using the `@` prefix. When it is invoked, it handles the chat request and is solely
|
||||
* responsible for providing a response to the user. A ChatParticipant is created using {@link chat.createChatParticipant}.
|
||||
*/
|
||||
export interface ChatParticipant {
|
||||
|
||||
/**
|
||||
* The short name by which this participant is referred to in the UI, e.g `workspace`.
|
||||
*/
|
||||
@@ -235,6 +242,7 @@ declare module 'vscode' {
|
||||
|
||||
/**
|
||||
* The full name of this participant.
|
||||
* TODO@API This is only used for the default participant, but it seems useful, so should we keep it so we can use it in the future?
|
||||
*/
|
||||
fullName: string;
|
||||
|
||||
@@ -301,7 +309,6 @@ declare module 'vscode' {
|
||||
* A resolved variable value is a name-value pair as well as the range in the prompt where a variable was used.
|
||||
*/
|
||||
export interface ChatResolvedVariable {
|
||||
|
||||
/**
|
||||
* The name of the variable.
|
||||
*
|
||||
@@ -323,7 +330,6 @@ declare module 'vscode' {
|
||||
}
|
||||
|
||||
export interface ChatRequest {
|
||||
|
||||
/**
|
||||
* The prompt as entered by the user.
|
||||
*
|
||||
@@ -344,7 +350,7 @@ declare module 'vscode' {
|
||||
*
|
||||
* *Note* that the prompt contains varibale references as authored and that it is up to the participant
|
||||
* to further modify the prompt, for instance by inlining variable values or creating links to
|
||||
* headings which contain the resolved values. vvariables are sorted in reverse by their range
|
||||
* headings which contain the resolved values. Variables are sorted in reverse by their range
|
||||
* in the prompt. That means the last variable in the prompt is the first in this list. This simplifies
|
||||
* string-manipulation of the prompt.
|
||||
*/
|
||||
@@ -352,8 +358,12 @@ declare module 'vscode' {
|
||||
readonly variables: readonly ChatResolvedVariable[];
|
||||
}
|
||||
|
||||
/**
|
||||
* The ChatResponseStream is how a participant is able to return content to the chat view. It provides several methods for streaming different types of content
|
||||
* which will be rendered in an appropriate way in the chat view. A participant can use the helper method for the type of content it wants to return, or it
|
||||
* can instantiate a {@link ChatResponsePart} and use the generic {@link ChatResponseStream.push} method to return it.
|
||||
*/
|
||||
export interface ChatResponseStream {
|
||||
|
||||
/**
|
||||
* Push a markdown part to this stream. Short-hand for
|
||||
* `push(new ChatResponseMarkdownPart(value))`.
|
||||
@@ -367,6 +377,7 @@ declare module 'vscode' {
|
||||
/**
|
||||
* Push an anchor part to this stream. Short-hand for
|
||||
* `push(new ChatResponseAnchorPart(value, title))`.
|
||||
* An anchor is an inline reference to some type of resource.
|
||||
*
|
||||
* @param value A uri or location
|
||||
* @param title An optional title that is rendered with value
|
||||
@@ -400,9 +411,6 @@ declare module 'vscode' {
|
||||
* @param value
|
||||
* @returns This stream.
|
||||
*/
|
||||
// TODO@API is this always inline or not
|
||||
// TODO@API is this markdown or string?
|
||||
// TODO@API this influences the rendering, it inserts new lines which is likely a bug
|
||||
progress(value: string): ChatResponseStream;
|
||||
|
||||
/**
|
||||
@@ -414,8 +422,6 @@ declare module 'vscode' {
|
||||
* @param value A uri or location
|
||||
* @returns This stream.
|
||||
*/
|
||||
// TODO@API support non-file uris, like http://example.com
|
||||
// TODO@API support mapped edits
|
||||
reference(value: Uri | Location): ChatResponseStream;
|
||||
|
||||
/**
|
||||
@@ -426,13 +432,6 @@ declare module 'vscode' {
|
||||
push(part: ChatResponsePart): ChatResponseStream;
|
||||
}
|
||||
|
||||
// TODO@API should the name suffix differentiate between rendered items (XYZPart)
|
||||
// and metadata like XYZItem
|
||||
export class ChatResponseTextPart {
|
||||
value: string;
|
||||
constructor(value: string);
|
||||
}
|
||||
|
||||
export class ChatResponseMarkdownPart {
|
||||
value: MarkdownString;
|
||||
constructor(value: string | MarkdownString);
|
||||
@@ -457,7 +456,6 @@ declare module 'vscode' {
|
||||
|
||||
export class ChatResponseProgressPart {
|
||||
value: string;
|
||||
// TODO@API inline
|
||||
constructor(value: string);
|
||||
}
|
||||
|
||||
@@ -474,12 +472,11 @@ declare module 'vscode' {
|
||||
/**
|
||||
* Represents the different chat response types.
|
||||
*/
|
||||
export type ChatResponsePart = ChatResponseTextPart | ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart
|
||||
export type ChatResponsePart = ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart
|
||||
| ChatResponseProgressPart | ChatResponseReferencePart | ChatResponseCommandButtonPart;
|
||||
|
||||
|
||||
export namespace chat {
|
||||
|
||||
/**
|
||||
* Create a new {@link ChatParticipant chat participant} instance.
|
||||
*
|
||||
@@ -489,21 +486,11 @@ declare module 'vscode' {
|
||||
* @returns A new chat participant
|
||||
*/
|
||||
export function createChatParticipant(name: string, handler: ChatRequestHandler): ChatParticipant;
|
||||
|
||||
/**
|
||||
* Register a variable which can be used in a chat request to any participant.
|
||||
* @param name The name of the variable, to be used in the chat input as `#name`.
|
||||
* @param description A description of the variable for the chat input suggest widget.
|
||||
* @param resolver Will be called to provide the chat variable's value when it is used.
|
||||
*/
|
||||
// TODO@API NAME: registerChatVariable, registerChatVariableResolver
|
||||
export function registerVariable(name: string, description: string, resolver: ChatVariableResolver): Disposable;
|
||||
}
|
||||
|
||||
/**
|
||||
* The detail level of this chat variable value.
|
||||
*/
|
||||
// TODO@API maybe for round2
|
||||
export enum ChatVariableLevel {
|
||||
Short = 1,
|
||||
Medium = 2,
|
||||
@@ -526,21 +513,4 @@ declare module 'vscode' {
|
||||
*/
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface ChatVariableContext {
|
||||
/**
|
||||
* The message entered by the user, which includes this variable.
|
||||
*/
|
||||
prompt: string;
|
||||
}
|
||||
|
||||
export interface ChatVariableResolver {
|
||||
/**
|
||||
* A callback to resolve the value of a chat variable.
|
||||
* @param name The name of the variable.
|
||||
* @param context Contextual information about this chat request.
|
||||
* @param token A cancellation token.
|
||||
*/
|
||||
resolve(name: string, context: ChatVariableContext, token: CancellationToken): ProviderResult<ChatVariableValue[]>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
export namespace chat {
|
||||
|
||||
/**
|
||||
* Register a variable which can be used in a chat request to any participant.
|
||||
* @param name The name of the variable, to be used in the chat input as `#name`.
|
||||
* @param description A description of the variable for the chat input suggest widget.
|
||||
* @param resolver Will be called to provide the chat variable's value when it is used.
|
||||
*/
|
||||
export function registerChatVariableResolver(name: string, description: string, resolver: ChatVariableResolver): Disposable;
|
||||
}
|
||||
|
||||
export interface ChatVariableValue {
|
||||
/**
|
||||
* The detail level of this chat variable value. If possible, variable resolvers should try to offer shorter values that will consume fewer tokens in an LLM prompt.
|
||||
*/
|
||||
level: ChatVariableLevel;
|
||||
|
||||
/**
|
||||
* The variable's value, which can be included in an LLM prompt as-is, or the chat participant may decide to read the value and do something else with it.
|
||||
*/
|
||||
value: string | Uri;
|
||||
|
||||
/**
|
||||
* A description of this value, which could be provided to the LLM as a hint.
|
||||
*/
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface ChatVariableContext {
|
||||
/**
|
||||
* The message entered by the user, which includes this variable.
|
||||
*/
|
||||
prompt: string;
|
||||
}
|
||||
|
||||
export interface ChatVariableResolver {
|
||||
/**
|
||||
* A callback to resolve the value of a chat variable.
|
||||
* @param name The name of the variable.
|
||||
* @param context Contextual information about this chat request.
|
||||
* @param token A cancellation token.
|
||||
*/
|
||||
resolve(name: string, context: ChatVariableContext, token: CancellationToken): ProviderResult<ChatVariableValue[]>;
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,11 @@ declare module 'vscode' {
|
||||
*/
|
||||
helpTextPrefix?: string | MarkdownString;
|
||||
|
||||
/**
|
||||
* A string that will be added before the listing of chat variables in `/help`.
|
||||
*/
|
||||
helpTextVariablesPrefix?: string | MarkdownString;
|
||||
|
||||
/**
|
||||
* A string that will be appended after the listing of chat participants in `/help`.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user