mirror of
https://github.com/microsoft/vscode.git
synced 2026-08-26 19:36:52 +01:00
Merge branch 'main' into tyriar/195804
This commit is contained in:
@@ -138,6 +138,19 @@ steps:
|
||||
condition: and(succeededOrFailed(), notIn(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues'))
|
||||
displayName: Generate artifact prefix
|
||||
|
||||
- script: mkdir $(agent.builddirectory)/vscode-alpine-$(VSCODE_ARCH)
|
||||
displayName: Make folder for SBOM
|
||||
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: Generate SBOM
|
||||
inputs:
|
||||
BuildDropPath: $(agent.builddirectory)/vscode-alpine-$(VSCODE_ARCH)
|
||||
PackageName: Visual Studio Code Server
|
||||
|
||||
- publish: $(agent.builddirectory)/vscode-alpine-$(VSCODE_ARCH)/_manifest
|
||||
displayName: Publish SBOM
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_vscode_alpine_$(VSCODE_ARCH)
|
||||
|
||||
- publish: $(SERVER_PATH)
|
||||
artifact: $(ARTIFACT_PREFIX)vscode_server_alpine_$(VSCODE_ARCH)_archive-unsigned
|
||||
displayName: Publish server archive
|
||||
|
||||
@@ -106,3 +106,26 @@ steps:
|
||||
- publish: $(Build.ArtifactStagingDirectory)/${{ parameters.VSCODE_CLI_ARTIFACT }}.tar.gz
|
||||
artifact: ${{ parameters.VSCODE_CLI_ARTIFACT }}
|
||||
displayName: Publish ${{ parameters.VSCODE_CLI_ARTIFACT }} artifact
|
||||
|
||||
# Make a folder for the SBOM for the specific artifact
|
||||
- ${{ if contains(parameters.VSCODE_CLI_TARGET, '-windows-') }}:
|
||||
- powershell: mkdir $(Build.ArtifactStagingDirectory)/sbom_${{ parameters.VSCODE_CLI_ARTIFACT }}
|
||||
displayName: Make folder for SBOM (Windows)
|
||||
|
||||
- ${{ else }}:
|
||||
- script: mkdir $(Build.ArtifactStagingDirectory)/sbom_${{ parameters.VSCODE_CLI_ARTIFACT }}
|
||||
displayName: Make folder for SBOM (non-Windows)
|
||||
|
||||
# The if cases above are for different OSes,
|
||||
# but we're still in the branch where the cli is being published in general.
|
||||
# Generate and publish an SBOM.
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: Generate SBOM
|
||||
inputs:
|
||||
BuildComponentPath: $(Build.SourcesDirectory)/cli
|
||||
BuildDropPath: $(Build.ArtifactStagingDirectory)/sbom_${{ parameters.VSCODE_CLI_ARTIFACT }}
|
||||
PackageName: Visual Studio Code CLI
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)/sbom_${{ parameters.VSCODE_CLI_ARTIFACT }}/_manifest
|
||||
displayName: Publish SBOM
|
||||
artifact: sbom_${{ parameters.VSCODE_CLI_ARTIFACT }}
|
||||
|
||||
@@ -219,16 +219,17 @@ steps:
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: Generate SBOM (server)
|
||||
inputs:
|
||||
BuildComponentPath: $(Build.SourcesDirectory)/remote
|
||||
BuildDropPath: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH)
|
||||
PackageName: Visual Studio Code Server
|
||||
|
||||
- publish: $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)/_manifest
|
||||
displayName: Publish SBOM (client)
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_client_darwin_$(VSCODE_ARCH)_sbom
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_vscode_client_darwin_$(VSCODE_ARCH)
|
||||
|
||||
- publish: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH)/_manifest
|
||||
displayName: Publish SBOM (server)
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_server_darwin_$(VSCODE_ARCH)_sbom
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_vscode_server_darwin_$(VSCODE_ARCH)
|
||||
|
||||
- publish: $(CLIENT_PATH)
|
||||
artifact: $(ARTIFACT_PREFIX)unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive
|
||||
|
||||
@@ -331,6 +331,7 @@ steps:
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: Generate SBOM (server)
|
||||
inputs:
|
||||
BuildComponentPath: $(Build.SourcesDirectory)/remote
|
||||
BuildDropPath: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH)
|
||||
PackageName: Visual Studio Code Server
|
||||
|
||||
|
||||
@@ -50,6 +50,19 @@ steps:
|
||||
echo "##vso[task.setvariable variable=SNAP_PATH]$SNAP_PATH"
|
||||
displayName: Prepare for publish
|
||||
|
||||
- script: mkdir -p $(agent.builddirectory)/vscode-snap-linux-$(VSCODE_ARCH)
|
||||
displayName: Make folder for SBOM
|
||||
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: Generate SBOM
|
||||
inputs:
|
||||
BuildDropPath: $(agent.builddirectory)/vscode-snap-linux-$(VSCODE_ARCH)
|
||||
PackageName: Visual Studio Code Snap
|
||||
|
||||
- publish: $(agent.builddirectory)/vscode-snap-linux-$(VSCODE_ARCH)/_manifest
|
||||
displayName: Publish SBOM
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_vscode_client_linux_snap_$(VSCODE_ARCH)
|
||||
|
||||
- publish: $(SNAP_PATH)
|
||||
artifact: vscode_client_linux_$(VSCODE_ARCH)_snap
|
||||
displayName: Publish snap package
|
||||
|
||||
@@ -107,6 +107,7 @@ steps:
|
||||
displayName: Build
|
||||
|
||||
- task: AzureCLI@2
|
||||
displayName: Fetch secrets from Azure
|
||||
inputs:
|
||||
azureSubscription: "vscode-builds-subscription"
|
||||
scriptType: pscore
|
||||
@@ -151,6 +152,16 @@ steps:
|
||||
condition: and(succeededOrFailed(), notIn(variables['Agent.JobStatus'], 'Succeeded', 'SucceededWithIssues'))
|
||||
displayName: Generate artifact prefix
|
||||
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: Generate SBOM
|
||||
inputs:
|
||||
BuildDropPath: $(agent.builddirectory)/vscode-web
|
||||
PackageName: Visual Studio Code Web
|
||||
|
||||
- publish: $(agent.builddirectory)/vscode-web/_manifest
|
||||
displayName: Publish SBOM (client)
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_vscode_web
|
||||
|
||||
- publish: $(WEB_PATH)
|
||||
artifact: $(ARTIFACT_PREFIX)vscode_web_linux_standalone_archive-unsigned
|
||||
condition: and(succeededOrFailed(), ne(variables['WEB_PATH'], ''))
|
||||
|
||||
@@ -322,17 +322,18 @@ steps:
|
||||
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
|
||||
displayName: Generate SBOM (server)
|
||||
inputs:
|
||||
BuildComponentPath: $(Build.SourcesDirectory)/remote
|
||||
BuildDropPath: $(agent.builddirectory)/vscode-server-win32-$(VSCODE_ARCH)
|
||||
PackageName: Visual Studio Code Server
|
||||
condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64'))
|
||||
|
||||
- publish: $(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)/_manifest
|
||||
displayName: Publish SBOM (client)
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_client_win32_$(VSCODE_ARCH)
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_vscode_client_win32_$(VSCODE_ARCH)
|
||||
|
||||
- publish: $(agent.builddirectory)/vscode-server-win32-$(VSCODE_ARCH)/_manifest
|
||||
displayName: Publish SBOM (server)
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_server_win32_$(VSCODE_ARCH)
|
||||
artifact: $(ARTIFACT_PREFIX)sbom_vscode_server_win32_$(VSCODE_ARCH)
|
||||
condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64'))
|
||||
|
||||
- publish: $(CLIENT_PATH)
|
||||
|
||||
@@ -73,7 +73,6 @@ const vscodeResources = [
|
||||
'out-build/vs/workbench/contrib/terminal/browser/media/*.sh',
|
||||
'out-build/vs/workbench/contrib/terminal/browser/media/*.zsh',
|
||||
'out-build/vs/workbench/contrib/webview/browser/pre/*.js',
|
||||
'out-build/vs/workbench/services/voiceRecognition/electron-sandbox/voiceTranscriptionWorklet.js',
|
||||
'out-build/vs/**/markdown.css',
|
||||
'out-build/vs/workbench/contrib/tasks/**/*.json',
|
||||
'!**/test/**'
|
||||
|
||||
@@ -82,10 +82,6 @@
|
||||
"name": "vs/workbench/services/assignment",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/voiceRecognition",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/extensions",
|
||||
"project": "vscode-workbench"
|
||||
|
||||
@@ -681,6 +681,7 @@
|
||||
"--vscode-textCodeBlock-background",
|
||||
"--vscode-textLink-activeForeground",
|
||||
"--vscode-textLink-foreground",
|
||||
"--vscode-textPreformat-background",
|
||||
"--vscode-textPreformat-foreground",
|
||||
"--vscode-textSeparator-foreground",
|
||||
"--vscode-titleBar-activeBackground",
|
||||
@@ -695,6 +696,8 @@
|
||||
"--vscode-tree-indentGuidesStroke",
|
||||
"--vscode-tree-tableColumnsBorder",
|
||||
"--vscode-tree-tableOddRowsBackground",
|
||||
"--vscode-voiceRecording-background",
|
||||
"--vscode-voiceRecording-dimmedBackground",
|
||||
"--vscode-walkThrough-embeddedEditorBackground",
|
||||
"--vscode-walkthrough-stepTitle-foreground",
|
||||
"--vscode-welcomePage-background",
|
||||
@@ -706,9 +709,7 @@
|
||||
"--vscode-widget-border",
|
||||
"--vscode-widget-shadow",
|
||||
"--vscode-window-activeBorder",
|
||||
"--vscode-window-inactiveBorder",
|
||||
"--vscode-voiceRecording-background",
|
||||
"--vscode-voiceRecording-dimmedBackground"
|
||||
"--vscode-window-inactiveBorder"
|
||||
],
|
||||
"others": [
|
||||
"--background-dark",
|
||||
@@ -782,4 +783,4 @@
|
||||
"--z-index-notebook-sticky-scroll",
|
||||
"--zoom-factor"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -510,7 +510,7 @@ impl<'a> ServerBuilder<'a> {
|
||||
let (mut origin, listen_rx) =
|
||||
monitor_server::<SocketMatcher, PathBuf>(child, Some(log_file), plog, false);
|
||||
|
||||
let socket = match timeout(Duration::from_secs(8), listen_rx).await {
|
||||
let socket = match timeout(Duration::from_secs(30), listen_rx).await {
|
||||
Err(e) => {
|
||||
origin.kill().await;
|
||||
Err(wrap(e, "timed out looking for socket"))
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"input.background": "#313131",
|
||||
"input.border": "#3C3C3C",
|
||||
"input.foreground": "#CCCCCC",
|
||||
"input.placeholderForeground": "#9D9D9D",
|
||||
"input.placeholderForeground": "#818181",
|
||||
"inputOption.activeBackground": "#2489DB82",
|
||||
"inputOption.activeBorder": "#2488DB",
|
||||
"keybindingLabel.foreground": "#CCCCCC",
|
||||
@@ -111,8 +111,10 @@
|
||||
"textBlockQuote.background": "#2B2B2B",
|
||||
"textBlockQuote.border": "#616161",
|
||||
"textCodeBlock.background": "#2B2B2B",
|
||||
"textLink.activeForeground": "#40A6FF",
|
||||
"textLink.foreground": "#40A6FF",
|
||||
"textLink.activeForeground": "#4daafc",
|
||||
"textLink.foreground": "#4daafc",
|
||||
"textPreformat.foreground": "#D0D0D0",
|
||||
"textPreformat.background": "#3C3C3C",
|
||||
"textSeparator.foreground": "#21262D",
|
||||
"titleBar.activeBackground": "#181818",
|
||||
"titleBar.activeForeground": "#CCCCCC",
|
||||
|
||||
@@ -131,6 +131,8 @@
|
||||
"textCodeBlock.background": "#F8F8F8",
|
||||
"textLink.activeForeground": "#005FB8",
|
||||
"textLink.foreground": "#005FB8",
|
||||
"textPreformat.foreground": "#3B3B3B",
|
||||
"textPreformat.background": "#0000001F",
|
||||
"textSeparator.foreground": "#21262D",
|
||||
"titleBar.activeBackground": "#F8F8F8",
|
||||
"titleBar.activeForeground": "#1E1E1E",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as jsonc from 'jsonc-parser';
|
||||
import { posix } from 'path';
|
||||
import { isAbsolute, posix } from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { Utils } from 'vscode-uri';
|
||||
import { coalesce } from '../utils/arrays';
|
||||
@@ -95,6 +95,10 @@ class TsconfigLinkProvider implements vscode.DocumentLinkProvider {
|
||||
}
|
||||
|
||||
private getFileTarget(document: vscode.TextDocument, node: jsonc.Node): vscode.Uri {
|
||||
if (isAbsolute(node.value)) {
|
||||
return vscode.Uri.file(node.value);
|
||||
}
|
||||
|
||||
return vscode.Uri.joinPath(Utils.dirname(document.uri), node.value);
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.84.0",
|
||||
"distro": "0f218422a902175f8b82cbf0f13fa4feb278f22a",
|
||||
"distro": "b30d9687a6941b0d17b73334fc5a0f12590bff90",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
@@ -96,14 +96,14 @@
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.4.0-beta.31",
|
||||
"xterm-addon-canvas": "0.6.0-beta.31",
|
||||
"xterm": "5.4.0-beta.32",
|
||||
"xterm-addon-canvas": "0.6.0-beta.32",
|
||||
"xterm-addon-image": "0.6.0-beta.21",
|
||||
"xterm-addon-search": "0.14.0-beta.30",
|
||||
"xterm-addon-serialize": "0.12.0-beta.30",
|
||||
"xterm-addon-unicode11": "0.7.0-beta.30",
|
||||
"xterm-addon-webgl": "0.17.0-beta.30",
|
||||
"xterm-headless": "5.4.0-beta.31",
|
||||
"xterm-addon-search": "0.14.0-beta.31",
|
||||
"xterm-addon-serialize": "0.12.0-beta.31",
|
||||
"xterm-addon-unicode11": "0.7.0-beta.31",
|
||||
"xterm-addon-webgl": "0.17.0-beta.31",
|
||||
"xterm-headless": "5.4.0-beta.32",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
|
||||
+7
-7
@@ -26,14 +26,14 @@
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.4.0-beta.31",
|
||||
"xterm-addon-canvas": "0.6.0-beta.31",
|
||||
"xterm": "5.4.0-beta.32",
|
||||
"xterm-addon-canvas": "0.6.0-beta.32",
|
||||
"xterm-addon-image": "0.6.0-beta.21",
|
||||
"xterm-addon-search": "0.14.0-beta.30",
|
||||
"xterm-addon-serialize": "0.12.0-beta.30",
|
||||
"xterm-addon-unicode11": "0.7.0-beta.30",
|
||||
"xterm-addon-webgl": "0.17.0-beta.30",
|
||||
"xterm-headless": "5.4.0-beta.31",
|
||||
"xterm-addon-search": "0.14.0-beta.31",
|
||||
"xterm-addon-serialize": "0.12.0-beta.31",
|
||||
"xterm-addon-unicode11": "0.7.0-beta.31",
|
||||
"xterm-addon-webgl": "0.17.0-beta.31",
|
||||
"xterm-headless": "5.4.0-beta.32",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
"tas-client-umd": "0.1.8",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.4.0-beta.31",
|
||||
"xterm-addon-canvas": "0.6.0-beta.31",
|
||||
"xterm": "5.4.0-beta.32",
|
||||
"xterm-addon-canvas": "0.6.0-beta.32",
|
||||
"xterm-addon-image": "0.6.0-beta.21",
|
||||
"xterm-addon-search": "0.14.0-beta.30",
|
||||
"xterm-addon-unicode11": "0.7.0-beta.30",
|
||||
"xterm-addon-webgl": "0.17.0-beta.30"
|
||||
"xterm-addon-search": "0.14.0-beta.31",
|
||||
"xterm-addon-unicode11": "0.7.0-beta.31",
|
||||
"xterm-addon-webgl": "0.17.0-beta.31"
|
||||
}
|
||||
}
|
||||
|
||||
+20
-20
@@ -68,32 +68,32 @@ vscode-textmate@9.0.0:
|
||||
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c"
|
||||
integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg==
|
||||
|
||||
xterm-addon-canvas@0.6.0-beta.31:
|
||||
version "0.6.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb"
|
||||
integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ==
|
||||
xterm-addon-canvas@0.6.0-beta.32:
|
||||
version "0.6.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.32.tgz#c9e74dd72fcc981a2e0cbd0b82827676bc5c74b9"
|
||||
integrity sha512-Xw7oE4dbS+x+pu6cGW1bDSXcVviuorLz1OLaYw46jjmDezIqQIIEMhSMOprExFEWgeRQ9AEN4lPqw6aH87V74w==
|
||||
|
||||
xterm-addon-image@0.6.0-beta.21:
|
||||
version "0.6.0-beta.21"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac"
|
||||
integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ==
|
||||
|
||||
xterm-addon-search@0.14.0-beta.30:
|
||||
version "0.14.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea"
|
||||
integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ==
|
||||
xterm-addon-search@0.14.0-beta.31:
|
||||
version "0.14.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.31.tgz#933ca5d2d642dacad29f2cfbd50830cff83bc274"
|
||||
integrity sha512-JRY1ukhoh32D0AMz78xpumQkLgkcP9d3GXj6gzVHZZsjLAMDaJYEubYq1bUhM7IGHUyg+x0sdRJyx7d6fJpiQg==
|
||||
|
||||
xterm-addon-unicode11@0.7.0-beta.30:
|
||||
version "0.7.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3"
|
||||
integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw==
|
||||
xterm-addon-unicode11@0.7.0-beta.31:
|
||||
version "0.7.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.31.tgz#abcba752172323f31312bd8a3f9b6a049dbca6e3"
|
||||
integrity sha512-vvBKJbBoLbeIf2++6D16VnOOwevZE3nyO/PDZ7cyTJK1eYR73rr8ZbjUrH92YoTu4Z8MpZFepGQOgK/vlAQMwQ==
|
||||
|
||||
xterm-addon-webgl@0.17.0-beta.30:
|
||||
version "0.17.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f"
|
||||
integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q==
|
||||
xterm-addon-webgl@0.17.0-beta.31:
|
||||
version "0.17.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.31.tgz#3cd29b4858e3f4f6dd5a8dd969454e85e1f43baa"
|
||||
integrity sha512-vYHj+HlTcqUlFFVuoCTjlgh89/lIoSkZ7Nc87cwSFTrJsl07qoKutmpupqFXyjhbEA1fQY2SuQLx08Gmf2jWkQ==
|
||||
|
||||
xterm@5.4.0-beta.31:
|
||||
version "5.4.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174"
|
||||
integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA==
|
||||
xterm@5.4.0-beta.32:
|
||||
version "5.4.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.32.tgz#1b4242cf1c0c1a5a1070da58d3f11956b537130a"
|
||||
integrity sha512-mWTwEiNBFMF89oqVfi6qTM2Py5gC1Mwvslx1KxmI2Ukgh9v3CrqKDhj29eY1ZeAo0uuYknFWKyuexqp+3SHJCA==
|
||||
|
||||
+28
-28
@@ -591,45 +591,45 @@ wrappy@1:
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
xterm-addon-canvas@0.6.0-beta.31:
|
||||
version "0.6.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb"
|
||||
integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ==
|
||||
xterm-addon-canvas@0.6.0-beta.32:
|
||||
version "0.6.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.32.tgz#c9e74dd72fcc981a2e0cbd0b82827676bc5c74b9"
|
||||
integrity sha512-Xw7oE4dbS+x+pu6cGW1bDSXcVviuorLz1OLaYw46jjmDezIqQIIEMhSMOprExFEWgeRQ9AEN4lPqw6aH87V74w==
|
||||
|
||||
xterm-addon-image@0.6.0-beta.21:
|
||||
version "0.6.0-beta.21"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac"
|
||||
integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ==
|
||||
|
||||
xterm-addon-search@0.14.0-beta.30:
|
||||
version "0.14.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea"
|
||||
integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ==
|
||||
xterm-addon-search@0.14.0-beta.31:
|
||||
version "0.14.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.31.tgz#933ca5d2d642dacad29f2cfbd50830cff83bc274"
|
||||
integrity sha512-JRY1ukhoh32D0AMz78xpumQkLgkcP9d3GXj6gzVHZZsjLAMDaJYEubYq1bUhM7IGHUyg+x0sdRJyx7d6fJpiQg==
|
||||
|
||||
xterm-addon-serialize@0.12.0-beta.30:
|
||||
version "0.12.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.30.tgz#80c4101f45a463ef139705bcd3dcaf0811f51ea4"
|
||||
integrity sha512-nZP0ip5bd9LBoCTN9vCnn4iLatF4RRwzLupQf9r2N9x1bULzTZ1kAXAQe5gghsXjSEDDtyY2LzGigqTd2KVAqQ==
|
||||
xterm-addon-serialize@0.12.0-beta.31:
|
||||
version "0.12.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.31.tgz#2a95dc1e12f4097e2894b04c9cb8fff0bc0b858c"
|
||||
integrity sha512-h2rWR+Lfi1Iv4VkLUlrBMYh5Mdq8vux2BKyCJe6a1ZnEu5Dzb0VuiNxfTKXTCT5M83nMn7TCB9TX0E8z6bs7xw==
|
||||
|
||||
xterm-addon-unicode11@0.7.0-beta.30:
|
||||
version "0.7.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3"
|
||||
integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw==
|
||||
xterm-addon-unicode11@0.7.0-beta.31:
|
||||
version "0.7.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.31.tgz#abcba752172323f31312bd8a3f9b6a049dbca6e3"
|
||||
integrity sha512-vvBKJbBoLbeIf2++6D16VnOOwevZE3nyO/PDZ7cyTJK1eYR73rr8ZbjUrH92YoTu4Z8MpZFepGQOgK/vlAQMwQ==
|
||||
|
||||
xterm-addon-webgl@0.17.0-beta.30:
|
||||
version "0.17.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f"
|
||||
integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q==
|
||||
xterm-addon-webgl@0.17.0-beta.31:
|
||||
version "0.17.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.31.tgz#3cd29b4858e3f4f6dd5a8dd969454e85e1f43baa"
|
||||
integrity sha512-vYHj+HlTcqUlFFVuoCTjlgh89/lIoSkZ7Nc87cwSFTrJsl07qoKutmpupqFXyjhbEA1fQY2SuQLx08Gmf2jWkQ==
|
||||
|
||||
xterm-headless@5.4.0-beta.31:
|
||||
version "5.4.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.31.tgz#9538553c7426222f94d7da7ed467e699ebaeeedd"
|
||||
integrity sha512-EE/ZlsZcBE5VOkjQU/KdRL4gvSkfrC2P7VxrmK1+PLc6+QMjPxs60A4Pun3mIIS0MFfN23p6hmN22GAXVckCXA==
|
||||
xterm-headless@5.4.0-beta.32:
|
||||
version "5.4.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.32.tgz#0d5cd35e1a0372888055ff0b06dfe17457979a6c"
|
||||
integrity sha512-DQduq8KSoQZyRrQAFB+FkcY2UMxCW39P1/duOpksebc6PT9pbGkyPe5s+AdUQGiYzriEpzVtKUzDcquoVmpPhA==
|
||||
|
||||
xterm@5.4.0-beta.31:
|
||||
version "5.4.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174"
|
||||
integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA==
|
||||
xterm@5.4.0-beta.32:
|
||||
version "5.4.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.32.tgz#1b4242cf1c0c1a5a1070da58d3f11956b537130a"
|
||||
integrity sha512-mWTwEiNBFMF89oqVfi6qTM2Py5gC1Mwvslx1KxmI2Ukgh9v3CrqKDhj29eY1ZeAo0uuYknFWKyuexqp+3SHJCA==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
@@ -602,14 +602,7 @@ export function getLargestChildWidth(parent: HTMLElement, children: HTMLElement[
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
export function isAncestor(testChild: Node | null, testAncestor: Node | null): boolean {
|
||||
while (testChild) {
|
||||
if (testChild === testAncestor) {
|
||||
return true;
|
||||
}
|
||||
testChild = testChild.parentNode;
|
||||
}
|
||||
|
||||
return false;
|
||||
return Boolean(testAncestor?.contains(testChild));
|
||||
}
|
||||
|
||||
const parentFlowToDataKey = 'parentFlowToElementId';
|
||||
|
||||
@@ -165,10 +165,6 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
const isUrlFromWebview = (requestingUrl: string | undefined) => requestingUrl?.startsWith(`${Schemas.vscodeWebview}://`);
|
||||
|
||||
const allowedPermissionsInMainFrame = new Set(
|
||||
this.productService.quality === 'stable' ? [] : ['media']
|
||||
);
|
||||
|
||||
const allowedPermissionsInWebview = new Set([
|
||||
'clipboard-read',
|
||||
'clipboard-sanitized-write',
|
||||
@@ -179,10 +175,6 @@ export class CodeApplication extends Disposable {
|
||||
return callback(allowedPermissionsInWebview.has(permission));
|
||||
}
|
||||
|
||||
if (details.isMainFrame && details.securityOrigin === `${Schemas.vscodeFileResource}://${VSCODE_AUTHORITY}/`) {
|
||||
return callback(allowedPermissionsInMainFrame.has(permission));
|
||||
}
|
||||
|
||||
return callback(false);
|
||||
});
|
||||
|
||||
@@ -191,10 +183,6 @@ export class CodeApplication extends Disposable {
|
||||
return allowedPermissionsInWebview.has(permission);
|
||||
}
|
||||
|
||||
if (details.isMainFrame && details.securityOrigin === `${Schemas.vscodeFileResource}://${VSCODE_AUTHORITY}/`) {
|
||||
return allowedPermissionsInMainFrame.has(permission);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { MessagePortMain, MessageEvent } from 'vs/base/parts/sandbox/node/electronTypes';
|
||||
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IVoiceRecognitionService } from 'vs/platform/voiceRecognition/node/voiceRecognitionService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { LimitedQueue, Queue } from 'vs/base/common/async';
|
||||
|
||||
export class VoiceTranscriptionManager extends Disposable {
|
||||
|
||||
private static USE_SLIDING_WINDOW = !!process.env.VSCODE_VOICE_USE_SLIDING_WINDOW;
|
||||
|
||||
constructor(
|
||||
private readonly onDidWindowConnectRaw: Event<MessagePortMain>,
|
||||
@IVoiceRecognitionService private readonly voiceRecognitionService: IVoiceRecognitionService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.onDidWindowConnectRaw(port => {
|
||||
this.logService.info(`[voice] transcriber: new connection (sliding window: ${VoiceTranscriptionManager.USE_SLIDING_WINDOW})`);
|
||||
|
||||
if (VoiceTranscriptionManager.USE_SLIDING_WINDOW) {
|
||||
this._register(new SlidingWindowVoiceTranscriber(port, this.voiceRecognitionService, this.logService));
|
||||
} else {
|
||||
this._register(new FullWindowVoiceTranscriber(port, this.voiceRecognitionService, this.logService));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class VoiceTranscriber extends Disposable {
|
||||
|
||||
protected static MAX_DATA_LENGTH = 30 /* seconds */ * 16000 /* sampling rate */ * 16 /* bith depth */ * 1 /* channels */ / 8;
|
||||
|
||||
constructor(
|
||||
protected readonly port: MessagePortMain,
|
||||
protected readonly voiceRecognitionService: IVoiceRecognitionService,
|
||||
protected readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
const cts = new CancellationTokenSource();
|
||||
this._register(toDisposable(() => cts.dispose(true)));
|
||||
|
||||
const requestHandler = (e: MessageEvent) => {
|
||||
if (!(e.data instanceof Float32Array)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleRequest(e.data, cts.token);
|
||||
};
|
||||
this.port.on('message', requestHandler);
|
||||
this._register(toDisposable(() => this.port.off('message', requestHandler)));
|
||||
|
||||
this.port.start();
|
||||
|
||||
let closed = false;
|
||||
this.port.on('close', () => {
|
||||
this.logService.info(`[voice] transcriber: closed connection`);
|
||||
|
||||
closed = true;
|
||||
this.dispose();
|
||||
});
|
||||
|
||||
this._register(toDisposable(() => {
|
||||
if (!closed) {
|
||||
this.port.close();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected abstract handleRequest(data: Float32Array, cancellation: CancellationToken): Promise<void>;
|
||||
|
||||
protected joinFloat32Arrays(float32Arrays: Float32Array[]): Float32Array {
|
||||
const result = new Float32Array(float32Arrays.reduce((prev, curr) => prev + curr.length, 0));
|
||||
|
||||
let offset = 0;
|
||||
for (const float32Array of float32Arrays) {
|
||||
result.set(float32Array, offset);
|
||||
offset += float32Array.length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class SlidingWindowVoiceTranscriber extends VoiceTranscriber {
|
||||
|
||||
private readonly transcriptionQueue = this._register(new Queue());
|
||||
|
||||
private transcribedResults: string[] = [];
|
||||
private data: Float32Array = new Float32Array(0);
|
||||
|
||||
protected async handleRequest(data: Float32Array, cancellation: CancellationToken): Promise<void> {
|
||||
if (data.length > 0) {
|
||||
this.logService.info(`[voice] transcriber: voice detected, storing in buffer`);
|
||||
|
||||
this.data = this.data ? this.joinFloat32Arrays([this.data, data]) : data;
|
||||
} else {
|
||||
this.logService.info(`[voice] transcriber: silence detected, transcribing window...`);
|
||||
|
||||
const data = this.data.slice(0);
|
||||
this.data = new Float32Array(0);
|
||||
|
||||
this.transcriptionQueue.queue(() => this.transcribe(data, cancellation));
|
||||
}
|
||||
}
|
||||
|
||||
private async transcribe(data: Float32Array, cancellation: CancellationToken): Promise<void> {
|
||||
if (cancellation.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.length > VoiceTranscriber.MAX_DATA_LENGTH) {
|
||||
this.logService.warn(`[voice] transcriber: refusing to accept more than 30s of audio data`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.length !== 0) {
|
||||
const result = await this.voiceRecognitionService.transcribe(data, cancellation);
|
||||
if (result) {
|
||||
this.transcribedResults.push(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (cancellation.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.port.postMessage(this.transcribedResults.join(' '));
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.data = new Float32Array(0);
|
||||
}
|
||||
}
|
||||
|
||||
class FullWindowVoiceTranscriber extends VoiceTranscriber {
|
||||
|
||||
private readonly transcriptionQueue = new LimitedQueue();
|
||||
|
||||
private data: Float32Array | undefined = undefined;
|
||||
|
||||
private transcribedDataLength = 0;
|
||||
private transcribedResult = '';
|
||||
|
||||
protected async handleRequest(data: Float32Array, cancellation: CancellationToken): Promise<void> {
|
||||
const dataCandidate = this.data ? this.joinFloat32Arrays([this.data, data]) : data;
|
||||
if (dataCandidate.length > VoiceTranscriber.MAX_DATA_LENGTH) {
|
||||
this.logService.warn(`[voice] transcriber: refusing to accept more than 30s of audio data`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.data = dataCandidate;
|
||||
|
||||
this.transcriptionQueue.queue(() => this.transcribe(cancellation));
|
||||
}
|
||||
|
||||
private async transcribe(cancellation: CancellationToken): Promise<void> {
|
||||
if (cancellation.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = this.data?.slice(0);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result: string;
|
||||
if (data.length === this.transcribedDataLength) {
|
||||
// Optimization: if the data is the same as the last time
|
||||
// we transcribed, don't transcribe again, just return the
|
||||
// same result as we had last time.
|
||||
this.logService.info(`[voice] transcriber: silence detected, reusing previous transcription result`);
|
||||
result = this.transcribedResult;
|
||||
} else {
|
||||
this.logService.info(`[voice] transcriber: voice detected, transcribing everything...`);
|
||||
result = await this.voiceRecognitionService.transcribe(data, cancellation);
|
||||
}
|
||||
|
||||
this.transcribedResult = result;
|
||||
this.transcribedDataLength = data.length;
|
||||
|
||||
if (cancellation.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.port.postMessage(result);
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.data = undefined;
|
||||
}
|
||||
}
|
||||
@@ -114,8 +114,6 @@ import { IRemoteSocketFactoryService, RemoteSocketFactoryService } from 'vs/plat
|
||||
import { RemoteConnectionType } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory';
|
||||
import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import { IVoiceRecognitionService, VoiceRecognitionService } from 'vs/platform/voiceRecognition/node/voiceRecognitionService';
|
||||
import { VoiceTranscriptionManager } from 'vs/code/node/sharedProcess/contrib/voiceTranscriber';
|
||||
import { SharedProcessRawConnection, SharedProcessLifecycle } from 'vs/platform/sharedProcess/common/sharedProcess';
|
||||
|
||||
class SharedProcessMain extends Disposable implements IClientConnectionFilter {
|
||||
@@ -183,8 +181,7 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
|
||||
instantiationService.createInstance(LogsDataCleaner),
|
||||
instantiationService.createInstance(LocalizationsUpdater),
|
||||
instantiationService.createInstance(ExtensionsContributions),
|
||||
instantiationService.createInstance(UserDataProfilesCleaner),
|
||||
instantiationService.createInstance(VoiceTranscriptionManager, this.onDidWindowConnectRaw.event)
|
||||
instantiationService.createInstance(UserDataProfilesCleaner)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -367,9 +364,6 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter {
|
||||
// Remote Tunnel
|
||||
services.set(IRemoteTunnelService, new SyncDescriptor(RemoteTunnelService));
|
||||
|
||||
// Voice Recognition
|
||||
services.set(IVoiceRecognitionService, new SyncDescriptor(VoiceRecognitionService));
|
||||
|
||||
return new InstantiationService(services);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ export class MenuId {
|
||||
static readonly EmptyEditorGroup = new MenuId('EmptyEditorGroup');
|
||||
static readonly EmptyEditorGroupContext = new MenuId('EmptyEditorGroupContext');
|
||||
static readonly EditorTabsBarContext = new MenuId('EditorTabsBarContext');
|
||||
static readonly EditorTabsBarShowTabsSubmenu = new MenuId('EditorTabsBarShowTabsSubmenu');
|
||||
static readonly ExplorerContext = new MenuId('ExplorerContext');
|
||||
static readonly ExplorerContextShare = new MenuId('ExplorerContextShare');
|
||||
static readonly ExtensionContext = new MenuId('ExtensionContext');
|
||||
|
||||
@@ -19,7 +19,6 @@ import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtil
|
||||
import { parseSharedProcessDebugPort } from 'vs/platform/environment/node/environmentService';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { SharedProcessChannelConnection, SharedProcessRawConnection, SharedProcessLifecycle } from 'vs/platform/sharedProcess/common/sharedProcess';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
export class SharedProcess extends Disposable {
|
||||
|
||||
@@ -35,8 +34,7 @@ export class SharedProcess extends Disposable {
|
||||
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@ILoggerMainService private readonly loggerMainService: ILoggerMainService,
|
||||
@IPolicyService private readonly policyService: IPolicyService,
|
||||
@IProductService private readonly productService: IProductService
|
||||
@IPolicyService private readonly policyService: IPolicyService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -165,8 +163,7 @@ export class SharedProcess extends Disposable {
|
||||
type: 'shared-process',
|
||||
entryPoint: 'vs/code/node/sharedProcess/sharedProcessMain',
|
||||
payload: this.createSharedProcessConfiguration(),
|
||||
execArgv,
|
||||
allowLoadingUnsignedLibraries: !!process.env.VSCODE_VOICE_MODULE_PATH && this.productService.quality !== 'stable' // TODO@bpasero package
|
||||
execArgv
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -227,8 +227,9 @@ export const selectionBackground = registerColor('selection.background', { light
|
||||
export const textSeparatorForeground = registerColor('textSeparator.foreground', { light: '#0000002e', dark: '#ffffff2e', hcDark: Color.black, hcLight: '#292929' }, nls.localize('textSeparatorForeground', "Color for text separators."));
|
||||
export const textLinkForeground = registerColor('textLink.foreground', { light: '#006AB1', dark: '#3794FF', hcDark: '#3794FF', hcLight: '#0F4A85' }, nls.localize('textLinkForeground', "Foreground color for links in text."));
|
||||
export const textLinkActiveForeground = registerColor('textLink.activeForeground', { light: '#006AB1', dark: '#3794FF', hcDark: '#3794FF', hcLight: '#0F4A85' }, nls.localize('textLinkActiveForeground', "Foreground color for links in text when clicked on and on mouse hover."));
|
||||
export const textPreformatForeground = registerColor('textPreformat.foreground', { light: '#A31515', dark: '#D7BA7D', hcDark: '#D7BA7D', hcLight: '#292929' }, nls.localize('textPreformatForeground', "Foreground color for preformatted text segments."));
|
||||
export const textBlockQuoteBackground = registerColor('textBlockQuote.background', { light: '#7f7f7f1a', dark: '#7f7f7f1a', hcDark: null, hcLight: '#F2F2F2' }, nls.localize('textBlockQuoteBackground', "Background color for block quotes in text."));
|
||||
export const textPreformatForeground = registerColor('textPreformat.foreground', { light: '#A31515', dark: '#D7BA7D', hcDark: '#000000', hcLight: '#FFFFFF' }, nls.localize('textPreformatForeground', "Foreground color for preformatted text segments."));
|
||||
export const textPreformatBackground = registerColor('textPreformat.background', { light: '#0000001A', dark: '#FFFFFF1A', hcDark: '#FFFFFF', hcLight: '#09345f' }, nls.localize('textPreformatBackground', "Background color for preformatted text segments."));
|
||||
export const textBlockQuoteBackground = registerColor('textBlockQuote.background', { light: '#f2f2f2', dark: '#222222', hcDark: null, hcLight: '#F2F2F2' }, nls.localize('textBlockQuoteBackground', "Background color for block quotes in text."));
|
||||
export const textBlockQuoteBorder = registerColor('textBlockQuote.border', { light: '#007acc80', dark: '#007acc80', hcDark: Color.white, hcLight: '#292929' }, nls.localize('textBlockQuoteBorder', "Border color for block quotes in text."));
|
||||
export const textCodeBlockBackground = registerColor('textCodeBlock.background', { light: '#dcdcdc66', dark: '#0a0a0a66', hcDark: Color.black, hcLight: '#F2F2F2' }, nls.localize('textCodeBlockBackground', "Background color for code blocks in text."));
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
export const IVoiceRecognitionService = createDecorator<IVoiceRecognitionService>('voiceRecognitionService');
|
||||
|
||||
export interface IVoiceRecognitionService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Given a buffer of audio data, attempts to
|
||||
* transcribe the spoken words into text.
|
||||
*
|
||||
* @param channelData the raw audio data obtained
|
||||
* from the microphone as uncompressed PCM data:
|
||||
* - 1 channel (mono)
|
||||
* - 16khz sampling rate
|
||||
* - 16bit sample size
|
||||
*/
|
||||
transcribe(channelData: Float32Array, cancellation: CancellationToken): Promise<string>;
|
||||
}
|
||||
|
||||
export class VoiceRecognitionService implements IVoiceRecognitionService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IProductService private readonly productService: IProductService
|
||||
) { }
|
||||
|
||||
async transcribe(channelData: Float32Array, cancellation: CancellationToken): Promise<string> {
|
||||
const modulePath = process.env.VSCODE_VOICE_MODULE_PATH; // TODO@bpasero package
|
||||
if (!modulePath || this.productService.quality === 'stable') {
|
||||
this.logService.error(`[voice] transcribe(${channelData.length}): Voice recognition not yet supported`);
|
||||
throw new Error('Voice recognition not yet supported!');
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
try {
|
||||
const voiceModule: {
|
||||
transcribe: (
|
||||
audioBuffer: { channelCount: 1; samplingRate: 16000; bitDepth: 16; channelData: Float32Array },
|
||||
options: {
|
||||
language: string | 'auto';
|
||||
signal: AbortSignal;
|
||||
}
|
||||
) => Promise<string>;
|
||||
} = require.__$__nodeRequire(modulePath);
|
||||
|
||||
const abortController = new AbortController();
|
||||
cancellation.onCancellationRequested(() => abortController.abort());
|
||||
|
||||
const text = await voiceModule.transcribe({
|
||||
samplingRate: 16000,
|
||||
bitDepth: 16,
|
||||
channelCount: 1,
|
||||
channelData
|
||||
}, {
|
||||
language: 'en',
|
||||
signal: abortController.signal
|
||||
});
|
||||
|
||||
this.logService.info(`[voice] transcribe(${channelData.length}): Text "${text}", took ${Date.now() - now}ms)`);
|
||||
|
||||
return text;
|
||||
} catch (error) {
|
||||
this.logService.error(`[voice] transcribe(${channelData.length}): Failed width "${error}", took ${Date.now() - now}ms)`);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,11 @@ import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataPro
|
||||
import { INativeWindowConfiguration } from 'vs/platform/window/common/window';
|
||||
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
export interface ICodeWindow extends IDisposable {
|
||||
export interface IBaseWindow extends IDisposable {
|
||||
focus(options?: { force: boolean }): void;
|
||||
}
|
||||
|
||||
export interface ICodeWindow extends IBaseWindow {
|
||||
|
||||
readonly onWillLoad: Event<ILoadEvent>;
|
||||
readonly onDidSignalReady: Event<void>;
|
||||
@@ -49,7 +53,6 @@ export interface ICodeWindow extends IDisposable {
|
||||
load(config: INativeWindowConfiguration, options?: { isReload?: boolean }): void;
|
||||
reload(cli?: NativeParsedArgs): void;
|
||||
|
||||
focus(options?: { force: boolean }): void;
|
||||
close(): void;
|
||||
|
||||
getBounds(): Rectangle;
|
||||
|
||||
@@ -35,7 +35,7 @@ import { getMenuBarVisibility, getTitleBarStyle, IFolderToOpen, INativeWindowCon
|
||||
import { defaultBrowserWindowOptions, IWindowsMainService, OpenContext } from 'vs/platform/windows/electron-main/windows';
|
||||
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService';
|
||||
import { IWindowState, ICodeWindow, ILoadEvent, WindowMode, WindowError, LoadReason, defaultWindowState } from 'vs/platform/window/electron-main/window';
|
||||
import { IWindowState, ICodeWindow, ILoadEvent, WindowMode, WindowError, LoadReason, defaultWindowState, IBaseWindow } from 'vs/platform/window/electron-main/window';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { IPolicyService } from 'vs/platform/policy/common/policy';
|
||||
import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';
|
||||
@@ -82,7 +82,7 @@ const enum ReadyState {
|
||||
READY
|
||||
}
|
||||
|
||||
export abstract class BaseWindow extends Disposable {
|
||||
export abstract class BaseWindow extends Disposable implements IBaseWindow {
|
||||
|
||||
protected abstract getWin(): BrowserWindow | null;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { Disposable, DisposableMap } from 'vs/base/common/lifecycle';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { UriComponents } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { ExtHostChatAgentsShape2, ExtHostContext, IChatResponseProgressDto, IChatResponseProgressFileTreeData, IExtensionChatAgentMetadata, ILocationDto, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { isCompleteInteractiveProgressTreeData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
@@ -44,13 +43,13 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
||||
this._proxy.$releaseSession(e.sessionId);
|
||||
}));
|
||||
this._register(this._chatService.onDidPerformUserAction(e => {
|
||||
if (e.agentId) {
|
||||
if (typeof e.agentId === 'string') {
|
||||
for (const [handle, agent] of this._agents) {
|
||||
if (agent.name === e.agentId) {
|
||||
if (e.action.kind === 'vote') {
|
||||
this._proxy.$acceptFeedback(handle, e.sessionId, e.action.direction);
|
||||
this._proxy.$acceptFeedback(handle, e.sessionId, e.requestId, e.action.direction);
|
||||
} else {
|
||||
this._proxy.$acceptAction(handle, e.sessionId, e);
|
||||
this._proxy.$acceptAction(handle, e.sessionId, e.requestId, e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -68,12 +67,11 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
||||
id: name,
|
||||
metadata: revive(metadata),
|
||||
invoke: async (request, progress, history, token) => {
|
||||
const requestId = generateUuid();
|
||||
this._pendingProgress.set(requestId, progress);
|
||||
this._pendingProgress.set(request.requestId, progress);
|
||||
try {
|
||||
return await this._proxy.$invokeAgent(handle, request.sessionId, requestId, request, { history }, token) ?? {};
|
||||
return await this._proxy.$invokeAgent(handle, request.sessionId, request.requestId, request, { history }, token) ?? {};
|
||||
} finally {
|
||||
this._pendingProgress.delete(requestId);
|
||||
this._pendingProgress.delete(request.requestId);
|
||||
}
|
||||
},
|
||||
provideFollowups: async (sessionId, token): Promise<IChatFollowup[]> => {
|
||||
|
||||
@@ -1185,8 +1185,8 @@ export interface ExtHostChatAgentsShape2 {
|
||||
$invokeAgent(handle: number, sessionId: string, requestId: string, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise<IChatAgentResult | undefined>;
|
||||
$provideSlashCommands(handle: number, token: CancellationToken): Promise<IChatAgentCommand[]>;
|
||||
$provideFollowups(handle: number, sessionId: string, token: CancellationToken): Promise<IChatFollowup[]>;
|
||||
$acceptFeedback(handle: number, sessionId: string, vote: InteractiveSessionVoteDirection): void;
|
||||
$acceptAction(handle: number, sessionId: string, action: IChatUserActionEvent): void;
|
||||
$acceptFeedback(handle: number, sessionId: string, requestId: string, vote: InteractiveSessionVoteDirection): void;
|
||||
$acceptAction(handle: number, sessionId: string, requestId: string, action: IChatUserActionEvent): void;
|
||||
$releaseSession(sessionId: string): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||
private readonly _proxy: MainThreadChatAgentsShape2;
|
||||
|
||||
private readonly _previousResultMap: Map<string, vscode.ChatAgentResult2> = new Map();
|
||||
private readonly _resultsBySessionAndRequestId: Map<string, Map<string, vscode.ChatAgentResult2>> = new Map();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
@@ -49,6 +50,10 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||
}
|
||||
|
||||
async $invokeAgent(handle: number, sessionId: string, requestId: string, request: IChatAgentRequest, context: { history: IChatMessage[] }, token: CancellationToken): Promise<IChatAgentResult | undefined> {
|
||||
// Clear the previous result so that $acceptFeedback or $acceptAction during a request will be ignored.
|
||||
// We may want to support sending those during a request.
|
||||
this._previousResultMap.delete(sessionId);
|
||||
|
||||
const agent = this._agents.get(handle);
|
||||
if (!agent) {
|
||||
throw new Error(`[CHAT](${handle}) CANNOT invoke agent because the agent is not registered`);
|
||||
@@ -100,6 +105,13 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||
return await raceCancellation(Promise.resolve(task).then((result) => {
|
||||
if (result) {
|
||||
this._previousResultMap.set(sessionId, result);
|
||||
let sessionResults = this._resultsBySessionAndRequestId.get(sessionId);
|
||||
if (!sessionResults) {
|
||||
sessionResults = new Map();
|
||||
this._resultsBySessionAndRequestId.set(sessionId, sessionResults);
|
||||
}
|
||||
sessionResults.set(requestId, result);
|
||||
|
||||
return { errorDetails: result.errorDetails }; // TODO timings here
|
||||
} else {
|
||||
this._previousResultMap.delete(sessionId);
|
||||
@@ -124,6 +136,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||
|
||||
$releaseSession(sessionId: string): void {
|
||||
this._previousResultMap.delete(sessionId);
|
||||
this._resultsBySessionAndRequestId.delete(sessionId);
|
||||
}
|
||||
|
||||
async $provideSlashCommands(handle: number, token: CancellationToken): Promise<IChatAgentCommand[]> {
|
||||
@@ -149,12 +162,12 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||
return agent.provideFollowups(result, token);
|
||||
}
|
||||
|
||||
$acceptFeedback(handle: number, sessionId: string, vote: InteractiveSessionVoteDirection): void {
|
||||
$acceptFeedback(handle: number, sessionId: string, requestId: string, vote: InteractiveSessionVoteDirection): void {
|
||||
const agent = this._agents.get(handle);
|
||||
if (!agent) {
|
||||
return;
|
||||
}
|
||||
const result = this._previousResultMap.get(sessionId);
|
||||
const result = this._resultsBySessionAndRequestId.get(sessionId)?.get(requestId);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
@@ -171,12 +184,12 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
||||
agent.acceptFeedback(Object.freeze({ result, kind }));
|
||||
}
|
||||
|
||||
$acceptAction(handle: number, sessionId: string, action: IChatUserActionEvent): void {
|
||||
$acceptAction(handle: number, sessionId: string, requestId: string, action: IChatUserActionEvent): void {
|
||||
const agent = this._agents.get(handle);
|
||||
if (!agent) {
|
||||
return;
|
||||
}
|
||||
const result = this._previousResultMap.get(sessionId);
|
||||
const result = this._resultsBySessionAndRequestId.get(sessionId)?.get(requestId);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
@@ -302,7 +315,6 @@ class ExtHostChatAgent {
|
||||
that._iconPath = v;
|
||||
updateMetadataSoon();
|
||||
},
|
||||
// onDidPerformAction
|
||||
get slashCommandProvider() {
|
||||
return that._slashCommandProvider;
|
||||
},
|
||||
|
||||
@@ -470,49 +470,87 @@ export class ToggleStatusbarVisibilityAction extends Action2 {
|
||||
|
||||
registerAction2(ToggleStatusbarVisibilityAction);
|
||||
|
||||
// --- Bse Class Toggle Boolean Setting Action
|
||||
// --- Hide Editor Tabs
|
||||
|
||||
abstract class BaseToggleBooleanSettingAction extends Action2 {
|
||||
export class HideEditorTabsAction extends Action2 {
|
||||
|
||||
protected abstract get settingId(): string;
|
||||
|
||||
override run(accessor: ServicesAccessor): Promise<void> {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
|
||||
const oldettingValue = configurationService.getValue<string>(this.settingId);
|
||||
const newSettingValue = !oldettingValue;
|
||||
|
||||
return configurationService.updateValue(this.settingId, newSettingValue);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Toggle Tabs Visibility
|
||||
|
||||
export class ToggleTabsVisibilityAction extends BaseToggleBooleanSettingAction {
|
||||
|
||||
static readonly ID = 'workbench.action.toggleTabsVisibility';
|
||||
static readonly ID = 'workbench.action.hideEditorTabs';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: ToggleTabsVisibilityAction.ID,
|
||||
id: HideEditorTabsAction.ID,
|
||||
title: {
|
||||
value: localize('toggleTabs', "Toggle Editor Tab Visibility"),
|
||||
original: 'Toggle Editor Tab Visibility'
|
||||
value: localize('hideEditorTabs', "Hide Editor Tabs"),
|
||||
original: 'Hide Editor Tabs'
|
||||
},
|
||||
category: Categories.View,
|
||||
precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none').negate(),
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
protected override get settingId(): string {
|
||||
return 'workbench.editor.showTabs';
|
||||
override run(accessor: ServicesAccessor): Promise<void> {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
return configurationService.updateValue('workbench.editor.showTabs', 'none');
|
||||
}
|
||||
}
|
||||
registerAction2(ToggleTabsVisibilityAction);
|
||||
registerAction2(HideEditorTabsAction);
|
||||
|
||||
// --- Show Multiple Editor Tabs
|
||||
|
||||
export class ShowMultipleEditorTabsAction extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.showMultipleEditorTabs';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: ShowMultipleEditorTabsAction.ID,
|
||||
title: {
|
||||
value: localize('showMultipleEditorTabs', "Show Multiple Editor Tabs"),
|
||||
original: 'Show Multiple Editor Tabs'
|
||||
},
|
||||
category: Categories.View,
|
||||
precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple').negate(),
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
override run(accessor: ServicesAccessor): Promise<void> {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
return configurationService.updateValue('workbench.editor.showTabs', 'multiple');
|
||||
}
|
||||
}
|
||||
registerAction2(ShowMultipleEditorTabsAction);
|
||||
|
||||
// --- Show Single Editor Tab
|
||||
|
||||
export class ShowSingleEditorTabAction extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.showEditorTab';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: ShowSingleEditorTabAction.ID,
|
||||
title: {
|
||||
value: localize('showSingleEditorTab', "Show Single Editor Tab"),
|
||||
original: 'Show Single Editor Tab'
|
||||
},
|
||||
category: Categories.View,
|
||||
precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single').negate(),
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
override run(accessor: ServicesAccessor): Promise<void> {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
return configurationService.updateValue('workbench.editor.showTabs', 'single');
|
||||
}
|
||||
}
|
||||
registerAction2(ShowSingleEditorTabAction);
|
||||
|
||||
// --- Toggle Pinned Tabs On Separate Row
|
||||
|
||||
export class ToggleSeparatePinnedTabsAction extends BaseToggleBooleanSettingAction {
|
||||
export class ToggleSeparatePinnedTabsAction extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.toggleSeparatePinnedEditorTabs';
|
||||
|
||||
@@ -524,13 +562,18 @@ export class ToggleSeparatePinnedTabsAction extends BaseToggleBooleanSettingActi
|
||||
original: 'Separate Pinned Editor Tabs'
|
||||
},
|
||||
category: Categories.View,
|
||||
precondition: ContextKeyExpr.has('config.workbench.editor.showTabs'),
|
||||
precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple'),
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
protected override get settingId(): string {
|
||||
return 'workbench.editor.pinnedTabsOnSeparateRow';
|
||||
override run(accessor: ServicesAccessor): Promise<void> {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
|
||||
const oldettingValue = configurationService.getValue<string>('workbench.editor.pinnedTabsOnSeparateRow');
|
||||
const newSettingValue = !oldettingValue;
|
||||
|
||||
return configurationService.updateValue('workbench.editor.pinnedTabsOnSeparateRow', newSettingValue);
|
||||
}
|
||||
}
|
||||
registerAction2(ToggleSeparatePinnedTabsAction);
|
||||
|
||||
@@ -271,7 +271,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
|
||||
}
|
||||
|
||||
private updateEditorAreaContextKeys(): void {
|
||||
this.editorTabsVisibleContext.set(!!this.editorGroupService.partOptions.showTabs);
|
||||
this.editorTabsVisibleContext.set(this.editorGroupService.partOptions.showTabs === 'multiple');
|
||||
}
|
||||
|
||||
private updateEditorContextKeys(): void {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { EventType, addDisposableListener, getClientArea, Dimension, position, size, IDimension, isAncestorUsingFlowTo, computeScreenAwareSize, getActiveDocument, getWindows } from 'vs/base/browser/dom';
|
||||
import { EventType, addDisposableListener, getClientArea, Dimension, position, size, IDimension, isAncestorUsingFlowTo, computeScreenAwareSize, getActiveDocument, getWindows, getActiveWindow } from 'vs/base/browser/dom';
|
||||
import { onDidChangeFullscreen, isFullscreen, isWCOEnabled } from 'vs/base/browser/browser';
|
||||
import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup';
|
||||
import { isWindows, isLinux, isMacintosh, isWeb, isNative, isIOS } from 'vs/base/common/platform';
|
||||
@@ -1238,8 +1238,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
this.state.runtime.zenMode.transitionDisposables.add(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
|
||||
}
|
||||
|
||||
if (config.hideTabs && this.editorGroupService.partOptions.showTabs) {
|
||||
this.state.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: false }));
|
||||
if (config.showTabs !== this.editorGroupService.partOptions.showTabs) {
|
||||
this.state.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: config.showTabs }));
|
||||
}
|
||||
|
||||
if (config.silentNotifications && zenModeExitInfo.handleNotificationsDoNotDisturbMode) {
|
||||
@@ -1463,8 +1463,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
}
|
||||
|
||||
resizePart(part: Parts, sizeChangeWidth: number, sizeChangeHeight: number): void {
|
||||
const sizeChangePxWidth = Math.sign(sizeChangeWidth) * computeScreenAwareSize(window, Math.abs(sizeChangeWidth));
|
||||
const sizeChangePxHeight = Math.sign(sizeChangeHeight) * computeScreenAwareSize(window, Math.abs(sizeChangeHeight));
|
||||
const sizeChangePxWidth = Math.sign(sizeChangeWidth) * computeScreenAwareSize(getActiveWindow(), Math.abs(sizeChangeWidth));
|
||||
const sizeChangePxHeight = Math.sign(sizeChangeHeight) * computeScreenAwareSize(getActiveWindow(), Math.abs(sizeChangeHeight));
|
||||
|
||||
let viewSize: IViewSize;
|
||||
|
||||
@@ -2311,7 +2311,7 @@ type ZenModeConfiguration = {
|
||||
hideActivityBar: boolean;
|
||||
hideLineNumbers: boolean;
|
||||
hideStatusBar: boolean;
|
||||
hideTabs: boolean;
|
||||
showTabs: 'multiple' | 'single' | 'none';
|
||||
restore: boolean;
|
||||
silentNotifications: boolean;
|
||||
};
|
||||
|
||||
@@ -64,7 +64,7 @@ import { Codicon } from 'vs/base/common/codicons';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
import { UntitledTextEditorInputSerializer, UntitledTextEditorWorkingCopyEditorHandler } from 'vs/workbench/services/untitled/common/untitledTextEditorHandler';
|
||||
import { DynamicEditorConfigurations } from 'vs/workbench/browser/parts/editor/editorConfiguration';
|
||||
import { ToggleSeparatePinnedTabsAction, ToggleTabsVisibilityAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
import { HideEditorTabsAction, ShowMultipleEditorTabsAction, ShowSingleEditorTabAction, ToggleSeparatePinnedTabsAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { ICommandAction } from 'vs/platform/action/common/action';
|
||||
|
||||
@@ -354,7 +354,10 @@ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '2_split', order: 20 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleTabsVisibilityAction.ID, title: localize('toggleTabs', "Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.showTabs') }, group: '3_config', order: 10 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { submenu: MenuId.EditorTabsBarShowTabsSubmenu, title: localize('showTabs', "Show Tabs"), group: '3_config', order: 10 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowMultipleEditorTabsAction.ID, title: localize('multipleTabs', "Multiple Tabs"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }, group: '1_config', order: 10 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowSingleEditorTabAction.ID, title: localize('singleTab', "Single Tab"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single') }, group: '1_config', order: 20 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: HideEditorTabsAction.ID, title: localize('hideTabBar', "Hide Tab Bar"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none') }, group: '1_config', order: 30 });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleSeparatePinnedTabsAction.ID, title: localize('toggleSeparatePinnedEditorTabs', "Separate Pinned Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.pinnedTabsOnSeparateRow') }, when: EditorPinnedAndUnpinnedTabsContext, group: '3_config', order: 20 });
|
||||
|
||||
// Editor Title Context Menu
|
||||
|
||||
@@ -25,7 +25,7 @@ export const DEFAULT_EDITOR_MIN_DIMENSIONS = new Dimension(220, 70);
|
||||
export const DEFAULT_EDITOR_MAX_DIMENSIONS = new Dimension(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
|
||||
|
||||
export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
|
||||
showTabs: true,
|
||||
showTabs: 'multiple',
|
||||
highlightModifiedTabs: false,
|
||||
tabCloseButton: 'right',
|
||||
tabSizing: 'fit',
|
||||
@@ -85,9 +85,21 @@ export function getEditorPartOptions(configurationService: IConfigurationService
|
||||
options.tabHeight = windowConfig.window.density.editorTabHeight;
|
||||
}
|
||||
|
||||
validateEditorPartOptions(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function validateEditorPartOptions(options: IEditorPartOptions) {
|
||||
// showTabs ensure correct enum value
|
||||
if (typeof options.showTabs === 'boolean') {
|
||||
// Migration service kicks in very late and can cause a flicker otherwise
|
||||
options.showTabs = options.showTabs ? 'multiple' : 'single';
|
||||
} else if (options.showTabs !== 'multiple' && options.showTabs !== 'single' && options.showTabs !== 'none') {
|
||||
options.showTabs = 'multiple';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to access editor groups across all opened editor parts.
|
||||
*/
|
||||
|
||||
@@ -530,7 +530,7 @@ class DropOverlay extends Themable {
|
||||
private getOverlayOffsetHeight(): number {
|
||||
|
||||
// With tabs and opened editors: use the area below tabs as drop target
|
||||
if (!this.groupView.isEmpty && this.editorGroupService.partOptions.showTabs) {
|
||||
if (!this.groupView.isEmpty && this.editorGroupService.partOptions.showTabs === 'multiple') {
|
||||
return this.groupView.titleHeight.offset;
|
||||
}
|
||||
|
||||
|
||||
@@ -464,7 +464,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
}
|
||||
|
||||
private updateTitleContainer(): void {
|
||||
this.titleContainer.classList.toggle('tabs', this.groupsView.partOptions.showTabs);
|
||||
this.titleContainer.classList.toggle('tabs', this.groupsView.partOptions.showTabs === 'multiple');
|
||||
this.titleContainer.classList.toggle('show-file-icons', this.groupsView.partOptions.showIcons);
|
||||
}
|
||||
|
||||
@@ -700,7 +700,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
// Title control switch between singleEditorTabs, multiEditorTabs and multiRowEditorTabs
|
||||
if (
|
||||
event.oldPartOptions.showTabs !== event.newPartOptions.showTabs ||
|
||||
(event.oldPartOptions.showTabs && event.oldPartOptions.pinnedTabsOnSeparateRow !== event.newPartOptions.pinnedTabsOnSeparateRow)
|
||||
(event.oldPartOptions.showTabs === 'multiple' && event.oldPartOptions.pinnedTabsOnSeparateRow !== event.newPartOptions.pinnedTabsOnSeparateRow)
|
||||
) {
|
||||
|
||||
// Re-layout
|
||||
@@ -1892,7 +1892,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
}
|
||||
|
||||
const { showTabs } = this.groupsView.partOptions;
|
||||
this.titleContainer.style.backgroundColor = this.getColor(showTabs ? EDITOR_GROUP_HEADER_TABS_BACKGROUND : EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND) || '';
|
||||
this.titleContainer.style.backgroundColor = this.getColor(showTabs === 'multiple' ? EDITOR_GROUP_HEADER_TABS_BACKGROUND : EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND) || '';
|
||||
|
||||
// Editor container
|
||||
this.editorContainer.style.backgroundColor = this.getColor(editorBackground) || '';
|
||||
|
||||
@@ -290,7 +290,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC
|
||||
|
||||
// Drag all tabs of the group if tabs are enabled
|
||||
let hasDataTransfer = false;
|
||||
if (this.groupsView.partOptions.showTabs) {
|
||||
if (this.groupsView.partOptions.showTabs === 'multiple') {
|
||||
hasDataTransfer = this.doFillResourceDataTransfers(this.groupView.getEditors(EditorsOrder.SEQUENTIAL), e);
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC
|
||||
// Drag Image
|
||||
if (this.groupView.activeEditor) {
|
||||
let label = this.groupView.activeEditor.getName();
|
||||
if (this.groupsView.partOptions.showTabs && this.groupView.count > 1) {
|
||||
if (this.groupsView.partOptions.showTabs === 'multiple' && this.groupView.count > 1) {
|
||||
label = localize('draggedEditorGroup', "{0} (+{1})", label, this.groupView.count - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { MultiRowEditorControl } from 'vs/workbench/browser/parts/editor/multiRowEditorTabsControl';
|
||||
import { IReadonlyEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { NoEditorTabsControl } from 'vs/workbench/browser/parts/editor/noEditorTabsControl';
|
||||
|
||||
export interface IEditorTitleControlDimensions {
|
||||
|
||||
@@ -57,23 +58,27 @@ export class EditorTitleControl extends Themable {
|
||||
}
|
||||
|
||||
private createEditorTabsControl(): IEditorTabsControl {
|
||||
let control: IEditorTabsControl;
|
||||
if (this.groupsView.partOptions.showTabs) {
|
||||
if (this.groupsView.partOptions.pinnedTabsOnSeparateRow) {
|
||||
control = this.instantiationService.createInstance(MultiRowEditorControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model);
|
||||
} else {
|
||||
control = this.instantiationService.createInstance(MultiEditorTabsControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model);
|
||||
}
|
||||
} else {
|
||||
control = this.instantiationService.createInstance(SingleEditorTabsControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model);
|
||||
let tabsControlType;
|
||||
switch (this.groupsView.partOptions.showTabs) {
|
||||
case 'none':
|
||||
tabsControlType = NoEditorTabsControl;
|
||||
break;
|
||||
case 'single':
|
||||
tabsControlType = SingleEditorTabsControl;
|
||||
break;
|
||||
case 'multiple':
|
||||
default:
|
||||
tabsControlType = this.groupsView.partOptions.pinnedTabsOnSeparateRow ? MultiRowEditorControl : MultiEditorTabsControl;
|
||||
break;
|
||||
}
|
||||
|
||||
const control = this.instantiationService.createInstance(tabsControlType, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model);
|
||||
return this.editorTabsControlDisposable.add(control);
|
||||
}
|
||||
|
||||
private createBreadcrumbsControl(): BreadcrumbsControlFactory | undefined {
|
||||
if (!this.groupsView.partOptions.showTabs) {
|
||||
return undefined; // single tabs have breadcrumbs inlined
|
||||
if (this.groupsView.partOptions.showTabs !== 'multiple') {
|
||||
return undefined; // Single tabs have breadcrumbs inlined. No tabs have no breadcrumbs.
|
||||
}
|
||||
|
||||
// Breadcrumbs container
|
||||
@@ -170,7 +175,7 @@ export class EditorTitleControl extends Themable {
|
||||
// Update editor tabs control if options changed
|
||||
if (
|
||||
oldOptions.showTabs !== newOptions.showTabs ||
|
||||
(newOptions.showTabs && oldOptions.pinnedTabsOnSeparateRow !== newOptions.pinnedTabsOnSeparateRow)
|
||||
(newOptions.showTabs === 'multiple' && oldOptions.pinnedTabsOnSeparateRow !== newOptions.pinnedTabsOnSeparateRow)
|
||||
) {
|
||||
// Clear old
|
||||
this.editorTabsControlDisposable.clear();
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/* Breadcrumbs (inline next to single editor tab) */
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .no-tabs.title-label {
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .single-tab.title-label {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/singleeditortabscontrol';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { EditorTabsControl, IToolbarActions } from 'vs/workbench/browser/parts/editor/editorTabsControl';
|
||||
import { Dimension } from 'vs/base/browser/dom';
|
||||
import { IEditorTitleControlDimensions } from 'vs/workbench/browser/parts/editor/editorTitleControl';
|
||||
|
||||
export class NoEditorTabsControl extends EditorTabsControl {
|
||||
|
||||
protected prepareEditorActions(editorActions: IToolbarActions): IToolbarActions {
|
||||
return {
|
||||
primary: [],
|
||||
secondary: []
|
||||
};
|
||||
}
|
||||
|
||||
openEditor(editor: EditorInput): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
openEditors(editors: EditorInput[]): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
beforeCloseEditor(editor: EditorInput): void { }
|
||||
|
||||
closeEditor(editor: EditorInput): void { }
|
||||
|
||||
closeEditors(editors: EditorInput[]): void { }
|
||||
|
||||
moveEditor(editor: EditorInput, fromIndex: number, targetIndex: number): void { }
|
||||
|
||||
pinEditor(editor: EditorInput): void { }
|
||||
|
||||
stickEditor(editor: EditorInput): void { }
|
||||
|
||||
unstickEditor(editor: EditorInput): void { }
|
||||
|
||||
setActive(isActive: boolean): void { }
|
||||
|
||||
updateEditorLabel(editor: EditorInput): void { }
|
||||
|
||||
updateEditorDirty(editor: EditorInput): void { }
|
||||
|
||||
getHeight(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
layout(dimensions: IEditorTitleControlDimensions): Dimension {
|
||||
return new Dimension(dimensions.container.width, this.getHeight());
|
||||
}
|
||||
}
|
||||
@@ -317,7 +317,7 @@ export class SingleEditorTabsControl extends EditorTabsControl {
|
||||
{
|
||||
title,
|
||||
italic: !isEditorPinned,
|
||||
extraClasses: ['no-tabs', 'title-label'].concat(editor.getLabelExtraClasses()),
|
||||
extraClasses: ['single-tab', 'title-label'].concat(editor.getLabelExtraClasses()),
|
||||
fileDecorations: {
|
||||
colors: Boolean(options.decorations?.colors),
|
||||
badges: Boolean(options.decorations?.badges)
|
||||
|
||||
@@ -172,12 +172,12 @@
|
||||
|
||||
.monaco-workbench .pane-composite-part > .title > .composite-bar-container > .composite-bar > .monaco-action-bar .action-item.icon .badge.compact .badge-content {
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
top: 12px;
|
||||
right: 0px;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
min-width: 12px;
|
||||
height: 12px;
|
||||
height: 11px;
|
||||
padding: 0 2px;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { INotificationsCenterController, NotificationActionRunner } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { isAncestor, Dimension } from 'vs/base/browser/dom';
|
||||
import { Dimension, isAncestorOfActiveElement } from 'vs/base/browser/dom';
|
||||
import { widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -25,6 +25,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { assertAllDefined, assertIsDefined } from 'vs/base/common/types';
|
||||
import { NotificationsCenterVisibleContext } from 'vs/workbench/common/contextkeys';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';
|
||||
|
||||
export class NotificationsCenter extends Themable implements INotificationsCenterController {
|
||||
|
||||
@@ -53,6 +54,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
|
||||
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IAccessibleNotificationService private readonly accessibleNotificationService: IAccessibleNotificationService
|
||||
) {
|
||||
super(themeService);
|
||||
|
||||
@@ -220,7 +222,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
|
||||
notificationsList.updateNotificationsList(e.index, 1, [e.item]);
|
||||
break;
|
||||
case NotificationChangeType.REMOVE:
|
||||
focusEditor = isAncestor(document.activeElement, notificationsCenterContainer);
|
||||
focusEditor = isAncestorOfActiveElement(notificationsCenterContainer);
|
||||
notificationsList.updateNotificationsList(e.index, 1);
|
||||
e.item.updateVisibility(false);
|
||||
break;
|
||||
@@ -245,7 +247,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
|
||||
return; // already hidden
|
||||
}
|
||||
|
||||
const focusEditor = isAncestor(document.activeElement, this.notificationsCenterContainer);
|
||||
const focusEditor = isAncestorOfActiveElement(this.notificationsCenterContainer);
|
||||
|
||||
// Hide
|
||||
this._isVisible = false;
|
||||
@@ -329,6 +331,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
|
||||
if (!notification.hasProgress) {
|
||||
notification.close();
|
||||
}
|
||||
this.accessibleNotificationService.notify(AccessibleNotificationEvent.Clear);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { ActionRunner, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { firstOrDefault } from 'vs/base/common/arrays';
|
||||
import { AccessibleNotificationEvent, IAccessibleNotificationService } from 'vs/platform/accessibility/common/accessibility';
|
||||
|
||||
// Center
|
||||
export const SHOW_NOTIFICATIONS_CENTER = 'notifications.showList';
|
||||
@@ -138,9 +139,11 @@ export function registerNotificationCommands(center: INotificationsCenterControl
|
||||
primary: KeyMod.CtrlCmd | KeyCode.Backspace
|
||||
},
|
||||
handler: (accessor, args?) => {
|
||||
const accessibleNotificationService = accessor.get(IAccessibleNotificationService);
|
||||
const notification = getNotificationFromContext(accessor.get(IListService), args);
|
||||
if (notification && !notification.hasProgress) {
|
||||
notification.close();
|
||||
accessibleNotificationService.notify(AccessibleNotificationEvent.Clear);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import 'vs/css!./media/notificationsList';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isAncestor, trackFocus } from 'vs/base/browser/dom';
|
||||
import { isAncestorOfActiveElement, trackFocus } from 'vs/base/browser/dom';
|
||||
import { WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IListAccessibilityProvider, IListOptions } from 'vs/base/browser/ui/list/listWidget';
|
||||
@@ -133,7 +133,7 @@ export class NotificationsList extends Disposable {
|
||||
|
||||
updateNotificationsList(start: number, deleteCount: number, items: INotificationViewItem[] = []) {
|
||||
const [list, listContainer] = assertAllDefined(this.list, this.listContainer);
|
||||
const listHasDOMFocus = isAncestor(document.activeElement, listContainer);
|
||||
const listHasDOMFocus = isAncestorOfActiveElement(listContainer);
|
||||
|
||||
// Remember focus and relative top of that item
|
||||
const focusedIndex = list.getFocus()[0];
|
||||
@@ -223,7 +223,7 @@ export class NotificationsList extends Disposable {
|
||||
return false; // not created yet
|
||||
}
|
||||
|
||||
return isAncestor(document.activeElement, this.listContainer);
|
||||
return isAncestorOfActiveElement(this.listContainer);
|
||||
}
|
||||
|
||||
layout(width: number, maxHeight?: number): void {
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'vs/css!./media/notificationsToasts';
|
||||
import { localize } from 'vs/nls';
|
||||
import { INotificationsModel, NotificationChangeType, INotificationChangeEvent, INotificationViewItem, NotificationViewItemContentChangeKind } from 'vs/workbench/common/notifications';
|
||||
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { isAncestor, addDisposableListener, EventType, Dimension, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
|
||||
import { addDisposableListener, EventType, Dimension, scheduleAtNextAnimationFrame, isAncestorOfActiveElement } from 'vs/base/browser/dom';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
@@ -322,7 +322,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast
|
||||
// UI
|
||||
const notificationToast = this.mapNotificationToToast.get(item);
|
||||
if (notificationToast) {
|
||||
const toastHasDOMFocus = isAncestor(document.activeElement, notificationToast.container);
|
||||
const toastHasDOMFocus = isAncestorOfActiveElement(notificationToast.container);
|
||||
if (toastHasDOMFocus) {
|
||||
focusEditor = !(this.focusNext() || this.focusPrevious()); // focus next if any, otherwise focus editor
|
||||
}
|
||||
@@ -380,7 +380,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
const focusEditor = this.notificationsToastsContainer ? isAncestor(document.activeElement, this.notificationsToastsContainer) : false;
|
||||
const focusEditor = this.notificationsToastsContainer ? isAncestorOfActiveElement(this.notificationsToastsContainer) : false;
|
||||
|
||||
this.removeToasts();
|
||||
|
||||
|
||||
@@ -444,12 +444,12 @@
|
||||
|
||||
.monaco-workbench .part.titlebar > .titlebar-container > .titlebar-right > .global-actions-container .monaco-action-bar .action-item.icon .badge.compact .badge-content {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
top: 11px;
|
||||
right: 0px;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
min-width: 12px;
|
||||
height: 12px;
|
||||
height: 11px;
|
||||
padding: 0 2px;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
|
||||
@@ -39,23 +39,29 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
|
||||
default: 'default',
|
||||
},
|
||||
'workbench.editor.showTabs': {
|
||||
'type': 'boolean',
|
||||
'description': localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."),
|
||||
'default': true
|
||||
'type': 'string',
|
||||
'enum': ['multiple', 'single', 'none'],
|
||||
'enumDescriptions': [
|
||||
localize('workbench.editor.showTabs.multiple', "Each editor is displayed as a tab in the editor title area."),
|
||||
localize('workbench.editor.showTabs.single', "The active editor is displayed as a single large tab in the editor title area."),
|
||||
localize('workbench.editor.showTabs.none', "The editor title area is not displayed."),
|
||||
],
|
||||
'description': localize('showEditorTabs', "Controls whether opened editors should show as individual tabs, one single large tab or if the title area should not be shown."),
|
||||
'default': 'multiple'
|
||||
},
|
||||
'workbench.editor.wrapTabs': {
|
||||
'type': 'boolean',
|
||||
'markdownDescription': localize('wrapTabs', "Controls whether tabs should be wrapped over multiple lines when exceeding available space or whether a scrollbar should appear instead. This value is ignored when `#workbench.editor.showTabs#` is disabled."),
|
||||
'markdownDescription': localize('wrapTabs', "Controls whether tabs should be wrapped over multiple lines when exceeding available space or whether a scrollbar should appear instead. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."),
|
||||
'default': false
|
||||
},
|
||||
'workbench.editor.scrollToSwitchTabs': {
|
||||
'type': 'boolean',
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'scrollToSwitchTabs' }, "Controls whether scrolling over tabs will open them or not. By default tabs will only reveal upon scrolling, but not open. You can press and hold the Shift-key while scrolling to change this behavior for that duration. This value is ignored when `#workbench.editor.showTabs#` is disabled."),
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'scrollToSwitchTabs' }, "Controls whether scrolling over tabs will open them or not. By default tabs will only reveal upon scrolling, but not open. You can press and hold the Shift-key while scrolling to change this behavior for that duration. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."),
|
||||
'default': false
|
||||
},
|
||||
'workbench.editor.highlightModifiedTabs': {
|
||||
'type': 'boolean',
|
||||
'markdownDescription': localize('highlightModifiedTabs', "Controls whether a top border is drawn on tabs for editors that have unsaved changes. This value is ignored when `#workbench.editor.showTabs#` is disabled."),
|
||||
'markdownDescription': localize('highlightModifiedTabs', "Controls whether a top border is drawn on tabs for editors that have unsaved changes. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."),
|
||||
'default': false
|
||||
},
|
||||
'workbench.editor.decorations.badges': {
|
||||
@@ -141,7 +147,7 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
|
||||
'type': 'string',
|
||||
'enum': ['left', 'right', 'off'],
|
||||
'default': 'right',
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'. This value is ignored when `#workbench.editor.showTabs#` is disabled.")
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.")
|
||||
},
|
||||
'workbench.editor.tabSizing': {
|
||||
'type': 'string',
|
||||
@@ -152,7 +158,7 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
|
||||
localize('workbench.editor.tabSizing.shrink', "Allow tabs to get smaller when the available space is not enough to show all tabs at once."),
|
||||
localize('workbench.editor.tabSizing.fixed', "Make all tabs the same size, while allowing them to get smaller when the available space is not enough to show all tabs at once.")
|
||||
],
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the size of editor tabs. This value is ignored when `#workbench.editor.showTabs#` is disabled.")
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the size of editor tabs. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.")
|
||||
},
|
||||
'workbench.editor.tabSizingFixedMinWidth': {
|
||||
'type': 'number',
|
||||
@@ -170,7 +176,7 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
|
||||
'type': 'string',
|
||||
'enum': ['default', 'compact'],
|
||||
'default': 'default',
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.editor.tabHeight' }, "Controls the height of editor tabs. Also applies to the title control bar when `#workbench.editor.showTabs#` is disabled.")
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.editor.tabHeight' }, "Controls the height of editor tabs. Also applies to the title control bar when `#workbench.editor.showTabs#` is not set to `multiple`.")
|
||||
},
|
||||
'workbench.editor.pinnedTabSizing': {
|
||||
'type': 'string',
|
||||
@@ -181,12 +187,12 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
|
||||
localize('workbench.editor.pinnedTabSizing.compact', "A pinned tab will show in a compact form with only icon or first letter of the editor name."),
|
||||
localize('workbench.editor.pinnedTabSizing.shrink', "A pinned tab shrinks to a compact fixed size showing parts of the editor name.")
|
||||
],
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'pinnedTabSizing' }, "Controls the size of pinned editor tabs. Pinned tabs are sorted to the beginning of all opened tabs and typically do not close until unpinned. This value is ignored when `#workbench.editor.showTabs#` is disabled.")
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'pinnedTabSizing' }, "Controls the size of pinned editor tabs. Pinned tabs are sorted to the beginning of all opened tabs and typically do not close until unpinned. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.")
|
||||
},
|
||||
'workbench.editor.pinnedTabsOnSeparateRow': {
|
||||
'type': 'boolean',
|
||||
'default': false,
|
||||
'markdownDescription': localize('workbench.editor.pinnedTabsOnSeparateRow', "When enabled, displays pinned tabs in a separate row above all other tabs. This value is ignored when `#workbench.editor.showTabs#` is disabled."),
|
||||
'markdownDescription': localize('workbench.editor.pinnedTabsOnSeparateRow', "When enabled, displays pinned tabs in a separate row above all other tabs. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`."),
|
||||
},
|
||||
'workbench.editor.preventPinnedEditorClose': {
|
||||
'type': 'string',
|
||||
@@ -318,7 +324,7 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
|
||||
'workbench.editor.doubleClickTabToToggleEditorGroupSizes': {
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'doubleClickTabToToggleEditorGroupSizes' }, "Controls whether to maximize/restore the editor group when double clicking on a tab. This value is ignored when `#workbench.editor.showTabs#` is disabled.")
|
||||
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'doubleClickTabToToggleEditorGroupSizes' }, "Controls whether to maximize/restore the editor group when double clicking on a tab. This value is ignored when `#workbench.editor.showTabs#` is not set to `multiple`.")
|
||||
},
|
||||
'workbench.editor.limit.enabled': {
|
||||
'type': 'boolean',
|
||||
@@ -721,10 +727,16 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
|
||||
'default': true,
|
||||
'description': localize('zenMode.centerLayout', "Controls whether turning on Zen Mode also centers the layout.")
|
||||
},
|
||||
'zenMode.hideTabs': {
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'description': localize('zenMode.hideTabs', "Controls whether turning on Zen Mode also hides workbench tabs.")
|
||||
'zenMode.showTabs': {
|
||||
'type': 'string',
|
||||
'enum': ['multiple', 'single', 'none'],
|
||||
'description': localize('zenMode.showTabs', "Controls whether turning on Zen Mode should show multiple editor tabs, a single editor tab or hide the editor title area completely."),
|
||||
'enumDescriptions': [
|
||||
localize('zenMode.showTabs.multiple', "Each editor is displayed as a tab in the editor title area."),
|
||||
localize('zenMode.showTabs.single', "The active editor is displayed as a single large tab in the editor title area."),
|
||||
localize('zenMode.showTabs.none', "The editor title area is not displayed."),
|
||||
],
|
||||
'default': 'multiple'
|
||||
},
|
||||
'zenMode.hideStatusBar': {
|
||||
'type': 'boolean',
|
||||
@@ -765,3 +777,24 @@ Registry.as<IConfigurationMigrationRegistry>(Extensions.ConfigurationMigration)
|
||||
return result;
|
||||
}
|
||||
}]);
|
||||
|
||||
Registry.as<IConfigurationMigrationRegistry>(Extensions.ConfigurationMigration)
|
||||
.registerConfigurationMigrations([{
|
||||
key: 'workbench.editor.showTabs', migrateFn: (value: any) => {
|
||||
if (typeof value === 'boolean') {
|
||||
value = value ? 'multiple' : 'single';
|
||||
}
|
||||
return [['workbench.editor.showTabs', { value: value }]];
|
||||
}
|
||||
}]);
|
||||
|
||||
Registry.as<IConfigurationMigrationRegistry>(Extensions.ConfigurationMigration)
|
||||
.registerConfigurationMigrations([{
|
||||
key: 'zenMode.hideTabs', migrateFn: (value: any) => {
|
||||
const result: ConfigurationKeyValuePairs = [['zenMode.hideTabs', { value: undefined }]];
|
||||
if (value === true) {
|
||||
result.push(['zenMode.showTabs', { value: 'single' }]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}]);
|
||||
|
||||
@@ -1096,7 +1096,7 @@ export interface IWorkbenchEditorConfiguration {
|
||||
}
|
||||
|
||||
interface IEditorPartConfiguration {
|
||||
showTabs?: boolean;
|
||||
showTabs?: 'multiple' | 'single' | 'none';
|
||||
wrapTabs?: boolean;
|
||||
scrollToSwitchTabs?: boolean;
|
||||
highlightModifiedTabs?: boolean;
|
||||
|
||||
@@ -256,7 +256,7 @@ export const EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND = registerColor('editorGroup
|
||||
light: editorBackground,
|
||||
hcDark: editorBackground,
|
||||
hcLight: editorBackground
|
||||
}, localize('editorGroupHeaderBackground', "Background color of the editor group title header when tabs are disabled (`\"workbench.editor.showTabs\": false`). Editor groups are the containers of editors."));
|
||||
}, localize('editorGroupHeaderBackground', "Background color of the editor group title header when (`\"workbench.editor.showTabs\": \"single\"`). Editor groups are the containers of editors."));
|
||||
|
||||
export const EDITOR_GROUP_HEADER_BORDER = registerColor('editorGroupHeader.border', {
|
||||
dark: null,
|
||||
@@ -911,7 +911,7 @@ export const COMMAND_CENTER_ACTIVEBACKGROUND = registerColor(
|
||||
);
|
||||
// border: active and inactive. defaults to active background
|
||||
export const COMMAND_CENTER_BORDER = registerColor(
|
||||
'commandCenter.border', { dark: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .20), hcDark: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .60), light: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .20), hcLight: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .60) },
|
||||
'commandCenter.border', { dark: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .20), hcDark: contrastBorder, light: transparent(TITLE_BAR_ACTIVE_FOREGROUND, .20), hcLight: contrastBorder },
|
||||
localize('commandCenter-border', "Border color of the command center"),
|
||||
false
|
||||
);
|
||||
|
||||
@@ -125,10 +125,10 @@ const configuration: IConfigurationNode = {
|
||||
...baseProperty
|
||||
},
|
||||
[AccessibilityAlertSettingId.Save]: {
|
||||
'markdownDescription': localize('alert.save', "When in screen reader mode, alerts when a file is saved. Also see {0}", '`#audioCues.save#`'),
|
||||
'markdownDescription': localize('alert.save', "When in screen reader mode, alerts when a file is saved. Note that this will be ignored when {0} is enabled.", '`#audioCues.save#`'),
|
||||
'type': 'string',
|
||||
'enum': ['userGesture', 'always', 'never'],
|
||||
'default': 'never',
|
||||
'default': 'always',
|
||||
'enumDescriptions': [
|
||||
localize('alert.save.userGesture', "Alerts when a file is saved via user gesture."),
|
||||
localize('alert.save.always', "Alerts whenever is a file is saved, including auto save."),
|
||||
@@ -137,10 +137,10 @@ const configuration: IConfigurationNode = {
|
||||
tags: ['accessibility']
|
||||
},
|
||||
[AccessibilityAlertSettingId.Format]: {
|
||||
'markdownDescription': localize('alert.format', "When in screen reader mode, alerts when a file or notebook cell is formatted. Also see {0}", '`#audioCues.format#`'),
|
||||
'markdownDescription': localize('alert.format', "When in screen reader mode, alerts when a file or notebook cell is formatted. Note that this will be ignored when {0} is enabled.", '`#audioCues.format#`'),
|
||||
'type': 'string',
|
||||
'enum': ['userGesture', 'always', 'never'],
|
||||
'default': 'never',
|
||||
'default': 'always',
|
||||
'enumDescriptions': [
|
||||
localize('alert.format.userGesture', "Alerts when a file is formatted via user gesture."),
|
||||
localize('alert.format.always', "Alerts whenever is a file is formatted, including auto save, on cell execution, and more."),
|
||||
|
||||
@@ -50,16 +50,19 @@ export class AccessibleNotificationService extends Disposable implements IAccess
|
||||
if (!alertSetting) {
|
||||
return;
|
||||
}
|
||||
const alertSettingValue: NotificationSetting = this._configurationService.getValue(alertSetting);
|
||||
if (this._shouldNotify(alertSettingValue, userGesture)) {
|
||||
this._logService.debug('AccessibleNotificationService alerting: ', alertMessage);
|
||||
this._accessibilityService.alert(alertMessage);
|
||||
}
|
||||
const audioCueSetting: NotificationSetting = this._configurationService.getValue(audioCue.settingsKey);
|
||||
if (this._shouldNotify(audioCueSetting, userGesture)) {
|
||||
this._logService.debug('AccessibleNotificationService playing sound: ', audioCue.name);
|
||||
console.log('AccessibleNotificationService playing sound: ', audioCue.name);
|
||||
// Play sound bypasses the usual audio cue checks IE screen reader optimized, auto, etc.
|
||||
this._audioCueService.playSound(audioCue.sound.getSound(), true);
|
||||
return;
|
||||
}
|
||||
const alertSettingValue: NotificationSetting = this._configurationService.getValue(alertSetting);
|
||||
if (this._shouldNotify(alertSettingValue, userGesture)) {
|
||||
this._logService.debug('AccessibleNotificationService alerting: ', alertMessage);
|
||||
console.log('AccessibleNotificationService alerting: ', alertMessage);
|
||||
this._accessibilityService.alert(alertMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EventType, addDisposableListener, isActiveElement } from 'vs/base/browser/dom';
|
||||
import { EventType, addDisposableListener, getActiveWindow, isActiveElement } from 'vs/base/browser/dom';
|
||||
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
@@ -57,7 +57,7 @@ export interface IAccessibleContentProvider {
|
||||
actions?: IAction[];
|
||||
provideContent(): string;
|
||||
onClose(): void;
|
||||
onKeyUp?(e: IKeyboardEvent): void;
|
||||
onKeyDown?(e: IKeyboardEvent): void;
|
||||
previous?(): void;
|
||||
next?(): void;
|
||||
/**
|
||||
@@ -264,7 +264,7 @@ export class AccessibleView extends Disposable {
|
||||
return;
|
||||
}
|
||||
const delegate: IContextViewDelegate = {
|
||||
getAnchor: () => { return { x: (window.innerWidth / 2) - ((Math.min(this._layoutService.dimension.width * 0.62 /* golden cut */, DIMENSIONS.MAX_WIDTH)) / 2), y: this._layoutService.offset.quickPickTop }; },
|
||||
getAnchor: () => { return { x: (getActiveWindow().innerWidth / 2) - ((Math.min(this._layoutService.dimension.width * 0.62 /* golden cut */, DIMENSIONS.MAX_WIDTH)) / 2), y: this._layoutService.offset.quickPickTop }; },
|
||||
render: (container) => {
|
||||
container.classList.add('accessible-view-container');
|
||||
return this._render(provider!, container, showAccessibleViewHelp);
|
||||
@@ -507,7 +507,6 @@ export class AccessibleView extends Disposable {
|
||||
setTimeout(() => provider.onClose(), 100);
|
||||
};
|
||||
const disposableStore = new DisposableStore();
|
||||
disposableStore.add(this._editorWidget.onKeyUp((e) => provider.onKeyUp?.(e)));
|
||||
disposableStore.add(this._editorWidget.onKeyDown((e) => {
|
||||
if (e.keyCode === KeyCode.Escape) {
|
||||
handleEscape(e);
|
||||
@@ -518,6 +517,7 @@ export class AccessibleView extends Disposable {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
provider.onKeyDown?.(e);
|
||||
}));
|
||||
disposableStore.add(addDisposableListener(this._toolbar.getElement(), EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
const keyboardEvent = new StandardKeyboardEvent(e);
|
||||
|
||||
@@ -28,7 +28,7 @@ import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatAct
|
||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { ICodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
||||
import { CONTEXT_IN_CHAT_SESSION, CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
import { IChatCopyAction, IChatService, IChatUserActionEvent, IDocumentContext, InteractiveSessionCopyKind } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatCopyAction, IChatService, IDocumentContext, InteractiveSessionCopyKind } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||
import { CTX_INLINE_CHAT_VISIBLE } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||
import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
|
||||
@@ -106,10 +106,11 @@ export function registerChatCodeBlockActions() {
|
||||
|
||||
if (isResponseVM(context.element)) {
|
||||
const chatService = accessor.get(IChatService);
|
||||
chatService.notifyUserAction(<IChatUserActionEvent>{
|
||||
chatService.notifyUserAction({
|
||||
providerId: context.element.providerId,
|
||||
agentId: context.element.agent?.id,
|
||||
sessionId: context.element.sessionId,
|
||||
requestId: context.element.requestId,
|
||||
action: <IChatCopyAction>{
|
||||
kind: 'copy',
|
||||
responseId: context.element.providerResponseId,
|
||||
@@ -154,6 +155,7 @@ export function registerChatCodeBlockActions() {
|
||||
providerId: context.element.providerId,
|
||||
agentId: context.element.agent?.id,
|
||||
sessionId: context.element.sessionId,
|
||||
requestId: context.element.requestId,
|
||||
action: {
|
||||
kind: 'copy',
|
||||
codeBlockIndex: context.codeBlockIndex,
|
||||
@@ -328,13 +330,14 @@ export function registerChatCodeBlockActions() {
|
||||
private notifyUserAction(accessor: ServicesAccessor, context: ICodeBlockActionContext) {
|
||||
if (isResponseVM(context.element)) {
|
||||
const chatService = accessor.get(IChatService);
|
||||
chatService.notifyUserAction(<IChatUserActionEvent>{
|
||||
chatService.notifyUserAction({
|
||||
providerId: context.element.providerId,
|
||||
agentId: context.element.agent?.id,
|
||||
sessionId: context.element.sessionId,
|
||||
requestId: context.element.requestId,
|
||||
action: {
|
||||
kind: 'insert',
|
||||
responseId: context.element.providerResponseId,
|
||||
responseId: context.element.providerResponseId!,
|
||||
codeBlockIndex: context.codeBlockIndex,
|
||||
totalCharacters: context.code.length,
|
||||
}
|
||||
@@ -376,13 +379,14 @@ export function registerChatCodeBlockActions() {
|
||||
editorService.openEditor(<IUntitledTextResourceEditorInput>{ contents: context.code, languageId: context.languageId, resource: undefined });
|
||||
|
||||
if (isResponseVM(context.element)) {
|
||||
chatService.notifyUserAction(<IChatUserActionEvent>{
|
||||
chatService.notifyUserAction({
|
||||
providerId: context.element.providerId,
|
||||
agentId: context.element.agent?.id,
|
||||
sessionId: context.element.sessionId,
|
||||
requestId: context.element.requestId,
|
||||
action: {
|
||||
kind: 'insert',
|
||||
responseId: context.element.providerResponseId,
|
||||
responseId: context.element.providerResponseId!,
|
||||
codeBlockIndex: context.codeBlockIndex,
|
||||
totalCharacters: context.code.length,
|
||||
newFile: true
|
||||
@@ -461,13 +465,14 @@ export function registerChatCodeBlockActions() {
|
||||
terminal.sendText(context.code, false, true);
|
||||
|
||||
if (isResponseVM(context.element)) {
|
||||
chatService.notifyUserAction(<IChatUserActionEvent>{
|
||||
chatService.notifyUserAction({
|
||||
providerId: context.element.providerId,
|
||||
agentId: context.element.agent?.id,
|
||||
sessionId: context.element.sessionId,
|
||||
requestId: context.element.requestId,
|
||||
action: {
|
||||
kind: 'runInTerminal',
|
||||
responseId: context.element.providerResponseId,
|
||||
responseId: context.element.providerResponseId!,
|
||||
codeBlockIndex: context.codeBlockIndex,
|
||||
languageId: context.languageId,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/
|
||||
import { CHAT_CATEGORY } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_REQUEST, CONTEXT_RESPONSE, CONTEXT_RESPONSE_FILTERED, CONTEXT_RESPONSE_VOTE } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
import { IChatService, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatService, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { isRequestVM, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellEditType, CellKind, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
@@ -52,14 +52,15 @@ export function registerChatTitleActions() {
|
||||
}
|
||||
|
||||
const chatService = accessor.get(IChatService);
|
||||
chatService.notifyUserAction(<IChatUserActionEvent>{
|
||||
chatService.notifyUserAction({
|
||||
providerId: item.providerId,
|
||||
agentId: item.agent?.id,
|
||||
sessionId: item.sessionId,
|
||||
requestId: item.requestId,
|
||||
action: {
|
||||
kind: 'vote',
|
||||
direction: InteractiveSessionVoteDirection.Up,
|
||||
responseId: item.providerResponseId,
|
||||
responseId: item.providerResponseId!,
|
||||
}
|
||||
});
|
||||
item.setVote(InteractiveSessionVoteDirection.Up);
|
||||
@@ -94,14 +95,15 @@ export function registerChatTitleActions() {
|
||||
}
|
||||
|
||||
const chatService = accessor.get(IChatService);
|
||||
chatService.notifyUserAction(<IChatUserActionEvent>{
|
||||
chatService.notifyUserAction({
|
||||
providerId: item.providerId,
|
||||
agentId: item.agent?.id,
|
||||
sessionId: item.sessionId,
|
||||
requestId: item.requestId,
|
||||
action: {
|
||||
kind: 'vote',
|
||||
direction: InteractiveSessionVoteDirection.Down,
|
||||
responseId: item.providerResponseId,
|
||||
responseId: item.providerResponseId!,
|
||||
}
|
||||
});
|
||||
item.setVote(InteractiveSessionVoteDirection.Down);
|
||||
|
||||
@@ -79,6 +79,9 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
private inputEditorHasText: IContextKey<boolean>;
|
||||
private providerId: string | undefined;
|
||||
|
||||
private cachedDimensions: dom.Dimension | undefined;
|
||||
private cachedToolbarWidth: number | undefined;
|
||||
|
||||
readonly inputUri = URI.parse(`${ChatInputPart.INPUT_SCHEME}:input-${ChatInputPart._counter++}`);
|
||||
|
||||
constructor(
|
||||
@@ -251,6 +254,11 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
}));
|
||||
this.toolbar.getElement().classList.add('interactive-execute-toolbar');
|
||||
this.toolbar.context = <IChatExecuteActionContext>{ widget };
|
||||
this._register(this.toolbar.onDidChangeMenuItems(() => {
|
||||
if (this.cachedDimensions && typeof this.cachedToolbarWidth === 'number' && this.cachedToolbarWidth !== this.toolbar.getItemsWidth()) {
|
||||
this.layout(this.cachedDimensions.height, this.cachedDimensions.width);
|
||||
}
|
||||
}));
|
||||
|
||||
if (this.options.renderStyle === 'compact') {
|
||||
const toolbarSide = this._register(this.instantiationService.createInstance(MenuWorkbenchToolBar, inputAndSideToolbar, MenuId.ChatInputSide, {
|
||||
@@ -285,6 +293,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
}
|
||||
|
||||
layout(height: number, width: number): number {
|
||||
this.cachedDimensions = new dom.Dimension(width, height);
|
||||
|
||||
return this._layout(height, width);
|
||||
}
|
||||
|
||||
@@ -301,7 +311,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
|
||||
const editorBorder = 2;
|
||||
const editorPadding = 8;
|
||||
const executeToolbarWidth = this.toolbar.getItemsWidth();
|
||||
const executeToolbarWidth = this.cachedToolbarWidth = this.toolbar.getItemsWidth();
|
||||
const sideToolbarWidth = this.options.renderStyle === 'compact' ? 20 : 0;
|
||||
|
||||
const initialEditorScrollWidth = this._inputEditor.getScrollWidth();
|
||||
|
||||
@@ -353,6 +353,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
||||
providerId: element.providerId,
|
||||
agentId: element.agent?.id,
|
||||
sessionId: element.sessionId,
|
||||
requestId: element.requestId,
|
||||
action: {
|
||||
kind: 'command',
|
||||
command: followup,
|
||||
@@ -620,7 +621,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
||||
});
|
||||
const container = $('.chat-used-context', undefined, buttonElement);
|
||||
collapseButton.label = referencesLabel;
|
||||
collapseButton.element.prepend(iconElement);
|
||||
collapseButton.element.append(iconElement);
|
||||
|
||||
container.classList.toggle('chat-used-context-collapsed', !element.usedReferencesExpanded);
|
||||
listDisposables.add(collapseButton.onDidClick(() => {
|
||||
|
||||
@@ -82,6 +82,10 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
|
||||
this.viewState.sessionId = model.sessionId;
|
||||
}
|
||||
|
||||
override shouldShowWelcome(): boolean {
|
||||
return !this.chatService.hasProviders();
|
||||
}
|
||||
|
||||
protected override renderBody(parent: HTMLElement): void {
|
||||
try {
|
||||
super.renderBody(parent);
|
||||
|
||||
@@ -412,20 +412,28 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||
|
||||
this._register(this.inputPart.onDidFocus(() => this._onDidFocus.fire()));
|
||||
this._register(this.inputPart.onDidAcceptFollowup(e => {
|
||||
// this.chatService.notifyUserAction
|
||||
if (!this.viewModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.acceptInput(e.followup.message);
|
||||
|
||||
if (!e.response) {
|
||||
// Followups can be shown by the welcome message, then there is no response associated.
|
||||
// At some point we probably want telemetry for these too.
|
||||
return;
|
||||
}
|
||||
|
||||
this.chatService.notifyUserAction({
|
||||
providerId: this.viewModel.providerId,
|
||||
sessionId: this.viewModel.sessionId,
|
||||
requestId: e.response.requestId,
|
||||
agentId: e.response?.agent?.id,
|
||||
action: {
|
||||
kind: 'followUp',
|
||||
followup: e.followup
|
||||
},
|
||||
});
|
||||
this.acceptInput(e.followup.message);
|
||||
}));
|
||||
this._register(this.inputPart.onDidChangeHeight(() => this.bodyDimension && this.layout(this.bodyDimension.height, this.bodyDimension.width)));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
padding: 16px 20px 16px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
gap: 8px;
|
||||
color: var(--vscode-interactive-session-foreground);
|
||||
|
||||
cursor: default;
|
||||
@@ -169,7 +169,11 @@
|
||||
.interactive-item-container .monaco-tokenized-source,
|
||||
.interactive-item-container code {
|
||||
font-family: var(--monaco-monospace-font);
|
||||
font-size: 12px;
|
||||
color: var(--vscode-textPreformat-foreground);
|
||||
background-color: var(--vscode-textPreformat-background);
|
||||
padding: 1px 3px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.interactive-item-container.interactive-item-compact {
|
||||
@@ -260,7 +264,7 @@
|
||||
.interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor,
|
||||
.interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor .margin,
|
||||
.interactive-response .interactive-result-code-block .interactive-result-editor .monaco-editor .monaco-editor-background {
|
||||
background-color: var(--vscode-interactive-result-editor-background-color);
|
||||
background-color: var(--vscode-interactive-result-editor-background-color) !important;
|
||||
}
|
||||
|
||||
.interactive-item-compact .interactive-result-code-block {
|
||||
@@ -332,10 +336,12 @@
|
||||
.interactive-session .interactive-input-part .interactive-input-followups .interactive-session-followups .monaco-button {
|
||||
display: block;
|
||||
color: var(--vscode-textLink-foreground);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.interactive-session .interactive-input-part .interactive-input-followups .interactive-session-followups code {
|
||||
font-family: var(--monaco-monospace-font);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.interactive-session .interactive-input-part .interactive-input-followups .interactive-session-followups .monaco-button .codicon-sparkle {
|
||||
@@ -356,7 +362,7 @@
|
||||
color: var(--vscode-icon-foreground) !important;
|
||||
}
|
||||
|
||||
.interactive-item-container.filtered-response .value .rendered-markdown {
|
||||
.interactive-item-container.filtered-response .value > .rendered-markdown {
|
||||
-webkit-mask-image: linear-gradient(rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.05));
|
||||
mask-image: linear-gradient(rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.05));
|
||||
}
|
||||
@@ -421,19 +427,26 @@
|
||||
.interactive-item-container .chat-resource-widget {
|
||||
background-color: var(--vscode-chat-slashCommandBackground);
|
||||
color: var(--vscode-chat-slashCommandForeground);
|
||||
border-radius: 3px;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
padding: 1px;
|
||||
padding: 1px 3px;
|
||||
}
|
||||
|
||||
.interactive-session .chat-used-context.chat-used-context-collapsed .chat-used-context-list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.interactive-session .chat-used-context {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.interactive-session .chat-used-context-list {
|
||||
border: 1px solid var(--vscode-chat-requestBorder);
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.interactive-session .chat-used-context-list .monaco-list .monaco-list-row {
|
||||
@@ -458,13 +471,16 @@
|
||||
padding: 0;
|
||||
text-align: initial;
|
||||
justify-content: initial;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.interactive-session .chat-used-context-label .monaco-text-button {
|
||||
outline-offset: unset !important;
|
||||
.interactive-session .chat-used-context-label .monaco-text-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.interactive-session .chat-used-context-label .monaco-text-button:focus-visible {
|
||||
outline: 1px solid var(--vscode-focusBorder);
|
||||
}
|
||||
|
||||
.interactive-session .chat-used-context .chat-used-context-label .monaco-button .codicon {
|
||||
margin: 0 2px 0 0;
|
||||
margin: 0 0 0 4px;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ export interface IChatResponseModel {
|
||||
readonly id: string;
|
||||
readonly providerId: string;
|
||||
readonly providerResponseId: string | undefined;
|
||||
readonly requestId: string;
|
||||
readonly username: string;
|
||||
readonly avatarIconUri?: URI;
|
||||
readonly session: IChatModel;
|
||||
@@ -294,6 +295,7 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel
|
||||
_response: IMarkdownString | ReadonlyArray<IMarkdownString | IChatResponseProgressFileTreeData | IChatContentInlineReference>,
|
||||
public readonly session: ChatModel,
|
||||
public readonly agent: IChatAgent | undefined,
|
||||
public readonly requestId: string,
|
||||
private _isComplete: boolean = false,
|
||||
private _isCanceled = false,
|
||||
private _vote?: InteractiveSessionVoteDirection,
|
||||
@@ -565,7 +567,7 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
const request = new ChatRequestModel(this, parsedRequest, raw.providerRequestId);
|
||||
if (raw.response || raw.responseErrorDetails) {
|
||||
const agent = raw.agent && this.chatAgentService.getAgents().find(a => a.id === raw.agent!.id); // TODO do something reasonable if this agent has disappeared since the last session
|
||||
request.response = new ChatResponseModel(raw.response ?? [new MarkdownString(raw.response)], this, agent, true, raw.isCanceled, raw.vote, raw.providerRequestId, raw.responseErrorDetails, raw.followups);
|
||||
request.response = new ChatResponseModel(raw.response ?? [new MarkdownString(raw.response)], this, agent, request.id, true, raw.isCanceled, raw.vote, raw.providerRequestId, raw.responseErrorDetails, raw.followups);
|
||||
if (raw.usedContext) { // @ulugbekna: if this's a new vscode sessions, doc versions are incorrect anyway?
|
||||
request.response.updateContent(raw.usedContext);
|
||||
}
|
||||
@@ -652,7 +654,7 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
}
|
||||
|
||||
const request = new ChatRequestModel(this, message);
|
||||
request.response = new ChatResponseModel([], this, chatAgent);
|
||||
request.response = new ChatResponseModel([], this, chatAgent, request.id);
|
||||
|
||||
this._requests.push(request);
|
||||
this._onDidChange.fire({ kind: 'addRequest', request });
|
||||
@@ -665,7 +667,7 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
}
|
||||
|
||||
if (!request.response) {
|
||||
request.response = new ChatResponseModel([], this, undefined);
|
||||
request.response = new ChatResponseModel([], this, undefined, request.id);
|
||||
}
|
||||
|
||||
if (request.response.isComplete) {
|
||||
@@ -710,7 +712,7 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
}
|
||||
|
||||
if (!request.response) {
|
||||
request.response = new ChatResponseModel([], this, undefined);
|
||||
request.response = new ChatResponseModel([], this, undefined, request.id);
|
||||
}
|
||||
|
||||
request.response.setErrorDetails(rawResponse.errorDetails);
|
||||
|
||||
@@ -212,7 +212,7 @@ export interface IChatCommandAction {
|
||||
|
||||
export interface IChatFollowupAction {
|
||||
kind: 'followUp';
|
||||
followup: IChatFollowup;
|
||||
followup: IChatReplyFollowup;
|
||||
}
|
||||
|
||||
export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction;
|
||||
@@ -222,6 +222,7 @@ export interface IChatUserActionEvent {
|
||||
providerId: string;
|
||||
agentId: string | undefined;
|
||||
sessionId: string;
|
||||
requestId: string;
|
||||
}
|
||||
|
||||
export interface IChatDynamicRequest {
|
||||
@@ -265,6 +266,7 @@ export interface IChatService {
|
||||
|
||||
onDidSubmitSlashCommand: Event<{ slashCommand: string; sessionId: string }>;
|
||||
registerProvider(provider: IChatProvider): IDisposable;
|
||||
hasProviders(): boolean;
|
||||
getProviderInfos(): IChatProviderInfo[];
|
||||
startSession(providerId: string, token: CancellationToken): ChatModel | undefined;
|
||||
getSession(sessionId: string): IChatModel | undefined;
|
||||
|
||||
@@ -12,7 +12,6 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { localize } from 'vs/nls';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -518,7 +517,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||
request = model.addRequest(parsedRequest, agent);
|
||||
const requestProps: IChatAgentRequest = {
|
||||
sessionId,
|
||||
requestId: generateUuid(),
|
||||
requestId: request.id,
|
||||
message,
|
||||
variables: {},
|
||||
command: agentSlashCommandPart?.command.name ?? '',
|
||||
@@ -760,6 +759,10 @@ export class ChatService extends Disposable implements IChatService {
|
||||
});
|
||||
}
|
||||
|
||||
hasProviders(): boolean {
|
||||
return this._providers.size > 0;
|
||||
}
|
||||
|
||||
getProviderInfos(): IChatProviderInfo[] {
|
||||
return Array.from(this._providers.values()).map(provider => {
|
||||
return {
|
||||
|
||||
@@ -88,6 +88,8 @@ export interface IChatResponseViewModel {
|
||||
readonly dataId: string;
|
||||
readonly providerId: string;
|
||||
readonly providerResponseId: string | undefined;
|
||||
/** The ID of the associated IChatRequestViewModel */
|
||||
readonly requestId: string;
|
||||
readonly username: string;
|
||||
readonly avatarIconUri?: URI;
|
||||
readonly agent?: IChatAgent;
|
||||
@@ -326,6 +328,10 @@ export class ChatResponseViewModel extends Disposable implements IChatResponseVi
|
||||
return this._model.vote;
|
||||
}
|
||||
|
||||
get requestId() {
|
||||
return this._model.requestId;
|
||||
}
|
||||
|
||||
renderData: IChatResponseRenderData | undefined = undefined;
|
||||
|
||||
currentRenderedHeight: number | undefined;
|
||||
|
||||
@@ -32,9 +32,13 @@ class VoiceChatActionsContributor extends Disposable implements IWorkbenchContri
|
||||
constructor(@ISpeechService speechService: ISpeechService) {
|
||||
super();
|
||||
|
||||
this._register(Event.once(speechService.onDidRegisterSpeechProvider)(() => {
|
||||
if (speechService.hasSpeechProvider) {
|
||||
registerVoiceChatActions();
|
||||
}));
|
||||
} else {
|
||||
this._register(Event.once(speechService.onDidRegisterSpeechProvider)(() => {
|
||||
registerVoiceChatActions();
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { addDisposableListener, onDidRegisterWindow } from 'vs/base/browser/dom';
|
||||
|
||||
const transientWordWrapState = 'transientWordWrapState';
|
||||
const isWordWrapMinifiedKey = 'isWordWrapMinified';
|
||||
@@ -255,7 +257,7 @@ function canToggleWordWrap(codeEditorService: ICodeEditorService, editor: ICodeE
|
||||
return true;
|
||||
}
|
||||
|
||||
class EditorWordWrapContextKeyTracker implements IWorkbenchContribution {
|
||||
class EditorWordWrapContextKeyTracker extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private readonly _canToggleWordWrap: IContextKey<boolean>;
|
||||
private readonly _editorWordWrap: IContextKey<boolean>;
|
||||
@@ -267,8 +269,11 @@ class EditorWordWrapContextKeyTracker implements IWorkbenchContribution {
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IContextKeyService private readonly _contextService: IContextKeyService,
|
||||
) {
|
||||
window.addEventListener('focus', () => this._update(), true);
|
||||
window.addEventListener('blur', () => this._update(), true);
|
||||
super();
|
||||
this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposableStore }) => {
|
||||
disposableStore.add(addDisposableListener(window, 'focus', () => this._update(), true));
|
||||
disposableStore.add(addDisposableListener(window, 'blur', () => this._update(), true));
|
||||
}, { window, disposableStore: this._store }));
|
||||
this._editorService.onDidActiveEditorChange(() => this._update());
|
||||
this._canToggleWordWrap = CAN_TOGGLE_WORD_WRAP.bindTo(this._contextService);
|
||||
this._editorWordWrap = EDITOR_WORD_WRAP.bindTo(this._contextService);
|
||||
|
||||
@@ -18,6 +18,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ITunnelService } from 'vs/platform/tunnel/common/tunnel';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { getWindow } from 'vs/base/browser/dom';
|
||||
|
||||
const CONTROL_CODES = '\\u0000-\\u0020\\u007f-\\u009f';
|
||||
const WEB_LINK_REGEX = new RegExp('(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\\/\\/|data:|www\\.)[^\\s' + CONTROL_CODES + '"]{2,}[^\\s' + CONTROL_CODES + '"\')}\\],:;.!?]', 'ug');
|
||||
@@ -201,7 +202,7 @@ export class LinkDetector {
|
||||
link.onmousemove = (event) => { link.classList.toggle('pointer', platform.isMacintosh ? event.metaKey : event.ctrlKey); };
|
||||
link.onmouseleave = () => link.classList.remove('pointer');
|
||||
link.onclick = (event) => {
|
||||
const selection = window.getSelection();
|
||||
const selection = getWindow(link).getSelection();
|
||||
if (!selection || selection.type === 'Range') {
|
||||
return; // do not navigate when user is selecting
|
||||
}
|
||||
|
||||
@@ -570,16 +570,18 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
|
||||
this._register(registerNavigableContainer({
|
||||
focusNotifiers: [this, this.filterWidget],
|
||||
focusNextWidget: () => {
|
||||
const element = this.tree?.getHTMLElement();
|
||||
if (this.filterWidget.hasFocus()) {
|
||||
this.tree?.domFocus();
|
||||
} else if (this.tree?.getHTMLElement() === document.activeElement) {
|
||||
} else if (element && dom.isActiveElement(element)) {
|
||||
this.focus();
|
||||
}
|
||||
},
|
||||
focusPreviousWidget: () => {
|
||||
const element = this.tree?.getHTMLElement();
|
||||
if (this.replInput.hasTextFocus()) {
|
||||
this.tree?.domFocus();
|
||||
} else if (this.tree?.getHTMLElement() === document.activeElement) {
|
||||
} else if (element && dom.isActiveElement(element)) {
|
||||
this.focusFilter();
|
||||
}
|
||||
}
|
||||
@@ -648,7 +650,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
|
||||
this._register(tree.onContextMenu(e => this.onContextMenu(e)));
|
||||
let lastSelectedString: string;
|
||||
this._register(tree.onMouseClick(() => {
|
||||
const selection = window.getSelection();
|
||||
const selection = dom.getWindow(this.treeContainer).getSelection();
|
||||
if (!selection || selection.type !== 'Range' || lastSelectedString === selection.toString()) {
|
||||
// only focus the input if the user is not currently selecting.
|
||||
this.replInput.focus();
|
||||
@@ -1070,7 +1072,7 @@ registerAction2(class extends Action2 {
|
||||
async run(accessor: ServicesAccessor, element: IReplElement): Promise<void> {
|
||||
const clipboardService = accessor.get(IClipboardService);
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const nativeSelection = window.getSelection();
|
||||
const nativeSelection = dom.getActiveWindow().getSelection();
|
||||
const selectedText = nativeSelection?.toString();
|
||||
if (selectedText && selectedText.length > 0) {
|
||||
return clipboardService.writeText(selectedText);
|
||||
|
||||
@@ -325,7 +325,7 @@ export class ExplorerView extends ViewPane implements IExplorerView {
|
||||
}
|
||||
|
||||
hasFocus(): boolean {
|
||||
return DOM.isAncestor(document.activeElement, this.container);
|
||||
return DOM.isAncestorOfActiveElement(this.container);
|
||||
}
|
||||
|
||||
getContext(respectMultiSelection: boolean): ExplorerItem[] {
|
||||
|
||||
@@ -621,11 +621,12 @@ export class FilesRenderer implements ICompressibleTreeRenderer<ExplorerItem, Fu
|
||||
while (true) {
|
||||
await timeout(0);
|
||||
|
||||
if (!document.hasFocus()) {
|
||||
const ownerDocument = inputBox.inputElement.ownerDocument;
|
||||
if (!ownerDocument.hasFocus()) {
|
||||
break;
|
||||
} if (document.activeElement === inputBox.inputElement) {
|
||||
} if (DOM.isActiveElement(inputBox.inputElement)) {
|
||||
return;
|
||||
} else if (document.activeElement instanceof HTMLElement && DOM.hasParentWithClass(document.activeElement, 'context-view')) {
|
||||
} else if (ownerDocument.activeElement instanceof HTMLElement && DOM.hasParentWithClass(ownerDocument.activeElement, 'context-view')) {
|
||||
await Event.toPromise(this.contextMenuService.onDidHideContextMenu);
|
||||
} else {
|
||||
break;
|
||||
|
||||
@@ -164,6 +164,15 @@
|
||||
margin: unset;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-chat .markdownMessage .message code {
|
||||
font-family: var(--monaco-monospace-font);
|
||||
font-size: 12px;
|
||||
color: var(--vscode-textPreformat-foreground);
|
||||
background-color: var(--vscode-textPreformat-background);
|
||||
padding: 1px 3px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-chat .markdownMessage .message .interactive-result-code-block {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ export class DiscardAction extends AbstractInlineChatAction {
|
||||
}
|
||||
|
||||
async runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController, _editor: ICodeEditor, ..._args: any[]): Promise<void> {
|
||||
ctrl.cancelSession();
|
||||
await ctrl.cancelSession();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ export class DiscardToClipboardAction extends AbstractInlineChatAction {
|
||||
|
||||
override async runInlineChatCommand(accessor: ServicesAccessor, ctrl: InlineChatController): Promise<void> {
|
||||
const clipboardService = accessor.get(IClipboardService);
|
||||
const changedText = ctrl.cancelSession();
|
||||
const changedText = await ctrl.cancelSession();
|
||||
if (changedText !== undefined) {
|
||||
clipboardService.writeText(changedText);
|
||||
}
|
||||
@@ -381,7 +381,7 @@ export class DiscardUndoToNewFileAction extends AbstractInlineChatAction {
|
||||
|
||||
override async runInlineChatCommand(accessor: ServicesAccessor, ctrl: InlineChatController, editor: ICodeEditor, ..._args: any[]): Promise<void> {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const changedText = ctrl.cancelSession();
|
||||
const changedText = await ctrl.cancelSession();
|
||||
if (changedText !== undefined) {
|
||||
const input: IUntitledTextResourceEditorInput = { forceUntitled: true, resource: undefined, contents: changedText, languageId: editor.getModel()?.getLanguageId() };
|
||||
editorService.openEditor(input, SIDE_GROUP);
|
||||
|
||||
@@ -8,16 +8,14 @@ import { Barrier, raceCancellationError } from 'vs/base/common/async';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { ModelDecorationOptions, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { InlineCompletionsController } from 'vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
@@ -39,7 +37,6 @@ import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { TextEdit } from 'vs/editor/common/languages';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IModelDeltaDecoration } from 'vs/editor/common/model';
|
||||
|
||||
export const enum State {
|
||||
CREATE_SESSION = 'CREATE_SESSION',
|
||||
@@ -93,12 +90,12 @@ export class InlineChatController implements IEditorContribution {
|
||||
return editor.getContribution<InlineChatController>(INLINE_CHAT_ID);
|
||||
}
|
||||
|
||||
private static _decoBlock = ModelDecorationOptions.register({
|
||||
description: 'inline-chat',
|
||||
showIfCollapsed: false,
|
||||
isWholeLine: true,
|
||||
className: 'inline-chat-block-selection',
|
||||
});
|
||||
// private static _decoBlock = ModelDecorationOptions.register({
|
||||
// description: 'inline-chat',
|
||||
// showIfCollapsed: false,
|
||||
// isWholeLine: true,
|
||||
// className: 'inline-chat-block-selection',
|
||||
// });
|
||||
|
||||
private static _promptHistory: string[] = [];
|
||||
private _historyOffset: number = -1;
|
||||
@@ -130,7 +127,6 @@ export class InlineChatController implements IEditorContribution {
|
||||
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@IDialogService private readonly _dialogService: IDialogService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
|
||||
@@ -335,22 +331,22 @@ export class InlineChatController implements IEditorContribution {
|
||||
|
||||
this._sessionStore.clear();
|
||||
|
||||
const wholeRangeDecoration = this._editor.createDecorationsCollection();
|
||||
const updateWholeRangeDecoration = () => {
|
||||
// const wholeRangeDecoration = this._editor.createDecorationsCollection();
|
||||
// const updateWholeRangeDecoration = () => {
|
||||
|
||||
const range = this._activeSession!.wholeRange.value;
|
||||
const decorations: IModelDeltaDecoration[] = [];
|
||||
if (!range.isEmpty()) {
|
||||
decorations.push({
|
||||
range,
|
||||
options: InlineChatController._decoBlock
|
||||
});
|
||||
}
|
||||
wholeRangeDecoration.set(decorations);
|
||||
};
|
||||
this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear()));
|
||||
this._sessionStore.add(this._activeSession.wholeRange.onDidChange(updateWholeRangeDecoration));
|
||||
updateWholeRangeDecoration();
|
||||
// const range = this._activeSession!.wholeRange.value;
|
||||
// const decorations: IModelDeltaDecoration[] = [];
|
||||
// if (!range.isEmpty()) {
|
||||
// decorations.push({
|
||||
// range,
|
||||
// options: InlineChatController._decoBlock
|
||||
// });
|
||||
// }
|
||||
// wholeRangeDecoration.set(decorations);
|
||||
// };
|
||||
// this._sessionStore.add(toDisposable(() => wholeRangeDecoration.clear()));
|
||||
// this._sessionStore.add(this._activeSession.wholeRange.onDidChange(updateWholeRangeDecoration));
|
||||
// updateWholeRangeDecoration();
|
||||
|
||||
this._zone.value.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []);
|
||||
this._updatePlaceholder();
|
||||
@@ -573,7 +569,7 @@ export class InlineChatController implements IEditorContribution {
|
||||
throw new Error('Progress in NOT supported in non-live mode');
|
||||
}
|
||||
progressEdits.push(data.edits);
|
||||
await this._makeChanges(progressEdits, false);
|
||||
await this._makeChanges(data.edits, true);
|
||||
await this._strategy?.renderProgressChanges();
|
||||
}
|
||||
});
|
||||
@@ -595,8 +591,8 @@ export class InlineChatController implements IEditorContribution {
|
||||
response = new MarkdownResponse(this._activeSession.textModelN.uri, reply);
|
||||
} else if (reply) {
|
||||
const editResponse = new EditResponse(this._activeSession.textModelN.uri, this._activeSession.textModelN.getAlternativeVersionId(), reply, progressEdits);
|
||||
if (editResponse.allLocalEdits.length > progressEdits.length) {
|
||||
await this._makeChanges(editResponse.allLocalEdits, true);
|
||||
for (let i = progressEdits.length; i < editResponse.allLocalEdits.length; i++) {
|
||||
await this._makeChanges(editResponse.allLocalEdits[i], true);
|
||||
}
|
||||
response = editResponse;
|
||||
} else {
|
||||
@@ -649,30 +645,20 @@ export class InlineChatController implements IEditorContribution {
|
||||
return State.SHOW_RESPONSE;
|
||||
}
|
||||
|
||||
private async _makeChanges(allEdits: TextEdit[][], computeMoreMinimalEdits: boolean) {
|
||||
private async _makeChanges(lastEdits: TextEdit[], computeMoreMinimalEdits: boolean) {
|
||||
assertType(this._activeSession);
|
||||
assertType(this._strategy);
|
||||
|
||||
if (allEdits.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// diff-changes from model0 -> modelN+1
|
||||
{
|
||||
const lastEdits = allEdits[allEdits.length - 1];
|
||||
const textModelNplus1 = this._modelService.createModel(createTextBufferFactoryFromSnapshot(this._activeSession.textModelN.createSnapshot()), null, undefined, true);
|
||||
textModelNplus1.applyEdits(lastEdits.map(TextEdit.asEditOperation));
|
||||
const diff = await this._editorWorkerService.computeDiff(this._activeSession.textModel0.uri, textModelNplus1.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced');
|
||||
this._activeSession.lastTextModelChanges = diff?.changes ?? [];
|
||||
textModelNplus1.dispose();
|
||||
}
|
||||
|
||||
// make changes from modelN -> modelN+1
|
||||
const lastEdits = allEdits[allEdits.length - 1];
|
||||
const moreMinimalEdits = computeMoreMinimalEdits ? await this._editorWorkerService.computeHumanReadableDiff(this._activeSession.textModelN.uri, lastEdits) : undefined;
|
||||
const moreMinimalEdits = computeMoreMinimalEdits ? await this._editorWorkerService.computeMoreMinimalEdits(this._activeSession.textModelN.uri, lastEdits) : undefined;
|
||||
const editOperations = (moreMinimalEdits ?? lastEdits).map(TextEdit.asEditOperation);
|
||||
this._log('edits from PROVIDER and after making them MORE MINIMAL', this._activeSession.provider.debugName, lastEdits, moreMinimalEdits);
|
||||
|
||||
if (editOperations.length === 0) {
|
||||
// nothing left to do
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._ignoreModelContentChanged = true;
|
||||
this._activeSession.wholeRange.trackEdits(editOperations);
|
||||
@@ -688,7 +674,6 @@ export class InlineChatController implements IEditorContribution {
|
||||
assertType(this._strategy);
|
||||
|
||||
const { response } = this._activeSession.lastExchange!;
|
||||
this._showWidget(false);
|
||||
|
||||
let status: string | undefined;
|
||||
|
||||
@@ -752,6 +737,7 @@ export class InlineChatController implements IEditorContribution {
|
||||
await this._strategy.renderChanges(response);
|
||||
}
|
||||
this._chatAccessibilityService.acceptResponse(status);
|
||||
this._showWidget(false);
|
||||
|
||||
return State.WAIT_FOR_INPUT;
|
||||
}
|
||||
@@ -910,11 +896,19 @@ export class InlineChatController implements IEditorContribution {
|
||||
this._messages.fire(Message.ACCEPT_SESSION);
|
||||
}
|
||||
|
||||
cancelSession() {
|
||||
const result = this._activeSession?.asChangedText();
|
||||
if (this._activeSession?.lastExchange && InlineChatController.isEditOrMarkdownResponse(this._activeSession.lastExchange.response)) {
|
||||
this._activeSession.provider.handleInlineChatResponseFeedback?.(this._activeSession.session, this._activeSession.lastExchange.response.raw, InlineChatResponseFeedbackKind.Undone);
|
||||
async cancelSession() {
|
||||
|
||||
let result: string | undefined;
|
||||
if (this._activeSession) {
|
||||
|
||||
const diff = await this._editorWorkerService.computeDiff(this._activeSession.textModel0.uri, this._activeSession.textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced');
|
||||
result = this._activeSession.asChangedText(diff?.changes ?? []);
|
||||
|
||||
if (this._activeSession.lastExchange && InlineChatController.isEditOrMarkdownResponse(this._activeSession.lastExchange.response)) {
|
||||
this._activeSession.provider.handleInlineChatResponseFeedback?.(this._activeSession.session, this._activeSession.lastExchange.response.raw, InlineChatResponseFeedbackKind.Undone);
|
||||
}
|
||||
}
|
||||
|
||||
this._messages.fire(Message.CANCEL_SESSION);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Dimension, h } from 'vs/base/browser/dom';
|
||||
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
|
||||
@@ -21,7 +21,7 @@ import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IEditorDecorationsCollection, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { lineRangeAsRange, invertLineRange } from 'vs/workbench/contrib/inlineChat/browser/utils';
|
||||
import { ResourceLabel } from 'vs/workbench/browser/labels';
|
||||
@@ -35,22 +35,24 @@ import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { FoldingController } from 'vs/editor/contrib/folding/browser/folding';
|
||||
import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
|
||||
private static readonly _hideId = 'overlayDiff';
|
||||
private readonly _hideId = `overlayDiff:${generateUuid()}`;
|
||||
|
||||
private readonly _elements = h('div.inline-chat-diff-widget@domNode');
|
||||
|
||||
private readonly _sessionStore = this._disposables.add(new DisposableStore());
|
||||
private readonly _decorationCollection: IEditorDecorationsCollection;
|
||||
private readonly _diffEditor: IDiffEditor;
|
||||
|
||||
private _dim: Dimension | undefined;
|
||||
private _isVisible: boolean = false;
|
||||
private _isDiffLocked: boolean = false;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
private readonly _session: Session,
|
||||
onDidChangeDiff: (() => void) | undefined,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@@ -60,6 +62,8 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
super.create();
|
||||
assertType(editor.hasModel());
|
||||
|
||||
this._decorationCollection = editor.createDecorationsCollection();
|
||||
|
||||
const diffContributions = EditorExtensionsRegistry
|
||||
.getEditorContributions()
|
||||
.filter(c => c.id !== INLINE_CHAT_ID && c.id !== FoldingController.ID);
|
||||
@@ -80,6 +84,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
stickyScroll: { enabled: false },
|
||||
minimap: { enabled: false },
|
||||
isInEmbeddedEditor: true,
|
||||
useInlineViewWhenSpaceIsLimited: false,
|
||||
overflowWidgetsDomNode: editor.getOverflowWidgetsDomNode(),
|
||||
onlyShowAccessibleDiffViewer: this.accessibilityService.isScreenReaderOptimized(),
|
||||
}, {
|
||||
@@ -93,6 +98,10 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
lineDecorationsWidth: editor.getLayoutInfo().decorationsWidth
|
||||
});
|
||||
|
||||
if (onDidChangeDiff) {
|
||||
this._disposables.add(this._diffEditor.onDidUpdateDiff(() => { onDidChangeDiff(); }));
|
||||
}
|
||||
|
||||
const highlighter = WordHighlighterContribution.get(editor);
|
||||
if (highlighter) {
|
||||
this._disposables.add(highlighter.linkWordHighlighters(this._diffEditor.getModifiedEditor()));
|
||||
@@ -132,61 +141,67 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
}
|
||||
|
||||
override hide(): void {
|
||||
this._decorationCollection.clear();
|
||||
this._cleanupFullDiff();
|
||||
this._sessionStore.clear();
|
||||
super.hide();
|
||||
this._isVisible = false;
|
||||
}
|
||||
|
||||
override show(): void {
|
||||
assertType(this.editor.hasModel());
|
||||
this._sessionStore.clear();
|
||||
this._isDiffLocked = false;
|
||||
throw new Error('use showForChanges');
|
||||
}
|
||||
|
||||
showForChanges(changes: readonly DetailedLineRangeMapping[]): void {
|
||||
const hasFocus = this._diffEditor.hasTextFocus();
|
||||
this._isVisible = true;
|
||||
|
||||
this._sessionStore.add(this._diffEditor.onDidUpdateDiff(() => {
|
||||
const result = this._diffEditor.getDiffComputationResult();
|
||||
const hasFocus = this._diffEditor.hasTextFocus();
|
||||
this._updateFromChanges(this._session.wholeRange.value, result?.changes2 ?? []);
|
||||
// TODO@jrieken find a better fix for this. this is the challenge:
|
||||
// the _doShowForChanges method invokes show of the zone widget which removes and adds the
|
||||
// zone and overlay parts. this dettaches and reattaches the dom nodes which means they lose
|
||||
// focus
|
||||
if (hasFocus) {
|
||||
this._diffEditor.focus();
|
||||
}
|
||||
}));
|
||||
this._updateFromChanges(this._session.wholeRange.value, this._session.lastTextModelChanges);
|
||||
}
|
||||
const onlyInserts = changes.every(change => change.original.isEmpty);
|
||||
|
||||
lockToDiff(): void {
|
||||
this._isDiffLocked = true;
|
||||
}
|
||||
|
||||
private _updateFromChanges(range: Range, changes: readonly DetailedLineRangeMapping[]): void {
|
||||
assertType(this.editor.hasModel());
|
||||
|
||||
if (this._isDiffLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (changes.length === 0 || this._session.textModel0.getValueLength() === 0) {
|
||||
if (onlyInserts || changes.length === 0 || this._session.textModel0.getValueLength() === 0) {
|
||||
// no change or changes to an empty file
|
||||
this._logService.debug('[IE] livePreview-mode: no diff');
|
||||
this._cleanupFullDiff();
|
||||
this._renderInsertWithHighlight(changes);
|
||||
} else {
|
||||
// complex changes
|
||||
this._logService.debug('[IE] livePreview-mode: full diff');
|
||||
this._renderChangesWithFullDiff(changes, range);
|
||||
this._decorationCollection.clear();
|
||||
this._renderChangesWithFullDiff(changes);
|
||||
}
|
||||
|
||||
// TODO@jrieken find a better fix for this. this is the challenge:
|
||||
// the `_updateFromChanges` method invokes show of the zone widget which removes and adds the
|
||||
// zone and overlay parts. this dettaches and reattaches the dom nodes which means they lose
|
||||
// focus
|
||||
if (hasFocus) {
|
||||
this._diffEditor.focus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private _renderInsertWithHighlight(changes: readonly DetailedLineRangeMapping[]) {
|
||||
assertType(this.editor.hasModel());
|
||||
|
||||
const ranges = this._computeHiddenRanges(this.editor.getModel(), changes);
|
||||
|
||||
this._decorationCollection.set([{
|
||||
range: lineRangeAsRange(ranges.modifiedHidden),
|
||||
options: {
|
||||
description: 'inline-chat-insert',
|
||||
showIfCollapsed: false,
|
||||
isWholeLine: true,
|
||||
className: 'inline-chat-lines-inserted-range',
|
||||
}
|
||||
}]);
|
||||
}
|
||||
|
||||
// --- full diff
|
||||
|
||||
private _renderChangesWithFullDiff(changes: readonly DetailedLineRangeMapping[], range: Range) {
|
||||
private _renderChangesWithFullDiff(changes: readonly DetailedLineRangeMapping[]) {
|
||||
assertType(this.editor.hasModel());
|
||||
|
||||
const modified = this.editor.getModel()!;
|
||||
const ranges = this._computeHiddenRanges(modified, range, changes);
|
||||
const modified = this.editor.getModel();
|
||||
const ranges = this._computeHiddenRanges(modified, changes);
|
||||
|
||||
this._hideEditorRanges(this.editor, [ranges.modifiedHidden]);
|
||||
this._hideEditorRanges(this._diffEditor.getOriginalEditor(), ranges.originalDiffHidden);
|
||||
@@ -197,25 +212,20 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
const lineCountModified = ranges.modifiedHidden.length;
|
||||
const lineCountOriginal = ranges.originalHidden.length;
|
||||
|
||||
const lineHeightDiff = Math.max(lineCountModified, lineCountOriginal);
|
||||
const lineHeightPadding = (this.editor.getOption(EditorOption.lineHeight) / 12) /* padding-top/bottom*/;
|
||||
const heightInLines = lineHeightDiff + lineHeightPadding;
|
||||
const heightInLines = Math.max(lineCountModified, lineCountOriginal);
|
||||
|
||||
super.show(ranges.anchor, heightInLines);
|
||||
this._logService.debug(`[IE] diff SHOWING at ${ranges.anchor} with ${heightInLines} lines height`);
|
||||
}
|
||||
|
||||
private _cleanupFullDiff() {
|
||||
this.editor.setHiddenAreas([], InlineChatLivePreviewWidget._hideId);
|
||||
this._diffEditor.getOriginalEditor().setHiddenAreas([], InlineChatLivePreviewWidget._hideId);
|
||||
this._diffEditor.getModifiedEditor().setHiddenAreas([], InlineChatLivePreviewWidget._hideId);
|
||||
this.editor.setHiddenAreas([], this._hideId);
|
||||
this._diffEditor.getOriginalEditor().setHiddenAreas([], this._hideId);
|
||||
this._diffEditor.getModifiedEditor().setHiddenAreas([], this._hideId);
|
||||
super.hide();
|
||||
}
|
||||
|
||||
private _computeHiddenRanges(model: ITextModel, range: Range, changes: readonly DetailedLineRangeMapping[]) {
|
||||
if (changes.length === 0) {
|
||||
changes = [new DetailedLineRangeMapping(LineRange.fromRange(range), LineRange.fromRange(range), undefined)];
|
||||
}
|
||||
private _computeHiddenRanges(model: ITextModel, changes: readonly DetailedLineRangeMapping[]) {
|
||||
|
||||
let originalLineRange = changes[0].original;
|
||||
let modifiedLineRange = changes[0].modified;
|
||||
@@ -224,16 +234,8 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
modifiedLineRange = modifiedLineRange.join(changes[i].modified);
|
||||
}
|
||||
|
||||
const startDelta = modifiedLineRange.startLineNumber - range.startLineNumber;
|
||||
if (startDelta > 0) {
|
||||
modifiedLineRange = new LineRange(modifiedLineRange.startLineNumber - startDelta, modifiedLineRange.endLineNumberExclusive);
|
||||
originalLineRange = new LineRange(originalLineRange.startLineNumber - startDelta, originalLineRange.endLineNumberExclusive);
|
||||
}
|
||||
|
||||
const endDelta = range.endLineNumber - (modifiedLineRange.endLineNumberExclusive - 1);
|
||||
if (endDelta > 0) {
|
||||
modifiedLineRange = new LineRange(modifiedLineRange.startLineNumber, modifiedLineRange.endLineNumberExclusive + endDelta);
|
||||
originalLineRange = new LineRange(originalLineRange.startLineNumber, originalLineRange.endLineNumberExclusive + endDelta);
|
||||
if (originalLineRange.isEmpty) {
|
||||
originalLineRange = new LineRange(originalLineRange.startLineNumber, originalLineRange.endLineNumberExclusive + 1);
|
||||
}
|
||||
|
||||
const originalDiffHidden = invertLineRange(originalLineRange, this._session.textModel0);
|
||||
@@ -266,7 +268,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
} else {
|
||||
hiddenRanges = lineRanges.map(lineRangeAsRange);
|
||||
}
|
||||
editor.setHiddenAreas(hiddenRanges, InlineChatLivePreviewWidget._hideId);
|
||||
editor.setHiddenAreas(hiddenRanges, this._hideId);
|
||||
this._logService.debug(`[IE] diff HIDING ${hiddenRanges} for ${editor.getId()} with ${String(editor.getModel()?.uri)}`);
|
||||
}
|
||||
|
||||
@@ -286,7 +288,7 @@ export class InlineChatLivePreviewWidget extends ZoneWidget {
|
||||
const newDim = new Dimension(widthInPixel, heightInPixel);
|
||||
if (!Dimension.equals(this._dim, newDim)) {
|
||||
this._dim = newDim;
|
||||
this._diffEditor.layout(this._dim.with(undefined, this._dim.height - 12 /* padding */));
|
||||
this._diffEditor.layout(this._dim.with(undefined, this._dim.height));
|
||||
this._logService.debug('[IE] diff LAYOUT', this._dim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { isCancellationError } from 'vs/base/common/errors';
|
||||
import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { raceCancellation } from 'vs/base/common/async';
|
||||
import { LineRangeMapping } from 'vs/editor/common/diff/rangeMapping';
|
||||
|
||||
export type Recording = {
|
||||
when: Date;
|
||||
@@ -112,7 +112,6 @@ export class Session {
|
||||
|
||||
private _lastInput: SessionPrompt | undefined;
|
||||
private _lastExpansionState: ExpansionState | undefined;
|
||||
private _lastTextModelChanges: readonly DetailedLineRangeMapping[] | undefined;
|
||||
private _isUnstashed: boolean = false;
|
||||
private readonly _exchange: SessionExchange[] = [];
|
||||
private readonly _startTime = new Date();
|
||||
@@ -187,26 +186,18 @@ export class Session {
|
||||
return this._exchange[this._exchange.length - 1];
|
||||
}
|
||||
|
||||
get lastTextModelChanges() {
|
||||
return this._lastTextModelChanges ?? [];
|
||||
}
|
||||
|
||||
set lastTextModelChanges(changes: readonly DetailedLineRangeMapping[]) {
|
||||
this._lastTextModelChanges = changes;
|
||||
}
|
||||
|
||||
get hasChangedText(): boolean {
|
||||
return !this.textModel0.equalsTextBuffer(this.textModelN.getTextBuffer());
|
||||
}
|
||||
|
||||
asChangedText(): string | undefined {
|
||||
if (!this._lastTextModelChanges || this._lastTextModelChanges.length === 0) {
|
||||
asChangedText(changes: readonly LineRangeMapping[]): string | undefined {
|
||||
if (changes.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let startLine = Number.MAX_VALUE;
|
||||
let endLine = Number.MIN_VALUE;
|
||||
for (const change of this._lastTextModelChanges) {
|
||||
for (const change of changes) {
|
||||
startLine = Math.min(startLine, change.modified.startLineNumber);
|
||||
endLine = Math.max(endLine, change.modified.endLineNumberExclusive);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { equals, tail } from 'vs/base/common/arrays';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { DetailedLineRangeMapping, LineRangeMapping } from 'vs/editor/common/diff/rangeMapping';
|
||||
import { IEditorDecorationsCollection } from 'vs/editor/common/editorCommon';
|
||||
import { TextEdit } from 'vs/editor/common/languages';
|
||||
import { ICursorStateComputer, IModelDecorationOptions, IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model';
|
||||
@@ -132,7 +133,7 @@ export class PreviewStrategy extends EditModeStrategy {
|
||||
override async renderChanges(response: EditResponse): Promise<void> {
|
||||
if (response.allLocalEdits.length > 0) {
|
||||
const allEditOperation = response.allLocalEdits.map(edits => edits.map(TextEdit.asEditOperation));
|
||||
this._widget.showEditsPreview(this._session.textModel0, allEditOperation, this._session.lastTextModelChanges);
|
||||
await this._widget.showEditsPreview(this._session.textModel0, this._session.textModelN, allEditOperation);
|
||||
} else {
|
||||
this._widget.hideEditsPreview();
|
||||
}
|
||||
@@ -238,12 +239,11 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
protected readonly _session: Session,
|
||||
protected readonly _editor: ICodeEditor,
|
||||
protected readonly _widget: InlineChatWidget,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IConfigurationService configService: IConfigurationService,
|
||||
@IStorageService protected _storageService: IStorageService,
|
||||
@IBulkEditService protected readonly _bulkEditService: IBulkEditService,
|
||||
@IEditorWorkerService protected readonly _editorWorkerService: IEditorWorkerService,
|
||||
@IInstantiationService private readonly _instaService: IInstantiationService,
|
||||
@IInstantiationService protected readonly _instaService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
this._diffEnabled = configService.getValue<boolean>('inlineChat.showDiff');
|
||||
@@ -327,9 +327,9 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
}
|
||||
|
||||
override async renderChanges(response: EditResponse) {
|
||||
|
||||
const diff = await this._editorWorkerService.computeDiff(this._session.textModel0.uri, this._session.textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced');
|
||||
this._updateSummaryMessage(diff?.changes ?? []);
|
||||
this._inlineDiffDecorations.update();
|
||||
this._updateSummaryMessage();
|
||||
|
||||
if (response.singleCreateFileEdit) {
|
||||
this._widget.showCreatePreview(response.singleCreateFileEdit.uri, await Promise.all(response.singleCreateFileEdit.edits));
|
||||
@@ -344,9 +344,9 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
protected _updateSummaryMessage() {
|
||||
protected _updateSummaryMessage(mappings: readonly LineRangeMapping[]) {
|
||||
let linesChanged = 0;
|
||||
for (const change of this._session.lastTextModelChanges) {
|
||||
for (const change of mappings) {
|
||||
linesChanged += change.changedLineCount;
|
||||
}
|
||||
let message: string;
|
||||
@@ -361,19 +361,11 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
}
|
||||
|
||||
override getWidgetPosition(): Position | undefined {
|
||||
const lastTextModelChanges = this._session.lastTextModelChanges;
|
||||
let lastLineOfLocalEdits: number | undefined;
|
||||
for (const change of lastTextModelChanges) {
|
||||
const changeEndLineNumber = change.modified.endLineNumberExclusive - 1;
|
||||
if (typeof lastLineOfLocalEdits === 'undefined' || lastLineOfLocalEdits < changeEndLineNumber) {
|
||||
lastLineOfLocalEdits = changeEndLineNumber;
|
||||
}
|
||||
}
|
||||
return lastLineOfLocalEdits ? new Position(lastLineOfLocalEdits, 1) : undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
override needsMargin(): boolean {
|
||||
return !Boolean(this._session.lastTextModelChanges.length);
|
||||
return true;
|
||||
}
|
||||
|
||||
hasFocus(): boolean {
|
||||
@@ -383,46 +375,98 @@ export class LiveStrategy extends EditModeStrategy {
|
||||
|
||||
export class LivePreviewStrategy extends LiveStrategy {
|
||||
|
||||
private readonly _diffZone: Lazy<InlineChatLivePreviewWidget>;
|
||||
private readonly _previewZone: Lazy<InlineChatFileCreatePreviewWidget>;
|
||||
private readonly _diffZonePool: InlineChatLivePreviewWidget[] = [];
|
||||
private _currentLineRangeGroups: DetailedLineRangeMapping[][] = [];
|
||||
|
||||
constructor(
|
||||
session: Session,
|
||||
editor: ICodeEditor,
|
||||
widget: InlineChatWidget,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IConfigurationService configService: IConfigurationService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IBulkEditService bulkEditService: IBulkEditService,
|
||||
@IEditorWorkerService editorWorkerService: IEditorWorkerService,
|
||||
@IInstantiationService instaService: IInstantiationService,
|
||||
) {
|
||||
super(session, editor, widget, contextKeyService, configService, storageService, bulkEditService, editorWorkerService, instaService);
|
||||
super(session, editor, widget, configService, storageService, bulkEditService, editorWorkerService, instaService);
|
||||
|
||||
this._diffZone = new Lazy(() => instaService.createInstance(InlineChatLivePreviewWidget, editor, session));
|
||||
this._previewZone = new Lazy(() => instaService.createInstance(InlineChatFileCreatePreviewWidget, editor));
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
this._diffZone.rawValue?.hide();
|
||||
this._diffZone.rawValue?.dispose();
|
||||
for (const zone of this._diffZonePool) {
|
||||
zone.hide();
|
||||
zone.dispose();
|
||||
}
|
||||
this._previewZone.rawValue?.hide();
|
||||
this._previewZone.rawValue?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
override async renderProgressChanges(): Promise<void> {
|
||||
if (!this._diffZone.value.isVisible) {
|
||||
this._diffZone.value.show();
|
||||
|
||||
private async _renderDiffZones() {
|
||||
const diff = await this._editorWorkerService.computeDiff(this._session.textModel0.uri, this._session.textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced');
|
||||
if (!diff || diff.changes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const groups: DetailedLineRangeMapping[][] = [];
|
||||
let group = [diff.changes[0]];
|
||||
groups.push(group);
|
||||
|
||||
for (let i = 1; i < diff.changes.length; i++) {
|
||||
const last = tail(group);
|
||||
const next = diff.changes[i];
|
||||
|
||||
// when the distance between the two changes is less than 75% of the total number of lines changed
|
||||
// they get merged into the same group
|
||||
const treshold = Math.ceil((next.modified.length + last.modified.length) * .75);
|
||||
if (next.modified.startLineNumber - last.modified.endLineNumberExclusive <= treshold) {
|
||||
group.push(next);
|
||||
} else {
|
||||
group = [next];
|
||||
groups.push(group);
|
||||
}
|
||||
}
|
||||
|
||||
const beforeAndNowAreEqual = equals(this._currentLineRangeGroups, groups, (groupA, groupB) => {
|
||||
return equals(groupA, groupB, (mappingA, mappingB) => {
|
||||
return mappingA.original.equals(mappingB.original) && mappingA.modified.equals(mappingB.modified);
|
||||
});
|
||||
});
|
||||
|
||||
if (beforeAndNowAreEqual) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateSummaryMessage(diff.changes);
|
||||
this._currentLineRangeGroups = groups;
|
||||
|
||||
const handleDiff = () => {
|
||||
this._renderDiffZones();
|
||||
};
|
||||
|
||||
// create enough zones
|
||||
while (groups.length > this._diffZonePool.length) {
|
||||
this._diffZonePool.push(this._instaService.createInstance(InlineChatLivePreviewWidget, this._editor, this._session, this._diffZonePool.length === 0 ? handleDiff : undefined));
|
||||
}
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
this._diffZonePool[i].showForChanges(groups[i]);
|
||||
}
|
||||
// hide unused zones
|
||||
for (let i = groups.length; i < this._diffZonePool.length; i++) {
|
||||
this._diffZonePool[i].hide();
|
||||
}
|
||||
}
|
||||
|
||||
override async renderProgressChanges(): Promise<void> {
|
||||
return this._renderDiffZones();
|
||||
}
|
||||
|
||||
override async renderChanges(response: EditResponse) {
|
||||
|
||||
this._updateSummaryMessage();
|
||||
if (this._diffEnabled) {
|
||||
this._diffZone.value.show();
|
||||
}
|
||||
await this._renderDiffZones();
|
||||
|
||||
if (response.singleCreateFileEdit) {
|
||||
this._previewZone.value.showCreation(this._session.wholeRange.value.collapseToEnd(), response.singleCreateFileEdit.uri, await Promise.all(response.singleCreateFileEdit.edits));
|
||||
@@ -431,30 +475,19 @@ export class LivePreviewStrategy extends LiveStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
override async undoChanges(response: EditResponse): Promise<void> {
|
||||
this._diffZone.value.lockToDiff();
|
||||
super.undoChanges(response);
|
||||
}
|
||||
|
||||
protected override _doToggleDiff(): void {
|
||||
const scrollState = StableEditorScrollState.capture(this._editor);
|
||||
if (this._diffEnabled) {
|
||||
this._diffZone.value.show();
|
||||
} else {
|
||||
this._diffZone.value.hide();
|
||||
}
|
||||
scrollState.restore(this._editor);
|
||||
}
|
||||
|
||||
override hasFocus(): boolean {
|
||||
return super.hasFocus() || this._diffZone.value.hasFocus() || this._previewZone.value.hasFocus();
|
||||
return super.hasFocus() || Boolean(this._previewZone.rawValue?.hasFocus()) || this._diffZonePool.some(zone => zone.isVisible && zone.hasFocus());
|
||||
}
|
||||
|
||||
override getWidgetPosition(): Position | undefined {
|
||||
if (this._session.lastTextModelChanges.length) {
|
||||
return this._session.wholeRange.value.getStartPosition().delta(-1);
|
||||
for (let i = this._diffZonePool.length - 1; i >= 0; i--) {
|
||||
const zone = this._diffZonePool[i];
|
||||
if (zone.isVisible && zone.position) {
|
||||
// above last view zone
|
||||
return zone.position;
|
||||
}
|
||||
}
|
||||
return this._session.wholeRange.value.getStartPosition().delta(-1);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ import { FileKind } from 'vs/platform/files/common/files';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
import { LanguageSelector } from 'vs/editor/common/languageSelector';
|
||||
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
||||
import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping';
|
||||
import { invertLineRange, lineRangeAsRange } from 'vs/workbench/contrib/inlineChat/browser/utils';
|
||||
import { ICodeEditorViewState, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
@@ -62,6 +61,7 @@ import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { editorForeground, inputBackground, editorBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { CodeBlockPart } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
|
||||
|
||||
const defaultAriaLabel = localize('aria-label', "Inline Chat Input");
|
||||
|
||||
@@ -215,7 +215,8 @@ export class InlineChatWidget {
|
||||
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IContextMenuService private readonly _contextMenuService: IContextMenuService,
|
||||
@IAccessibleViewService private readonly _accessibleViewService: IAccessibleViewService
|
||||
@IAccessibleViewService private readonly _accessibleViewService: IAccessibleViewService,
|
||||
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService
|
||||
) {
|
||||
|
||||
// input editor logic
|
||||
@@ -664,27 +665,29 @@ export class InlineChatWidget {
|
||||
|
||||
// --- preview
|
||||
|
||||
showEditsPreview(textModelv0: ITextModel, allEdits: ISingleEditOperation[][], changes: readonly DetailedLineRangeMapping[]) {
|
||||
if (changes.length === 0) {
|
||||
async showEditsPreview(textModel0: ITextModel, textModelN: ITextModel, allEdits: ISingleEditOperation[][]) {
|
||||
|
||||
const diff = await this._editorWorkerService.computeDiff(textModel0.uri, textModelN.uri, { ignoreTrimWhitespace: false, maxComputationTimeMs: 5000, computeMoves: false }, 'advanced');
|
||||
if (!diff || diff.changes.length === 0) {
|
||||
this.hideEditsPreview();
|
||||
return;
|
||||
}
|
||||
|
||||
this._elements.previewDiff.classList.remove('hidden');
|
||||
|
||||
const languageSelection: ILanguageSelection = { languageId: textModelv0.getLanguageId(), onDidChange: Event.None };
|
||||
const modified = this._modelService.createModel(createTextBufferFactoryFromSnapshot(textModelv0.createSnapshot()), languageSelection, undefined, true);
|
||||
const languageSelection: ILanguageSelection = { languageId: textModel0.getLanguageId(), onDidChange: Event.None };
|
||||
const modified = this._modelService.createModel(createTextBufferFactoryFromSnapshot(textModel0.createSnapshot()), languageSelection, undefined, true);
|
||||
for (const edits of allEdits) {
|
||||
modified.applyEdits(edits, false);
|
||||
}
|
||||
this._previewDiffEditor.value.setModel({ original: textModelv0, modified });
|
||||
this._previewDiffEditor.value.setModel({ original: textModel0, modified });
|
||||
|
||||
// joined ranges
|
||||
let originalLineRange = changes[0].original;
|
||||
let modifiedLineRange = changes[0].modified;
|
||||
for (let i = 1; i < changes.length; i++) {
|
||||
originalLineRange = originalLineRange.join(changes[i].original);
|
||||
modifiedLineRange = modifiedLineRange.join(changes[i].modified);
|
||||
let originalLineRange = diff.changes[0].original;
|
||||
let modifiedLineRange = diff.changes[0].modified;
|
||||
for (let i = 1; i < diff.changes.length; i++) {
|
||||
originalLineRange = originalLineRange.join(diff.changes[i].original);
|
||||
modifiedLineRange = modifiedLineRange.join(diff.changes[i].modified);
|
||||
}
|
||||
|
||||
// apply extra padding
|
||||
@@ -695,10 +698,10 @@ export class InlineChatWidget {
|
||||
|
||||
const newEndLineModified = Math.min(modifiedLineRange.endLineNumberExclusive + pad, modified.getLineCount());
|
||||
modifiedLineRange = new LineRange(modifiedLineRange.startLineNumber, newEndLineModified);
|
||||
const newEndLineOriginal = Math.min(originalLineRange.endLineNumberExclusive + pad, textModelv0.getLineCount());
|
||||
const newEndLineOriginal = Math.min(originalLineRange.endLineNumberExclusive + pad, textModel0.getLineCount());
|
||||
originalLineRange = new LineRange(originalLineRange.startLineNumber, newEndLineOriginal);
|
||||
|
||||
const hiddenOriginal = invertLineRange(originalLineRange, textModelv0);
|
||||
const hiddenOriginal = invertLineRange(originalLineRange, textModel0);
|
||||
const hiddenModified = invertLineRange(modifiedLineRange, modified);
|
||||
this._previewDiffEditor.value.getOriginalEditor().setHiddenAreas(hiddenOriginal.map(lineRangeAsRange), 'diff-hidden');
|
||||
this._previewDiffEditor.value.getModifiedEditor().setHiddenAreas(hiddenModified.map(lineRangeAsRange), 'diff-hidden');
|
||||
|
||||
@@ -12,8 +12,12 @@ export function invertLineRange(range: LineRange, model: ITextModel): LineRange[
|
||||
return [];
|
||||
}
|
||||
const result: LineRange[] = [];
|
||||
result.push(new LineRange(1, range.startLineNumber));
|
||||
result.push(new LineRange(range.endLineNumberExclusive, model.getLineCount() + 1));
|
||||
if (range.startLineNumber > 1) {
|
||||
result.push(new LineRange(1, range.startLineNumber));
|
||||
}
|
||||
if (range.endLineNumberExclusive < model.getLineCount() + 1) {
|
||||
result.push(new LineRange(range.endLineNumberExclusive, model.getLineCount() + 1));
|
||||
}
|
||||
return result.filter(r => !r.isEmpty);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ suite('InteractiveChatController', function () {
|
||||
const run = ctrl.run({ message: 'Hello', autoSend: true });
|
||||
await p;
|
||||
assert.ok(ctrl.getWidgetPosition() !== undefined);
|
||||
ctrl.cancelSession();
|
||||
await ctrl.cancelSession();
|
||||
|
||||
await run;
|
||||
|
||||
@@ -205,7 +205,7 @@ suite('InteractiveChatController', function () {
|
||||
assert.ok(session);
|
||||
assert.deepStrictEqual(session.wholeRange.value, new Range(1, 1, 1, 6));
|
||||
|
||||
ctrl.cancelSession();
|
||||
await ctrl.cancelSession();
|
||||
d.dispose();
|
||||
});
|
||||
|
||||
@@ -235,7 +235,7 @@ suite('InteractiveChatController', function () {
|
||||
assert.ok(session);
|
||||
assert.deepStrictEqual(session.wholeRange.value, new Range(1, 1, 1, 6));
|
||||
|
||||
ctrl.cancelSession();
|
||||
await ctrl.cancelSession();
|
||||
d.dispose();
|
||||
});
|
||||
|
||||
@@ -298,7 +298,7 @@ suite('InteractiveChatController', function () {
|
||||
|
||||
assert.deepStrictEqual(session.wholeRange.value, new Range(1, 1, 4, 12));
|
||||
|
||||
ctrl.cancelSession();
|
||||
await ctrl.cancelSession();
|
||||
await r;
|
||||
});
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ export class MarkersView extends FilterViewPane implements IMarkersView {
|
||||
}
|
||||
|
||||
public override focus(): void {
|
||||
if (this.widget.getHTMLElement() === document.activeElement) {
|
||||
if (dom.isActiveElement(this.widget.getHTMLElement())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -772,7 +772,7 @@ export class MarkersView extends FilterViewPane implements IMarkersView {
|
||||
|
||||
private updateRangeHighlights() {
|
||||
this.rangeHighlightDecorations.removeHighlightRange();
|
||||
if (this.widget.getHTMLElement() === document.activeElement) {
|
||||
if (dom.isActiveElement(this.widget.getHTMLElement())) {
|
||||
this.highlightCurrentSelectedMarkerRange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import { Categories } from 'vs/platform/action/common/actionCommonCategories';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { showWindowLogActionId } from 'vs/workbench/services/log/common/logConstants';
|
||||
import { getActiveElement } from 'vs/base/browser/dom';
|
||||
import { getActiveElement, getWindow } from 'vs/base/browser/dom';
|
||||
|
||||
let _logging: boolean = false;
|
||||
function toggleLogging() {
|
||||
@@ -309,7 +309,7 @@ export class NotebookClipboardContribution extends Disposable {
|
||||
}
|
||||
|
||||
private _focusInsideEmebedMonaco(editor: INotebookEditor) {
|
||||
const windowSelection = window.getSelection();
|
||||
const windowSelection = getWindow(editor.getDomNode()).getSelection();
|
||||
|
||||
if (windowSelection?.rangeCount !== 1) {
|
||||
return false;
|
||||
|
||||
@@ -1996,7 +1996,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
||||
return false;
|
||||
}
|
||||
|
||||
const windowSelection = window.getSelection();
|
||||
const windowSelection = DOM.getWindow(this.getDomNode()).getSelection();
|
||||
if (windowSelection?.rangeCount !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -531,7 +531,11 @@
|
||||
line-height: 15px;
|
||||
/** For some reason, this is needed, otherwise <code> will take up 20px height */
|
||||
font-family: var(--monaco-monospace-font);
|
||||
font-size: 11px;
|
||||
color: var(--vscode-textPreformat-foreground);
|
||||
background-color: var(--vscode-textPreformat-background);
|
||||
padding: 1px 3px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body .settings-tree-container .setting-item-contents .setting-item-markdown .monaco-tokenized-source {
|
||||
@@ -597,7 +601,12 @@
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown code {
|
||||
font-family: var(--monaco-monospace-font);
|
||||
font-size: 12px;
|
||||
color: var(--vscode-textPreformat-foreground);
|
||||
background-color: var(--vscode-textPreformat-background);
|
||||
padding: 2px 5px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.monaco-select-box-dropdown-container > .select-box-details-pane > .select-box-description-markdown a,
|
||||
|
||||
@@ -33,6 +33,7 @@ import { MANAGE_TRUST_COMMAND_ID, WorkspaceTrustContext } from 'vs/workbench/con
|
||||
import { IQuickDiffService } from 'vs/workbench/contrib/scm/common/quickDiff';
|
||||
import { QuickDiffService } from 'vs/workbench/contrib/scm/common/quickDiffService';
|
||||
import { SCMSyncViewPane } from 'vs/workbench/contrib/scm/browser/scmSyncViewPane';
|
||||
import { getActiveElement } from 'vs/base/browser/dom';
|
||||
|
||||
ModesRegistry.registerLanguage({
|
||||
id: 'scminput',
|
||||
@@ -227,7 +228,7 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
|
||||
localize('scm.providerCountBadge.auto', "Only show count badge for Source Control Provider when non-zero."),
|
||||
localize('scm.providerCountBadge.visible', "Show Source Control Provider count badges.")
|
||||
],
|
||||
description: localize('scm.providerCountBadge', "Controls the count badges on Source Control Provider headers. These headers only appear when there is more than one provider."),
|
||||
markdownDescription: localize('scm.providerCountBadge', "Controls the count badges on Source Control Provider headers. These headers appear in the \"Source Control\", and \"Source Control Sync\" views when there is more than one provider or when the {0} setting is enabled, as well as in the \"Source Control Repositories\" view.", '\`#scm.alwaysShowRepositories#\`'),
|
||||
default: 'hidden'
|
||||
},
|
||||
'scm.defaultViewMode': {
|
||||
@@ -308,7 +309,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
primary: KeyMod.CtrlCmd | KeyCode.Enter,
|
||||
handler: accessor => {
|
||||
const contextKeyService = accessor.get(IContextKeyService);
|
||||
const context = contextKeyService.getContext(document.activeElement);
|
||||
const context = contextKeyService.getContext(getActiveElement());
|
||||
const repositoryId = context.getValue<string | undefined>('scmRepository');
|
||||
|
||||
if (!repositoryId) {
|
||||
@@ -336,7 +337,7 @@ const viewNextCommitCommand = {
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const contextKeyService = accessor.get(IContextKeyService);
|
||||
const scmService = accessor.get(ISCMService);
|
||||
const context = contextKeyService.getContext(document.activeElement);
|
||||
const context = contextKeyService.getContext(getActiveElement());
|
||||
const repositoryId = context.getValue<string | undefined>('scmRepository');
|
||||
const repository = repositoryId ? scmService.getRepository(repositoryId) : undefined;
|
||||
repository?.input.showNextHistoryValue();
|
||||
@@ -349,7 +350,7 @@ const viewPreviousCommitCommand = {
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const contextKeyService = accessor.get(IContextKeyService);
|
||||
const scmService = accessor.get(ISCMService);
|
||||
const context = contextKeyService.getContext(document.activeElement);
|
||||
const context = contextKeyService.getContext(getActiveElement());
|
||||
const repositoryId = context.getValue<string | undefined>('scmRepository');
|
||||
const repository = repositoryId ? scmService.getRepository(repositoryId) : undefined;
|
||||
repository?.input.showPreviousHistoryValue();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import 'vs/css!./media/scm';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane';
|
||||
import { append, $ } from 'vs/base/browser/dom';
|
||||
import { IListVirtualDelegate, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list';
|
||||
@@ -24,6 +25,7 @@ import { RepositoryRenderer } from 'vs/workbench/contrib/scm/browser/scmReposito
|
||||
import { collectContextMenuActions, getActionViewItemProvider } from 'vs/workbench/contrib/scm/browser/util';
|
||||
import { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
||||
class ListDelegate implements IListVirtualDelegate<ISCMRepository> {
|
||||
|
||||
@@ -39,6 +41,7 @@ class ListDelegate implements IListVirtualDelegate<ISCMRepository> {
|
||||
export class SCMRepositoriesViewPane extends ViewPane {
|
||||
|
||||
private list!: WorkbenchList<ISCMRepository>;
|
||||
private readonly disposables = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
options: IViewPaneOptions,
|
||||
@@ -61,6 +64,14 @@ export class SCMRepositoriesViewPane extends ViewPane {
|
||||
|
||||
const listContainer = append(container, $('.scm-view.scm-repositories-view'));
|
||||
|
||||
const updateProviderCountVisibility = () => {
|
||||
const value = this.configurationService.getValue<'hidden' | 'auto' | 'visible'>('scm.providerCountBadge');
|
||||
listContainer.classList.toggle('hide-provider-counts', value === 'hidden');
|
||||
listContainer.classList.toggle('auto-provider-counts', value === 'auto');
|
||||
};
|
||||
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.providerCountBadge'), this.disposables)(updateProviderCountVisibility));
|
||||
updateProviderCountVisibility();
|
||||
|
||||
const delegate = new ListDelegate();
|
||||
const renderer = this.instantiationService.createInstance(RepositoryRenderer, getActionViewItemProvider(this.instantiationService));
|
||||
const identityProvider = { getId: (r: ISCMRepository) => r.provider.id };
|
||||
@@ -179,4 +190,9 @@ export class SCMRepositoriesViewPane extends ViewPane {
|
||||
this.list.setFocus([selection[0]]);
|
||||
}
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
this.disposables.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1072,7 +1072,7 @@ export class SearchView extends ViewPane {
|
||||
}
|
||||
|
||||
private updateTextFromFindWidget(controller: CommonFindController, { allowSearchOnType = true }): boolean {
|
||||
if (!this.searchConfig.seedWithNearestWord && (window.getSelection()?.toString() ?? '') === '') {
|
||||
if (!this.searchConfig.seedWithNearestWord && (dom.getActiveWindow().getSelection()?.toString() ?? '') === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1275,7 +1275,7 @@ export class SearchView extends ViewPane {
|
||||
}
|
||||
|
||||
private getSearchTextFromEditor(allowUnselectedWord: boolean, editor?: IEditor): string | null {
|
||||
if (dom.isAncestor(document.activeElement, this.getContainer())) {
|
||||
if (dom.isAncestorOfActiveElement(this.getContainer())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ export interface ISpeechService {
|
||||
readonly onDidRegisterSpeechProvider: Event<ISpeechProvider>;
|
||||
readonly onDidUnregisterSpeechProvider: Event<ISpeechProvider>;
|
||||
|
||||
readonly hasSpeechProvider: boolean;
|
||||
|
||||
registerSpeechProvider(identifier: string, provider: ISpeechProvider): IDisposable;
|
||||
|
||||
createSpeechToTextSession(token: CancellationToken): ISpeechToTextSession;
|
||||
@@ -62,6 +64,8 @@ export class SpeechService implements ISpeechService {
|
||||
private readonly _onDidUnregisterSpeechProvider = new Emitter<ISpeechProvider>();
|
||||
readonly onDidUnregisterSpeechProvider = this._onDidUnregisterSpeechProvider.event;
|
||||
|
||||
get hasSpeechProvider(): boolean { return this.providers.size > 0; }
|
||||
|
||||
private readonly providers = new Map<string, ISpeechProvider>();
|
||||
|
||||
constructor(@ILogService private readonly logService: ILogService) { }
|
||||
|
||||
@@ -865,6 +865,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
// The container changed, reattach
|
||||
this._container = container;
|
||||
this._container.appendChild(this._wrapperElement);
|
||||
|
||||
// If xterm is already attached, call open again to pick up any changes to the window.
|
||||
if (this.xterm?.raw.element) {
|
||||
this.xterm.raw.open(this.xterm.raw.element);
|
||||
}
|
||||
|
||||
this.xterm?.refresh();
|
||||
|
||||
setTimeout(() => this._initDragAndDrop(container));
|
||||
|
||||
+27
-5
@@ -3,11 +3,14 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
|
||||
import { TerminalCapability, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities';
|
||||
import { ICurrentPartialCommand } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';
|
||||
import { TerminalSettingId } from 'vs/platform/terminal/common/terminal';
|
||||
@@ -28,17 +31,18 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements
|
||||
private _bufferTracker: BufferContentTracker,
|
||||
customHelp: () => string,
|
||||
@IModelService _modelService: IModelService,
|
||||
@IConfigurationService _configurationService: IConfigurationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IContextKeyService _contextKeyService: IContextKeyService,
|
||||
@ITerminalService _terminalService: ITerminalService
|
||||
@ITerminalService _terminalService: ITerminalService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService
|
||||
) {
|
||||
super();
|
||||
this.options.customHelp = customHelp;
|
||||
this.options.position = _configurationService.getValue(TerminalSettingId.AccessibleViewPreserveCursorPosition) ? 'initial-bottom' : 'bottom';
|
||||
this.options.position = configurationService.getValue(TerminalSettingId.AccessibleViewPreserveCursorPosition) ? 'initial-bottom' : 'bottom';
|
||||
this.add(this._instance.onDisposed(() => this._onDidRequestClearProvider.fire(AccessibleViewProviderId.Terminal)));
|
||||
this.add(_configurationService.onDidChangeConfiguration(e => {
|
||||
this.add(configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(TerminalSettingId.AccessibleViewPreserveCursorPosition)) {
|
||||
this.options.position = _configurationService.getValue(TerminalSettingId.AccessibleViewPreserveCursorPosition) ? 'initial-bottom' : 'bottom';
|
||||
this.options.position = configurationService.getValue(TerminalSettingId.AccessibleViewPreserveCursorPosition) ? 'initial-bottom' : 'bottom';
|
||||
}
|
||||
}));
|
||||
this._focusedInstance = _terminalService.activeInstance;
|
||||
@@ -50,6 +54,13 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements
|
||||
}));
|
||||
}
|
||||
|
||||
onKeyDown(e: IKeyboardEvent): void {
|
||||
if (!shouldFocusTerminal(e.browserEvent, this._keybindingService)) {
|
||||
return;
|
||||
}
|
||||
this._instance.focus();
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this._instance.focus();
|
||||
}
|
||||
@@ -115,3 +126,14 @@ export class TerminalAccessibleBufferProvider extends DisposableStore implements
|
||||
}
|
||||
}
|
||||
export interface ICommandWithEditorLine { command: ITerminalCommand | ICurrentPartialCommand; lineNumber: number }
|
||||
|
||||
function shouldFocusTerminal(event: KeyboardEvent, keybindingService: IKeybindingService): boolean {
|
||||
const standardKeyboardEvent = new StandardKeyboardEvent(event);
|
||||
const resolveResult = keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target);
|
||||
|
||||
const isValidChord = resolveResult.kind === ResultKind.MoreChordsNeeded;
|
||||
if (keybindingService.inChordMode || isValidChord) {
|
||||
return false;
|
||||
}
|
||||
return event.key.length === 1 && !event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import { UILabelProvider } from 'vs/base/common/keybindingLabels';
|
||||
import { OS, OperatingSystem } from 'vs/base/common/platform';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { addDisposableListener, Dimension, safeInnerHtml, size } from 'vs/base/browser/dom';
|
||||
import { addDisposableListener, Dimension, getWindow, safeInnerHtml, size } from 'vs/base/browser/dom';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -156,7 +156,7 @@ export class WalkThroughPart extends EditorPane {
|
||||
this.content.addEventListener('click', event => {
|
||||
for (let node = event.target as HTMLElement; node; node = node.parentNode as HTMLElement) {
|
||||
if (node instanceof HTMLAnchorElement && node.href) {
|
||||
const baseElement = window.document.getElementsByTagName('base')[0] || window.location;
|
||||
const baseElement = node.ownerDocument.getElementsByTagName('base')[0] || getWindow(node).location;
|
||||
if (baseElement && node.href.indexOf(baseElement.href) >= 0 && node.hash) {
|
||||
const scrollTarget = this.content.querySelector(node.hash);
|
||||
const innerContent = this.content.firstElementChild;
|
||||
|
||||
@@ -408,9 +408,9 @@ suite('EditorGroupsService', () => {
|
||||
const currentOptions = part.partOptions;
|
||||
assert.ok(currentOptions);
|
||||
|
||||
disposables.add(part.enforcePartOptions({ showTabs: false }));
|
||||
assert.strictEqual(part.partOptions.showTabs, false);
|
||||
assert.strictEqual(newOptions.showTabs, false);
|
||||
disposables.add(part.enforcePartOptions({ showTabs: 'single' }));
|
||||
assert.strictEqual(part.partOptions.showTabs, 'single');
|
||||
assert.strictEqual(newOptions.showTabs, 'single');
|
||||
assert.strictEqual(oldOptions, currentOptions);
|
||||
});
|
||||
|
||||
|
||||
@@ -687,6 +687,10 @@ export class DefaultSettings extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
if (!enumToUse && (prop.enumItemLabels || enumDescriptions || enumDescriptionsAreMarkdown)) {
|
||||
console.error(`The setting ${key} has enum-related fields, but doesn't have an enum field. This setting may render improperly in the Settings editor.`);
|
||||
}
|
||||
|
||||
result.push({
|
||||
key,
|
||||
value,
|
||||
@@ -706,6 +710,7 @@ export class DefaultSettings extends Disposable {
|
||||
enum: enumToUse,
|
||||
enumDescriptions: enumDescriptions,
|
||||
enumDescriptionsAreMarkdown: enumDescriptionsAreMarkdown,
|
||||
enumItemLabels: prop.enumItemLabels,
|
||||
uniqueItems: prop.uniqueItems,
|
||||
tags: prop.tags,
|
||||
disallowSyncIgnore: prop.disallowSyncIgnore,
|
||||
@@ -714,7 +719,6 @@ export class DefaultSettings extends Disposable {
|
||||
deprecationMessage: prop.markdownDeprecationMessage || prop.deprecationMessage,
|
||||
deprecationMessageIsMarkdown: !!prop.markdownDeprecationMessage,
|
||||
validator: createValidator(prop),
|
||||
enumItemLabels: prop.enumItemLabels,
|
||||
allKeysAreBoolean,
|
||||
editPresentation: prop.editPresentation,
|
||||
order: prop.order,
|
||||
@@ -1058,7 +1062,7 @@ class SettingsContentBuilder {
|
||||
setting.descriptionRanges.push({ startLineNumber: this.lineCountWithOffset, startColumn: this.lastLine.indexOf(line) + 1, endLineNumber: this.lineCountWithOffset, endColumn: this.lastLine.length });
|
||||
}
|
||||
|
||||
if (setting.enumDescriptions && setting.enumDescriptions.some(desc => !!desc)) {
|
||||
if (setting.enum && setting.enumDescriptions?.some(desc => !!desc)) {
|
||||
setting.enumDescriptions.forEach((desc, i) => {
|
||||
const displayEnum = escapeInvisibleChars(String(setting.enum![i]));
|
||||
const line = desc ?
|
||||
|
||||
-127
@@ -1,127 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare class AudioWorkletProcessor {
|
||||
|
||||
readonly port: MessagePort;
|
||||
|
||||
process(inputs: [Float32Array[]], outputs: [Float32Array[]]): boolean;
|
||||
}
|
||||
|
||||
interface IVoiceTranscriptionWorkletOptions extends AudioWorkletNodeOptions {
|
||||
processorOptions: {
|
||||
readonly bufferTimespan: number;
|
||||
readonly vadThreshold: number;
|
||||
};
|
||||
}
|
||||
|
||||
class VoiceTranscriptionWorklet extends AudioWorkletProcessor {
|
||||
|
||||
private startTime: number | undefined = undefined;
|
||||
private stopped: boolean = false;
|
||||
|
||||
private buffer: Float32Array[] = [];
|
||||
|
||||
private sharedProcessConnection: MessagePort | undefined = undefined;
|
||||
|
||||
constructor(private readonly options: IVoiceTranscriptionWorkletOptions) {
|
||||
super();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners() {
|
||||
this.port.onmessage = event => {
|
||||
switch (event.data) {
|
||||
case 'vscode:startVoiceTranscription': {
|
||||
this.sharedProcessConnection = event.ports[0];
|
||||
|
||||
this.sharedProcessConnection.onmessage = event => {
|
||||
if (this.stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof event.data === 'string') {
|
||||
this.port.postMessage(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.sharedProcessConnection.start();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'vscode:stopVoiceTranscription': {
|
||||
this.stopped = true;
|
||||
|
||||
this.sharedProcessConnection?.close();
|
||||
this.sharedProcessConnection = undefined;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
override process(inputs: [Float32Array[]]): boolean {
|
||||
if (this.startTime === undefined) {
|
||||
this.startTime = Date.now();
|
||||
}
|
||||
|
||||
const inputChannelData = inputs[0][0];
|
||||
if ((!(inputChannelData instanceof Float32Array))) {
|
||||
return !this.stopped;
|
||||
}
|
||||
|
||||
this.buffer.push(inputChannelData.slice(0));
|
||||
|
||||
if (Date.now() - this.startTime > this.options.processorOptions.bufferTimespan && this.sharedProcessConnection) {
|
||||
const buffer = this.joinFloat32Arrays(this.buffer);
|
||||
this.buffer = [];
|
||||
|
||||
// Send buffer to shared process for transcription.
|
||||
// Send an empty buffer if it appears to be silence
|
||||
// so that we can still trigger the transcription
|
||||
// service and let it know about this.
|
||||
|
||||
this.sharedProcessConnection.postMessage(this.appearsToBeSilence(buffer) ? new Float32Array(0) : buffer);
|
||||
|
||||
this.startTime = Date.now();
|
||||
}
|
||||
|
||||
return !this.stopped;
|
||||
}
|
||||
|
||||
private appearsToBeSilence(data: Float32Array): boolean {
|
||||
|
||||
// This is the most simple Voice Activity Detection (VAD)
|
||||
// and it is based on the Root Mean Square (RMS) of the signal
|
||||
// with a certain threshold. Good for testing but probably
|
||||
// not suitable for shipping to stable (TODO@bpasero).
|
||||
|
||||
let sum = 0;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
sum += data[i] * data[i];
|
||||
}
|
||||
|
||||
const rms = Math.sqrt(sum / data.length);
|
||||
|
||||
return rms < this.options.processorOptions.vadThreshold;
|
||||
}
|
||||
|
||||
private joinFloat32Arrays(float32Arrays: Float32Array[]): Float32Array {
|
||||
const result = new Float32Array(float32Arrays.reduce((prev, curr) => prev + curr.length, 0));
|
||||
|
||||
let offset = 0;
|
||||
for (const float32Array of float32Arrays) {
|
||||
result.set(float32Array, offset);
|
||||
offset += float32Array.length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
registerProcessor('voice-transcription-worklet', VoiceTranscriptionWorklet);
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { DeferredPromise } from 'vs/base/common/async';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export const IWorkbenchVoiceRecognitionService = createDecorator<IWorkbenchVoiceRecognitionService>('workbenchVoiceRecognitionService');
|
||||
|
||||
export interface IWorkbenchVoiceRecognitionOptions {
|
||||
|
||||
/**
|
||||
* Optional event that is fired when the user cancels the voice recognition.
|
||||
*/
|
||||
readonly onDidCancel?: () => void;
|
||||
}
|
||||
|
||||
export interface IWorkbenchVoiceRecognitionService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Starts listening to the microphone transcribing the voice to text. Microphone
|
||||
* recording starts when the returned promise is resolved.
|
||||
*
|
||||
* @param cancellation a cancellation token to stop transcribing and
|
||||
* listening to the microphone.
|
||||
*/
|
||||
transcribe(cancellation: CancellationToken, options?: IWorkbenchVoiceRecognitionOptions): Promise<Event<string>>;
|
||||
}
|
||||
|
||||
interface IVoiceTranscriptionWorkletOptions extends AudioWorkletNodeOptions {
|
||||
processorOptions: {
|
||||
readonly bufferTimespan: number;
|
||||
readonly vadThreshold: number;
|
||||
};
|
||||
}
|
||||
|
||||
class VoiceTranscriptionWorkletNode extends AudioWorkletNode {
|
||||
|
||||
constructor(
|
||||
context: BaseAudioContext,
|
||||
options: IVoiceTranscriptionWorkletOptions,
|
||||
private readonly onDidTranscribe: Emitter<string>,
|
||||
private readonly sharedProcessService: ISharedProcessService
|
||||
) {
|
||||
super(context, 'voice-transcription-worklet', options);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.port.onmessage = e => {
|
||||
if (typeof e.data === 'string') {
|
||||
this.onDidTranscribe.fire(e.data);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async start(token: CancellationToken): Promise<void> {
|
||||
token.onCancellationRequested(() => this.stop());
|
||||
|
||||
const sharedProcessConnection = await this.sharedProcessService.createRawConnection();
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
this.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.port.postMessage('vscode:startVoiceTranscription', [sharedProcessConnection]);
|
||||
}
|
||||
|
||||
private stop(): void {
|
||||
this.port.postMessage('vscode:stopVoiceTranscription');
|
||||
this.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkbenchVoiceRecognitionService implements IWorkbenchVoiceRecognitionService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private static readonly AUDIO_SAMPLING_RATE = 16000;
|
||||
private static readonly AUDIO_BIT_DEPTH = 16;
|
||||
private static readonly AUDIO_CHANNELS = 1;
|
||||
|
||||
private static readonly BUFFER_TIMESPAN = 1000;
|
||||
private static readonly VAD_THRESHOLD = 0.02;
|
||||
|
||||
constructor(
|
||||
@IProgressService private readonly progressService: IProgressService,
|
||||
@ISharedProcessService private readonly sharedProcessService: ISharedProcessService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) { }
|
||||
|
||||
async transcribe(cancellation: CancellationToken, options?: IWorkbenchVoiceRecognitionOptions): Promise<Event<string>> {
|
||||
const cts = new CancellationTokenSource(cancellation);
|
||||
|
||||
const onDidTranscribe = new Emitter<string>();
|
||||
cts.token.onCancellationRequested(() => {
|
||||
onDidTranscribe.dispose();
|
||||
options?.onDidCancel?.();
|
||||
});
|
||||
|
||||
await this.doTranscribe(onDidTranscribe, cts);
|
||||
|
||||
return onDidTranscribe.event;
|
||||
}
|
||||
|
||||
private doTranscribe(onDidTranscribe: Emitter<string>, cts: CancellationTokenSource): Promise<void> {
|
||||
const recordingReady = new DeferredPromise<void>();
|
||||
cts.token.onCancellationRequested(() => recordingReady.complete());
|
||||
|
||||
this.progressService.withProgress({
|
||||
location: ProgressLocation.Window,
|
||||
title: localize('voiceTranscription', "Voice Transcription"),
|
||||
cancellable: true
|
||||
}, async progress => {
|
||||
const recordingDone = new DeferredPromise<void>();
|
||||
try {
|
||||
progress.report({ message: localize('voiceTranscriptionGettingReady', "Getting microphone ready...") });
|
||||
|
||||
const microphoneDevice = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
sampleRate: WorkbenchVoiceRecognitionService.AUDIO_SAMPLING_RATE,
|
||||
sampleSize: WorkbenchVoiceRecognitionService.AUDIO_BIT_DEPTH,
|
||||
channelCount: WorkbenchVoiceRecognitionService.AUDIO_CHANNELS,
|
||||
autoGainControl: true,
|
||||
noiseSuppression: true,
|
||||
echoCancellation: false
|
||||
}
|
||||
});
|
||||
|
||||
if (cts.token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
const audioContext = new AudioContext({
|
||||
sampleRate: WorkbenchVoiceRecognitionService.AUDIO_SAMPLING_RATE,
|
||||
latencyHint: 'interactive'
|
||||
});
|
||||
|
||||
const microphoneSource = audioContext.createMediaStreamSource(microphoneDevice);
|
||||
|
||||
cts.token.onCancellationRequested(() => {
|
||||
try {
|
||||
for (const track of microphoneDevice.getTracks()) {
|
||||
track.stop();
|
||||
}
|
||||
|
||||
microphoneSource.disconnect();
|
||||
audioContext.close();
|
||||
} finally {
|
||||
recordingDone.complete();
|
||||
}
|
||||
});
|
||||
|
||||
await audioContext.audioWorklet.addModule(FileAccess.asBrowserUri('vs/workbench/services/voiceRecognition/electron-sandbox/voiceTranscriptionWorklet.js').toString(true));
|
||||
|
||||
if (cts.token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
const voiceTranscriptionTarget = new VoiceTranscriptionWorkletNode(audioContext, {
|
||||
channelCount: WorkbenchVoiceRecognitionService.AUDIO_CHANNELS,
|
||||
channelCountMode: 'explicit',
|
||||
processorOptions: {
|
||||
bufferTimespan: WorkbenchVoiceRecognitionService.BUFFER_TIMESPAN,
|
||||
vadThreshold: WorkbenchVoiceRecognitionService.VAD_THRESHOLD
|
||||
}
|
||||
}, onDidTranscribe, this.sharedProcessService);
|
||||
await voiceTranscriptionTarget.start(cts.token);
|
||||
|
||||
if (cts.token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
microphoneSource.connect(voiceTranscriptionTarget);
|
||||
|
||||
progress.report({ message: localize('voiceTranscriptionRecording', "Recording from microphone...") });
|
||||
recordingReady.complete();
|
||||
|
||||
return recordingDone.p;
|
||||
} catch (error) {
|
||||
this.notificationService.error(localize('voiceTranscriptionError', "Voice transcription failed: {0}", error.message));
|
||||
|
||||
recordingReady.error(error);
|
||||
recordingDone.error(error);
|
||||
}
|
||||
}, () => {
|
||||
cts.cancel();
|
||||
});
|
||||
|
||||
return recordingReady.p;
|
||||
}
|
||||
}
|
||||
|
||||
// Register Service
|
||||
registerSingleton(IWorkbenchVoiceRecognitionService, WorkbenchVoiceRecognitionService, InstantiationType.Delayed);
|
||||
@@ -75,7 +75,6 @@ import 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentServi
|
||||
import 'vs/workbench/services/integrity/electron-sandbox/integrityService';
|
||||
import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService';
|
||||
import 'vs/workbench/services/checksum/electron-sandbox/checksumService';
|
||||
import 'vs/workbench/services/voiceRecognition/electron-sandbox/workbenchVoiceRecognitionService';
|
||||
import 'vs/platform/remote/electron-sandbox/sharedProcessTunnelService';
|
||||
import 'vs/workbench/services/tunnel/electron-sandbox/tunnelService';
|
||||
import 'vs/platform/diagnostics/electron-sandbox/diagnosticsService';
|
||||
|
||||
@@ -64,7 +64,7 @@ declare module 'vscode' {
|
||||
export interface InteractiveSessionFollowupAction {
|
||||
// eslint-disable-next-line local/vscode-dts-string-type-literals
|
||||
kind: 'followUp';
|
||||
followup: InteractiveSessionFollowup;
|
||||
followup: InteractiveSessionReplyFollowup;
|
||||
}
|
||||
|
||||
export type InteractiveSessionUserAction = InteractiveSessionVoteAction | InteractiveSessionCopyAction | InteractiveSessionInsertAction | InteractiveSessionTerminalAction | InteractiveSessionCommandAction;
|
||||
|
||||
@@ -10375,45 +10375,45 @@ xtend@~4.0.0, xtend@~4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
xterm-addon-canvas@0.6.0-beta.31:
|
||||
version "0.6.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.31.tgz#04ebde31c5e01b2595b966a2861deaec9927e1cb"
|
||||
integrity sha512-/Dz90IF5FQqzAitKi3k/JEyyRMhSuQG8PVtB2NwOlWUcE3Ukp6gJMFdkyfOOt0Lx/8oyWR7xoDgKY3bxbzpkGQ==
|
||||
xterm-addon-canvas@0.6.0-beta.32:
|
||||
version "0.6.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.6.0-beta.32.tgz#c9e74dd72fcc981a2e0cbd0b82827676bc5c74b9"
|
||||
integrity sha512-Xw7oE4dbS+x+pu6cGW1bDSXcVviuorLz1OLaYw46jjmDezIqQIIEMhSMOprExFEWgeRQ9AEN4lPqw6aH87V74w==
|
||||
|
||||
xterm-addon-image@0.6.0-beta.21:
|
||||
version "0.6.0-beta.21"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.6.0-beta.21.tgz#e3708bc504c56a23ff31f12a2eeb335331a92aac"
|
||||
integrity sha512-8/PTaXVPa4kQ0xzVeuZZk10OpbZBj2cgfwhM2B0ChSPvwrk0lX+ksnXdtDKH3tg+JYvo7fIhNXtkr4NwWt7VJQ==
|
||||
|
||||
xterm-addon-search@0.14.0-beta.30:
|
||||
version "0.14.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.30.tgz#a84321ded127ab13a0bdbf901d2524900330f6ea"
|
||||
integrity sha512-e5qb68lmpxQ1cG4oJKq9NC61oV2xGynRyruB2luerGeXPhqkGj9RSDeOqgCWbnQNTfBmkROzrn02MeJAsoqvGQ==
|
||||
xterm-addon-search@0.14.0-beta.31:
|
||||
version "0.14.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.14.0-beta.31.tgz#933ca5d2d642dacad29f2cfbd50830cff83bc274"
|
||||
integrity sha512-JRY1ukhoh32D0AMz78xpumQkLgkcP9d3GXj6gzVHZZsjLAMDaJYEubYq1bUhM7IGHUyg+x0sdRJyx7d6fJpiQg==
|
||||
|
||||
xterm-addon-serialize@0.12.0-beta.30:
|
||||
version "0.12.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.30.tgz#80c4101f45a463ef139705bcd3dcaf0811f51ea4"
|
||||
integrity sha512-nZP0ip5bd9LBoCTN9vCnn4iLatF4RRwzLupQf9r2N9x1bULzTZ1kAXAQe5gghsXjSEDDtyY2LzGigqTd2KVAqQ==
|
||||
xterm-addon-serialize@0.12.0-beta.31:
|
||||
version "0.12.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.12.0-beta.31.tgz#2a95dc1e12f4097e2894b04c9cb8fff0bc0b858c"
|
||||
integrity sha512-h2rWR+Lfi1Iv4VkLUlrBMYh5Mdq8vux2BKyCJe6a1ZnEu5Dzb0VuiNxfTKXTCT5M83nMn7TCB9TX0E8z6bs7xw==
|
||||
|
||||
xterm-addon-unicode11@0.7.0-beta.30:
|
||||
version "0.7.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.30.tgz#2de2c412d41823f31b66f68c7d8d0fb9e1a66cd3"
|
||||
integrity sha512-pLSSBxwCOD5aShGnk6VveLHpjDwEDrIci2WnVcuWIbPaqHkB16d6l17jJ50843TaW66k1Np3ZCpDteOoC0Z6Kw==
|
||||
xterm-addon-unicode11@0.7.0-beta.31:
|
||||
version "0.7.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.7.0-beta.31.tgz#abcba752172323f31312bd8a3f9b6a049dbca6e3"
|
||||
integrity sha512-vvBKJbBoLbeIf2++6D16VnOOwevZE3nyO/PDZ7cyTJK1eYR73rr8ZbjUrH92YoTu4Z8MpZFepGQOgK/vlAQMwQ==
|
||||
|
||||
xterm-addon-webgl@0.17.0-beta.30:
|
||||
version "0.17.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.30.tgz#e4d7b18eb8f2b0be6ee8bf35185e91b33570e67f"
|
||||
integrity sha512-SjdfIOmx9xunom2Bk//iQ2DoqYlvAsunEWD3nxdED0oYYf1SPlKxt3I47YHWVshacw6QPZEJHVXJ6K+kHlel/Q==
|
||||
xterm-addon-webgl@0.17.0-beta.31:
|
||||
version "0.17.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.17.0-beta.31.tgz#3cd29b4858e3f4f6dd5a8dd969454e85e1f43baa"
|
||||
integrity sha512-vYHj+HlTcqUlFFVuoCTjlgh89/lIoSkZ7Nc87cwSFTrJsl07qoKutmpupqFXyjhbEA1fQY2SuQLx08Gmf2jWkQ==
|
||||
|
||||
xterm-headless@5.4.0-beta.31:
|
||||
version "5.4.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.31.tgz#9538553c7426222f94d7da7ed467e699ebaeeedd"
|
||||
integrity sha512-EE/ZlsZcBE5VOkjQU/KdRL4gvSkfrC2P7VxrmK1+PLc6+QMjPxs60A4Pun3mIIS0MFfN23p6hmN22GAXVckCXA==
|
||||
xterm-headless@5.4.0-beta.32:
|
||||
version "5.4.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.4.0-beta.32.tgz#0d5cd35e1a0372888055ff0b06dfe17457979a6c"
|
||||
integrity sha512-DQduq8KSoQZyRrQAFB+FkcY2UMxCW39P1/duOpksebc6PT9pbGkyPe5s+AdUQGiYzriEpzVtKUzDcquoVmpPhA==
|
||||
|
||||
xterm@5.4.0-beta.31:
|
||||
version "5.4.0-beta.31"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.31.tgz#598f66cfa49609d4e4935fbaf00aadff8e23d174"
|
||||
integrity sha512-lAuiiWxxU8s0UaDwuJZupoBOtb9bY5ouBkOufnfpLK05ACm0046TPxs3bg05jPUI8y5y/qLgKqK0L5TxAiZ8WA==
|
||||
xterm@5.4.0-beta.32:
|
||||
version "5.4.0-beta.32"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.4.0-beta.32.tgz#1b4242cf1c0c1a5a1070da58d3f11956b537130a"
|
||||
integrity sha512-mWTwEiNBFMF89oqVfi6qTM2Py5gC1Mwvslx1KxmI2Ukgh9v3CrqKDhj29eY1ZeAo0uuYknFWKyuexqp+3SHJCA==
|
||||
|
||||
y18n@^3.2.1:
|
||||
version "3.2.2"
|
||||
|
||||
Reference in New Issue
Block a user