Merge branch 'main' into aamunger/notebookInfoRegistration2

This commit is contained in:
Aaron Munger 2023-07-06 08:03:10 -07:00 committed by GitHub
commit f5f7127f8f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 413 additions and 336 deletions

11
.github/commands/codespaces_issue.yml vendored Normal file
View file

@ -0,0 +1,11 @@
# Learn more about the syntax here:
# https://docs.github.com/en/early-access/github/save-time-with-slash-commands/syntax-for-user-defined-slash-commands
---
trigger: codespaces_issue
title: Codespaces Issue
description: Report downstream
steps:
- type: fill
template: |-
This looks like an issue with the Codespaces service which we don't track in this repository. You can report this to the Codespaces team at https://github.com/orgs/community/discussions/categories/codespaces

View file

@ -520,9 +520,9 @@ safe-buffer@~5.2.0:
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
semver@^7.3.5:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
version "7.5.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
dependencies:
lru-cache "^6.0.0"

79
build/win32/Cargo.lock generated
View file

@ -19,12 +19,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "build_const"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7"
[[package]]
name = "byteorder"
version = "1.4.3"
@ -39,13 +33,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc"
version = "1.8.1"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
dependencies = [
"build_const",
"crc-catalog",
]
[[package]]
name = "crc-catalog"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484"
[[package]]
name = "crossbeam-channel"
version = "0.5.5"
@ -109,14 +109,14 @@ dependencies = [
[[package]]
name = "inno_updater"
version = "0.9.0"
version = "0.10.0"
dependencies = [
"byteorder",
"crc",
"slog",
"slog-async",
"slog-term",
"winapi",
"windows-sys",
]
[[package]]
@ -329,3 +329,60 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"

View file

@ -1,18 +1,30 @@
[package]
name = "inno_updater"
version = "0.9.0"
version = "0.10.0"
authors = ["Microsoft <monacotools@microsoft.com>"]
build = "build.rs"
[dependencies]
byteorder = "1"
crc = "^1.0.0"
slog = "2.1.1"
slog-async = "2.2.0"
slog-term = "2.3.0"
byteorder = "1.4.3"
crc = "3.0.1"
slog = "2.7.0"
slog-async = "2.7.0"
slog-term = "2.9.0"
[target.'cfg(windows)'.dependencies]
winapi = { version = "^0.3.9", features = ["winuser", "libloaderapi", "commctrl", "processthreadsapi", "tlhelp32", "handleapi", "psapi", "errhandlingapi", "winbase", "shellapi"] }
[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.42"
features = [
"Win32_Foundation",
"Win32_System_Shutdown",
"Win32_UI_WindowsAndMessaging",
"Win32_System_Threading",
"Win32_System_LibraryLoader",
"Win32_System_Diagnostics_Debug",
"Win32_Storage_FileSystem",
"Win32_Security",
"Win32_System_ProcessStatus",
"Win32_System_Diagnostics_ToolHelp"
]
[profile.release]
lto = true

Binary file not shown.

View file

@ -34,9 +34,9 @@ minimatch@^5.1.0:
brace-expansion "^2.0.1"
semver@^7.3.7:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
version "7.5.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
dependencies:
lru-cache "^6.0.0"

View file

@ -78,7 +78,7 @@ export function activate(context: vscode.ExtensionContext) {
const lineResult = parseSearchResults(document, token)[position.line];
if (!lineResult) { return []; }
if (lineResult.type === 'file') {
return lineResult.allLocations;
return lineResult.allLocations.map(l => ({ ...l, originSelectionRange: lineResult.location.originSelectionRange }));
}
const location = lineResult.locations.find(l => l.originSelectionRange.contains(position));

View file

@ -661,9 +661,9 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
version "7.5.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
dependencies:
lru-cache "^6.0.0"

View file

@ -4,38 +4,32 @@
*--------------------------------------------------------------------------------------------*/
import { isStandalone } from 'vs/base/browser/browser';
import { CancellationToken } from 'vs/base/common/cancellation';
import { parse } from 'vs/base/common/marshalling';
import { Emitter } from 'vs/base/common/event';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { isEqual } from 'vs/base/common/resources';
import { URI, UriComponents } from 'vs/base/common/uri';
import { request } from 'vs/base/parts/request/browser/request';
import product from 'vs/platform/product/common/product';
import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/window/common/window';
import { create } from 'vs/workbench/workbench.web.main';
import { posix } from 'vs/base/common/path';
import { ltrim } from 'vs/base/common/strings';
import type { ICredentialsProvider } from 'vs/platform/credentials/common/credentials';
import type { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService';
import type { IWorkbenchConstructionOptions } from 'vs/workbench/browser/web.api';
import type { IWorkspace, IWorkspaceProvider } from 'vs/workbench/services/host/browser/browserHostService';
import { ISecretStorageProvider } from 'vs/platform/secrets/common/secrets';
import { AuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService';
interface ICredential {
service: string;
account: string;
password: string;
}
class LocalStorageSecretStorageProvider implements ISecretStorageProvider {
private static readonly STORAGE_KEY = 'secrets.provider';
class LocalStorageCredentialsProvider implements ICredentialsProvider {
private _secrets: Record<string, string> | undefined;
private static readonly CREDENTIALS_STORAGE_KEY = 'credentials.provider';
private readonly authService: string | undefined;
type: 'in-memory' | 'persisted' | 'unknown' = 'persisted';
constructor() {
let authSessionInfo: { readonly id: string; readonly accessToken: string; readonly providerId: string; readonly canSignOut?: boolean; readonly scopes: string[][] } | undefined;
let authSessionInfo: (AuthenticationSessionInfo & { scopes: string[][] }) | undefined;
const authSessionElement = document.getElementById('vscode-workbench-auth-session');
const authSessionElementAttribute = authSessionElement ? authSessionElement.getAttribute('data-settings') : undefined;
if (authSessionElementAttribute) {
@ -46,11 +40,15 @@ class LocalStorageCredentialsProvider implements ICredentialsProvider {
if (authSessionInfo) {
// Settings Sync Entry
this.setPassword(`${product.urlProtocol}.login`, 'account', JSON.stringify(authSessionInfo));
this.set(`${product.urlProtocol}.loginAccount`, JSON.stringify(authSessionInfo));
// Auth extension Entry
this.authService = `${product.urlProtocol}-${authSessionInfo.providerId}.login`;
this.setPassword(this.authService, 'account', JSON.stringify(authSessionInfo.scopes.map(scopes => ({
if (authSessionInfo.providerId !== 'github') {
console.error(`Unexpected auth provider: ${authSessionInfo.providerId}. Expected 'github'.`);
return;
}
const authAccount = JSON.stringify({ extensionId: 'vscode.github-authentication', key: 'github.auth' });
this.set(authAccount, JSON.stringify(authSessionInfo.scopes.map(scopes => ({
id: authSessionInfo!.id,
scopes,
accessToken: authSessionInfo!.accessToken
@ -58,121 +56,44 @@ class LocalStorageCredentialsProvider implements ICredentialsProvider {
}
}
private _credentials: ICredential[] | undefined;
private get credentials(): ICredential[] {
if (!this._credentials) {
get(key: string): Promise<string | undefined> {
return Promise.resolve(this.secrets[key]);
}
set(key: string, value: string): Promise<void> {
this.secrets[key] = value;
this.save();
return Promise.resolve();
}
async delete(key: string): Promise<void> {
delete this.secrets[key];
this.save();
return Promise.resolve();
}
private get secrets(): Record<string, string> {
if (!this._secrets) {
try {
const serializedCredentials = window.localStorage.getItem(LocalStorageCredentialsProvider.CREDENTIALS_STORAGE_KEY);
const serializedCredentials = window.localStorage.getItem(LocalStorageSecretStorageProvider.STORAGE_KEY);
if (serializedCredentials) {
this._credentials = JSON.parse(serializedCredentials);
this._secrets = JSON.parse(serializedCredentials);
}
} catch (error) {
// ignore
}
if (!Array.isArray(this._credentials)) {
this._credentials = [];
if (!(this._secrets instanceof Object)) {
this._secrets = {};
}
}
return this._credentials;
return this._secrets;
}
private save(): void {
window.localStorage.setItem(LocalStorageCredentialsProvider.CREDENTIALS_STORAGE_KEY, JSON.stringify(this.credentials));
}
async getPassword(service: string, account: string): Promise<string | null> {
return this.doGetPassword(service, account);
}
private async doGetPassword(service: string, account?: string): Promise<string | null> {
for (const credential of this.credentials) {
if (credential.service === service) {
if (typeof account !== 'string' || account === credential.account) {
return credential.password;
}
}
}
return null;
}
async setPassword(service: string, account: string, password: string): Promise<void> {
this.doDeletePassword(service, account);
this.credentials.push({ service, account, password });
this.save();
try {
if (password && service === this.authService) {
const value = JSON.parse(password);
if (Array.isArray(value) && value.length === 0) {
await this.logout(service);
}
}
} catch (error) {
console.log(error);
}
}
async deletePassword(service: string, account: string): Promise<boolean> {
const result = await this.doDeletePassword(service, account);
if (result && service === this.authService) {
try {
await this.logout(service);
} catch (error) {
console.log(error);
}
}
return result;
}
private async doDeletePassword(service: string, account: string): Promise<boolean> {
let found = false;
this._credentials = this.credentials.filter(credential => {
if (credential.service === service && credential.account === account) {
found = true;
return false;
}
return true;
});
if (found) {
this.save();
}
return found;
}
async findPassword(service: string): Promise<string | null> {
return this.doGetPassword(service);
}
async findCredentials(service: string): Promise<Array<{ account: string; password: string }>> {
return this.credentials
.filter(credential => credential.service === service)
.map(({ account, password }) => ({ account, password }));
}
private async logout(service: string): Promise<void> {
const queryValues: Map<string, string> = new Map();
queryValues.set('logout', String(true));
queryValues.set('service', service);
await request({
url: doCreateUri('/auth/logout', queryValues).toString(true)
}, CancellationToken.None);
}
async clear(): Promise<void> {
window.localStorage.removeItem(LocalStorageCredentialsProvider.CREDENTIALS_STORAGE_KEY);
window.localStorage.setItem(LocalStorageSecretStorageProvider.STORAGE_KEY, JSON.stringify(this.secrets));
}
}
@ -469,24 +390,6 @@ class WorkspaceProvider implements IWorkspaceProvider {
}
}
function doCreateUri(path: string, queryValues: Map<string, string>): URI {
let query: string | undefined = undefined;
if (queryValues) {
let index = 0;
queryValues.forEach((value, key) => {
if (!query) {
query = '';
}
const prefix = (index++ === 0) ? '' : '&';
query += `${prefix}${key}=${encodeURIComponent(value)}`;
});
}
return URI.parse(window.location.href).with({ path, query });
}
(function () {
// Find config by checking for DOM
@ -504,6 +407,6 @@ function doCreateUri(path: string, queryValues: Map<string, string>): URI {
settingsSyncOptions: config.settingsSyncOptions ? { enabled: config.settingsSyncOptions.enabled, } : undefined,
workspaceProvider: WorkspaceProvider.create(config),
urlCallbackProvider: new LocalStorageURLCallbackProvider(config.callbackRoute),
credentialsProvider: config.remoteAuthority ? undefined /* with a remote, we don't use a local credentials provider */ : new LocalStorageCredentialsProvider()
secretStorageProvider: config.remoteAuthority ? undefined /* with a remote, we don't use a local secret storage provider */ : new LocalStorageSecretStorageProvider()
});
})();

View file

@ -70,6 +70,7 @@ import { ILoggerMainService, LoggerMainService } from 'vs/platform/log/electron-
import { LogService } from 'vs/platform/log/common/logService';
import { massageMessageBoxOptions } from 'vs/platform/dialogs/common/dialogs';
import { SaveStrategy, StateService } from 'vs/platform/state/node/stateService';
import { FileUserDataProvider } from 'vs/platform/userData/common/fileUserDataProvider';
/**
* The main VS Code entry point.
@ -178,6 +179,10 @@ class CodeMain {
const diskFileSystemProvider = new DiskFileSystemProvider(logService);
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
// Use FileUserDataProvider for user data to
// enable atomic read / write operations.
fileService.registerProvider(Schemas.vscodeUserData, new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.vscodeUserData, logService));
// URI Identity
const uriIdentityService = new UriIdentityService(fileService);
services.set(IUriIdentityService, uriIdentityService);

View file

@ -26,7 +26,6 @@ import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsServ
import { IDownloadService } from 'vs/platform/download/common/download';
import { DownloadService } from 'vs/platform/download/common/downloadService';
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { SharedProcessEnvironmentService } from 'vs/platform/sharedProcess/node/sharedProcessEnvironmentService';
import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
@ -112,6 +111,7 @@ import { RemoteStorageService } from 'vs/platform/storage/common/storageService'
import { IRemoteSocketFactoryService, RemoteSocketFactoryService } from 'vs/platform/remote/common/remoteSocketFactoryService';
import { RemoteConnectionType } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory';
import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
class SharedProcessMain extends Disposable {
@ -191,7 +191,7 @@ class SharedProcessMain extends Disposable {
services.set(IPolicyService, policyService);
// Environment
const environmentService = new SharedProcessEnvironmentService(this.configuration.args, productService);
const environmentService = new NativeEnvironmentService(this.configuration.args, productService);
services.set(INativeEnvironmentService, environmentService);
// Logger

View file

@ -16,4 +16,17 @@
position: absolute;
display: flex;
align-items: center;
justify-content: center;
}
/*
Ensure spinning icons are pixel-perfectly centered and avoid wobble.
This is only applied to icons that spin to avoid unnecessary
GPU layers and blurry subpixel AA.
*/
.monaco-editor .glyph-margin-widgets .cgmr.codicon-modifier-spin::before {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

View file

@ -5,7 +5,7 @@
import { toLocalISOString } from 'vs/base/common/date';
import { memoize } from 'vs/base/common/decorators';
import { FileAccess } from 'vs/base/common/network';
import { FileAccess, Schemas } from 'vs/base/common/network';
import { dirname, join, normalize, resolve } from 'vs/base/common/path';
import { env } from 'vs/base/common/process';
import { joinPath } from 'vs/base/common/resources';
@ -65,10 +65,10 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
get stateResource(): URI { return joinPath(this.appSettingsHome, 'globalStorage', 'storage.json'); }
@memoize
get userRoamingDataHome(): URI { return this.appSettingsHome; }
get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.vscodeUserData }); }
@memoize
get userDataSyncHome(): URI { return joinPath(this.userRoamingDataHome, 'sync'); }
get userDataSyncHome(): URI { return joinPath(this.appSettingsHome, 'sync'); }
get logsHome(): URI {
if (!this.args.logsPath) {

View file

@ -12,7 +12,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { Metadata, isIExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtension, IExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { FileOperationResult, IFileService, toFileOperationResult } from 'vs/platform/files/common/files';
import { FileOperationResult, IFileService, hasFileAtomicWriteCapability, toFileOperationResult } from 'vs/platform/files/common/files';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
@ -290,7 +290,8 @@ export abstract class AbstractExtensionsProfileScannerService extends Disposable
relativeLocation: this.toRelativePath(e.location),
metadata: e.metadata
}));
await this.fileService.writeFile(file, VSBuffer.fromString(JSON.stringify(storedProfileExtensions)));
const fsp = this.fileService.getProvider(file.scheme);
await this.fileService.writeFile(file, VSBuffer.fromString(JSON.stringify(storedProfileExtensions)), fsp && hasFileAtomicWriteCapability(fsp) ? { atomic: { postfix: '.vsctmp' } } : undefined);
}
return extensions;

View file

@ -1,16 +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 { memoize } from 'vs/base/common/decorators';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
export class SharedProcessEnvironmentService extends NativeEnvironmentService {
@memoize
override get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.vscodeUserData }); }
}

View file

@ -23,8 +23,8 @@ export class ElectronPtyHostStarter extends Disposable implements IPtyHostStarte
private utilityProcess: UtilityProcess | undefined = undefined;
private readonly _onBeforeWindowConnection = new Emitter<void>();
readonly onBeforeWindowConnection = this._onBeforeWindowConnection.event;
private readonly _onRequestConnection = new Emitter<void>();
readonly onRequestConnection = this._onRequestConnection.event;
private readonly _onWillShutdown = new Emitter<void>();
readonly onWillShutdown = this._onWillShutdown.event;
@ -104,7 +104,7 @@ export class ElectronPtyHostStarter extends Disposable implements IPtyHostStarte
}
private _onWindowConnection(e: IpcMainEvent, nonce: string) {
this._onBeforeWindowConnection.fire();
this._onRequestConnection.fire();
const port = this.utilityProcess!.connect();

View file

@ -14,7 +14,7 @@ export interface IPtyHostConnection {
}
export interface IPtyHostStarter extends IDisposable {
onBeforeWindowConnection?: Event<void>;
onRequestConnection?: Event<void>;
onWillShutdown?: Event<void>;
/**

View file

@ -88,6 +88,7 @@ async function startPtyHost() {
// Clean up
process.once('exit', () => {
logService.trace('Pty host exiting');
logService.dispose();
heartbeatService.dispose();
ptyService.dispose();

View file

@ -5,10 +5,10 @@
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { IProcessEnvironment, OperatingSystem, isWindows } from 'vs/base/common/platform';
import { IProcessEnvironment, OS, OperatingSystem, isWindows } from 'vs/base/common/platform';
import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService, ILoggerService } from 'vs/platform/log/common/log';
import { ILogService, ILoggerService, LogLevel } from 'vs/platform/log/common/log';
import { RemoteLoggerChannelClient } from 'vs/platform/log/common/logIpc';
import { getResolvedShellEnv } from 'vs/platform/shell/node/shellEnv';
import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/capabilities/capabilities';
@ -19,6 +19,7 @@ import { IGetTerminalLayoutInfoArgs, IProcessDetails, ISetTerminalLayoutInfoArgs
import { IPtyHostConnection, IPtyHostStarter } from 'vs/platform/terminal/node/ptyHost';
import { detectAvailableProfiles } from 'vs/platform/terminal/node/terminalProfiles';
import * as performance from 'vs/base/common/performance';
import { getSystemShell } from 'vs/base/node/shell';
enum Constants {
MaxRestarts = 5
@ -43,6 +44,13 @@ export class PtyHostService extends Disposable implements IPtyService {
this._ensurePtyHost();
return this.__proxy!;
}
/**
* Get the proxy if it exists, otherwise undefined. This is used when calls are not needed to be
* passed through to the pty host if it has not yet been spawned.
*/
private get _optionalProxy(): IPtyService | undefined {
return this.__proxy;
}
private _ensurePtyHost() {
if (!this.__connection) {
@ -102,12 +110,9 @@ export class PtyHostService extends Disposable implements IPtyService {
this._resolveVariablesRequestStore = this._register(new RequestStore(undefined, this._logService));
this._resolveVariablesRequestStore.onCreateRequest(this._onPtyHostRequestResolveVariables.fire, this._onPtyHostRequestResolveVariables);
// Force the pty host to start as the first window is starting if the starter has that
// capability
if (this._ptyHostStarter.onBeforeWindowConnection) {
Event.once(this._ptyHostStarter.onBeforeWindowConnection)(() => this._ensurePtyHost());
} else {
this._ensurePtyHost();
// Start the pty host when a window requests a connection, if the starter has that capability.
if (this._ptyHostStarter.onRequestConnection) {
Event.once(this._ptyHostStarter.onRequestConnection)(() => this._ensurePtyHost());
}
this._ptyHostStarter.onWillShutdown?.(() => this._wasQuitRequested = true);
@ -118,7 +123,7 @@ export class PtyHostService extends Disposable implements IPtyService {
}
private async _refreshIgnoreProcessNames(): Promise<void> {
return this._proxy.refreshIgnoreProcessNames?.(this._ignoreProcessNames);
return this._optionalProxy?.refreshIgnoreProcessNames?.(this._ignoreProcessNames);
}
private async _resolveShellEnv(): Promise<typeof process.env> {
@ -139,6 +144,11 @@ export class PtyHostService extends Disposable implements IPtyService {
const connection = this._ptyHostStarter.start();
const client = connection.client;
// Log a full stack trace which will tell the exact reason the pty host is starting up
if (this._logService.getLevel() === LogLevel.Trace) {
this._logService.trace('PtyHostService#_startPtyHost', new Error().stack?.replace(/^Error/, ''));
}
// Setup heartbeat service and trigger a heartbeat immediately to reset the timeouts
const heartbeatService = ProxyChannel.toService<IHeartbeatService>(client.getChannel(TerminalIpcChannels.Heartbeat));
heartbeatService.onBeat(() => this._handleHeartbeat());
@ -224,13 +234,10 @@ export class PtyHostService extends Disposable implements IPtyService {
return this._proxy.listProcesses();
}
async getPerformanceMarks(): Promise<performance.PerformanceMark[]> {
if (!this.__proxy) {
return [];
}
return this._proxy.getPerformanceMarks();
return this._optionalProxy?.getPerformanceMarks() ?? [];
}
reduceConnectionGraceTime(): Promise<void> {
return this._proxy.reduceConnectionGraceTime();
async reduceConnectionGraceTime(): Promise<void> {
return this._optionalProxy?.reduceConnectionGraceTime();
}
start(id: number): Promise<ITerminalLaunchError | { injectedArgs: string[] } | undefined> {
return this._proxy.start(id);
@ -280,7 +287,7 @@ export class PtyHostService extends Disposable implements IPtyService {
}
getDefaultSystemShell(osOverride?: OperatingSystem): Promise<string> {
return this._proxy.getDefaultSystemShell(osOverride);
return this._optionalProxy?.getDefaultSystemShell(osOverride) ?? getSystemShell(osOverride ?? OS, process.env);
}
async getProfiles(workspaceId: string, profiles: unknown, defaultProfile: unknown, includeDetectedProfiles: boolean = false): Promise<ITerminalProfile[]> {
const shellEnv = await this._resolveShellEnv();

View file

@ -13,7 +13,7 @@ import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/co
import { URI } from 'vs/base/common/uri';
import { Promises } from 'vs/base/node/pfs';
import { localize } from 'vs/nls';
import { ILogService } from 'vs/platform/log/common/log';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { FlowControlConstants, IShellLaunchConfig, ITerminalChildProcess, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap as IProcessPropertyMap, ProcessPropertyType, TerminalShellType, IProcessReadyEvent, ITerminalProcessOptions, PosixShellType, IProcessReadyWindowsPty } from 'vs/platform/terminal/common/terminal';
import { ChildProcessMonitor } from 'vs/platform/terminal/node/childProcessMonitor';
@ -353,6 +353,9 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
// Allow any trailing data events to be sent before the exit event is sent.
// See https://github.com/Tyriar/node-pty/issues/72
private _queueProcessExit() {
if (this._logService.getLevel() === LogLevel.Trace) {
this._logService.trace('TerminalProcess#_queueProcessExit', new Error().stack?.replace(/^Error/, ''));
}
if (this._closeTimeout) {
clearTimeout(this._closeTimeout);
}
@ -417,6 +420,9 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
}
shutdown(immediate: boolean): void {
if (this._logService.getLevel() === LogLevel.Trace) {
this._logService.trace('TerminalProcess#shutdown', new Error().stack?.replace(/^Error/, ''));
}
// don't force immediate disposal of the terminal processes on Windows as an additional
// mitigation for https://github.com/microsoft/vscode/issues/71966 which causes the pty host
// to become unresponsive, disconnecting all terminals across all windows.

View file

@ -4,13 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { Event, Emitter } from 'vs/base/common/event';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IFileSystemProviderWithFileReadWriteCapability, IFileChange, IWatchOptions, IStat, IFileOverwriteOptions, FileType, IFileWriteOptions, IFileDeleteOptions, FileSystemProviderCapabilities, IFileSystemProviderWithFileReadStreamCapability, IFileReadStreamOptions, IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileFolderCopyCapability, hasFileFolderCopyCapability } from 'vs/platform/files/common/files';
import { IFileSystemProviderWithFileReadWriteCapability, IFileChange, IWatchOptions, IStat, IFileOverwriteOptions, FileType, IFileWriteOptions, IFileDeleteOptions, FileSystemProviderCapabilities, IFileSystemProviderWithFileReadStreamCapability, IFileReadStreamOptions, IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileFolderCopyCapability, hasFileFolderCopyCapability, hasFileAtomicWriteCapability } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { CancellationToken } from 'vs/base/common/cancellation';
import { newWriteableStream, ReadableStreamEvents } from 'vs/base/common/stream';
import { ILogService } from 'vs/platform/log/common/log';
import { TernarySearchTree } from 'vs/base/common/ternarySearchTree';
import { VSBuffer } from 'vs/base/common/buffer';
import { isObject } from 'vs/base/common/types';
/**
* This is a wrapper on top of the local filesystem provider which will
@ -85,6 +86,9 @@ export class FileUserDataProvider extends Disposable implements
}
writeFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise<void> {
if (!isObject(opts.atomic) && hasFileAtomicWriteCapability(this.fileSystemProvider)) {
opts = { ...opts, atomic: { postfix: '.vsctmp' } };
}
return this.fileSystemProvider.writeFile(this.toFileSystemResource(resource), content, opts);
}

View file

@ -9,6 +9,8 @@ import { NativeEnvironmentService } from 'vs/platform/environment/node/environme
import { OPTIONS, OptionDescriptions } from 'vs/platform/environment/node/argv';
import { refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { memoize } from 'vs/base/common/decorators';
import { URI } from 'vs/base/common/uri';
export const serverOptions: OptionDescriptions<Required<ServerParsedArgs>> = {
@ -211,5 +213,7 @@ export interface IServerEnvironmentService extends INativeEnvironmentService {
}
export class ServerEnvironmentService extends NativeEnvironmentService implements IServerEnvironmentService {
@memoize
override get userRoamingDataHome(): URI { return this.appSettingsHome; }
override get args(): ServerParsedArgs { return super.args as ServerParsedArgs; }
}

View file

@ -110,6 +110,7 @@ class OldMainThreadSecretState extends Disposable implements MainThreadSecretSta
export class MainThreadSecretState extends Disposable implements MainThreadSecretStateShape {
private readonly _proxy: ExtHostSecretStateShape;
// TODO: Remove this when all known embedders implement a secret storage provider
private readonly _oldMainThreadSecretState: OldMainThreadSecretState | undefined;
private readonly _sequencer = new SequencerByKey<string>();
@ -131,7 +132,11 @@ export class MainThreadSecretState extends Disposable implements MainThreadSecre
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSecretState);
if (environmentService.options?.credentialsProvider) {
// If the embedder doesn't implement a secret storage provider, then we need to use the old API
// to ensure that secrets are still stored in a secure way. This is only temporary until all
// embedders implement a secret storage provider.
// TODO: Remove this when all known embedders implement a secret storage provider
if (environmentService.options?.credentialsProvider && !environmentService.options?.secretStorageProvider) {
this._oldMainThreadSecretState = this._register(new OldMainThreadSecretState(
this._proxy,
credentialsService,
@ -158,7 +163,7 @@ export class MainThreadSecretState extends Disposable implements MainThreadSecre
}
private async doGetPassword(extensionId: string, key: string): Promise<string | undefined> {
// TODO: Remove this when we remove the old API
// TODO: Remove this when all known embedders implement a secret storage provider
if (this._oldMainThreadSecretState) {
return await this._oldMainThreadSecretState.$getPassword(extensionId, key);
}
@ -184,7 +189,7 @@ export class MainThreadSecretState extends Disposable implements MainThreadSecre
}
private async doSetPassword(extensionId: string, key: string, value: string): Promise<void> {
// TODO: Remove this when we remove the old API
// TODO: Remove this when all known embedders implement a secret storage provider
if (this._oldMainThreadSecretState) {
return await this._oldMainThreadSecretState.$setPassword(extensionId, key, value);
}
@ -200,7 +205,7 @@ export class MainThreadSecretState extends Disposable implements MainThreadSecre
}
private async doDeletePassword(extensionId: string, key: string): Promise<void> {
// TODO: Remove this when we remove the old API
// TODO: Remove this when all known embedders implement a secret storage provider
if (this._oldMainThreadSecretState) {
return await this._oldMainThreadSecretState.$deletePassword(extensionId, key);
}

View file

@ -41,6 +41,7 @@ import { ICredentialsService } from 'vs/platform/credentials/common/credentials'
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { ILogService } from 'vs/platform/log/common/log';
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
export class ViewContainerActivityAction extends ActivityAction {
@ -235,7 +236,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
private readonly problematicProviders: Set<string> = new Set();
private initialized = false;
private sessionFromEmbedder = getCurrentAuthenticationSessionInfo(this.credentialsService, this.productService);
private sessionFromEmbedder = getCurrentAuthenticationSessionInfo(this.credentialsService, this.secretStorageService, this.productService);
constructor(
action: ActivityAction,
@ -253,6 +254,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
@IConfigurationService configurationService: IConfigurationService,
@IStorageService private readonly storageService: IStorageService,
@IKeybindingService keybindingService: IKeybindingService,
@ISecretStorageService private readonly secretStorageService: ISecretStorageService,
@ICredentialsService private readonly credentialsService: ICredentialsService,
@ILogService private readonly logService: ILogService
) {

View file

@ -92,6 +92,10 @@ import { BrowserRemoteResourceLoader } from 'vs/workbench/services/remote/browse
import { BufferLogger } from 'vs/platform/log/common/bufferLog';
import { FileLoggerService } from 'vs/platform/log/common/fileLog';
import { IEmbedderTerminalService } from 'vs/workbench/services/terminal/common/embedderTerminalService';
import { BrowserSecretStorageService } from 'vs/workbench/services/secrets/browser/secretStorageService';
import { EncryptionService } from 'vs/workbench/services/encryption/browser/encryptionService';
import { IEncryptionService } from 'vs/platform/encryption/common/encryptionService';
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
export class BrowserMain extends Disposable {
@ -384,9 +388,14 @@ export class BrowserMain extends Disposable {
const credentialsService = new BrowserCredentialsService(environmentService, remoteAgentService, productService);
serviceCollection.set(ICredentialsService, credentialsService);
const encryptionService = new EncryptionService();
serviceCollection.set(IEncryptionService, encryptionService);
const secretStorageService = new BrowserSecretStorageService(storageService, encryptionService, environmentService, logService);
serviceCollection.set(ISecretStorageService, secretStorageService);
// Userdata Initialize Service
const userDataInitializers: IUserDataInitializer[] = [];
userDataInitializers.push(new UserDataSyncInitializer(environmentService, credentialsService, userDataSyncStoreManagementService, fileService, userDataProfilesService, storageService, productService, requestService, logService, uriIdentityService));
userDataInitializers.push(new UserDataSyncInitializer(environmentService, secretStorageService, credentialsService, userDataSyncStoreManagementService, fileService, userDataProfilesService, storageService, productService, requestService, logService, uriIdentityService));
if (environmentService.options.profile) {
userDataInitializers.push(new UserDataProfileInitializer(environmentService, fileService, userDataProfileService, storageService, logService, uriIdentityService, requestService));
}

View file

@ -25,6 +25,7 @@ import { IUserDataSyncMachinesService, UserDataSyncMachinesService } from 'vs/pl
import { Emitter } from 'vs/base/common/event';
import { CancellationError } from 'vs/base/common/errors';
import { EditSessionsStoreClient } from 'vs/workbench/contrib/editSessions/common/editSessionsStorageClient';
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
type ExistingSession = IQuickPickItem & { session: AuthenticationSession & { providerId: string } };
type AuthenticationProviderOption = IQuickPickItem & { provider: IAuthenticationProvider };
@ -81,6 +82,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
@IProductService private readonly productService: IProductService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IDialogService private readonly dialogService: IDialogService,
@ISecretStorageService private readonly secretStorageService: ISecretStorageService,
@ICredentialsService private readonly credentialsService: ICredentialsService
) {
super();
@ -278,7 +280,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
// If settings sync is already enabled, avoid asking again to authenticate
if (this.shouldAttemptEditSessionInit()) {
this.logService.info(`Reusing user data sync enablement`);
const authenticationSessionInfo = await getCurrentAuthenticationSessionInfo(this.credentialsService, this.productService);
const authenticationSessionInfo = await getCurrentAuthenticationSessionInfo(this.credentialsService, this.secretStorageService, this.productService);
if (authenticationSessionInfo !== undefined) {
this.logService.info(`Using current authentication session with ID ${authenticationSessionInfo.id}`);
this.existingSessionId = authenticationSessionInfo.id;

View file

@ -40,6 +40,18 @@
height: 22px;
}
.monaco-workbench .notebookOverlay .notebook-toolbar-container .notebook-toolbar-left .monaco-action-bar li a[tabindex="0"]:focus {
outline: none !important;
}
.monaco-workbench .notebookOverlay .notebook-toolbar-container .notebook-toolbar-left .monaco-action-bar li:has(a:focus) {
outline-width: 1px;
outline-style: solid;
outline-offset: -1px;
outline-color: var(--vscode-focusBorder);
opacity: 1;
}
.monaco-workbench .notebookOverlay .notebook-toolbar-container .notebook-toolbar-left .monaco-action-bar .action-item .action-label.separator {
margin: 5px 0px !important;
padding: 0px !important;

View file

@ -18,9 +18,8 @@
.settings-editor > .settings-body .settings-tree-container .setting-item.setting-item-list .setting-list-sibling,
.settings-editor > .settings-body .settings-tree-container .setting-item.setting-item-list .setting-list-object-widget .setting-list-object-key,
.settings-editor > .settings-body .settings-tree-container .setting-item.setting-item-list .setting-list-object-widget .setting-list-object-value {
white-space: pre;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
overflow-wrap: normal;
}
.settings-editor > .settings-body .settings-tree-container .setting-item-bool .setting-value-checkbox {

View file

@ -8,8 +8,8 @@ import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_HOST_NAME_FOREGROUND } from
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
import { IRemoteAgentService, remoteConnectionLatencyMeasurer } from 'vs/workbench/services/remote/common/remoteAgentService';
import { RunOnceScheduler, retry } from 'vs/base/common/async';
import { Event } from 'vs/base/common/event';
import { Disposable, dispose } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { MenuId, IMenuService, MenuItemAction, MenuRegistry, registerAction2, Action2, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/browser/statusbar';
@ -47,7 +47,7 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { DomEmitter } from 'vs/base/browser/event';
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ThemeIcon } from 'vs/base/common/themables';
import { infoIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
import { IOpenerService } from 'vs/platform/opener/common/opener';
@ -115,6 +115,9 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
private loggedInvalidGroupNames: { [group: string]: boolean } = Object.create(null);
private readonly remoteExtensionMetadata: RemoteExtensionMetadata[];
private remoteMetadataInitialized: boolean = false;
private readonly _onDidChangeEntries = this._register(new Emitter<void>());
private readonly onDidChangeEntries: Event<void> = this._onDidChangeEntries.event;
constructor(
@IStatusbarService private readonly statusbarService: IStatusbarService,
@IBrowserWorkbenchEnvironmentService private readonly environmentService: IBrowserWorkbenchEnvironmentService,
@ -322,25 +325,22 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
for (let i = 0; i < this.remoteExtensionMetadata.length; i++) {
const extensionId = this.remoteExtensionMetadata[i].id;
const supportedPlatforms = this.remoteExtensionMetadata[i].supportedPlatforms;
// Update compatibility
const token = new CancellationTokenSource();
const galleryExtension = (await this.extensionGalleryService.getExtensions([{ id: extensionId }], token.token))[0];
if (!await this.extensionManagementService.canInstall(galleryExtension)) {
this.remoteExtensionMetadata[i].isPlatformCompatible = false;
const isInstalled = (await this.extensionManagementService.getInstalled()).find(value => ExtensionIdentifier.equals(value.identifier.id, extensionId)) ? true : false;
this.remoteExtensionMetadata[i].installed = isInstalled;
if (isInstalled) {
this.remoteExtensionMetadata[i].isPlatformCompatible = true;
}
else if (supportedPlatforms && !supportedPlatforms.includes(currentPlatform)) {
this.remoteExtensionMetadata[i].isPlatformCompatible = false;
}
else {
this.remoteExtensionMetadata[i].isPlatformCompatible = true;
this.remoteExtensionMetadata[i].dependencies = galleryExtension.properties.extensionPack ?? [];
}
// Check if installed and enabled
this.remoteExtensionMetadata[i].installed = (await this.extensionManagementService.getInstalled()).find(value => ExtensionIdentifier.equals(value.identifier.id, extensionId)) ? true : false;
}
this.remoteMetadataInitialized = true;
this._onDidChangeEntries.fire();
showRemoteStartEntry.bindTo(this.contextKeyService).set(true);
this.updateRemoteStatusIndicator();
}
@ -551,15 +551,8 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
}
}
// Show when there are commands or installable remote extensions.
if (this.hasRemoteMenuCommands(true) || this.remoteExtensionMetadata.some(ext => !ext.installed && ext.isPlatformCompatible)) {
this.renderRemoteStatusIndicator(`$(remote)`, nls.localize('noHost.tooltip', "Open a Remote Window"));
return;
}
// No Remote Extensions: hide status indicator
dispose(this.remoteStatusEntry);
this.remoteStatusEntry = undefined;
this.renderRemoteStatusIndicator(`$(remote)`, nls.localize('noHost.tooltip', "Open a Remote Window"));
return;
}
private renderRemoteStatusIndicator(initialText: string, initialTooltip?: string | MarkdownString, command?: string, showProgress?: boolean): void {
@ -573,7 +566,7 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
text,
showProgress,
tooltip,
command: command ?? (this.hasRemoteMenuCommands(false) || this.remoteExtensionMetadata.some(ext => !ext.installed && ext.isPlatformCompatible)) ? RemoteStatusIndicator.REMOTE_ACTIONS_COMMAND_ID : undefined
command: command ?? RemoteStatusIndicator.REMOTE_ACTIONS_COMMAND_ID
};
if (this.remoteStatusEntry) {
@ -834,17 +827,15 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
const itemUpdater = this.remoteIndicatorMenu.onDidChange(() => quickPick.items = computeItems());
quickPick.onDidHide(itemUpdater.dispose);
if (!this.remoteMetadataInitialized) {
quickPick.busy = true;
this._register(this.onDidChangeEntries(() => {
// If quick pick is open, update the quick pick items after initialization.
quickPick.busy = false;
quickPick.items = computeItems();
}));
}
quickPick.show();
}
private hasRemoteMenuCommands(ignoreInstallAdditional: boolean): boolean {
if (this.remoteAuthority !== undefined || this.virtualWorkspaceLocation !== undefined) {
if (RemoteStatusIndicator.SHOW_CLOSE_REMOTE_COMMAND_ID) {
return true;
}
} else if (!ignoreInstallAdditional && this.extensionGalleryService.isEnabled()) {
return true;
}
return this.getRemoteMenuActions().length > 0;
}
}

View file

@ -210,6 +210,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
protected _taskSystemInfos: Map<string, ITaskSystemInfo[]>;
protected _workspaceTasksPromise?: Promise<Map<string, IWorkspaceFolderTaskResult>>;
protected readonly _whenTaskSystemReady: Promise<void>;
protected _taskSystem?: ITaskSystem;
protected _taskSystemListeners?: IDisposable[] = [];
@ -267,7 +268,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
super();
this._whenTaskSystemReady = Event.toPromise(this.onDidChangeTaskSystemInfo);
this._workspaceTasksPromise = undefined;
this._taskSystem = undefined;
this._taskSystemListeners = undefined;
@ -373,7 +374,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this._tasksReconnected = true;
return;
}
this._getTaskSystem();
this.getWorkspaceTasks().then(async () => {
this._tasksReconnected = await this._reconnectTasks();
});
@ -2200,9 +2200,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
return new Map();
}
await this._waitForSupportedExecutions;
// The build task might be run before folder open. On folder open, we need to update the tasks so that
// all tasks are parsed. #173384
if (runSource !== TaskRunSource.FolderOpen && this._workspaceTasksPromise) {
await this._whenTaskSystemReady;
if (this._workspaceTasksPromise) {
return this._workspaceTasksPromise;
}
return this._updateWorkspaceTasks(runSource);

View file

@ -6,7 +6,7 @@
import { DeferredPromise } from 'vs/base/common/async';
import { Emitter } from 'vs/base/common/event';
import { revive } from 'vs/base/common/marshalling';
import { PerformanceMark } from 'vs/base/common/performance';
import { PerformanceMark, mark } from 'vs/base/common/performance';
import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@ -324,22 +324,28 @@ class RemoteTerminalBackend extends BaseTerminalBackend implements ITerminalBack
// Revive processes if needed
const serializedState = this._storageService.get(TerminalStorageKeys.TerminalBufferState, StorageScope.WORKSPACE);
const parsed = this._deserializeTerminalState(serializedState);
if (parsed) {
try {
// Note that remote terminals do not get their environment re-resolved unlike in local terminals
if (!parsed) {
return undefined;
}
await this._remoteTerminalChannel.reviveTerminalProcesses(parsed, Intl.DateTimeFormat().resolvedOptions().locale);
this._storageService.remove(TerminalStorageKeys.TerminalBufferState, StorageScope.WORKSPACE);
// If reviving processes, send the terminal layout info back to the pty host as it
// will not have been persisted on application exit
const layoutInfo = this._storageService.get(TerminalStorageKeys.TerminalLayoutInfo, StorageScope.WORKSPACE);
if (layoutInfo) {
await this._remoteTerminalChannel.setTerminalLayoutInfo(JSON.parse(layoutInfo));
this._storageService.remove(TerminalStorageKeys.TerminalLayoutInfo, StorageScope.WORKSPACE);
}
} catch {
// no-op
try {
// Note that remote terminals do not get their environment re-resolved unlike in local terminals
mark('code/terminal/willReviveTerminalProcessesRemote');
await this._remoteTerminalChannel.reviveTerminalProcesses(parsed, Intl.DateTimeFormat().resolvedOptions().locale);
mark('code/terminal/didReviveTerminalProcessesRemote');
this._storageService.remove(TerminalStorageKeys.TerminalBufferState, StorageScope.WORKSPACE);
// If reviving processes, send the terminal layout info back to the pty host as it
// will not have been persisted on application exit
const layoutInfo = this._storageService.get(TerminalStorageKeys.TerminalLayoutInfo, StorageScope.WORKSPACE);
if (layoutInfo) {
mark('code/terminal/willSetTerminalLayoutInfoRemote');
await this._remoteTerminalChannel.setTerminalLayoutInfo(JSON.parse(layoutInfo));
mark('code/terminal/didSetTerminalLayoutInfoRemote');
this._storageService.remove(TerminalStorageKeys.TerminalLayoutInfo, StorageScope.WORKSPACE);
}
} catch (e: unknown) {
this._logService.warn('RemoteTerminalBackend#getTerminalLayoutInfo Error', e && typeof e === 'object' && 'message' in e ? e.message : e);
}
return this._remoteTerminalChannel.getTerminalLayoutInfo();

View file

@ -2080,7 +2080,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._refreshEnvironmentVariableInfoWidgetState(info);
}
private _refreshEnvironmentVariableInfoWidgetState(info?: IEnvironmentVariableInfo): void {
private async _refreshEnvironmentVariableInfoWidgetState(info?: IEnvironmentVariableInfo): Promise<void> {
// Check if the status should exist
if (!info) {
this.statusList.remove(TerminalStatus.RelaunchNeeded);
@ -2088,16 +2088,25 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
return;
}
// Recreate the process if the terminal has not yet been interacted with and it's not a
// special terminal (eg. extension terminal)
// Recreate the process seamlessly without informing the use if the following conditions are
// met.
if (
// The change requires a relaunch
info.requiresAction &&
// The feature is enabled
this._configHelper.config.environmentChangesRelaunch &&
// Has not been interacted with
!this._processManager.hasWrittenData &&
// Not a feature terminal or is a reconnecting task terminal (TODO: Need to explain the latter case)
(!this._shellLaunchConfig.isFeatureTerminal || (this.reconnectionProperties && this._configurationService.getValue(TaskSettingId.Reconnection) === true)) &&
!this._shellLaunchConfig.customPtyImplementation
&& !this._shellLaunchConfig.isExtensionOwnedTerminal &&
!this._shellLaunchConfig.attachPersistentProcess
// Not a custom pty
!this._shellLaunchConfig.customPtyImplementation &&
// Not an extension owned terminal
!this._shellLaunchConfig.isExtensionOwnedTerminal &&
// Not a reconnected or revived terminal
!this._shellLaunchConfig.attachPersistentProcess &&
// Not a Windows remote using ConPTY (#187084)
!(this._processManager.remoteAuthority && this._configHelper.config.windowsEnableConpty && (await this._processManager.getBackendOS()) === OperatingSystem.Windows)
) {
this.relaunch();
return;

View file

@ -422,7 +422,7 @@ export class TerminalService implements ITerminalService {
private _setConnected() {
this._connectionState = TerminalConnectionState.Connected;
this._onDidChangeConnectionState.fire();
this._logService.trace('Reconnected to terminals');
this._logService.trace('Pty host ready');
}
private async _reconnectToRemoteTerminals(): Promise<void> {
@ -444,6 +444,8 @@ export class TerminalService implements ITerminalService {
// now that terminals have been restored,
// attach listeners to update remote when terminals are changed
this._attachProcessLayoutListeners();
this._logService.trace('Reconnected to remote terminals');
}
private async _reconnectToLocalTerminals(): Promise<void> {
@ -462,6 +464,8 @@ export class TerminalService implements ITerminalService {
// now that terminals have been restored,
// attach listeners to update local state when terminals are changed
this._attachProcessLayoutListeners();
this._logService.trace('Reconnected to local terminals');
}
private _recreateTerminalGroups(layoutInfo?: ITerminalsLayoutInfo): Promise<ITerminalGroup[]> {

View file

@ -54,7 +54,7 @@ class TerminalLinkContribution extends DisposableStore implements ITerminalContr
this._processManager.onProcessReady(() => {
linkManager.setWidgetManager(this._widgetManager);
});
this._linkManager = linkManager;
this._linkManager = this.add(linkManager);
// Attach the link provider(s) to the instance and listen for changes
for (const linkProvider of this._terminalLinkProviderService.linkProviders) {

View file

@ -77,7 +77,7 @@ export class TerminalLinkManager extends DisposableStore {
this._setupLinkDetector(TerminalMultiLineLinkDetector.id, this._instantiationService.createInstance(TerminalMultiLineLinkDetector, this._xterm, this._processManager, this._linkResolver));
this._setupLinkDetector(TerminalLocalLinkDetector.id, this._instantiationService.createInstance(TerminalLocalLinkDetector, this._xterm, capabilities, this._processManager, this._linkResolver));
}
this._setupLinkDetector(TerminalWordLinkDetector.id, this._instantiationService.createInstance(TerminalWordLinkDetector, this._xterm));
this._setupLinkDetector(TerminalWordLinkDetector.id, this.add(this._instantiationService.createInstance(TerminalWordLinkDetector, this._xterm)));
// Setup link openers
const localFileOpener = this._instantiationService.createInstance(TerminalLocalFileLinkOpener);

View file

@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { escapeRegExpCharacters } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@ -27,7 +28,7 @@ interface Word {
text: string;
}
export class TerminalWordLinkDetector implements ITerminalLinkDetector {
export class TerminalWordLinkDetector extends Disposable implements ITerminalLinkDetector {
static id = 'word';
// Word links typically search the workspace so it makes sense that their maximum link length is
@ -41,12 +42,14 @@ export class TerminalWordLinkDetector implements ITerminalLinkDetector {
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IProductService private readonly _productService: IProductService,
) {
super();
this._refreshSeparatorCodes();
this._configurationService.onDidChangeConfiguration(e => {
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(TerminalSettingId.WordSeparators)) {
this._refreshSeparatorCodes();
}
});
}));
}
detect(lines: IBufferLine[], startLine: number, endLine: number): ITerminalSimpleLink[] {

View file

@ -12,6 +12,7 @@ import { flatTestItemDelimiter } from 'vs/workbench/contrib/testing/browser/expl
import { ITestTreeProjection, TestExplorerTreeElement, TestItemTreeElement, TestTreeErrorMessage, getChildrenForParent, testIdentityProvider } from 'vs/workbench/contrib/testing/browser/explorerProjections/index';
import { ISerializedTestTreeCollapseState, isCollapsedInSerializedTestTree } from 'vs/workbench/contrib/testing/browser/explorerProjections/testingViewState';
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
import { TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult';
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
import { ITestItemUpdate, InternalTestItem, TestDiffOpType, TestItemExpandState, TestResultState, TestsDiff, applyTestItemUpdate } from 'vs/workbench/contrib/testing/common/testTypes';
@ -106,6 +107,10 @@ export class ListProjection extends Disposable implements ITestTreeProjection {
// when test states change, reflect in the tree
this._register(results.onTestChanged(ev => {
if (ev.reason === TestResultItemChangeReason.NewMessage) {
return; // no effect in the tree
}
let result = ev.item;
// if the state is unset, or the latest run is not making the change,
// double check that it's valid. Retire calls might cause previous

View file

@ -139,6 +139,10 @@ export class TreeProjection extends Disposable implements ITestTreeProjection {
// when test states change, reflect in the tree
this._register(results.onTestChanged(ev => {
if (ev.reason === TestResultItemChangeReason.NewMessage) {
return; // no effect in the tree
}
let result = ev.item;
// if the state is unset, or the latest run is not making the change,
// double check that it's valid. Retire calls might cause previous

View file

@ -183,6 +183,10 @@
border-bottom-width: 2px;
}
.test-output-peek-message-container {
overflow: hidden;
}
.test-output-peek-message-container,
.test-output-peek-tree {
height: 100%;
@ -229,10 +233,6 @@
max-width: none;
}
.testing-filter-wrapper {
height: 27px;
}
.testing-filter-action-item .testing-filter-wrapper {
flex-grow: 1;
}

View file

@ -566,7 +566,8 @@ class TestingExplorerViewModel extends Disposable {
keyboardNavigationLabelProvider: instantiationService.createInstance(TreeKeyboardNavigationLabelProvider),
accessibilityProvider: instantiationService.createInstance(ListAccessibilityProvider),
filter: this.filter,
findWidgetEnabled: false
findWidgetEnabled: false,
openOnSingleClick: false,
}) as TestingObjectTree<FuzzyScore>;
@ -612,7 +613,7 @@ class TestingExplorerViewModel extends Disposable {
testService.excluded.onTestExclusionsChanged,
)(this.tree.refilter, this.tree));
this._register(this.tree.onMouseDblClick(e => {
this._register(this.tree.onDidOpen(e => {
if (e.element instanceof TestItemTreeElement && !e.element.children.size && e.element.test.item.uri) {
commandService.executeCommand('vscode.revealTest', e.element.test.item.extId);
}

View file

@ -15,7 +15,7 @@ import { ICompressedTreeElement, ICompressedTreeNode } from 'vs/base/browser/ui/
import { ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree';
import { ITreeContextMenuEvent, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { Action, IAction, Separator } from 'vs/base/common/actions';
import { RunOnceScheduler } from 'vs/base/common/async';
import { Delayer, RunOnceScheduler } from 'vs/base/common/async';
import { Codicon } from 'vs/base/common/codicons';
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
@ -26,7 +26,6 @@ import { Iterable } from 'vs/base/common/iterator';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { Lazy } from 'vs/base/common/lazy';
import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { clamp } from 'vs/base/common/numbers';
import { count } from 'vs/base/common/strings';
import { ThemeIcon } from 'vs/base/common/themables';
import { URI } from 'vs/base/common/uri';
@ -520,8 +519,8 @@ export class TestingOutputPeekController extends Disposable implements IEditorCo
* Shows a peek for the message in the editor.
*/
public async show(uri: URI) {
const subjecet = this.retrieveTest(uri);
if (!subjecet) {
const subject = this.retrieveTest(uri);
if (!subject) {
return;
}
@ -537,12 +536,12 @@ export class TestingOutputPeekController extends Disposable implements IEditorCo
this.peek.value!.create();
}
if (subjecet instanceof MessageSubject) {
const message = subjecet.messages[subjecet.messageIndex];
if (subject instanceof MessageSubject) {
const message = subject.messages[subject.messageIndex];
alert(renderStringAsPlaintext(message.message));
}
this.peek.value.setModel(subjecet);
this.peek.value.setModel(subject);
this.currentPeekUri = uri;
}
@ -711,13 +710,10 @@ class TestResultsViewContent extends Disposable {
historyVisible: IObservableValue<boolean>;
showRevealLocationOnMessages: boolean;
},
@IContextKeyService contextKeyService: IContextKeyService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ITextModelService protected readonly modelService: ITextModelService,
) {
super();
TestingContextKeys.isInPeek.bindTo(contextKeyService);
}
public fillBody(containerElement: HTMLElement): void {
@ -806,6 +802,7 @@ class TestResultsPeek extends PeekViewWidget {
private readonly visibilityChange = this._disposables.add(new Emitter<boolean>());
private readonly content: TestResultsViewContent;
private scopedContextKeyService?: IContextKeyService;
private dimension?: dom.Dimension;
public current?: InspectSubject;
@ -821,7 +818,6 @@ class TestResultsPeek extends PeekViewWidget {
) {
super(editor, { showFrame: true, frameWidth: 1, showArrow: true, isResizeable: true, isAccessible: true, className: 'test-output-peek' }, instantiationService);
TestingContextKeys.isInPeek.bindTo(contextKeyService);
this._disposables.add(themeService.onDidColorThemeChange(this.applyTheme, this));
this._disposables.add(this.onDidClose(() => this.visibilityChange.fire(false)));
this.content = this._disposables.add(instantiationService.createInstance(TestResultsViewContent, editor, { historyVisible: testingPeek.historyVisible, showRevealLocationOnMessages: false }));
@ -841,6 +837,15 @@ class TestResultsPeek extends PeekViewWidget {
});
}
protected override _fillContainer(container: HTMLElement): void {
if (!this.scopedContextKeyService) {
this.scopedContextKeyService = this._disposables.add(this.contextKeyService.createScoped(container));
TestingContextKeys.isInPeek.bindTo(this.scopedContextKeyService).set(true);
}
super._fillContainer(container);
}
protected override _fillHead(container: HTMLElement): void {
super._fillHead(container);
@ -1016,7 +1021,7 @@ const diffEditorOptions: IDiffEditorConstructionOptions = {
diffAlgorithm: 'advanced',
};
const isDiffable = (message: ITestMessage): message is ITestErrorMessage & { actualOutput: string; expectedOutput: string } =>
const isDiffable = (message: ITestMessage): message is ITestErrorMessage & { actual: string; expected: string } =>
message.type === TestMessageType.Error && message.actual !== undefined && message.expected !== undefined;
class DiffContentProvider extends Disposable implements IPeekOutputRenderer {
@ -1222,6 +1227,7 @@ class PlainTextMessagePeek extends Disposable implements IPeekOutputRenderer {
class TerminalMessagePeek extends Disposable implements IPeekOutputRenderer {
private dimensions?: dom.IDimension;
private readonly terminalCwd = this._register(new MutableObservableValue<string>(''));
private readonly xtermLayoutDelayer = this._register(new Delayer(50));
/** Active terminal instance. */
private readonly terminal = this._register(new MutableDisposable<IDetachedXtermTerminal>());
@ -1337,6 +1343,7 @@ class TerminalMessagePeek extends Disposable implements IPeekOutputRenderer {
private clear() {
this.outputDataListener.clear();
this.xtermLayoutDelayer.cancel();
this.terminal.clear();
}
@ -1353,10 +1360,12 @@ class TerminalMessagePeek extends Disposable implements IPeekOutputRenderer {
height = this.dimensions?.height ?? this.container.clientHeight
) {
width -= 10 + 20; // scrollbar width + margin
const scaled = getXtermScaledDimensions(xterm.getFont(), width, height);
if (scaled) {
xterm.resize(scaled.cols, scaled.rows);
}
this.xtermLayoutDelayer.trigger(() => {
const scaled = getXtermScaledDimensions(xterm.getFont(), width, height);
if (scaled) {
xterm.resize(scaled.cols, scaled.rows);
}
});
}
}
@ -1371,8 +1380,9 @@ const firstLine = (str: string) => {
};
const isMultiline = (str: string | undefined) => !!str && str.includes('\n');
const hintPeekStrHeight = (str: string | undefined) =>
clamp(str ? Math.max(count(str, '\n'), Math.ceil(str.length / 80)) + 3 : 0, 14, 24);
// add 5ish lines for the size of the title and decorations in the peek.
const hintPeekStrHeight = (str: string) => Math.min(count(str, '\n') + 5, 24);
class SimpleDiffEditorModel extends EditorModel {
public readonly original = this._original.object.textEditorModel;
@ -1696,7 +1706,9 @@ class OutputPeekTree extends Disposable {
const itemNode = taskNode.itemsCache.get(e.item);
if (itemNode && this.tree.hasElement(itemNode)) {
this.tree.setChildren(itemNode, getTestChildren(result, e.item, index), { diffIdentityProvider });
if (e.reason === TestResultItemChangeReason.NewMessage) {
this.tree.setChildren(itemNode, getTestChildren(result, e.item, index), { diffIdentityProvider });
}
itemNode.changeEmitter.fire();
return;
}
@ -1990,7 +2002,7 @@ class TreeActionsProvider {
const extId = element.test.item.extId;
primary.push(new Action(
'testing.outputPeek.goToFile',
localize('testing.goToFile', "Go to File"),
localize('testing.goToFile', "Go to Source"),
ThemeIcon.asClassName(Codicon.goToFile),
undefined,
() => this.commandService.executeCommand('vscode.revealTest', extId),

View file

@ -82,7 +82,7 @@ export class TestingProgressTrigger extends Disposable {
}
private openTestView() {
this.viewsService.openView(Testing.ExplorerViewId, false);
this.viewsService.openView(Testing.ResultsViewId, false);
}
}

View file

@ -215,11 +215,13 @@ const itemToNode = (controllerId: string, item: ITestItem, parent: string | null
export const enum TestResultItemChangeReason {
ComputedStateChange,
OwnStateChange,
NewMessage,
}
export type TestResultItemChange = { item: TestResultItem; result: ITestResult } & (
| { reason: TestResultItemChangeReason.ComputedStateChange }
| { reason: TestResultItemChangeReason.OwnStateChange; previousState: TestResultState; previousOwnDuration: number | undefined }
| { reason: TestResultItemChangeReason.NewMessage }
);
/**
@ -319,8 +321,10 @@ export class LiveTestResult implements ITestResult {
type: TestMessageType.Output,
};
if (testId) {
this.testById.get(testId)?.tasks[index].messages.push(message);
const test = testId && this.testById.get(testId);
if (test) {
test.tasks[index].messages.push(message);
this.changeEmitter.fire({ item: test, result: this, reason: TestResultItemChangeReason.NewMessage });
} else {
task.otherMessages.push(message);
}
@ -390,13 +394,7 @@ export class LiveTestResult implements ITestResult {
}
entry.tasks[this.mustGetTaskIndex(taskId)].messages.push(message);
this.changeEmitter.fire({
item: entry,
result: this,
reason: TestResultItemChangeReason.OwnStateChange,
previousState: entry.ownComputedState,
previousOwnDuration: entry.ownDuration,
});
this.changeEmitter.fire({ item: entry, result: this, reason: TestResultItemChangeReason.NewMessage });
}
/**

View file

@ -35,7 +35,7 @@ export namespace TestingContextKeys {
export const viewMode = new RawContextKey<TestExplorerViewMode>('testing.explorerViewMode', TestExplorerViewMode.List);
export const viewSorting = new RawContextKey<TestExplorerViewSorting>('testing.explorerViewSorting', TestExplorerViewSorting.ByLocation);
export const isRunning = new RawContextKey<boolean>('testing.isRunning', false);
export const isInPeek = new RawContextKey<boolean>('testing.isInPeek', true);
export const isInPeek = new RawContextKey<boolean>('testing.isInPeek', false);
export const isPeekVisible = new RawContextKey<boolean>('testing.isPeekVisible', false);
export const peekItemType = new RawContextKey<string | undefined>('peekItemType', undefined, {

View file

@ -224,7 +224,8 @@ export class DesktopMain extends Disposable {
const diskFileSystemProvider = this._register(new DiskFileSystemProvider(mainProcessService, utilityProcessWorkerWorkbenchService, logService));
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
// User Data Provider
// Use FileUserDataProvider for user data to
// enable atomic read / write operations.
fileService.registerProvider(Schemas.vscodeUserData, this._register(new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.vscodeUserData, logService)));
// URI Identity

View file

@ -19,6 +19,7 @@ import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/
import { Severity } from 'vs/platform/notification/common/notification';
import { IProductService } from 'vs/platform/product/common/productService';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
import { IAuthenticationCreateSessionOptions, AuthenticationProviderInformation, AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationProvider, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication';
@ -76,9 +77,17 @@ export function addAccountUsage(storageService: IStorageService, providerId: str
storageService.store(accountKey, JSON.stringify(usages), StorageScope.APPLICATION, StorageTarget.MACHINE);
}
// TODO: pull this out into its own service
export type AuthenticationSessionInfo = { readonly id: string; readonly accessToken: string; readonly providerId: string; readonly canSignOut?: boolean };
export async function getCurrentAuthenticationSessionInfo(credentialsService: ICredentialsService, productService: IProductService): Promise<AuthenticationSessionInfo | undefined> {
const authenticationSessionValue = await credentialsService.getPassword(`${productService.urlProtocol}.login`, 'account');
export async function getCurrentAuthenticationSessionInfo(
// TODO: Remove when all known embedders implement SecretStorageProviders instead of CredentialsProviders
credentialsService: ICredentialsService,
secretStorageService: ISecretStorageService,
productService: IProductService
): Promise<AuthenticationSessionInfo | undefined> {
const authenticationSessionValue =
await secretStorageService.get(`${productService.urlProtocol}.loginAccount`)
?? await credentialsService.getPassword(`${productService.urlProtocol}.login`, 'account');
if (authenticationSessionValue) {
try {
const authenticationSessionInfo: AuthenticationSessionInfo = JSON.parse(authenticationSessionValue);
@ -90,7 +99,8 @@ export async function getCurrentAuthenticationSessionInfo(credentialsService: IC
return authenticationSessionInfo;
}
} catch (e) {
// ignore as this is a best effort operation.
// This is a best effort operation.
console.error(`Failed parsing current auth session value: ${e}`);
}
}
return undefined;

View file

@ -84,9 +84,6 @@ export class NativeWorkbenchEnvironmentService extends AbstractNativeEnvironment
};
}
@memoize
override get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.vscodeUserData }); }
@memoize
get windowLogsPath(): URI { return joinPath(this.logsHome, `window${this.configuration.windowId}`); }

View file

@ -5,9 +5,7 @@
import { IEncryptionService } from 'vs/platform/encryption/common/encryptionService';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ISecretStorageProvider, ISecretStorageService, BaseSecretStorageService } from 'vs/platform/secrets/common/secrets';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
@ -20,8 +18,6 @@ export class BrowserSecretStorageService extends BaseSecretStorageService {
@IStorageService storageService: IStorageService,
@IEncryptionService encryptionService: IEncryptionService,
@IBrowserWorkbenchEnvironmentService environmentService: IBrowserWorkbenchEnvironmentService,
@IInstantiationService instantiationService: IInstantiationService,
@INotificationService notificationService: INotificationService,
@ILogService logService: ILogService
) {
super(storageService, encryptionService, logService);

View file

@ -35,6 +35,7 @@ import { TasksInitializer } from 'vs/platform/userDataSync/common/tasksSync';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
import { IUserDataInitializer } from 'vs/workbench/services/userData/browser/userDataInit';
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
export class UserDataSyncInitializer implements IUserDataInitializer {
@ -46,6 +47,7 @@ export class UserDataSyncInitializer implements IUserDataInitializer {
constructor(
@IBrowserWorkbenchEnvironmentService private readonly environmentService: IBrowserWorkbenchEnvironmentService,
@ISecretStorageService private readonly secretStorageService: ISecretStorageService,
@ICredentialsService private readonly credentialsService: ICredentialsService,
@IUserDataSyncStoreManagementService private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService,
@IFileService private readonly fileService: IFileService,
@ -90,7 +92,7 @@ export class UserDataSyncInitializer implements IUserDataInitializer {
let authenticationSession;
try {
authenticationSession = await getCurrentAuthenticationSessionInfo(this.credentialsService, this.productService);
authenticationSession = await getCurrentAuthenticationSessionInfo(this.credentialsService, this.secretStorageService, this.productService);
} catch (error) {
this.logService.error(error);
}

View file

@ -39,6 +39,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
import { isDiffEditorInput } from 'vs/workbench/common/editor';
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
import { ISecretStorageService } from 'vs/platform/secrets/common/secrets';
type AccountQuickPickItem = { label: string; authenticationProvider: IAuthenticationProvider; account?: UserDataSyncAccount; description?: string };
@ -105,6 +106,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat
@IExtensionService private readonly extensionService: IExtensionService,
@IBrowserWorkbenchEnvironmentService private readonly environmentService: IBrowserWorkbenchEnvironmentService,
@ICredentialsService private readonly credentialsService: ICredentialsService,
@ISecretStorageService private readonly secretStorageService: ISecretStorageService,
@INotificationService private readonly notificationService: INotificationService,
@IProgressService private readonly progressService: IProgressService,
@IDialogService private readonly dialogService: IDialogService,
@ -169,7 +171,7 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat
}
private async initialize(): Promise<void> {
const authenticationSession = await getCurrentAuthenticationSessionInfo(this.credentialsService, this.productService);
const authenticationSession = await getCurrentAuthenticationSessionInfo(this.credentialsService, this.secretStorageService, this.productService);
if (this.currentSessionId === undefined && authenticationSession?.id) {
if (this.environmentService.options?.settingsSyncOptions?.authenticationProvider && this.environmentService.options.settingsSyncOptions.enabled) {
this.currentSessionId = authenticationSession.id;