Merge branch 'main' into tyriar/170991

This commit is contained in:
Daniel Imms 2023-01-11 10:28:54 -08:00 committed by GitHub
commit 727ed13d70
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
90 changed files with 1065 additions and 650 deletions

View file

@ -9,10 +9,10 @@ export = new class NoTestOnly implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
['MemberExpression[object.name="test"][property.name="only"]']: (node: any) => {
['MemberExpression[object.name=/^(test|suite)$/][property.name="only"]']: (node: any) => {
return context.report({
node,
message: 'test.only is a dev-time tool and CANNOT be pushed'
message: 'only is a dev-time tool and CANNOT be pushed'
});
}
};

View file

@ -149,6 +149,7 @@ steps:
security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12
security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign
export CODESIGN_IDENTITY=$(security find-identity -v -p codesigning $(agent.tempdirectory)/buildagent.keychain | grep -oEi "([0-9A-F]{40})" | head -n 1)
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain
VSCODE_ARCH=$(VSCODE_ARCH) DEBUG=electron-osx-sign* node build/darwin/sign.js
displayName: Set Hardened Entitlements

View file

@ -237,6 +237,7 @@ steps:
security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12
security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign
export CODESIGN_IDENTITY=$(security find-identity -v -p codesigning $(agent.tempdirectory)/buildagent.keychain | grep -oEi "([0-9A-F]{40})" | head -n 1)
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain
VSCODE_ARCH=$(VSCODE_ARCH) DEBUG=electron-osx-sign* node build/darwin/sign.js
displayName: Set Hardened Entitlements

View file

@ -13,6 +13,7 @@ async function main() {
const buildDir = process.env['AGENT_BUILDDIRECTORY'];
const tempDir = process.env['AGENT_TEMPDIRECTORY'];
const arch = process.env['VSCODE_ARCH'];
const identity = process.env['CODESIGN_IDENTITY'];
if (!buildDir) {
throw new Error('$AGENT_BUILDDIRECTORY not set');
}
@ -38,7 +39,7 @@ async function main() {
'pre-embed-provisioning-profile': false,
keychain: path.join(tempDir, 'buildagent.keychain'),
version: util.getElectronVersion(),
identity: '99FM488X57',
identity,
'gatekeeper-assess': false
};
const appOpts = {
@ -104,4 +105,4 @@ if (require.main === module) {
process.exit(1);
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNpZ24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Z0dBR2dHOztBQUVoRyw4Q0FBOEM7QUFDOUMsNkJBQTZCO0FBQzdCLG9DQUFvQztBQUNwQyw4Q0FBOEM7QUFDOUMscUVBQW9EO0FBRXBELEtBQUssVUFBVSxJQUFJO0lBQ2xCLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUNyRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixDQUFDLENBQUM7SUFDbkQsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUV4QyxJQUFJLENBQUMsUUFBUSxFQUFFO1FBQ2QsTUFBTSxJQUFJLEtBQUssQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO0tBQ2pEO0lBRUQsSUFBSSxDQUFDLE9BQU8sRUFBRTtRQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQztLQUNoRDtJQUVELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDeEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsaUJBQWlCLElBQUksRUFBRSxDQUFDLENBQUM7SUFDN0QsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFFBQVEsR0FBRyxNQUFNLENBQUM7SUFDMUMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQy9FLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQztJQUM1QyxNQUFNLGdCQUFnQixHQUFHLGlCQUFpQixHQUFHLG1CQUFtQixDQUFDO0lBQ2pFLE1BQU0scUJBQXFCLEdBQUcsaUJB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
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNpZ24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Z0dBR2dHOztBQUVoRyw4Q0FBOEM7QUFDOUMsNkJBQTZCO0FBQzdCLG9DQUFvQztBQUNwQyw4Q0FBOEM7QUFDOUMscUVBQW9EO0FBRXBELEtBQUssVUFBVSxJQUFJO0lBQ2xCLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUNyRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixDQUFDLENBQUM7SUFDbkQsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUN4QyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFFbEQsSUFBSSxDQUFDLFFBQVEsRUFBRTtRQUNkLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztLQUNqRDtJQUVELElBQUksQ0FBQyxPQUFPLEVBQUU7UUFDYixNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7S0FDaEQ7SUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3hDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLGlCQUFpQixJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzdELE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDO0lBQzFDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUMvRSxNQUFNLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUM7SUFDNUMsTUFBTSxnQkFB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

View file

@ -13,6 +13,7 @@ async function main(): Promise<void> {
const buildDir = process.env['AGENT_BUILDDIRECTORY'];
const tempDir = process.env['AGENT_TEMPDIRECTORY'];
const arch = process.env['VSCODE_ARCH'];
const identity = process.env['CODESIGN_IDENTITY'];
if (!buildDir) {
throw new Error('$AGENT_BUILDDIRECTORY not set');
@ -42,7 +43,7 @@ async function main(): Promise<void> {
'pre-embed-provisioning-profile': false,
keychain: path.join(tempDir, 'buildagent.keychain'),
version: util.getElectronVersion(),
identity: '99FM488X57',
identity,
'gatekeeper-assess': false
};

View file

@ -5,8 +5,8 @@
import { Model } from '../model';
import { Repository as BaseRepository, Resource } from '../repository';
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider } from './git';
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands } from 'vscode';
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider, RefQuery } from './git';
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands, CancellationToken } from 'vscode';
import { combinedDisposable, mapEvent } from '../util';
import { toGitUri } from '../uri';
import { GitExtensionImpl } from './extension';
@ -170,14 +170,18 @@ export class ApiRepository implements Repository {
return this.repository.getBranch(name);
}
getBranches(query: BranchQuery): Promise<Ref[]> {
return this.repository.getBranches(query);
getBranches(query: BranchQuery, cancellationToken?: CancellationToken): Promise<Ref[]> {
return this.repository.getBranches(query, cancellationToken);
}
setBranchUpstream(name: string, upstream: string): Promise<void> {
return this.repository.setBranchUpstream(name, upstream);
}
getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise<Ref[]> {
return this.repository.getRefs(query, cancellationToken);
}
getMergeBase(ref1: string, ref2: string): Promise<string> {
return this.repository.getMergeBase(ref1, ref2);
}

View file

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri, Event, Disposable, ProviderResult, Command } from 'vscode';
import { Uri, Event, Disposable, ProviderResult, Command, CancellationToken } from 'vscode';
export { ProviderResult } from 'vscode';
export interface Git {
@ -156,11 +156,15 @@ export interface FetchOptions {
depth?: number;
}
export interface BranchQuery {
readonly remote?: boolean;
readonly pattern?: string;
readonly count?: number;
export interface RefQuery {
readonly contains?: string;
readonly count?: number;
readonly pattern?: string;
readonly sort?: 'alphabetically' | 'committerdate';
}
export interface BranchQuery extends RefQuery {
readonly remote?: boolean;
}
export interface Repository {
@ -204,9 +208,11 @@ export interface Repository {
createBranch(name: string, checkout: boolean, ref?: string): Promise<void>;
deleteBranch(name: string, force?: boolean): Promise<void>;
getBranch(name: string): Promise<Branch>;
getBranches(query: BranchQuery): Promise<Ref[]>;
getBranches(query: BranchQuery, cancellationToken?: CancellationToken): Promise<Ref[]>;
setBranchUpstream(name: string, upstream: string): Promise<void>;
getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise<Ref[]>;
getMergeBase(ref1: string, ref2: string): Promise<string>;
tag(name: string, upstream: string): Promise<void>;

View file

@ -2189,12 +2189,6 @@ export class CommandCenter {
}
private async _branch(repository: Repository, defaultName?: string, from = false): Promise<void> {
const branchName = await this.promptForBranchName(repository, defaultName);
if (!branchName) {
return;
}
let target = 'HEAD';
if (from) {
@ -2202,7 +2196,7 @@ export class CommandCenter {
return [new HEADItem(repository), ...await createCheckoutItems(repository)];
};
const placeHolder = l10n.t('Select a ref to create the "{0}" branch from', branchName);
const placeHolder = l10n.t('Select a ref to create the branch from');
const choice = await window.showQuickPick(getRefPicks(), { placeHolder });
if (!choice) {
@ -2214,6 +2208,12 @@ export class CommandCenter {
}
}
const branchName = await this.promptForBranchName(repository, defaultName);
if (!branchName) {
return;
}
await repository.branch(branchName, true, target);
}

View file

@ -15,7 +15,7 @@ import * as filetype from 'file-type';
import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter, Versions, isWindows } from './util';
import { CancellationError, CancellationToken, ConfigurationChangeEvent, LogOutputChannel, Progress, Uri, workspace } from 'vscode';
import { detectEncoding } from './encoding';
import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, BranchQuery } from './api/git';
import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, RefQuery } from './api/git';
import * as byline from 'byline';
import { StringDecoder } from 'string_decoder';
@ -2164,32 +2164,32 @@ export class Repository {
.map(([ref]) => ({ name: ref, type: RefType.Head } as Branch));
}
async getRefs(opts?: { sort?: 'alphabetically' | 'committerdate'; contains?: string; pattern?: string; count?: number; cancellationToken?: CancellationToken }): Promise<Ref[]> {
if (opts?.cancellationToken && opts?.cancellationToken.isCancellationRequested) {
async getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise<Ref[]> {
if (cancellationToken && cancellationToken.isCancellationRequested) {
throw new CancellationError();
}
const args = ['for-each-ref'];
if (opts?.count) {
args.push(`--count=${opts.count}`);
if (query.count) {
args.push(`--count=${query.count}`);
}
if (opts && opts.sort && opts.sort !== 'alphabetically') {
args.push('--sort', `-${opts.sort}`);
if (query.sort && query.sort !== 'alphabetically') {
args.push('--sort', `-${query.sort}`);
}
args.push('--format', '%(refname) %(objectname) %(*objectname)');
if (opts?.pattern) {
args.push(opts.pattern);
if (query.pattern) {
args.push(query.pattern.startsWith('refs/') ? query.pattern : `refs/${query.pattern}`);
}
if (opts?.contains) {
args.push('--contains', opts.contains);
if (query.contains) {
args.push('--contains', query.contains);
}
const result = await this.exec(args, { cancellationToken: opts?.cancellationToken });
const result = await this.exec(args, { cancellationToken });
const fn = (line: string): Ref | null => {
let match: RegExpExecArray | null;
@ -2404,11 +2404,6 @@ export class Repository {
return Promise.reject<Branch>(new Error('No such branch'));
}
async getBranches(query: BranchQuery): Promise<Ref[]> {
const refs = await this.getRefs({ contains: query.contains, pattern: query.pattern ? `refs/${query.pattern}` : undefined, count: query.count });
return refs.filter(value => (value.type !== RefType.Tag) && (query.remote || !value.remote));
}
// TODO: Support core.commentChar
stripCommitMessageComments(message: string): string {
return message.replace(/^\s*#.*$\n?/gm, '').trim();

View file

@ -8,7 +8,7 @@ import * as path from 'path';
import * as picomatch from 'picomatch';
import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, FileDecoration, commands, Tab, TabInputTextDiff, TabInputNotebookDiff, RelativePattern, CancellationTokenSource, LogOutputChannel, LogLevel, CancellationError, l10n } from 'vscode';
import TelemetryReporter from '@vscode/extension-telemetry';
import { Branch, Change, ForcePushMode, GitErrorCodes, LogOptions, Ref, Remote, Status, CommitOptions, BranchQuery, FetchOptions } from './api/git';
import { Branch, Change, ForcePushMode, GitErrorCodes, LogOptions, Ref, Remote, Status, CommitOptions, BranchQuery, FetchOptions, RefQuery, RefType } from './api/git';
import { AutoFetcher } from './autofetch';
import { debounce, memoize, throttle } from './decorators';
import { Commit, GitError, Repository as BaseRepository, Stash, Submodule, LogFileOptions, PullOptions } from './git';
@ -1374,12 +1374,22 @@ export class Repository implements Disposable {
return await this.run(Operation.GetBranch, () => this.repository.getBranch(name));
}
async getBranches(query: BranchQuery): Promise<Ref[]> {
return await this.run(Operation.GetBranches, () => this.repository.getBranches(query));
async getBranches(query: BranchQuery = {}, cancellationToken?: CancellationToken): Promise<Ref[]> {
return await this.run(Operation.GetBranches, async () => {
const refs = await this.getRefs(query, cancellationToken);
return refs.filter(value => (value.type === RefType.Head || value.type === RefType.RemoteHead) && (query.remote || !value.remote));
});
}
async getRefs(opts?: { sort?: 'alphabetically' | 'committerdate'; contains?: string; pattern?: string; count?: number; cancellationToken?: CancellationToken }): Promise<Ref[]> {
return await this.run(Operation.GetRefs, () => this.repository.getRefs(opts));
async getRefs(query: RefQuery = {}, cancellationToken?: CancellationToken): Promise<Ref[]> {
const config = workspace.getConfiguration('git');
let defaultSort = config.get<'alphabetically' | 'committerdate'>('branchSortOrder');
if (defaultSort !== 'alphabetically' && defaultSort !== 'committerdate') {
defaultSort = 'alphabetically';
}
query = { ...query, sort: query?.sort ?? defaultSort };
return await this.run(Operation.GetRefs, () => this.repository.getRefs(query, cancellationToken));
}
async getRemoteRefs(remote: string, opts?: { heads?: boolean; tags?: boolean }): Promise<Ref[]> {
@ -1992,16 +2002,10 @@ export class Repository implements Disposable {
this._sourceControl.commitTemplate = commitTemplate;
// Execute cancellable long-running operations
const config = workspace.getConfiguration('git');
let sort = config.get<'alphabetically' | 'committerdate'>('branchSortOrder') || 'alphabetically';
if (sort !== 'alphabetically' && sort !== 'committerdate') {
sort = 'alphabetically';
}
const [resourceGroups, refs] =
await Promise.all([
this.getStatus(cancellationToken),
this.repository.getRefs({ sort, cancellationToken })]);
this.getRefs({}, cancellationToken)]);
this._refs = refs!;
this._updateResourceGroupsState(resourceGroups);

View file

@ -48,6 +48,14 @@ function renderImage(outputInfo: OutputItem, element: HTMLElement): IDisposable
}
};
if (element.firstChild) {
const display = element.firstChild as HTMLElement;
if (display.firstChild && display.firstChild.nodeName === 'IMG' && display.firstChild instanceof HTMLImageElement) {
display.firstChild.src = src;
return disposable;
}
}
const image = document.createElement('img');
image.src = src;
const display = document.createElement('div');
@ -301,6 +309,7 @@ export const activate: ActivationFunction<void> = (ctx) => {
case 'image/jpeg':
case 'image/git':
{
disposables.get(outputInfo.id)?.dispose();
const disposable = renderImage(outputInfo, element);
disposables.set(outputInfo.id, disposable);
}

View file

@ -132,7 +132,7 @@
"@vscode/l10n-dev": "0.0.21",
"@vscode/telemetry-extractor": "^1.9.8",
"@vscode/test-web": "^0.0.32",
"@vscode/vscode-perf": "^0.0.1",
"@vscode/vscode-perf": "^0.0.2",
"ansi-colors": "^3.2.3",
"asar": "^3.0.3",
"chromium-pickle-js": "^0.2.0",

View file

@ -685,10 +685,6 @@ export class MouseController<T> implements IDisposable {
return;
}
if (e.browserEvent.defaultPrevented) {
return;
}
const focus = e.index;
if (typeof focus === 'undefined') {
@ -713,7 +709,6 @@ export class MouseController<T> implements IDisposable {
this.list.setSelection([focus], e.browserEvent);
}
e.browserEvent.preventDefault();
this._onPointer.fire(e);
}
@ -726,13 +721,8 @@ export class MouseController<T> implements IDisposable {
return;
}
if (e.browserEvent.defaultPrevented) {
return;
}
const focus = this.list.getFocus();
this.list.setSelection(focus, e.browserEvent);
e.browserEvent.preventDefault();
}
private changeSelection(e: IListMouseEvent<T> | IListTouchEvent<T>): void {

View file

@ -1358,10 +1358,6 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
return;
}
if (e.browserEvent.defaultPrevented) {
return;
}
const node = e.element;
if (!node) {
@ -1413,10 +1409,6 @@ class TreeNodeListMouseController<T, TFilterData, TRef> extends MouseController<
return;
}
if (e.browserEvent.defaultPrevented) {
return;
}
super.onDoubleClick(e);
}
}

View file

@ -821,24 +821,32 @@ export class CodeApplication extends Disposable {
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
const urlService = accessor.get(IURLService);
const nativeHostMainService = accessor.get(INativeHostMainService);
const logService = this.logService;
// Signal phase: ready (services set)
this.lifecycleMainService.phase = LifecycleMainPhase.Ready;
// Check for initial URLs to handle from protocol link invocations
const protocolLinksFromCommandLine = this.environmentMainService.args['open-url'] ? this.environmentMainService.args._urls || [] : []; // Windows/Linux: protocol handler invokes CLI with --open-url
if (protocolLinksFromCommandLine.length) {
logService.trace('app#openFirstWindow() protocol links from command line:', protocolLinksFromCommandLine);
}
const protocolLinksFromEvent = ((<any>global).getOpenUrls() || []) as string[]; // macOS: open-url events
if (protocolLinksFromEvent.length) {
logService.trace(`app#openFirstWindow() protocol links from macOS 'open-url' event:`, protocolLinksFromEvent);
}
const pendingWindowOpenablesFromProtocolLinks: IWindowOpenable[] = [];
const pendingProtocolLinksToHandle = [
// Windows/Linux: protocol handler invokes CLI with --open-url
...this.environmentMainService.args['open-url'] ? this.environmentMainService.args._urls || [] : [],
// macOS: open-url events
...((<any>global).getOpenUrls() || []) as string[]
...protocolLinksFromCommandLine,
...protocolLinksFromEvent
].map(url => {
try {
return { uri: URI.parse(url), url };
} catch {
logService.trace('app#openFirstWindow() protocol link failed to parse:', url);
return undefined;
}
}).filter((obj): obj is { uri: URI; url: string } => {
@ -848,6 +856,8 @@ export class CodeApplication extends Disposable {
// If URI should be blocked, filter it out
if (this.shouldBlockURI(obj.uri)) {
logService.trace('app#openFirstWindow() protocol link was blocked:', obj.uri.toString(true));
return false;
}
@ -856,11 +866,15 @@ export class CodeApplication extends Disposable {
// previous workspace too.
const windowOpenable = this.getWindowOpenableFromProtocolLink(obj.uri);
if (windowOpenable) {
logService.trace('app#openFirstWindow() protocol link will be handled as window to open:', obj.uri.toString(true), windowOpenable);
pendingWindowOpenablesFromProtocolLinks.push(windowOpenable);
return false;
}
logService.trace('app#openFirstWindow() protocol link will be passed to active window for handling:', obj.uri.toString(true));
return true;
});
@ -870,11 +884,11 @@ export class CodeApplication extends Disposable {
const app = this;
const environmentService = this.environmentMainService;
const productService = this.productService;
const logService = this.logService;
urlService.registerHandler({
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
logService.trace('app#handleURL: ', uri.toString(true), options);
logService.trace('app#handleURL():', uri.toString(true), options);
// Support 'workspace' URLs (https://github.com/microsoft/vscode/issues/124263)
if (uri.scheme === productService.urlProtocol && uri.path === 'workspace') {
uri = uri.with({
authority: 'file',
@ -885,6 +899,8 @@ export class CodeApplication extends Disposable {
// If URI should be blocked, behave as if it's handled
if (app.shouldBlockURI(uri)) {
logService.trace('app#handleURL() protocol link was blocked:', uri.toString(true));
return true;
}
@ -893,26 +909,37 @@ export class CodeApplication extends Disposable {
// We should handle the URI in a new window if the URL contains `windowId=_blank`
const params = new URLSearchParams(uri.query);
if (params.get('windowId') === '_blank') {
logService.trace(`app#handleURL() found 'windowId=_blank' as parameter, setting shouldOpenInNewWindow=true:`, uri.toString(true));
params.delete('windowId');
uri = uri.with({ query: params.toString() });
shouldOpenInNewWindow = true;
}
// or if no window is open (macOS only)
shouldOpenInNewWindow ||= isMacintosh && windowsMainService.getWindowCount() === 0;
else if (isMacintosh && windowsMainService.getWindowCount() === 0) {
logService.trace(`app#handleURL() running on macOS with no window open, setting shouldOpenInNewWindow=true:`, uri.toString(true));
shouldOpenInNewWindow = true;
}
// Pass along whether the application is being opened via a Continue On flow
const continueOn = params.get('continueOn');
if (continueOn !== null) {
environmentService.continueOn = continueOn ?? undefined;
logService.trace(`app#handleURL() found 'continueOn' as parameter:`, uri.toString(true));
params.delete('continueOn');
uri = uri.with({ query: params.toString() });
environmentService.continueOn = continueOn ?? undefined;
}
// Check for URIs to open in window
// Check if the protocol link is a window openable to open...
const windowOpenableFromProtocolLink = app.getWindowOpenableFromProtocolLink(uri);
logService.trace('app#handleURL: windowOpenableFromProtocolLink = ', windowOpenableFromProtocolLink);
if (windowOpenableFromProtocolLink) {
logService.trace('app#handleURL() opening protocol link as window:', windowOpenableFromProtocolLink, uri.toString(true));
const [window] = await windowsMainService.open({
context: OpenContext.API,
cli: { ...environmentService.args },
@ -927,7 +954,10 @@ export class CodeApplication extends Disposable {
return true;
}
// ...or if we should open in a new window and then handle it within that window
if (shouldOpenInNewWindow) {
logService.trace('app#handleURL() opening empty window and passing in protocol link:', uri.toString(true));
const [window] = await windowsMainService.open({
context: OpenContext.API,
cli: { ...environmentService.args },
@ -958,7 +988,7 @@ export class CodeApplication extends Disposable {
urlService.registerHandler(new URLHandlerChannelClient(urlHandlerChannel));
// Watch Electron URLs and forward them to the UrlService
this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentMainService, this.productService));
this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentMainService, this.productService, this.logService));
// Open our first window
const args = this.environmentMainService.args;

View file

@ -466,6 +466,10 @@ export class TextAreaHandler extends ViewPart {
}));
}
public writeScreenReaderContent(reason: string): void {
this._textAreaInput.writeScreenReaderContent(reason);
}
public override dispose(): void {
super.dispose();
}

View file

@ -929,6 +929,11 @@ export interface ICodeEditor extends editorCommon.IEditor {
*/
setAriaOptions(options: IEditorAriaOptions): void;
/**
* Write the screen reader content to be the current selection
*/
writeScreenReaderContent(reason: string): void;
/**
* @internal
*/

View file

@ -487,6 +487,10 @@ export class View extends ViewEventHandler {
}
}
public writeScreenReaderContent(reason: string): void {
this._textAreaHandler.writeScreenReaderContent(reason);
}
public focus(): void {
this._textAreaHandler.focusTextArea();
}

View file

@ -398,6 +398,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
this._codeEditorService.addCodeEditor(this);
}
public writeScreenReaderContent(reason: string): void {
this._modelData?.view.writeScreenReaderContent(reason);
}
protected _createConfiguration(isSimpleWidget: boolean, options: Readonly<IEditorConstructionOptions>, accessibilityService: IAccessibilityService): EditorConfiguration {
return new EditorConfiguration(isSimpleWidget, options, this._domElement, accessibilityService);
}

View file

@ -292,7 +292,7 @@ export class ModelService extends Disposable implements IModelService {
const language = modelData.model.getLanguageId();
const uri = modelData.model.uri;
if (e && !e.affectsConfiguration('editor', { overrideIdentifier: language, resource: uri })) {
if (e && !e.affectsConfiguration('editor', { overrideIdentifier: language, resource: uri }) && !e.affectsConfiguration('files.eol', { overrideIdentifier: language, resource: uri })) {
continue; // perf: skip if this model is not affected by configuration change
}

4
src/vs/monaco.d.ts vendored
View file

@ -5631,6 +5631,10 @@ declare namespace monaco.editor {
* Get the vertical position (top offset) for the position w.r.t. to the first line.
*/
getTopForPosition(lineNumber: number, column: number): number;
/**
* Write the screen reader content to be the current selection
*/
writeScreenReaderContent(reason: string): void;
/**
* Returns the editor's container dom node
*/

View file

@ -184,7 +184,11 @@ export class ActionList<T extends IActionItem> extends Disposable {
getHeight: element => element.kind === ActionListItemKind.Header ? this._headerLineHeight : this._actionLineHeight,
getTemplateId: element => element.kind
};
this._list = this._register(new List(user, this.domNode, virtualDelegate, [new ActionItemRenderer<IListMenuItem<IActionItem>>(preview, this._keybindingService), new HeaderRenderer()], {
this._list = this._register(new List(user, this.domNode, virtualDelegate, [
new ActionItemRenderer<IListMenuItem<IActionItem>>(preview, this._keybindingService),
new HeaderRenderer(),
], {
keyboardSupport: false,
accessibilityProvider: {
getAriaLabel: element => {
@ -228,8 +232,8 @@ export class ActionList<T extends IActionItem> extends Disposable {
layout(minWidth: number): number {
// Updating list height, depending on how many separators and headers there are.
const numHeaders = this._allMenuItems.filter(item => item.kind === 'header').length;
const height = this._allMenuItems.length * this._actionLineHeight;
const heightWithHeaders = height + numHeaders * this._headerLineHeight - numHeaders * this._actionLineHeight;
const itemsHeight = this._allMenuItems.length * this._actionLineHeight;
const heightWithHeaders = itemsHeight + numHeaders * this._headerLineHeight - numHeaders * this._actionLineHeight;
this._list.layout(heightWithHeaders);
// For finding width dynamically (not using resize observer)
@ -246,9 +250,12 @@ export class ActionList<T extends IActionItem> extends Disposable {
// resize observer - can be used in the future since list widget supports dynamic height but not width
const width = Math.max(...itemWidths, minWidth);
this._list.layout(heightWithHeaders, width);
this.domNode.style.height = `${heightWithHeaders}px`;
const maxVhPrecentage = 0.7;
const height = Math.min(heightWithHeaders, document.body.clientHeight * maxVhPrecentage);
this._list.layout(height, width);
this.domNode.style.height = `${height}px`;
this._list.domFocus();
return width;

View file

@ -54,10 +54,6 @@
outline: 0 !important;
}
.action-widget .monaco-list .monaco-scrollable-element .monaco-list-rows {
height: 100% !important;
}
.action-widget .monaco-list .monaco-scrollable-element {
overflow: visible;
}
@ -123,7 +119,6 @@
/* Action bar */
.action-widget .action-widget-action-bar {
margin-top: 4px;
background-color: var(--vscode-editorHoverWidget-statusBarBackground);
border-top: 1px solid var(--vscode-editorHoverWidget-border);
}

View file

@ -69,7 +69,7 @@ export class AudioCueService extends Disposable implements IAudioCueService {
}
this.playingSounds.add(sound);
console.log('playing', sound);
const url = FileAccess.asBrowserUri(
`vs/platform/audioCues/browser/media/${sound.fileName}`
).toString();
@ -77,6 +77,7 @@ export class AudioCueService extends Disposable implements IAudioCueService {
audio.volume = this.getVolumeInPercent() / 100;
audio.addEventListener('ended', () => {
this.playingSounds.delete(sound);
console.log('ending', sound);
});
try {
try {

View file

@ -102,8 +102,8 @@ export const OPTIONS: OptionDescriptions<Required<NativeParsedArgs>> = {
'no-cached-data': { type: 'boolean' },
'prof-startup-prefix': { type: 'string' },
'prof-v8-extensions': { type: 'boolean' },
'disable-extensions': { type: 'boolean', deprecates: ['disableExtensions'], cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") },
'disable-extension': { type: 'string[]', cat: 't', args: 'ext-id', description: localize('disableExtension', "Disable an extension.") },
'disable-extensions': { type: 'boolean', deprecates: ['disableExtensions'], cat: 't', description: localize('disableExtensions', "Disable all installed extensions. This option is not persisted and is effective only when the command opens a new window.") },
'disable-extension': { type: 'string[]', cat: 't', args: 'ext-id', description: localize('disableExtension', "Disable the provided extension. This option is not persisted and is effective only when the command opens a new window.") },
'sync': { type: 'string', cat: 't', description: localize('turn sync', "Turn sync on or off."), args: ['on | off'] },
'inspect-extensions': { type: 'string', allowEmptyValue: true, deprecates: ['debugPluginHost'], args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") },

View file

@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IProcessEnvironment } from 'vs/base/common/platform';
export enum EnvironmentVariableMutatorType {
Replace = 1,
Append = 2,
@ -12,8 +14,47 @@ export interface IEnvironmentVariableMutator {
readonly value: string;
readonly type: EnvironmentVariableMutatorType;
}
export interface IEnvironmentVariableCollection {
readonly map: ReadonlyMap<string, IEnvironmentVariableMutator>;
}
/** [variable, mutator] */
export type ISerializableEnvironmentVariableCollection = [string, IEnvironmentVariableMutator][];
/** [extension, collection] */
export type ISerializableEnvironmentVariableCollections = [string, ISerializableEnvironmentVariableCollection][];
export interface IExtensionOwnedEnvironmentVariableMutator extends IEnvironmentVariableMutator {
readonly extensionIdentifier: string;
}
export interface IMergedEnvironmentVariableCollectionDiff {
added: ReadonlyMap<string, IExtensionOwnedEnvironmentVariableMutator[]>;
changed: ReadonlyMap<string, IExtensionOwnedEnvironmentVariableMutator[]>;
removed: ReadonlyMap<string, IExtensionOwnedEnvironmentVariableMutator[]>;
}
type VariableResolver = (str: string) => Promise<string>;
/**
* Represents an environment variable collection that results from merging several collections
* together.
*/
export interface IMergedEnvironmentVariableCollection {
readonly collections: ReadonlyMap<string, IEnvironmentVariableCollection>;
readonly map: ReadonlyMap<string, IExtensionOwnedEnvironmentVariableMutator[]>;
/**
* Applies this collection to a process environment.
* @param variableResolver An optional function to use to resolve variables within the
* environment values.
*/
applyToProcessEnvironment(env: IProcessEnvironment, variableResolver?: VariableResolver): Promise<void>;
/**
* Generates a diff of this collection against another. Returns undefined if the collections are
* the same.
*/
diff(other: IMergedEnvironmentVariableCollection): IMergedEnvironmentVariableCollectionDiff | undefined;
}

View file

@ -4,8 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
import { EnvironmentVariableMutatorType, IEnvironmentVariableCollection, IExtensionOwnedEnvironmentVariableMutator, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { VariableResolver } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { EnvironmentVariableMutatorType, IEnvironmentVariableCollection, IExtensionOwnedEnvironmentVariableMutator, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff } from 'vs/platform/terminal/common/environmentVariable';
type VariableResolver = (str: string) => Promise<string>;
export class MergedEnvironmentVariableCollection implements IMergedEnvironmentVariableCollection {
readonly map: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> = new Map();

View file

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IEnvironmentVariableCollection, IEnvironmentVariableMutator, ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IEnvironmentVariableCollection, IEnvironmentVariableMutator, ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariable';
// This file is shared between the renderer and extension host

View file

@ -7,7 +7,7 @@ import * as os from 'os';
import { FileAccess } from 'vs/base/common/network';
import { getCaseInsensitive } from 'vs/base/common/objects';
import * as path from 'vs/base/common/path';
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform';
import * as process from 'vs/base/common/process';
import { format } from 'vs/base/common/strings';
import { isString } from 'vs/base/common/types';
@ -15,6 +15,9 @@ import * as pfs from 'vs/base/node/pfs';
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { IShellLaunchConfig, ITerminalEnvironment, ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal';
import { EnvironmentVariableMutatorType } from 'vs/platform/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariableShared';
import { MergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableCollection';
export function getWindowsBuildNumber(): number {
const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release());
@ -104,7 +107,7 @@ export interface IShellIntegrationConfigInjection {
*/
export function getShellIntegrationInjection(
shellLaunchConfig: IShellLaunchConfig,
options: Pick<ITerminalProcessOptions, 'shellIntegration' | 'windowsEnableConpty'>,
options: ITerminalProcessOptions,
env: ITerminalEnvironment | undefined,
logService: ILogService,
productService: IProductService
@ -151,6 +154,7 @@ export function getShellIntegrationInjection(
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash);
} else if (areZshBashLoginArgs(originalArgs)) {
envMixin['VSCODE_SHELL_LOGIN'] = '1';
addEnvMixinPathPrefix(options, envMixin);
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Bash);
}
if (!newArgs) {
@ -166,6 +170,7 @@ export function getShellIntegrationInjection(
const oldDataDirs = env?.XDG_DATA_DIRS ?? '/usr/local/share:/usr/share';
const newDataDir = path.join(appRoot, 'out/vs/workbench/contrib/xdg_data');
envMixin['XDG_DATA_DIRS'] = `${oldDataDirs}:${newDataDir}`;
addEnvMixinPathPrefix(options, envMixin);
return { newArgs: undefined, envMixin };
}
case 'pwsh': {
@ -186,6 +191,7 @@ export function getShellIntegrationInjection(
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.Zsh);
} else if (areZshBashLoginArgs(originalArgs)) {
newArgs = shellIntegrationArgs.get(ShellIntegrationExecutable.ZshLogin);
addEnvMixinPathPrefix(options, envMixin);
} else if (originalArgs === shellIntegrationArgs.get(ShellIntegrationExecutable.Zsh) || originalArgs === shellIntegrationArgs.get(ShellIntegrationExecutable.ZshLogin)) {
newArgs = originalArgs;
}
@ -230,6 +236,39 @@ export function getShellIntegrationInjection(
return undefined;
}
/**
* On macOS the profile calls path_helper which adds a bunch of standard bin directories to the
* beginning of the PATH. This causes significant problems for the environment variable
* collection API as the custom paths added to the end will now be somewhere in the middle of
* the PATH. To combat this, VSCODE_PATH_PREFIX is used to re-apply any prefix after the profile
* has run. This will cause duplication in the PATH but should fix the issue.
*
* See #99878 for more information.
*/
function addEnvMixinPathPrefix(options: ITerminalProcessOptions, envMixin: IProcessEnvironment): void {
if (isMacintosh && options.environmentVariableCollections) {
// Deserialize and merge
const deserialized = deserializeEnvironmentVariableCollections(options.environmentVariableCollections);
const merged = new MergedEnvironmentVariableCollection(deserialized);
// Get all prepend PATH entries
const pathEntry = merged.map.get('PATH');
const prependToPath: string[] = [];
if (pathEntry) {
for (const mutator of pathEntry) {
if (mutator.type === EnvironmentVariableMutatorType.Prepend) {
prependToPath.push(mutator.value);
}
}
}
// Add to the environment mixin to be applied in the shell integration script
if (prependToPath.length > 0) {
envMixin['VSCODE_PATH_PREFIX'] = prependToPath.join('');
}
}
}
enum ShellIntegrationExecutable {
WindowsPwsh = 'windows-pwsh',
WindowsPwshLogin = 'windows-pwsh-login',

View file

@ -202,7 +202,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
let injection: IShellIntegrationConfigInjection | undefined;
if (this._options.shellIntegration.enabled) {
injection = getShellIntegrationInjection(this.shellLaunchConfig, { shellIntegration: this._options.shellIntegration, windowsEnableConpty: this._options.windowsEnableConpty }, this._ptyOptions.env, this._logService, this._productService);
injection = getShellIntegrationInjection(this.shellLaunchConfig, this._options, this._ptyOptions.env, this._logService, this._productService);
if (injection) {
this._onDidChangeProperty.fire({ type: ProcessPropertyType.UsedShellIntegrationInjection, value: true });
if (injection.envMixin) {

View file

@ -11,9 +11,9 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal';
import { getShellIntegrationInjection, IShellIntegrationConfigInjection } from 'vs/platform/terminal/node/terminalEnvironment';
const enabledProcessOptions: Pick<ITerminalProcessOptions, 'shellIntegration' | 'windowsEnableConpty'> = { shellIntegration: { enabled: true }, windowsEnableConpty: true };
const disabledProcessOptions: Pick<ITerminalProcessOptions, 'shellIntegration' | 'windowsEnableConpty'> = { shellIntegration: { enabled: false }, windowsEnableConpty: true };
const winptyProcessOptions: Pick<ITerminalProcessOptions, 'shellIntegration' | 'windowsEnableConpty'> = { shellIntegration: { enabled: true }, windowsEnableConpty: false };
const enabledProcessOptions: ITerminalProcessOptions = { shellIntegration: { enabled: true }, windowsEnableConpty: true, environmentVariableCollections: undefined };
const disabledProcessOptions: ITerminalProcessOptions = { shellIntegration: { enabled: false }, windowsEnableConpty: true, environmentVariableCollections: undefined };
const winptyProcessOptions: ITerminalProcessOptions = { shellIntegration: { enabled: true }, windowsEnableConpty: false, environmentVariableCollections: undefined };
const pwshExe = process.platform === 'win32' ? 'pwsh.exe' : 'pwsh';
const repoRoot = process.platform === 'win32' ? process.cwd()[0].toLowerCase() + process.cwd().substring(1) : process.cwd();
const logService = new NullLogService();

View file

@ -10,18 +10,11 @@ import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecyc
import { isWindows } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { IURLService } from 'vs/platform/url/common/url';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
function uriFromRawUrl(url: string): URI | null {
try {
return URI.parse(url);
} catch (e) {
return null;
}
}
/**
* A listener for URLs that are opened from the OS and handled by VSCode.
* Depending on the platform, this works differently:
@ -37,15 +30,17 @@ export class ElectronURLListener {
private uris: { uri: URI; url: string }[] = [];
private retryCount = 0;
private flushDisposable: IDisposable = Disposable.None;
private disposables = new DisposableStore();
private readonly disposables = new DisposableStore();
constructor(
initialUrisToHandle: { uri: URI; url: string }[],
private readonly urlService: IURLService,
windowsMainService: IWindowsMainService,
environmentMainService: IEnvironmentMainService,
productService: IProductService
productService: IProductService,
private readonly logService: ILogService
) {
logService.trace('ElectronURLListener initialUrisToHandle:', initialUrisToHandle.map(initialUri => initialUri.url));
// the initial set of URIs we need to handle once the window is ready
this.uris = initialUrisToHandle;
@ -62,12 +57,12 @@ export class ElectronURLListener {
Event.fromNodeEventEmitter(app, 'open-url', (event: ElectronEvent, url: string) => ({ event, url })),
({ event, url }) => {
event.preventDefault(); // always prevent default and return the url as string
return url;
});
this.disposables.add(onOpenElectronUrl(url => {
const uri = uriFromRawUrl(url);
const uri = this.uriFromRawUrl(url);
if (!uri) {
return;
}
@ -77,27 +72,46 @@ export class ElectronURLListener {
// Send initial links to the window once it has loaded
const isWindowReady = windowsMainService.getWindows()
.filter(w => w.isReady)
.filter(window => window.isReady)
.length > 0;
if (isWindowReady) {
logService.trace('ElectronURLListener: window is ready to handle URLs');
this.flush();
} else {
logService.trace('ElectronURLListener: waiting for window to be ready to handle URLs...');
Event.once(windowsMainService.onDidSignalReadyWindow)(this.flush, this, this.disposables);
}
}
private uriFromRawUrl(url: string): URI | undefined {
try {
return URI.parse(url);
} catch (e) {
return undefined;
}
}
private async flush(): Promise<void> {
if (this.retryCount++ > 10) {
this.logService.trace('ElectronURLListener#flush(): giving up after 10 retries');
return;
}
this.logService.trace('ElectronURLListener#flush(): flushing URLs');
const uris: { uri: URI; url: string }[] = [];
for (const obj of this.uris) {
const handled = await this.urlService.open(obj.uri, { originalUrl: obj.url });
if (handled) {
this.logService.trace('ElectronURLListener#flush(): URL was handled', obj.url);
} else {
this.logService.trace('ElectronURLListener#flush(): URL was not yet handled', obj.url);
if (!handled) {
uris.push(obj);
}
}

View file

@ -20,9 +20,9 @@ import { IGetTerminalLayoutInfoArgs, ISetTerminalLayoutInfoArgs } from 'vs/platf
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { createURITransformer } from 'vs/workbench/api/node/uriTransformer';
import { CLIServerBase, ICommandsExecuter } from 'vs/workbench/api/node/extHostCLIServer';
import { IEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { IEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
import { MergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableCollection';
import { deserializeEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableShared';
import { ICreateTerminalProcessArguments, ICreateTerminalProcessResult, IWorkspaceFolderData } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel';
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';

View file

@ -44,28 +44,40 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
}
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, data: INotebookContributionData | undefined): void {
const registration = this._notebookService.registerNotebookSerializer(viewType, extension, {
const disposables = new DisposableStore();
disposables.add(this._notebookService.registerNotebookSerializer(viewType, extension, {
options,
dataToNotebook: async (data: VSBuffer): Promise<NotebookData> => {
const sw = new StopWatch(true);
const dto = await this._proxy.$dataToNotebook(handle, data, CancellationToken.None);
const result = NotebookDto.fromNotebookDataDto(dto.value);
this._logService.trace('[NotebookSerializer] dataToNotebook DONE', extension.id, sw.elapsed());
this._logService.trace(`[NotebookSerializer] dataToNotebook DONE after ${sw.elapsed()}ms`, {
viewType,
extensionId: extension.id.value,
});
return result;
},
notebookToData: (data: NotebookData): Promise<VSBuffer> => {
const sw = new StopWatch(true);
const result = this._proxy.$notebookToData(handle, new SerializableObjectWithBuffers(NotebookDto.toNotebookDataDto(data)), CancellationToken.None);
this._logService.trace('[NotebookSerializer] notebookToData DONE', extension.id, sw.elapsed());
this._logService.trace(`[NotebookSerializer] notebookToData DONE after ${sw.elapsed()}`, {
viewType,
extensionId: extension.id.value,
});
return result;
}
});
const disposables = new DisposableStore();
disposables.add(registration);
}));
if (data) {
disposables.add(this._notebookService.registerContributedNotebookType(viewType, data));
}
this._notebookSerializer.set(handle, disposables);
this._logService.trace('[NotebookSerializer] registered notebook serializer', {
viewType,
extensionId: extension.id.value,
});
}
$unregisterNotebookSerializer(handle: number): void {

View file

@ -14,8 +14,8 @@ import { IProcessProperty, IShellLaunchConfig, IShellLaunchConfigDto, ProcessPro
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroupService, ITerminalInstance, ITerminalLink, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy';
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { IEnvironmentVariableService } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableShared';
import { IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy, ITerminalProfileResolverService, ITerminalProfileService, ITerminalQuickFixService } from 'vs/workbench/contrib/terminal/common/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { withNullAsUndefined } from 'vs/base/common/types';
@ -26,6 +26,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities';
import { ITerminalOutputMatch, ITerminalOutputMatcher, ITerminalQuickFix, ITerminalQuickFixOptions } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { TerminalQuickFixType } from 'vs/workbench/api/common/extHostTypes';
import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
@extHostNamedCustomer(MainContext.MainThreadTerminalService)

View file

@ -55,7 +55,7 @@ import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { OutputChannelUpdateMode } from 'vs/workbench/services/output/common/output';
import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
import { IWorkspaceSymbol } from 'vs/workbench/contrib/search/common/search';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
import { CoverageDetails, ExtensionRunTestsRequest, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, IStartControllerTests, TestResultState, TestsDiffOp } from 'vs/workbench/contrib/testing/common/testTypes';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
import { TypeHierarchyItem } from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';

View file

@ -16,7 +16,6 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import * as types from 'vs/workbench/api/common/extHostTypes';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import type * as vscode from 'vscode';
import { ExtHostCommentsShape, IMainContext, MainContext, CommentThreadChanges, CommentChanges } from './extHost.protocol';
import { ExtHostCommands } from './extHostCommands';
@ -338,12 +337,10 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
private _state?: vscode.CommentThreadState;
get state(): vscode.CommentThreadState {
checkProposedApiEnabled(this.extensionDescription, 'commentsResolvedState');
return this._state!;
}
set state(newState: vscode.CommentThreadState) {
checkProposedApiEnabled(this.extensionDescription, 'commentsResolvedState');
this._state = newState;
this.modifications.state = newState;
this._onDidUpdateCommentThread.fire();

View file

@ -14,10 +14,10 @@ import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType, Termina
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { localize } from 'vs/nls';
import { NotSupportedError } from 'vs/base/common/errors';
import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { serializeEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableShared';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { generateUuid } from 'vs/base/common/uuid';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
import { ICreateContributedTerminalProfileOptions, IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalLocation, IProcessProperty, ProcessPropertyType, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { ThemeColor } from 'vs/platform/theme/common/themeService';

View file

@ -19,7 +19,7 @@ import { IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platf
import { ActivityAction, ActivityActionViewItem, IActivityActionViewItemOptions, IActivityHoverOptions, ICompositeBar, ICompositeBarColors, ToggleCompositeBadgeAction, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
import { IActivity } from 'vs/workbench/common/activity';
import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_PROFILE_BACKGROUND, ACTIVITY_BAR_PROFILE_HOVER_FOREGROUND } from 'vs/workbench/common/theme';
import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_PROFILE_HOVER_FOREGROUND } from 'vs/workbench/common/theme';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
@ -508,11 +508,6 @@ registerThemingParticipant((theme, collector) => {
const activityBarForegroundColor = theme.getColor(ACTIVITY_BAR_FOREGROUND);
if (activityBarForegroundColor) {
collector.addRule(`
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label:not(.codicon):not(.profile-activity-item),
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label:not(.codicon):not(.profile-activity-item),
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label:not(.codicon):not(.profile-activity-item) {
background-color: ${activityBarForegroundColor} !important;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label.codicon,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label.codicon,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label.codicon {
@ -521,23 +516,12 @@ registerThemingParticipant((theme, collector) => {
`);
}
const activityBarProfileBgColor = theme.getColor(ACTIVITY_BAR_PROFILE_BACKGROUND);
if (activityBarProfileBgColor) {
collector.addRule(`
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label.profile-activity-item,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label.profile-activity-item,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item .action-label.profile-activity-item {
background-color: ${activityBarProfileBgColor} !important;
}
`);
}
const activityBarProfileHoverFgColor = theme.getColor(ACTIVITY_BAR_PROFILE_HOVER_FOREGROUND);
if (activityBarProfileHoverFgColor) {
collector.addRule(`
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label.profile-activity-item,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label.profile-activity-item,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label.profile-activity-item {
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active.profile-activity-item .action-label,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.profile-activity-item:focus .action-label,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.profile-activity-item:hover .action-label {
color: ${activityBarProfileHoverFgColor} !important;
}
`);

View file

@ -43,7 +43,7 @@ import { StringSHA1 } from 'vs/base/common/hash';
import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';
import { GestureEvent } from 'vs/base/browser/touch';
import { IPaneCompositePart, IPaneCompositeSelectorPart } from 'vs/workbench/browser/parts/paneCompositePart';
import { IUserDataProfileService, PROFILES_TTILE } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { IUserDataProfileService, PROFILES_TTILE, defaultUserDataProfileIcon } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
interface IPlaceholderViewContainer {
@ -618,11 +618,11 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
private createProfilesActivity(): IProfileActivity {
const shortName = this.userDataProfileService.getShortName(this.userDataProfileService.currentProfile);
const icon = ThemeIcon.fromString(shortName);
const icon = ThemeIcon.fromString(shortName) ?? defaultUserDataProfileIcon;
return {
id: 'workbench.actions.profiles',
name: icon ? this.userDataProfileService.currentProfile.name : shortName,
cssClass: icon ? `${ThemeIcon.asClassName(icon)} profile-activity-item` : 'profile-activity-item',
cssClass: ThemeIcon.asClassName(icon),
icon: !!icon
};
}

View file

@ -176,26 +176,8 @@
vertical-align: baseline;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label.profile-activity-item {
height: 20px;
width: 32px;
margin: 14px 8px;
padding: 0px;
justify-content: center;
align-items: center;
font-size: 11px;
font-weight: 600;
border-radius: 10px;
}
/* Right aligned */
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon):not(.profile-activity-item) {
margin-left: 0;
padding: 0 48px 0 0;
background-position: calc(100% - 9px) center;
}
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .badge {
left: auto;
right: 0;

View file

@ -137,7 +137,7 @@ export class DynamicEditorConfigurations extends Disposable implements IWorkbenc
properties: {
'workbench.editorAssociations': {
type: 'object',
markdownDescription: localize('editor.editorAssociations', "Configure glob patterns to editors (for example `\"*.hex\": \"hexEditor.hexEdit\"`). These have precedence over the default behavior."),
markdownDescription: localize('editor.editorAssociations', "Configure glob patterns to editors (for example `\"*.hex\": \"hexEditor.hexedit\"`). These have precedence over the default behavior."),
patternProperties: {
'.*': {
type: 'string',

View file

@ -233,8 +233,8 @@ export class TextDiffEditor extends AbstractTextEditor<IDiffEditorViewState> imp
}
}
protected override shouldComputeConfiguration(e: ITextResourceConfigurationChangeEvent, resource: URI): boolean {
if (super.shouldComputeConfiguration(e, resource)) {
protected override shouldHandleConfigurationChangeEvent(e: ITextResourceConfigurationChangeEvent, resource: URI): boolean {
if (super.shouldHandleConfigurationChangeEvent(e, resource)) {
return true;
}

View file

@ -64,16 +64,8 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
) {
super(id, AbstractTextEditor.VIEW_STATE_PREFERENCE_KEY, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorService, editorGroupService);
this._register(this.textResourceConfigurationService.onDidChangeConfiguration(e => {
const resource = this.getActiveResource();
if (!this.shouldComputeConfiguration(e, resource)) {
return;
}
const value = resource ? this.textResourceConfigurationService.getValue<IEditorConfiguration>(resource) : undefined;
return this.handleConfigurationChangeEvent(value);
}));
// Listen to configuration changes
this._register(this.textResourceConfigurationService.onDidChangeConfiguration(e => this.handleConfigurationChangeEvent(e)));
// ARIA: if a group is added or removed, update the editor's ARIA
// label so that it appears in the label for when there are > 1 groups
@ -90,14 +82,23 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidChangeFileSystemProvider(e.scheme)));
}
private handleConfigurationChangeEvent(configuration?: IEditorConfiguration): void {
private handleConfigurationChangeEvent(e: ITextResourceConfigurationChangeEvent): void {
const resource = this.getActiveResource();
if (!this.shouldHandleConfigurationChangeEvent(e, resource)) {
return;
}
if (this.isVisible()) {
this.updateEditorConfiguration(configuration);
this.updateEditorConfiguration(resource);
} else {
this.hasPendingConfigurationChange = true;
}
}
protected shouldHandleConfigurationChangeEvent(e: ITextResourceConfigurationChangeEvent, resource: URI | undefined): boolean {
return e.affectsConfiguration(resource, 'editor');
}
private consumePendingConfigurationChangeEvent(): void {
if (this.hasPendingConfigurationChange) {
this.updateEditorConfiguration();
@ -105,10 +106,6 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
}
}
protected shouldComputeConfiguration(e: ITextResourceConfigurationChangeEvent, resource: URI | undefined): boolean {
return e.affectsConfiguration(resource, 'editor');
}
protected computeConfiguration(configuration: IEditorConfiguration): ICodeEditorOptions {
// Specific editor options always overwrite user configuration
@ -257,12 +254,10 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
return input.resource;
}
private updateEditorConfiguration(configuration?: IEditorConfiguration): void {
if (!configuration) {
const resource = this.getActiveResource();
if (resource) {
configuration = this.textResourceConfigurationService.getValue<IEditorConfiguration>(resource);
}
private updateEditorConfiguration(resource = this.getActiveResource()): void {
let configuration: IEditorConfiguration | undefined = undefined;
if (resource) {
configuration = this.textResourceConfigurationService.getValue<IEditorConfiguration>(resource);
}
if (!configuration) {

View file

@ -639,13 +639,6 @@ export const ACTIVITY_BAR_PROFILE_HOVER_FOREGROUND = registerColor('activityBarI
hcLight: ACTIVITY_BAR_FOREGROUND
}, localize('activityBarItem.profilesHoverForeground', "Foreground color for the profile entry on the activity bar when hovering."));
export const ACTIVITY_BAR_PROFILE_BACKGROUND = registerColor('activityBarItem.profilesBackground', {
dark: lighten(ACTIVITY_BAR_BACKGROUND, 0.5),
light: darken(ACTIVITY_BAR_BACKGROUND, 0.12),
hcDark: null,
hcLight: null
}, localize('activityBarItem.profilesBackground', "Background color for the profile entry on the activity bar."));
// < --- Remote --- >
export const STATUS_BAR_HOST_NAME_BACKGROUND = registerColor('statusBarItem.remoteBackground', {

View file

@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/customEditor';
import { coalesce } from 'vs/base/common/arrays';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
@ -17,8 +18,6 @@ import { FileOperation, IFileService } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform';
import { IStorageService } from 'vs/platform/storage/common/storage';
import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
import { DEFAULT_EDITOR_ASSOCIATION, EditorExtensions, GroupIdentifier, IEditorFactoryRegistry, IResourceDiffEditorInput } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
@ -262,10 +261,3 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
}
}
}
registerThemingParticipant((theme, collector) => {
const shadow = theme.getColor(colorRegistry.scrollbarShadow);
if (shadow) {
collector.addRule(`.webview.modified { box-shadow: -6px 0 5px -5px ${shadow}; }`);
}
});

View file

@ -0,0 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.webview.modified {
box-shadow: -6px 0 5px -5px var(--vscode-scrollbar-shadow);
}

View file

@ -317,7 +317,7 @@ export class DebugSession implements IDebugSession {
supportsVariableType: true, // #8858
supportsVariablePaging: true, // #9537
supportsRunInTerminalRequest: true, // #10574
locale: platform.locale,
locale: platform.language, // #169114
supportsProgressReporting: true, // #92253
supportsInvalidatedEvent: true, // #106745
supportsMemoryReferences: true, //#129684

View file

@ -30,14 +30,14 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { IQuickInputButton, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ContextKeyExpr, ContextKeyExpression, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { getVirtualWorkspaceLocation } from 'vs/platform/workspace/common/virtualWorkspace';
import { Schemas } from 'vs/base/common/network';
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionService, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { EditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessionsLogService';
import { IViewContainersRegistry, Extensions as ViewExtensions, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
@ -61,10 +61,14 @@ import { ILocalizedString } from 'vs/platform/action/common/action';
import { Codicon } from 'vs/base/common/codicons';
import { CancellationError } from 'vs/base/common/errors';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IExtensionsViewPaneContainer, VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
registerSingleton(IEditSessionsLogService, EditSessionsLogService, InstantiationType.Delayed);
registerSingleton(IEditSessionsStorageService, EditSessionsWorkbenchService, InstantiationType.Delayed);
const continueWorkingOnCommand: IAction2Options = {
id: '_workbench.editSessions.actions.continueEditSession',
title: { value: localize('continue working on', "Continue Working On..."), original: 'Continue Working On...' },
@ -82,6 +86,23 @@ const showOutputChannelCommand: IAction2Options = {
title: { value: localize('show log', 'Show Log'), original: 'Show Log' },
category: EDIT_SESSION_SYNC_CATEGORY
};
const installAdditionalContinueOnOptionsCommand = {
id: 'workbench.action.continueOn.extensions',
title: localize('continueOn.installAdditional', 'Install additional development environment options'),
};
registerAction2(class extends Action2 {
constructor() {
super({ ...installAdditionalContinueOnOptionsCommand, f1: false });
}
async run(accessor: ServicesAccessor): Promise<void> {
const paneCompositePartService = accessor.get(IPaneCompositePartService);
const viewlet = await paneCompositePartService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar, true);
const view = viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer | undefined;
view?.search('@tag:continueOn');
}
});
const resumeProgressOptionsTitle = `[${localize('resuming working changes window', 'Resuming working changes...')}](command:${showOutputChannelCommand.id})`;
const resumeProgressOptions = {
location: ProgressLocation.Window,
@ -124,6 +145,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
@IActivityService private readonly activityService: IActivityService,
@IEditorService private readonly editorService: IEditorService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
@IExtensionService private readonly extensionService: IExtensionService,
) {
super();
@ -809,7 +831,8 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
if (remoteGroup !== undefined) {
MenuRegistry.appendMenuItem(MenuId.StatusBarRemoteIndicatorMenu, {
group: remoteGroup,
command: command
command: command,
when: command.precondition
});
}
}
@ -851,14 +874,22 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
: this.contextService.getWorkspace().folders.map((folder) => folder.name).join(', ');
quickPick.placeholder = localize('continueEditSessionPick.title.v2', "Select a development environment to continue working on {0} in", `'${workspaceContext}'`);
quickPick.items = this.createPickItems();
this.extensionService.onDidChangeExtensions(() => {
quickPick.items = this.createPickItems();
});
const command = await new Promise<string | undefined>((resolve, reject) => {
quickPick.onDidHide(() => resolve(undefined));
quickPick.onDidAccept((e) => {
const selection = quickPick.activeItems[0].command;
resolve(selection);
quickPick.hide();
if (selection === installAdditionalContinueOnOptionsCommand.id) {
void this.commandService.executeCommand(installAdditionalContinueOnOptionsCommand.id);
} else {
resolve(selection);
quickPick.hide();
}
});
quickPick.show();
@ -912,7 +943,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
}
}
private createPickItems(): ContinueEditSessionItem[] {
private createPickItems(): (ContinueEditSessionItem | IQuickPickSeparator)[] {
const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when));
if (getVirtualWorkspaceLocation(this.contextService.getWorkspace()) !== undefined && isNative) {
@ -923,7 +954,8 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
));
}
return items.sort((item1, item2) => item1.label.localeCompare(item2.label));
const sortedItems: (ContinueEditSessionItem | IQuickPickSeparator)[] = items.sort((item1, item2) => item1.label.localeCompare(item2.label));
return sortedItems.concat({ type: 'separator' }, new ContinueEditSessionItem(installAdditionalContinueOnOptionsCommand.title, installAdditionalContinueOnOptionsCommand.id));
}
}

View file

@ -41,6 +41,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
const folderName = 'test-folder';
const folderUri = URI.file(`/${folderName}`);
@ -75,6 +76,9 @@ suite('Edit session sync', () => {
override onDidSignIn = Event.None;
override onDidSignOut = Event.None;
});
instantiationService.stub(IExtensionService, new class extends mock<IExtensionService>() {
override onDidChangeExtensions = Event.None;
});
instantiationService.stub(IProgressService, ProgressService);
instantiationService.stub(ISCMService, SCMService);
instantiationService.stub(IEnvironmentService, TestEnvironmentService);

View file

@ -127,16 +127,20 @@ export class OutputElement extends Disposable {
private _renderSearchForMimetype(viewModel: ICellOutputViewModel, mimeType: string): IInsetRenderOutput {
const query = `@tag:notebookRenderer ${mimeType}`;
const p = DOM.$('p', undefined, `No renderer could be found for mimetype "${mimeType}", but one might be available on the Marketplace.`);
const a = DOM.$('a', { href: `command:workbench.extensions.search?%22${query}%22`, class: 'monaco-button monaco-text-button', tabindex: 0, role: 'button', style: 'padding: 8px; text-decoration: none; color: rgb(255, 255, 255); background-color: rgb(14, 99, 156); max-width: 200px;' }, `Search Marketplace`);
return {
type: RenderOutputType.Html,
source: viewModel,
htmlContent: `<p>No renderer could be found for mimetype "${mimeType}", but one might be available on the Marketplace.</p>
<a href="command:workbench.extensions.search?%22${query}%22" class="monaco-button monaco-text-button" tabindex="0" role="button" style="padding: 8px; text-decoration: none; color: rgb(255, 255, 255); background-color: rgb(14, 99, 156); max-width: 200px;">Search Marketplace</a>`
htmlContent: p.outerHTML + a.outerHTML,
};
}
private _renderMessage(viewModel: ICellOutputViewModel, message: string): IInsetRenderOutput {
return { type: RenderOutputType.Html, source: viewModel, htmlContent: `<p>${message}</p>` };
const el = DOM.$('p', undefined, message);
return { type: RenderOutputType.Html, source: viewModel, htmlContent: el.outerHTML };
}
private async pickActiveMimeTypeRenderer(notebookTextModel: NotebookTextModel, viewModel: ICellOutputViewModel) {

View file

@ -29,6 +29,7 @@ import { CodeCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/vi
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CellUri, IOrderedMimeType, NotebookCellOutputsSplice, RENDERER_NOT_AVAILABLE } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
@ -236,16 +237,20 @@ class CellOutputElement extends Disposable {
private _renderSearchForMimetype(viewModel: ICellOutputViewModel, mimeType: string): IInsetRenderOutput {
const query = `@tag:notebookRenderer ${mimeType}`;
const p = DOM.$('p', undefined, `No renderer could be found for mimetype "${mimeType}", but one might be available on the Marketplace.`);
const a = DOM.$('a', { href: `command:workbench.extensions.search?%22${query}%22`, class: 'monaco-button monaco-text-button', tabindex: 0, role: 'button', style: 'padding: 8px; text-decoration: none; color: rgb(255, 255, 255); background-color: rgb(14, 99, 156); max-width: 200px;' }, `Search Marketplace`);
return {
type: RenderOutputType.Html,
source: viewModel,
htmlContent: `<p>No renderer could be found for mimetype "${mimeType}", but one might be available on the Marketplace.</p>
<a href="command:workbench.extensions.search?%22${query}%22" class="monaco-button monaco-text-button" tabindex="0" role="button" style="padding: 8px; text-decoration: none; color: rgb(255, 255, 255); background-color: rgb(14, 99, 156); max-width: 200px;">Search Marketplace</a>`
htmlContent: p.outerHTML + a.outerHTML
};
}
private _renderMessage(viewModel: ICellOutputViewModel, message: string): IInsetRenderOutput {
return { type: RenderOutputType.Html, source: viewModel, htmlContent: `<p>${message}</p>` };
const el = DOM.$('p', undefined, message);
return { type: RenderOutputType.Html, source: viewModel, htmlContent: el.outerHTML };
}
private async _attachToolbar(outputItemDiv: HTMLElement, notebookTextModel: NotebookTextModel, kernel: INotebookKernel | undefined, index: number, mimeTypes: readonly IOrderedMimeType[]) {
@ -427,6 +432,11 @@ class OutputEntryViewHandler {
}
}
const enum CellOutputUpdateContext {
Execution = 1,
Other = 2
}
export class CellOutputContainer extends CellContentPart {
private _outputEntries: OutputEntryViewHandler[] = [];
@ -440,12 +450,23 @@ export class CellOutputContainer extends CellContentPart {
private readonly templateData: CodeCellRenderTemplate,
private options: { limit: number },
@IOpenerService private readonly openerService: IOpenerService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super();
this._register(viewCell.onDidStartExecution(() => {
viewCell.updateOutputMinHeight(viewCell.layoutInfo.outputTotalHeight);
}));
this._register(viewCell.onDidStopExecution(() => {
this._validateFinalOutputHeight(false);
}));
this._register(viewCell.onDidChangeOutputs(splice => {
this._updateOutputs(splice);
const executionState = this._notebookExecutionStateService.getCellExecution(viewCell.uri);
const context = executionState ? CellOutputUpdateContext.Execution : CellOutputUpdateContext.Other;
this._updateOutputs(splice, context);
}));
this._register(viewCell.onDidChangeLayout(() => {
@ -539,7 +560,7 @@ export class CellOutputContainer extends CellContentPart {
}
}
private _updateOutputs(splice: NotebookCellOutputsSplice) {
private _updateOutputs(splice: NotebookCellOutputsSplice, context: CellOutputUpdateContext = CellOutputUpdateContext.Other) {
const previousOutputHeight = this.viewCell.layoutInfo.outputTotalHeight;
// for cell output update, we make sure the cell does not shrink before the new outputs are rendered.
@ -552,10 +573,10 @@ export class CellOutputContainer extends CellContentPart {
}
this.viewCell.spliceOutputHeights(splice.start, splice.deleteCount, splice.newOutputs.map(_ => 0));
this._renderNow(splice);
this._renderNow(splice, context);
}
private _renderNow(splice: NotebookCellOutputsSplice) {
private _renderNow(splice: NotebookCellOutputsSplice, context: CellOutputUpdateContext) {
if (splice.start >= this.options.limit) {
// splice items out of limit
return;
@ -660,7 +681,8 @@ export class CellOutputContainer extends CellContentPart {
this._relayoutCell();
// if it's clearing all outputs, or outputs are all rendered synchronously
// shrink immediately as the final output height will be zero.
this._validateFinalOutputHeight(false || this.viewCell.outputsViewModels.length === 0);
// if it's rerun, then the output clearing might be temporary, so we don't shrink immediately
this._validateFinalOutputHeight(false || (context === CellOutputUpdateContext.Other && this.viewCell.outputsViewModels.length === 0));
}
private _generateShowMoreElement(disposables: DisposableStore): HTMLElement {

View file

@ -182,40 +182,6 @@ async function webviewPreloads(ctx: PreloadContext) {
document.body.addEventListener('click', handleInnerClick);
const preservedScriptAttributes: (keyof HTMLScriptElement)[] = [
'type', 'src', 'nonce', 'noModule', 'async',
];
// derived from https://github.com/jquery/jquery/blob/d0ce00cdfa680f1f0c38460bc51ea14079ae8b07/src/core/DOMEval.js
const domEval = (container: Element) => {
const arr = Array.from(container.getElementsByTagName('script'));
for (let n = 0; n < arr.length; n++) {
const node = arr[n];
const scriptTag = document.createElement('script');
const trustedScript = ttPolicy?.createScript(node.innerText) ?? node.innerText;
scriptTag.text = trustedScript as string;
for (const key of preservedScriptAttributes) {
const val = node[key] || node.getAttribute && node.getAttribute(key);
if (val) {
scriptTag.setAttribute(key, val as any);
}
}
// TODO@connor4312: should script with src not be removed?
container.appendChild(scriptTag).parentNode!.removeChild(scriptTag);
}
};
async function loadScriptSource(url: string, originalUri: string): Promise<string> {
const res = await fetch(url);
const text = await res.text();
if (!res.ok) {
throw new Error(`Unexpected ${res.status} requesting ${originalUri}: ${text || res.statusText}`);
}
return text;
}
interface RendererContext extends rendererApi.RendererContext<unknown> {
readonly settings: RenderOptions;
}
@ -248,24 +214,9 @@ async function webviewPreloads(ctx: PreloadContext) {
});
}
const invokeSourceWithGlobals = (functionSrc: string, globals: { [name: string]: unknown }) => {
const args = Object.entries(globals);
return new Function(...args.map(([k]) => k), functionSrc)(...args.map(([, v]) => v));
};
async function runKernelPreload(url: string, originalUri: string, forceLoadAsModule: boolean): Promise<void> {
if (forceLoadAsModule) {
return activateModuleKernelPreload(url);
}
const text = await loadScriptSource(url, originalUri);
const isModule = /\bexport\b.*\bactivate\b/.test(text);
async function runKernelPreload(url: string): Promise<void> {
try {
if (isModule) {
return activateModuleKernelPreload(url);
} else {
return invokeSourceWithGlobals(text, { ...kernelPreloadGlobals, scriptUrl: url });
}
return await activateModuleKernelPreload(url);
} catch (e) {
console.error(e);
throw e;
@ -842,12 +793,6 @@ async function webviewPreloads(ctx: PreloadContext) {
const onDidReceiveKernelMessage = createEmitter<unknown>();
const kernelPreloadGlobals = {
acquireVsCodeApi,
onDidReceiveKernelMessage: onDidReceiveKernelMessage.event,
postKernelMessage: (data: unknown) => postNotebookMessage('customKernelMessage', { message: data }),
};
const ttPolicy = window.trustedTypes?.createPolicy('notebookRenderer', {
createHTML: value => value,
createScript: value => value,
@ -1233,8 +1178,8 @@ async function webviewPreloads(ctx: PreloadContext) {
}
case 'preload': {
const resources = event.data.resources;
for (const { uri, originalUri } of resources) {
kernelPreloads.load(uri, originalUri, false);
for (const { uri } of resources) {
kernelPreloads.load(uri);
}
break;
}
@ -1486,9 +1431,9 @@ async function webviewPreloads(ctx: PreloadContext) {
* @param uri URI to load from
* @param originalUri URI to show in an error message if the preload is invalid.
*/
public load(uri: string, originalUri: string, forceLoadAsModule: boolean) {
public load(uri: string) {
const promise = Promise.all([
runKernelPreload(uri, originalUri, forceLoadAsModule),
runKernelPreload(uri),
this.waitForAllCurrent(),
]);
@ -2253,7 +2198,7 @@ async function webviewPreloads(ctx: PreloadContext) {
});
for (const preload of ctx.staticPreloadsData) {
kernelPreloads.load(preload.entrypoint, preload.entrypoint, true);
kernelPreloads.load(preload.entrypoint);
}
function postNotebookMessage<T extends webviewMessages.FromWebviewMessage>(
@ -2312,7 +2257,6 @@ async function webviewPreloads(ctx: PreloadContext) {
if (content.type === 0 /* RenderOutputType.Html */) {
const trustedHtml = ttPolicy?.createHTML(content.htmlContent) ?? content.htmlContent;
this.element.innerHTML = trustedHtml as string;
domEval(this.element);
} else if (preloadErrors.some(e => e instanceof Error)) {
const errors = preloadErrors.filter((e): e is Error => e instanceof Error);
showRenderError(`Error loading preloads`, this.element, errors);

View file

@ -21,6 +21,7 @@ import { NotebookOptionsChangeEvent } from 'vs/workbench/contrib/notebook/common
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { BaseCellViewModel } from './baseCellViewModel';
import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents';
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
export class CodeCellViewModel extends BaseCellViewModel implements ICellViewModel {
readonly cellKind = CellKind.Code;
@ -28,6 +29,11 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
protected readonly _onLayoutInfoRead = this._register(new Emitter<void>());
readonly onLayoutInfoRead = this._onLayoutInfoRead.event;
protected readonly _onDidStartExecution = this._register(new Emitter<void>());
readonly onDidStartExecution = this._onDidStartExecution.event;
protected readonly _onDidStopExecution = this._register(new Emitter<void>());
readonly onDidStopExecution = this._onDidStopExecution.event;
protected readonly _onDidChangeOutputs = this._register(new Emitter<NotebookCellOutputsSplice>());
readonly onDidChangeOutputs = this._onDidChangeOutputs.event;
@ -116,6 +122,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
readonly viewContext: ViewContext,
@IConfigurationService configurationService: IConfigurationService,
@INotebookService private readonly _notebookService: INotebookService,
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService,
@ITextModelService modelService: ITextModelService,
@IUndoRedoService undoRedoService: IUndoRedoService,
@ICodeEditorService codeEditorService: ICodeEditorService
@ -144,6 +151,16 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
dispose(removedOutputs);
}));
this._register(this._notebookExecutionStateService.onDidChangeCellExecution(e => {
if (e.affectsCell(model.uri)) {
if (e.changed) {
this._onDidStartExecution.fire();
} else {
this._onDidStopExecution.fire();
}
}
}));
this._outputCollection = new Array(this.model.outputs.length);
this._layoutInfo = {

View file

@ -25,13 +25,13 @@ export class NotebookCellOutputTextModel extends Disposable implements ICellOutp
}
constructor(
readonly _rawOutput: IOutputDto
private _rawOutput: IOutputDto
) {
super();
}
replaceData(items: IOutputItemDto[]) {
this._rawOutput.outputs = items;
replaceData(rawData: IOutputDto) {
this._rawOutput = rawData;
this._onDidChangeData.fire();
}

View file

@ -280,23 +280,25 @@ export class NotebookCellTextModel extends Disposable implements ICell {
}
spliceNotebookCellOutputs(splice: NotebookCellOutputsSplice): void {
this.outputs.splice(splice.start, splice.deleteCount, ...splice.newOutputs);
this._onDidChangeOutputs.fire(splice);
if (splice.deleteCount > 0 && splice.newOutputs.length > 0) {
const commonLen = Math.min(splice.deleteCount, splice.newOutputs.length);
// update
for (let i = 0; i < commonLen; i++) {
const currentOutput = this.outputs[splice.start + i];
const newOutput = splice.newOutputs[i];
this.replaceOutput(currentOutput.outputId, newOutput);
}
this.outputs.splice(splice.start + commonLen, splice.deleteCount - commonLen, ...splice.newOutputs.slice(commonLen));
this._onDidChangeOutputs.fire({ start: splice.start + commonLen, deleteCount: splice.deleteCount - commonLen, newOutputs: splice.newOutputs.slice(commonLen) });
} else {
this.outputs.splice(splice.start, splice.deleteCount, ...splice.newOutputs);
this._onDidChangeOutputs.fire(splice);
}
}
changeOutputItems(outputId: string, append: boolean, items: IOutputItemDto[]): boolean {
const outputIndex = this.outputs.findIndex(output => output.outputId === outputId);
if (outputIndex < 0) {
return false;
}
const output = this.outputs[outputIndex];
if (append) {
output.appendData(items);
} else {
output.replaceData(items);
}
private _optimizeOutputItems(output: ICellOutput) {
if (output.outputs.length > 1 && output.outputs.every(item => isTextStreamMime(item.mime))) {
// Look for the mimes in the items, and keep track of their order.
// Merge the streams into one output item, per mime type.
@ -322,7 +324,37 @@ export class NotebookCellTextModel extends Disposable implements ICell {
});
});
}
}
replaceOutput(outputId: string, newOutputItem: ICellOutput) {
const outputIndex = this.outputs.findIndex(output => output.outputId === outputId);
if (outputIndex < 0) {
return false;
}
const output = this.outputs[outputIndex];
output.replaceData(newOutputItem);
this._optimizeOutputItems(output);
this._onDidChangeOutputItems.fire();
return true;
}
changeOutputItems(outputId: string, append: boolean, items: IOutputItemDto[]): boolean {
const outputIndex = this.outputs.findIndex(output => output.outputId === outputId);
if (outputIndex < 0) {
return false;
}
const output = this.outputs[outputIndex];
if (append) {
output.appendData(items);
} else {
output.replaceData({ outputId: outputId, outputs: items, metadata: output.metadata });
}
this._optimizeOutputItems(output);
this._onDidChangeOutputItems.fire();
return true;
}

View file

@ -205,7 +205,7 @@ export interface ICellOutput {
metadata?: Record<string, any>;
outputId: string;
onDidChangeData: Event<void>;
replaceData(items: IOutputItemDto[]): void;
replaceData(items: IOutputDto): void;
appendData(items: IOutputItemDto[]): void;
}

View file

@ -981,7 +981,7 @@ export class SettingsEditor2 extends EditorPane {
private onDidChangeSetting(key: string, value: any, type: SettingValueType | SettingValueType[], manualReset: boolean, scope: ConfigurationScope | undefined): void {
const parsedQuery = parseQuery(this.searchWidget.getValue());
const languageFilter = parsedQuery.languageFilter;
if (this.pendingSettingUpdate && this.pendingSettingUpdate.key !== key) {
if (manualReset || (this.pendingSettingUpdate && this.pendingSettingUpdate.key !== key)) {
this.updateChangedSetting(key, value, manualReset, languageFilter, scope);
}

View file

@ -17,8 +17,7 @@ import { localize } from 'vs/nls';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { getIgnoredSettings } from 'vs/platform/userDataSync/common/settingsMerge';
import { getDefaultIgnoredSettings, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
import { SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels';
import { POLICY_SETTING_TAG } from 'vs/workbench/contrib/preferences/common/preferences';
import { IHoverOptions, IHoverService, IHoverWidget } from 'vs/workbench/services/hover/browser/hover';
@ -39,6 +38,19 @@ interface SettingIndicator {
disposables: DisposableStore;
}
/**
* Contains a set of the sync-ignored settings
* to keep the sync ignored indicator and the getIndicatorsLabelAriaLabel() function in sync.
* SettingsTreeIndicatorsLabel#updateSyncIgnored provides the source of truth.
*/
let cachedSyncIgnoredSettingsSet: Set<string> = new Set<string>();
/**
* Contains a copy of the sync-ignored settings to determine when to update
* cachedSyncIgnoredSettingsSet.
*/
let cachedSyncIgnoredSettings: string[] = [];
/**
* Renders the indicators next to a setting, such as "Also Modified In".
*/
@ -214,6 +226,10 @@ export class SettingsTreeIndicatorsLabel implements IDisposable {
this.syncIgnoredIndicator.element.style.display = this.userDataSyncEnablementService.isEnabled()
&& ignoredSettings.includes(element.setting.key) ? 'inline' : 'none';
this.render();
if (cachedSyncIgnoredSettings !== ignoredSettings) {
cachedSyncIgnoredSettings = ignoredSettings;
cachedSyncIgnoredSettingsSet = new Set<string>(cachedSyncIgnoredSettings);
}
}
private getInlineScopeDisplayText(completeScope: string): string {
@ -455,8 +471,7 @@ export function getIndicatorsLabelAriaLabel(element: SettingsTreeSettingElement,
}
// Add sync ignored text
const ignoredSettings = getIgnoredSettings(getDefaultIgnoredSettings(), configurationService);
if (ignoredSettings.includes(element.setting.key)) {
if (cachedSyncIgnoredSettingsSet.has(element.setting.key)) {
ariaLabelSections.push(localize('syncIgnoredAriaLabel', "Setting ignored during sync"));
}

View file

@ -57,6 +57,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files';
import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
class DiffActionRunner extends ActionRunner {
@ -464,9 +465,11 @@ export class GotoPreviousChangeAction extends EditorAction {
});
}
run(accessor: ServicesAccessor): void {
async run(accessor: ServicesAccessor): Promise<void> {
const outerEditor = getOuterEditorFromDiffEditor(accessor);
const audioCueService = accessor.get(IAudioCueService);
const accessibilityService = accessor.get(IAccessibilityService);
const codeEditorService = accessor.get(ICodeEditorService);
if (!outerEditor || !outerEditor.hasModel()) {
return;
@ -486,11 +489,9 @@ export class GotoPreviousChangeAction extends EditorAction {
const index = model.findPreviousClosestChange(lineNumber, false);
const change = model.changes[index];
playAudioCueForChange(change, audioCueService);
const position = new Position(change.modifiedStartLineNumber, 1);
outerEditor.setPosition(position);
outerEditor.revealPositionInCenter(position);
await playAudioCueForChange(change, audioCueService);
// The audio cue can take up to a second to load. Give it a chance to play before we read the line content
await setTimeout(() => setPositionAndSelection(change, outerEditor, accessibilityService, codeEditorService), 500);
}
}
registerEditorAction(GotoPreviousChangeAction);
@ -507,9 +508,11 @@ export class GotoNextChangeAction extends EditorAction {
});
}
run(accessor: ServicesAccessor): void {
async run(accessor: ServicesAccessor): Promise<void> {
const audioCueService = accessor.get(IAudioCueService);
const outerEditor = getOuterEditorFromDiffEditor(accessor);
const accessibilityService = accessor.get(IAccessibilityService);
const codeEditorService = accessor.get(ICodeEditorService);
if (!outerEditor || !outerEditor.hasModel()) {
return;
@ -530,23 +533,31 @@ export class GotoNextChangeAction extends EditorAction {
const index = model.findNextClosestChange(lineNumber, false);
const change = model.changes[index];
playAudioCueForChange(change, audioCueService);
const position = new Position(change.modifiedStartLineNumber, 1);
outerEditor.setPosition(position);
outerEditor.revealPositionInCenter(position);
await playAudioCueForChange(change, audioCueService);
// The audio cue can take up to a second to load. Give it a chance to play before we read the line content
await setTimeout(() => setPositionAndSelection(change, outerEditor, accessibilityService, codeEditorService), 500);
}
}
function playAudioCueForChange(change: IChange, audioCueService: IAudioCueService) {
function setPositionAndSelection(change: IChange, editor: ICodeEditor, accessibilityService: IAccessibilityService, codeEditorService: ICodeEditorService) {
const position = new Position(change.modifiedStartLineNumber, 1);
editor.setPosition(position);
editor.revealPositionInCenter(position);
if (accessibilityService.isScreenReaderOptimized()) {
editor.setSelection({ startLineNumber: change.modifiedStartLineNumber, startColumn: 0, endLineNumber: change.modifiedStartLineNumber, endColumn: Number.MAX_VALUE });
codeEditorService.getActiveCodeEditor()?.writeScreenReaderContent('diff-navigation');
}
}
async function playAudioCueForChange(change: IChange, audioCueService: IAudioCueService) {
const changeType = getChangeType(change);
switch (changeType) {
case ChangeType.Add:
audioCueService.playAudioCue(AudioCue.diffLineInserted);
audioCueService.playAudioCue(AudioCue.diffLineInserted, true);
case ChangeType.Delete:
audioCueService.playAudioCue(AudioCue.diffLineDeleted);
audioCueService.playAudioCue(AudioCue.diffLineDeleted, true);
case ChangeType.Modify:
audioCueService.playAudioCue(AudioCue.diffLineModified);
audioCueService.playAudioCue(AudioCue.diffLineModified, true);
}
}

View file

@ -24,6 +24,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IFileService, IFileStatWithPartialMetadata } from 'vs/platform/files/common/files';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { minimapFindMatch, overviewRulerFindMatchForeground } from 'vs/platform/theme/common/colorRegistry';
@ -864,6 +865,7 @@ export class FolderMatchWorkspaceRoot extends FolderMatchWithResource {
@IInstantiationService instantiationService: IInstantiationService,
@ILabelService labelService: ILabelService,
@IUriIdentityService uriIdentityService: IUriIdentityService,
@ILogService private readonly _logService: ILogService,
) {
super(_resource, _id, _index, _query, _parent, _searchModel, null, replaceService, instantiationService, labelService, uriIdentityService);
}
@ -894,15 +896,29 @@ export class FolderMatchWorkspaceRoot extends FolderMatchWithResource {
const normalizedResource = this.uriIdentityService.extUri.normalizePath(this.resource);
let uri = this.normalizedUriParent(rawFileMatch.resource);
const debug: string[] = ['[search model building]'];
if (this._logService.getLevel() === LogLevel.Trace) {
debug.push(`Starting with normalized resource ${normalizedResource}`);
}
while (!this.uriEquals(normalizedResource, uri)) {
fileMatchParentParts.unshift(uri);
const prevUri = uri;
uri = this.normalizedUriParent(uri);
if (this._logService.getLevel() === LogLevel.Trace) {
debug.push(`current uri parent ${uri} comparing with ${prevUri}`);
}
if (this.uriEquals(prevUri, uri)) {
this._logService.trace(debug.join('\n\n'));
throw Error(`${rawFileMatch.resource} is not correctly configured as a child of its ${normalizedResource}`);
}
}
if (this._logService.getLevel() === LogLevel.Trace) {
this._logService.trace(debug.join('\n\n'));
}
const root = this.closestRoot ?? this;
let parent: FolderMatch = this;
for (let i = 0; i < fileMatchParentParts.length; i++) {

View file

@ -284,8 +284,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this._updateSetup(folderSetup);
return this._updateWorkspaceTasks(TaskRunSource.FolderOpen);
}));
this._register(this._configurationService.onDidChangeConfiguration(() => {
if (!this._taskSystem && !this._workspaceTasksPromise) {
this._register(this._configurationService.onDidChangeConfiguration((e) => {
if (!e.affectsConfiguration('tasks') || (!this._taskSystem && !this._workspaceTasksPromise)) {
return;
}

View file

@ -3,13 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EnvironmentVariableMutatorType, IEnvironmentVariableInfo, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { localize } from 'vs/nls';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { Codicon } from 'vs/base/common/codicons';
import { IHoverAction } from 'vs/workbench/services/hover/browser/hover';
import { EnvironmentVariableMutatorType, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff } from 'vs/platform/terminal/common/environmentVariable';
export class EnvironmentVariableInfoStale implements IEnvironmentVariableInfo {
readonly requiresAction = true;

View file

@ -31,6 +31,12 @@ if [ "$VSCODE_INJECTION" == "1" ]; then
. ~/.profile
fi
builtin unset VSCODE_SHELL_LOGIN
# Apply any explicit path prefix (see #99878)
if [ -n "$VSCODE_PATH_PREFIX" ]; then
export PATH=$VSCODE_PATH_PREFIX$PATH
builtin unset VSCODE_PATH_PREFIX
fi
fi
builtin unset VSCODE_INJECTION
fi

View file

@ -7,4 +7,10 @@ if [[ $options[norcs] = off && -o "login" && -f $USER_ZDOTDIR/.zprofile ]]; the
ZDOTDIR=$USER_ZDOTDIR
. $USER_ZDOTDIR/.zprofile
ZDOTDIR=$VSCODE_ZDOTDIR
# Apply any explicit path prefix (see #99878)
if (( ${+VSCODE_PATH_PREFIX} )); then
export PATH=$VSCODE_PATH_PREFIX$PATH
fi
builtin unset VSCODE_PATH_PREFIX
fi

View file

@ -22,6 +22,12 @@ or exit
set --global VSCODE_SHELL_INTEGRATION 1
# Apply any explicit path prefix (see #99878)
if status --is-login; and set -q VSCODE_PATH_PREFIX
fish_add_path -p $VSCODE_PATH_PREFIX
end
set -e VSCODE_PATH_PREFIX
# Helper function
function __vsc_esc -d "Emit escape sequences for VS Code shell integration"
builtin printf "\e]633;%s\a" (string join ";" $argv)

View file

@ -211,6 +211,20 @@ registerSendSequenceKeybinding('\x1b[1;2H', { // Shift+home
mac: { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.LeftArrow }
});
// Map ctrl+alt+r -> ctrl+r when in accessibility mode due to default run recent command keybinding
registerSendSequenceKeybinding('\x12', {
when: ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyR,
mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyR }
});
// Map ctrl+alt+g -> ctrl+g due to default go to recent directory keybinding
registerSendSequenceKeybinding('\x07', {
when: TerminalContextKeys.focus,
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyG,
mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyG }
});
// send ctrl+c to the iPad when the terminal is focused and ctrl+c is pressed to kill the process (work around for #114009)
if (isIOS) {
registerSendSequenceKeybinding(String.fromCharCode('C'.charCodeAt(0) - Constants.CtrlLetterOffset), { // ctrl+c

View file

@ -12,7 +12,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IKeyMods } from 'vs/platform/quickinput/common/quickInput';
import { IMarkProperties, ITerminalCapabilityStore, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities';
import { IExtensionTerminalProfile, IReconnectionProperties, IShellIntegration, IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
import { ITerminalQuickFixOptions } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { IEditableData } from 'vs/workbench/common/views';
@ -931,11 +930,6 @@ export interface ITerminalInstance {
*/
openRecentLink(type: 'localFile' | 'url'): Promise<void>;
/**
* Registers quick fix providers
*/
registerQuickFixProvider(...options: ITerminalQuickFixOptions[]): void;
/**
* Attempts to detect and kill the process listening on specified port.
* If successful, places commandToRun on the command line

View file

@ -325,7 +325,21 @@ export function registerTerminalActions() {
title: { value: localize('workbench.action.terminal.runRecentCommand', "Run Recent Command..."), original: 'Run Recent Command...' },
f1: true,
category,
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated)
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
keybinding: [
{
primary: KeyMod.CtrlCmd | KeyCode.KeyR,
mac: { primary: KeyMod.WinCtrl | KeyCode.KeyR },
when: ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
weight: KeybindingWeight.WorkbenchContrib
},
{
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyR,
mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyR },
when: ContextKeyExpr.and(TerminalContextKeys.focus, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
weight: KeybindingWeight.WorkbenchContrib
}
]
});
}
async run(accessor: ServicesAccessor): Promise<void> {
@ -375,7 +389,12 @@ export function registerTerminalActions() {
title: { value: localize('workbench.action.terminal.goToRecentDirectory', "Go to Recent Directory..."), original: 'Go to Recent Directory...' },
f1: true,
category,
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated)
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
keybinding: {
primary: KeyMod.CtrlCmd | KeyCode.KeyG,
when: TerminalContextKeys.focus,
weight: KeybindingWeight.WorkbenchContrib
}
});
}
async run(accessor: ServicesAccessor): Promise<void> {

View file

@ -59,7 +59,7 @@ import { IDetectedLinks, TerminalLinkManager } from 'vs/workbench/contrib/termin
import { TerminalLinkQuickpick } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkQuickpick';
import { IRequestAddInstanceToGroupEvent, ITerminalExternalLinkProvider, ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalLaunchHelpAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { freePort, gitCreatePr, gitPushSetUpstream, gitSimilar, gitTwoDashes } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions';
import { freePort, gitCreatePr, gitPushSetUpstream, gitSimilar, gitTwoDashes, pwshGeneralError as pwshGeneralError, pwshUnixCommandNotFoundError } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput';
import { TerminalFindWidget } from 'vs/workbench/contrib/terminal/browser/terminalFindWidget';
@ -75,8 +75,8 @@ import { ITerminalQuickFixAddon, TerminalQuickFixAddon } from 'vs/workbench/cont
import { LineDataEventAddon } from 'vs/workbench/contrib/terminal/browser/xterm/lineDataEventAddon';
import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/xterm/navigationModeAddon';
import { XtermTerminal } from 'vs/workbench/contrib/terminal/browser/xterm/xtermTerminal';
import { IEnvironmentVariableCollection, IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollections } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariableShared';
import { getCommandHistory, getDirectoryHistory } from 'vs/workbench/contrib/terminal/common/history';
import { DEFAULT_COMMANDS_TO_SKIP_SHELL, INavigationMode, ITerminalProcessManager, ITerminalProfileResolverService, ProcessState, TerminalCommandId, TERMINAL_CREATION_COMMANDS, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
@ -91,6 +91,7 @@ import { IAudioCueService, AudioCue } from 'vs/platform/audioCues/browser/audioC
import { ITerminalQuickFixOptions } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files';
import { preparePathForShell } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { IEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
const enum Constants {
/**
@ -621,9 +622,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
return undefined;
}
registerQuickFixProvider(...options: ITerminalQuickFixOptions[]): void {
private _registerQuickFixProvider(quickFixAddon: ITerminalQuickFixAddon, ...options: ITerminalQuickFixOptions[]): void {
for (const actionOption of options) {
this.quickFix?.registerCommandFinishedListener(actionOption);
quickFixAddon.registerCommandFinishedListener(actionOption);
}
}
@ -738,7 +739,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this.xterm = xterm;
this._quickFixAddon = this._scopedInstantiationService.createInstance(TerminalQuickFixAddon, this._aliases, this.capabilities);
this.xterm?.raw.loadAddon(this._quickFixAddon);
this.registerQuickFixProvider(gitTwoDashes(), freePort(this), gitSimilar(), gitPushSetUpstream(), gitCreatePr());
this._registerQuickFixProvider(this._quickFixAddon, gitTwoDashes(), freePort(this), gitSimilar(), gitPushSetUpstream(), gitCreatePr(), pwshUnixCommandNotFoundError(), pwshGeneralError());
this._register(this._quickFixAddon.onDidRequestRerunCommand(async (e) => await this.runCommand(e.command, e.addNewLine || false)));
this.updateAccessibilitySupport();
this.xterm.onDidRequestRunCommand(e => {

View file

@ -25,9 +25,9 @@ import { TerminalRecorder } from 'vs/platform/terminal/common/terminalRecorder';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { EnvironmentVariableInfoChangesActive, EnvironmentVariableInfoStale } from 'vs/workbench/contrib/terminal/browser/environmentVariableInfo';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IEnvironmentVariableCollection, IEnvironmentVariableInfo, IEnvironmentVariableService, IMergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
import { serializeEnvironmentVariableCollections } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { IEnvironmentVariableInfo, IEnvironmentVariableService } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { MergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableCollection';
import { serializeEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariableShared';
import { IBeforeProcessDataEvent, ITerminalBackend, ITerminalConfigHelper, ITerminalProcessManager, ITerminalProfileResolverService, ProcessState } from 'vs/workbench/contrib/terminal/common/terminal';
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
@ -38,6 +38,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
import { TaskSettingId } from 'vs/workbench/contrib/tasks/common/tasks';
import Severity from 'vs/base/common/severity';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IEnvironmentVariableCollection, IMergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
const enum ProcessConstants {
/**

View file

@ -5,7 +5,7 @@
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { IInternalOptions, ITerminalCommandMatchResult, TerminalQuickFixActionInternal, TerminalQuickFixType } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { IInternalOptions, ITerminalCommandMatchResult, ITerminalQuickFixCommandAction, TerminalQuickFixActionInternal, TerminalQuickFixType } from 'vs/platform/terminal/common/xterm/terminalQuickFix';
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
export const GitCommandLineRegex = /git/;
@ -17,6 +17,8 @@ export const GitPushOutputRegex = /git push --set-upstream origin (?<branchName>
// The previous line starts with "Create a pull request for \'([^\s]+)\' on GitHub by visiting:\s*"
// it's safe to assume it's a github pull request if the URL includes `/pull/`
export const GitCreatePrOutputRegex = /remote:\s*(?<link>https:\/\/github\.com\/.+\/.+\/pull\/new\/.+)/;
export const PwshGeneralErrorOutputRegex = /Suggestion \[General\]:/;
export const PwshUnixCommandNotFoundErrorOutputRegex = /Suggestion \[cmd-not-found\]:/;
export const enum QuickFixSource {
Builtin = 'builtin'
@ -193,3 +195,120 @@ export function gitCreatePr(): IInternalOptions {
}
};
}
export function pwshGeneralError(): IInternalOptions {
return {
id: 'Pwsh General Error',
type: 'internal',
commandLineMatcher: /.+/,
outputMatcher: {
lineMatcher: PwshGeneralErrorOutputRegex,
anchor: 'bottom',
offset: 0,
length: 10
},
commandExitResult: 'error',
getQuickFixes: (matchResult: ITerminalCommandMatchResult) => {
const lines = matchResult.outputMatch?.regexMatch.input?.split('\n');
if (!lines) {
return;
}
// Find the start
let i = 0;
let inFeedbackProvider = false;
for (; i < lines.length; i++) {
if (lines[i].match(PwshGeneralErrorOutputRegex)) {
inFeedbackProvider = true;
break;
}
}
if (!inFeedbackProvider) {
return;
}
const suggestions = lines[i + 1].match(/The most similar commands are: (?<values>.+)./)?.groups?.values?.split(', ');
if (!suggestions) {
return;
}
const result: ITerminalQuickFixCommandAction[] = [];
for (const suggestion of suggestions) {
result.push({
id: 'Pwsh General Error',
type: TerminalQuickFixType.Command,
terminalCommand: suggestion,
source: QuickFixSource.Builtin
});
}
return result;
}
};
}
export function pwshUnixCommandNotFoundError(): IInternalOptions {
return {
id: 'Unix Command Not Found',
type: 'internal',
commandLineMatcher: /.+/,
outputMatcher: {
lineMatcher: PwshUnixCommandNotFoundErrorOutputRegex,
anchor: 'bottom',
offset: 0,
length: 10
},
commandExitResult: 'error',
getQuickFixes: (matchResult: ITerminalCommandMatchResult) => {
const lines = matchResult.outputMatch?.regexMatch.input?.split('\n');
if (!lines) {
return;
}
// Find the start
let i = 0;
let inFeedbackProvider = false;
for (; i < lines.length; i++) {
if (lines[i].match(PwshUnixCommandNotFoundErrorOutputRegex)) {
inFeedbackProvider = true;
break;
}
}
if (!inFeedbackProvider) {
return;
}
// Always remove the first element as it's the "Suggestion [cmd-not-found]"" line
const result: ITerminalQuickFixCommandAction[] = [];
let inSuggestions = false;
for (; i < lines.length; i++) {
const line = lines[i].trim();
if (line.length === 0) {
break;
}
const installCommand = line.match(/You also have .+ installed, you can run '(?<command>.+)' instead./)?.groups?.command;
if (installCommand) {
result.push({
id: 'Pwsh Unix Command Not Found Error',
type: TerminalQuickFixType.Command,
terminalCommand: installCommand,
source: QuickFixSource.Builtin
});
inSuggestions = false;
continue;
}
if (line.match(/Command '.+' not found, but can be installed with:/)) {
inSuggestions = true;
continue;
}
if (inSuggestions) {
result.push({
id: 'Pwsh Unix Command Not Found Error',
type: TerminalQuickFixType.Command,
terminalCommand: line.trim(),
source: QuickFixSource.Builtin
});
}
}
return result;
}
};
}

View file

@ -290,6 +290,10 @@ export async function getQuickFixesForCommand(
onDidRequestRerunCommand?: Emitter<{ command: string; addNewLine?: boolean }>,
getResolvedFixes?: (selector: ITerminalQuickFixOptions, lines?: string[]) => Promise<ITerminalQuickFix | ITerminalQuickFix[] | undefined>
): Promise<ITerminalAction[] | undefined> {
// Prevent duplicates by tracking added entries
const commandQuickFixSet: Set<string> = new Set();
const openQuickFixSet: Set<string> = new Set();
const fixes: ITerminalAction[] = [];
const newCommand = terminalCommand.command;
for (const options of quickFixOptions.values()) {
@ -329,6 +333,10 @@ export async function getQuickFixesForCommand(
switch (quickFix.type) {
case TerminalQuickFixType.Command: {
const fix = quickFix as ITerminalQuickFixCommandAction;
if (commandQuickFixSet.has(fix.terminalCommand)) {
continue;
}
commandQuickFixSet.add(fix.terminalCommand);
const label = localize('quickFix.command', 'Run: {0}', fix.terminalCommand);
action = {
type: TerminalQuickFixType.Command,
@ -353,6 +361,10 @@ export async function getQuickFixesForCommand(
if (!fix.uri) {
return;
}
if (openQuickFixSet.has(fix.uri.toString())) {
continue;
}
openQuickFixSet.add(fix.uri.toString());
const isUrl = (fix.uri.scheme === Schemas.http || fix.uri.scheme === Schemas.https);
const uriLabel = isUrl ? encodeURI(fix.uri.toString(true)) : labelService.getUriLabel(fix.uri);
const label = localize('quickFix.opener', 'Open: {0}', uriLabel);

View file

@ -5,63 +5,11 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { VariableResolver } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { IEnvironmentVariableCollection, IMergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
export const IEnvironmentVariableService = createDecorator<IEnvironmentVariableService>('environmentVariableService');
export enum EnvironmentVariableMutatorType {
Replace = 1,
Append = 2,
Prepend = 3
}
export interface IEnvironmentVariableMutator {
readonly value: string;
readonly type: EnvironmentVariableMutatorType;
}
export interface IExtensionOwnedEnvironmentVariableMutator extends IEnvironmentVariableMutator {
readonly extensionIdentifier: string;
}
export interface IEnvironmentVariableCollection {
readonly map: ReadonlyMap<string, IEnvironmentVariableMutator>;
}
export interface IEnvironmentVariableCollectionWithPersistence extends IEnvironmentVariableCollection {
readonly persistent: boolean;
}
export interface IMergedEnvironmentVariableCollectionDiff {
added: ReadonlyMap<string, IExtensionOwnedEnvironmentVariableMutator[]>;
changed: ReadonlyMap<string, IExtensionOwnedEnvironmentVariableMutator[]>;
removed: ReadonlyMap<string, IExtensionOwnedEnvironmentVariableMutator[]>;
}
/**
* Represents an environment variable collection that results from merging several collections
* together.
*/
export interface IMergedEnvironmentVariableCollection {
readonly collections: ReadonlyMap<string, IEnvironmentVariableCollection>;
readonly map: ReadonlyMap<string, IExtensionOwnedEnvironmentVariableMutator[]>;
/**
* Applies this collection to a process environment.
* @param variableResolver An optional function to use to resolve variables within the
* environment values.
*/
applyToProcessEnvironment(env: IProcessEnvironment, variableResolver?: VariableResolver): Promise<void>;
/**
* Generates a diff of this connection against another. Returns undefined if the collections are
* the same.
*/
diff(other: IMergedEnvironmentVariableCollection): IMergedEnvironmentVariableCollectionDiff | undefined;
}
/**
* Tracks and persists environment variable collections as defined by extensions.
*/
@ -97,11 +45,9 @@ export interface IEnvironmentVariableService {
delete(extensionIdentifier: string): void;
}
/** [variable, mutator] */
export type ISerializableEnvironmentVariableCollection = [string, IEnvironmentVariableMutator][];
/** [extension, collection] */
export type ISerializableEnvironmentVariableCollections = [string, ISerializableEnvironmentVariableCollection][];
export interface IEnvironmentVariableCollectionWithPersistence extends IEnvironmentVariableCollection {
readonly persistent: boolean;
}
export interface IEnvironmentVariableInfo {
readonly requiresAction: boolean;

View file

@ -7,10 +7,11 @@ import { Event, Emitter } from 'vs/base/common/event';
import { debounce, throttle } from 'vs/base/common/decorators';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { IEnvironmentVariableCollectionWithPersistence, IEnvironmentVariableService, IMergedEnvironmentVariableCollection, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { MergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableCollection';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableShared';
import { IEnvironmentVariableCollectionWithPersistence, IEnvironmentVariableService } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { TerminalStorageKeys } from 'vs/workbench/contrib/terminal/common/terminalStorageKeys';
import { IMergedEnvironmentVariableCollection, ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
interface ISerializableExtensionEnvironmentVariableCollection {
extensionIdentifier: string;

View file

@ -11,18 +11,19 @@ import { IWorkbenchConfigurationService } from 'vs/workbench/services/configurat
import { ILogService } from 'vs/platform/log/common/log';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { serializeEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableShared';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { SideBySideEditor, EditorResourceAccessor } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { Schemas } from 'vs/base/common/network';
import { ILabelService } from 'vs/platform/label/common/label';
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IEnvironmentVariableService } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IProcessDataEvent, IRequestResolveVariablesEvent, IShellLaunchConfigDto, ITerminalLaunchError, ITerminalProfile, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalIcon, IProcessProperty, ProcessPropertyType, IProcessPropertyMap, TitleEventSource, ISerializedTerminalState, IPtyHostController, ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal';
import { IGetTerminalLayoutInfoArgs, IProcessDetails, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess';
import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform';
import { ICompleteTerminalConfiguration } from 'vs/workbench/contrib/terminal/common/terminal';
import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/capabilities/capabilities';
import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';
export const REMOTE_TERMINAL_CHANNEL_NAME = 'remoteterminal';

View file

@ -16,7 +16,7 @@ import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/commo
import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { gitSimilar, freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, GitSimilarOutputRegex, gitTwoDashes, GitTwoDashesRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions';
import { gitSimilar, freePort, FreePortOutputRegex, gitCreatePr, GitCreatePrOutputRegex, GitPushOutputRegex, gitPushSetUpstream, GitSimilarOutputRegex, gitTwoDashes, GitTwoDashesRegex, pwshUnixCommandNotFoundError, PwshUnixCommandNotFoundErrorOutputRegex, pwshGeneralError, PwshGeneralErrorOutputRegex } from 'vs/workbench/contrib/terminal/browser/terminalQuickFixBuiltinActions';
import { TerminalQuickFixAddon, getQuickFixesForCommand } from 'vs/workbench/contrib/terminal/browser/xterm/quickFixAddon';
import { URI } from 'vs/base/common/uri';
import { Terminal } from 'xterm';
@ -333,6 +333,102 @@ suite('QuickFixAddon', () => {
});
});
});
suite('pwsh feedback providers', () => {
suite('General', () => {
const expectedMap = new Map();
const command = `not important`;
const output = [
`...`,
``,
`Suggestion [General]:`,
` The most similar commands are: python3, python3m, pamon, python3.6, rtmon, echo, pushd, etsn, pwsh, pwconv.`,
``,
`Suggestion [cmd-not-found]:`,
` Command 'python' not found, but can be installed with:`,
` sudo apt install python3`,
` sudo apt install python`,
` sudo apt install python-minimal`,
` You also have python3 installed, you can run 'python3' instead.'`,
``,
].join('\n');
const exitCode = 128;
const actions = [
'python3',
'python3m',
'pamon',
'python3.6',
'rtmon',
'echo',
'pushd',
'etsn',
'pwsh',
'pwconv',
].map(command => {
return {
id: 'Pwsh General Error',
enabled: true,
label: `Run: ${command}`,
tooltip: `Run: ${command}`,
command: command
};
});
setup(() => {
const pushCommand = pwshGeneralError();
quickFixAddon.registerCommandFinishedListener(pushCommand);
expectedMap.set(pushCommand.commandLineMatcher.toString(), [pushCommand]);
});
test('returns undefined when output does not match', async () => {
strictEqual((await getQuickFixesForCommand([], terminal, createCommand(command, `invalid output`, PwshGeneralErrorOutputRegex, exitCode), expectedMap, openerService, labelService)), undefined);
});
test('returns actions when output matches', async () => {
assertMatchOptions((await getQuickFixesForCommand([], terminal, createCommand(command, output, PwshGeneralErrorOutputRegex, exitCode), expectedMap, openerService, labelService)), actions);
});
});
suite('Unix cmd-not-found', () => {
const expectedMap = new Map();
const command = `not important`;
const output = [
`...`,
``,
`Suggestion [General]`,
` The most similar commands are: python3, python3m, pamon, python3.6, rtmon, echo, pushd, etsn, pwsh, pwconv.`,
``,
`Suggestion [cmd-not-found]:`,
` Command 'python' not found, but can be installed with:`,
` sudo apt install python3`,
` sudo apt install python`,
` sudo apt install python-minimal`,
` You also have python3 installed, you can run 'python3' instead.'`,
``,
].join('\n');
const exitCode = 128;
const actions = [
'sudo apt install python3',
'sudo apt install python',
'sudo apt install python-minimal',
'python3',
].map(command => {
return {
id: 'Pwsh Unix Command Not Found Error',
enabled: true,
label: `Run: ${command}`,
tooltip: `Run: ${command}`,
command: command
};
});
setup(() => {
const pushCommand = pwshUnixCommandNotFoundError();
quickFixAddon.registerCommandFinishedListener(pushCommand);
expectedMap.set(pushCommand.commandLineMatcher.toString(), [pushCommand]);
});
test('returns undefined when output does not match', async () => {
strictEqual((await getQuickFixesForCommand([], terminal, createCommand(command, `invalid output`, PwshUnixCommandNotFoundErrorOutputRegex, exitCode), expectedMap, openerService, labelService)), undefined);
});
test('returns actions when output matches', async () => {
assertMatchOptions((await getQuickFixesForCommand([], terminal, createCommand(command, output, PwshUnixCommandNotFoundErrorOutputRegex, exitCode), expectedMap, openerService, labelService)), actions);
});
});
});
});
function createCommand(command: string, output: string, outputMatcher?: RegExp | string, exitCode?: number): ITerminalCommand {
@ -357,19 +453,18 @@ function createCommand(command: string, output: string, outputMatcher?: RegExp |
type TestAction = Pick<IAction, 'id' | 'label' | 'tooltip' | 'enabled'> & { command?: string; uri?: URI };
function assertMatchOptions(actual: TestAction[] | undefined, expected: TestAction[]): void {
strictEqual(actual?.length, expected.length);
let index = 0;
for (const i of actual) {
const j = expected[index];
strictEqual(i.id, j.id, `ID`);
strictEqual(i.enabled, j.enabled, `enabled`);
strictEqual(i.label, j.label, `label`);
strictEqual(i.tooltip, j.tooltip, `tooltip`);
if (j.command) {
strictEqual(i.command, j.command);
for (let i = 0; i < expected.length; i++) {
const expectedItem = expected[i];
const actualItem: any = actual[i];
strictEqual(actualItem.id, expectedItem.id, `ID`);
strictEqual(actualItem.enabled, expectedItem.enabled, `enabled`);
strictEqual(actualItem.label, expectedItem.label, `label`);
strictEqual(actualItem.tooltip, expectedItem.tooltip, `tooltip`);
if (expectedItem.command) {
strictEqual(actualItem.command, expectedItem.command);
}
if (j.uri) {
strictEqual(i.uri!.toString(), j.uri.toString());
if (expectedItem.uri) {
strictEqual(actualItem.uri!.toString(), expectedItem.uri.toString());
}
index++;
}
}

View file

@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { deepStrictEqual, strictEqual } from 'assert';
import { EnvironmentVariableMutatorType } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { EnvironmentVariableMutatorType } from 'vs/platform/terminal/common/environmentVariable';
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { MergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableCollection';
import { deserializeEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableShared';
suite('EnvironmentVariable - MergedEnvironmentVariableCollection', () => {
suite('ctor', () => {

View file

@ -6,7 +6,7 @@
import { deepStrictEqual } from 'assert';
import { TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
import { EnvironmentVariableService } from 'vs/workbench/contrib/terminal/common/environmentVariableService';
import { EnvironmentVariableMutatorType, IEnvironmentVariableMutator } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { EnvironmentVariableMutatorType, IEnvironmentVariableMutator } from 'vs/platform/terminal/common/environmentVariable';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';

View file

@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { deepStrictEqual } from 'assert';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { EnvironmentVariableMutatorType, IEnvironmentVariableMutator } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariableShared';
import { EnvironmentVariableMutatorType, IEnvironmentVariableMutator } from 'vs/platform/terminal/common/environmentVariable';
suite('EnvironmentVariable - deserializeEnvironmentVariableCollection', () => {
test('should construct correctly with 3 arguments', () => {

View file

@ -19,11 +19,9 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { RenameProfileAction } from 'vs/workbench/contrib/userDataProfile/browser/userDataProfileActions';
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { CURRENT_PROFILE_CONTEXT, HAS_PROFILES_CONTEXT, isUserDataProfileTemplate, IS_CURRENT_PROFILE_TRANSIENT_CONTEXT, IS_PROFILE_IMPORT_IN_PROGRESS_CONTEXT, IUserDataProfileImportExportService, IUserDataProfileManagementService, IUserDataProfileService, IUserDataProfileTemplate, ManageProfilesSubMenu, PROFILES_CATEGORY, PROFILES_ENABLEMENT_CONTEXT, PROFILES_TTILE, PROFILE_FILTER, IS_PROFILE_EXPORT_IN_PROGRESS_CONTEXT } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { CURRENT_PROFILE_CONTEXT, HAS_PROFILES_CONTEXT, isUserDataProfileTemplate, IS_CURRENT_PROFILE_TRANSIENT_CONTEXT, IS_PROFILE_IMPORT_IN_PROGRESS_CONTEXT, IUserDataProfileImportExportService, IUserDataProfileManagementService, IUserDataProfileService, IUserDataProfileTemplate, ManageProfilesSubMenu, PROFILES_CATEGORY, PROFILES_ENABLEMENT_CONTEXT, PROFILES_TTILE, PROFILE_FILTER, IS_PROFILE_EXPORT_IN_PROGRESS_CONTEXT, defaultUserDataProfileIcon } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { charCount } from 'vs/base/common/strings';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { Codicon } from 'vs/base/common/codicons';
import { IFileService } from 'vs/platform/files/common/files';
@ -34,9 +32,22 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceTagsService } from 'vs/workbench/contrib/tags/common/workspaceTags';
import { getErrorMessage } from 'vs/base/common/errors';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
const SelectProfileSubMenu = new MenuId('SelectProfile');
const CREATE_EMPTY_PROFILE_ACTION_ID = 'workbench.profiles.actions.createEmptyProfile';
const CREATE_EMPTY_PROFILE_ACTION_TITLE = {
value: localize('create empty profile', "Create an Empty Profile..."),
original: 'Create an Empty Profile...'
};
const CREATE_FROM_CURRENT_PROFILE_ACTION_ID = 'workbench.profiles.actions.createFromCurrentProfile';
const CREATE_FROM_CURRENT_PROFILE_ACTION_TITLE = {
value: localize('save profile as', "Create from Current Profile..."),
original: 'Create from Current Profile...'
};
export class UserDataProfilesWorkbenchContribution extends Disposable implements IWorkbenchContribution {
private readonly currentProfileContext: IContextKey<string>;
@ -52,6 +63,8 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IWorkspaceTagsService private readonly workspaceTagsService: IWorkspaceTagsService,
@IContextKeyService contextKeyService: IContextKeyService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@INotificationService private readonly notificationService: INotificationService,
@ILifecycleService private readonly lifecycleService: ILifecycleService,
) {
super();
@ -108,6 +121,10 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
this.registerCurrentProfilesActions();
this._register(Event.any(this.userDataProfileService.onDidChangeCurrentProfile, this.userDataProfileService.onDidUpdateCurrentProfile)(() => this.registerCurrentProfilesActions()));
this.registerCreateEmptyProfileAction();
this.registerCreateFromCurrentProfileAction();
this.registerCreateProfileAction();
}
private registerManageProfilesSubMenu(): void {
@ -166,24 +183,22 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
private readonly currentprofileActionsDisposable = this._register(new MutableDisposable<DisposableStore>());
private registerCurrentProfilesActions(): void {
this.currentprofileActionsDisposable.value = new DisposableStore();
this.currentprofileActionsDisposable.value.add(this.registerUpdateCurrentProfileShortNameAction());
this.currentprofileActionsDisposable.value.add(this.registerChangeIconForCurrentProfileAction());
this.currentprofileActionsDisposable.value.add(this.registerRenameCurrentProfileAction());
this.currentprofileActionsDisposable.value.add(this.registerShowCurrentProfileContentsAction());
this.currentprofileActionsDisposable.value.add(this.registerExportCurrentProfileAction());
this.currentprofileActionsDisposable.value.add(this.registerImportProfileAction());
}
private registerUpdateCurrentProfileShortNameAction(): IDisposable {
private registerChangeIconForCurrentProfileAction(): IDisposable {
const that = this;
return registerAction2(class UpdateCurrentProfileShortName extends Action2 {
return registerAction2(class ChangeIconForCurrentProfileAction extends Action2 {
constructor() {
const shortName = that.userDataProfileService.getShortName(that.userDataProfileService.currentProfile);
const themeIcon = ThemeIcon.fromString(shortName);
super({
id: `workbench.profiles.actions.updateCurrentProfileShortName`,
id: `workbench.profiles.actions.changeIconForCurrentProfile`,
title: {
value: localize('change short name profile', "Change Profile Short Name ({0})...", themeIcon?.id ?? shortName),
original: `Change Profile Short Name (${themeIcon?.id ?? shortName})...`
value: localize('change icon', "Change Icon..."),
original: `Change Icon...`
},
menu: [
{
@ -196,35 +211,13 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
});
}
async run(accessor: ServicesAccessor) {
const quickInputService = accessor.get(IQuickInputService);
const notificationService = accessor.get(INotificationService);
const profile = that.userDataProfileService.currentProfile;
const shortName = await quickInputService.input({
value: that.userDataProfileService.getShortName(profile),
title: localize('change short name', "Change Short Name..."),
validateInput: async (value: string) => {
if (profile.shortName === value) {
return undefined;
}
const themeIcon = ThemeIcon.fromString(value);
if (themeIcon) {
if (Codicon.getAll().some(c => c.id === themeIcon.id)) {
return undefined;
}
return localize('invalid codicon', "Invalid codicon. Please use a valid codicon id.");
}
if (charCount(value) > 2) {
return localize('invalid short name', "Short name should be at most 2 characters long.");
}
return undefined;
}
});
const shortName = await that.pickIcon(profile);
if (shortName && shortName !== profile.shortName) {
try {
await that.userDataProfileManagementService.updateProfile(profile, { shortName });
} catch (error) {
notificationService.error(error);
that.notificationService.error(error);
}
}
}
@ -238,8 +231,8 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
super({
id: `workbench.profiles.actions.renameCurrentProfile`,
title: {
value: localize('rename profile', "Rename Profile ({0})...", that.userDataProfileService.currentProfile.name),
original: `Rename Profile (${that.userDataProfileService.currentProfile.name})...`
value: localize('rename profile', "Rename..."),
original: `Rename...`
},
menu: [
{
@ -258,15 +251,14 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
}
private registerShowCurrentProfileContentsAction(): IDisposable {
const that = this;
const id = 'workbench.profiles.actions.showProfileContents';
return registerAction2(class ShowProfileContentsAction extends Action2 {
constructor() {
super({
id,
title: {
value: localize('show profile contents', "Show Profile Contents ({0})...", that.userDataProfileService.currentProfile.name),
original: `Show Profile Contents (${that.userDataProfileService.currentProfile.name})...`
value: localize('show profile contents', "Show Contents..."),
original: `ShowContents...`
},
category: PROFILES_CATEGORY,
menu: [
@ -464,6 +456,124 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
return disposables;
}
private registerCreateFromCurrentProfileAction(): void {
const that = this;
this._register(registerAction2(class CreateFromCurrentProfileAction extends Action2 {
constructor() {
super({
id: CREATE_FROM_CURRENT_PROFILE_ACTION_ID,
title: CREATE_FROM_CURRENT_PROFILE_ACTION_TITLE,
category: PROFILES_CATEGORY,
f1: true,
precondition: PROFILES_ENABLEMENT_CONTEXT
});
}
run(accessor: ServicesAccessor) {
return that.createProfile(true);
}
}));
}
private registerCreateEmptyProfileAction(): void {
const that = this;
this._register(registerAction2(class CreateEmptyProfileAction extends Action2 {
constructor() {
super({
id: CREATE_EMPTY_PROFILE_ACTION_ID,
title: CREATE_EMPTY_PROFILE_ACTION_TITLE,
category: PROFILES_CATEGORY,
f1: true,
precondition: PROFILES_ENABLEMENT_CONTEXT
});
}
run(accessor: ServicesAccessor) {
return that.createProfile(false);
}
}));
}
private async createProfile(fromExisting: boolean): Promise<void> {
const name = await this.quickInputService.input({
placeHolder: localize('name', "Profile name"),
title: fromExisting ? localize('create from current profle', "Create from Current Profile...") : localize('create empty profile', "Create an Empty Profile..."),
validateInput: async (value: string) => {
if (this.userDataProfilesService.profiles.some(p => p.name === value)) {
return localize('profileExists', "Profile with name {0} already exists.", value);
}
return undefined;
}
});
if (!name) {
return;
}
const icon = await this.pickIcon();
if (!icon) {
return;
}
try {
await this.userDataProfileManagementService.createAndEnterProfile(name, { shortName: icon }, fromExisting);
} catch (error) {
this.notificationService.error(error);
}
}
private async pickIcon(profile?: IUserDataProfile): Promise<string | undefined> {
const codiconQuickPicks: Array<IQuickPickItem | IQuickPickSeparator> = [];
codiconQuickPicks.push({ label: `$(${defaultUserDataProfileIcon.id})`, description: localize('default', "Default") });
codiconQuickPicks.push({ label: '', type: 'separator' });
const currentIcon = profile?.shortName ? ThemeIcon.fromString(profile.shortName) : undefined;
for (const codicon of Codicon.getAll()) {
codiconQuickPicks.push({ label: `$(${codicon.id})`, description: `${codicon.id}${currentIcon?.id === codicon.id ? ` (${localize('current', "Current")})` : ''}` });
}
const result = await this.quickInputService.pick(codiconQuickPicks, {
title: profile ? localize('change icon title', "Change icon for {0} Profile", profile.name) : localize('pick icon', "Pick icon..."),
matchOnDescription: true,
});
return result?.label;
}
private registerCreateProfileAction(): void {
this._register(registerAction2(class CreateProfileAction extends Action2 {
constructor() {
super({
id: 'workbench.profiles.actions.createProfile',
title: {
value: localize('create profile', "Create Profile..."),
original: 'Create Profile...'
},
category: PROFILES_CATEGORY,
precondition: PROFILES_ENABLEMENT_CONTEXT,
menu: [
{
id: ManageProfilesSubMenu,
group: '3_manage_profiles',
when: PROFILES_ENABLEMENT_CONTEXT,
order: 1
}
]
});
}
async run(accessor: ServicesAccessor) {
const quickInputService = accessor.get(IQuickInputService);
const commandService = accessor.get(ICommandService);
const pick = await quickInputService.pick(
[{
id: CREATE_EMPTY_PROFILE_ACTION_ID,
label: CREATE_EMPTY_PROFILE_ACTION_TITLE.value,
}, {
id: CREATE_FROM_CURRENT_PROFILE_ACTION_ID,
label: CREATE_FROM_CURRENT_PROFILE_ACTION_TITLE.value,
}], { hideInput: true, canPickMany: false, title: localize('create profile title', "{0}: Create...", PROFILES_CATEGORY.value) });
if (pick?.id) {
return commandService.executeCommand(pick.id);
}
}
}));
}
private async reportWorkspaceProfileInfo(): Promise<void> {
await this.lifecycleService.when(LifecyclePhase.Eventually);
const workspaceId = await this.workspaceTagsService.getTelemetryWorkspaceId(this.workspaceContextService.getWorkspace(), this.workspaceContextService.getWorkbenchState());

View file

@ -17,128 +17,6 @@ import { Codicon } from 'vs/base/common/codicons';
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IAction, Separator } from 'vs/base/common/actions';
class CreateFromCurrentProfileAction extends Action2 {
static readonly ID = 'workbench.profiles.actions.createFromCurrentProfile';
static readonly TITLE = {
value: localize('save profile as', "Create from Current Profile..."),
original: 'Create from Current Profile...'
};
constructor() {
super({
id: CreateFromCurrentProfileAction.ID,
title: CreateFromCurrentProfileAction.TITLE,
category: PROFILES_CATEGORY,
f1: true,
precondition: PROFILES_ENABLEMENT_CONTEXT
});
}
async run(accessor: ServicesAccessor) {
const quickInputService = accessor.get(IQuickInputService);
const notificationService = accessor.get(INotificationService);
const userDataProfileManagementService = accessor.get(IUserDataProfileManagementService);
const userDataProfilesService = accessor.get(IUserDataProfilesService);
const name = await quickInputService.input({
placeHolder: localize('name', "Profile name"),
title: localize('save profile as', "Create from Current Profile..."),
validateInput: async (value: string) => {
if (userDataProfilesService.profiles.some(p => p.name === value)) {
return localize('profileExists', "Profile with name {0} already exists.", value);
}
return undefined;
}
});
if (name) {
try {
await userDataProfileManagementService.createAndEnterProfile(name, undefined, true);
} catch (error) {
notificationService.error(error);
}
}
}
}
registerAction2(CreateFromCurrentProfileAction);
class CreateEmptyProfileAction extends Action2 {
static readonly ID = 'workbench.profiles.actions.createEmptyProfile';
static readonly TITLE = {
value: localize('create empty profile', "Create an Empty Profile..."),
original: 'Create an Empty Profile...'
};
constructor() {
super({
id: CreateEmptyProfileAction.ID,
title: CreateEmptyProfileAction.TITLE,
category: PROFILES_CATEGORY,
f1: true,
precondition: PROFILES_ENABLEMENT_CONTEXT
});
}
async run(accessor: ServicesAccessor) {
const quickInputService = accessor.get(IQuickInputService);
const userDataProfileManagementService = accessor.get(IUserDataProfileManagementService);
const notificationService = accessor.get(INotificationService);
const userDataProfilesService = accessor.get(IUserDataProfilesService);
const name = await quickInputService.input({
placeHolder: localize('name', "Profile name"),
title: localize('create and enter empty profile', "Create an Empty Profile..."),
validateInput: async (value: string) => {
if (userDataProfilesService.profiles.some(p => p.name === value)) {
return localize('profileExists', "Profile with name {0} already exists.", value);
}
return undefined;
}
});
if (name) {
try {
await userDataProfileManagementService.createAndEnterProfile(name, undefined, undefined);
} catch (error) {
notificationService.error(error);
}
}
}
}
registerAction2(CreateEmptyProfileAction);
registerAction2(class CreateProfileAction extends Action2 {
constructor() {
super({
id: 'workbench.profiles.actions.createProfile',
title: {
value: localize('create profile', "Create Profile..."),
original: 'Create Profile...'
},
category: PROFILES_CATEGORY,
precondition: PROFILES_ENABLEMENT_CONTEXT,
menu: [
{
id: ManageProfilesSubMenu,
group: '3_manage_profiles',
when: PROFILES_ENABLEMENT_CONTEXT,
order: 1
}
]
});
}
async run(accessor: ServicesAccessor) {
const quickInputService = accessor.get(IQuickInputService);
const commandService = accessor.get(ICommandService);
const pick = await quickInputService.pick(
[{
id: CreateEmptyProfileAction.ID,
label: CreateEmptyProfileAction.TITLE.value,
}, {
id: CreateFromCurrentProfileAction.ID,
label: CreateFromCurrentProfileAction.TITLE.value,
}], { hideInput: true, canPickMany: false, title: localize('create profile title', "{0}: Create...", PROFILES_CATEGORY.value) });
if (pick?.id) {
return commandService.executeCommand(pick.id);
}
}
});
class CreateTransientProfileAction extends Action2 {
static readonly ID = 'workbench.profiles.actions.createTemporaryProfile';
static readonly TITLE = {

View file

@ -43,7 +43,7 @@ const editorAssociationsConfigurationNode: IConfigurationNode = {
properties: {
'workbench.editorAssociations': {
type: 'object',
markdownDescription: localize('editor.editorAssociations', "Configure glob patterns to editors (for example `\"*.hex\": \"hexEditor.hexEdit\"`). These have precedence over the default behavior."),
markdownDescription: localize('editor.editorAssociations', "Configure glob patterns to editors (for example `\"*.hex\": \"hexEditor.hexedit\"`). These have precedence over the default behavior."),
additionalProperties: {
type: 'string'
}

View file

@ -8,7 +8,6 @@
export const allApiProposals = Object.freeze({
authSession: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authSession.d.ts',
codiconDecoration: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.codiconDecoration.d.ts',
commentsResolvedState: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentsResolvedState.d.ts',
contribCommentEditorActionsMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentEditorActionsMenu.d.ts',
contribCommentPeekContext: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentPeekContext.d.ts',
contribCommentThreadAdditionalMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentThreadAdditionalMenu.d.ts',

View file

@ -478,6 +478,7 @@ export abstract class AbstractTimerService implements ITimerService {
private readonly _barrier = new Barrier();
private readonly _marks = new PerfMarks();
private readonly rndValueShouldSendTelemetry = Math.random() < .3;
private _startupMetrics?: IStartupMetrics;
@ -581,13 +582,15 @@ export abstract class AbstractTimerService implements ITimerService {
this._telemetryService.publicLog('startupTimeVaried', metrics);
}
private readonly _shouldReportPerfMarks = Math.random() < .3;
protected _shouldReportPerfMarks(): boolean {
return this.rndValueShouldSendTelemetry;
}
private _reportPerformanceMarks(source: string, marks: perf.PerformanceMark[]) {
if (!this._shouldReportPerfMarks) {
if (!this._shouldReportPerfMarks()) {
// the `startup.timer.mark` event is send very often. In order to save resources
// we let only a third of our instances send this event
// we let some of our instances/sessions send this event
return;
}

View file

@ -83,6 +83,11 @@ export class TimerService extends AbstractTimerService {
// ignore, be on the safe side with these hardware method calls
}
}
protected override _shouldReportPerfMarks(): boolean {
// always send when running with the prof-append-timers flag
return super._shouldReportPerfMarks() || Boolean(this._environmentService.args['prof-append-timers']);
}
}
registerSingleton(ITimerService, TimerService, InstantiationType.Delayed);

View file

@ -6,6 +6,7 @@
import { Promises } from 'vs/base/common/async';
import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { defaultUserDataProfileIcon, DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
@ -56,16 +57,10 @@ export class UserDataProfileService extends Disposable implements IUserDataProfi
}
getShortName(profile: IUserDataProfile): string {
if (profile.isDefault) {
return `$(${defaultUserDataProfileIcon.id})`;
}
if (profile.shortName) {
if (!profile.isDefault && profile.shortName && ThemeIcon.fromId(profile.shortName)) {
return profile.shortName;
}
if (profile.isTransient) {
return `T${profile.name.charAt(profile.name.length - 1)}`;
}
return profile.name.substring(0, 2).toUpperCase();
return `$(${defaultUserDataProfileIcon.id})`;
}
}

View file

@ -15222,6 +15222,14 @@ declare module 'vscode' {
Preview = 1
}
/**
* The state of a comment thread.
*/
export enum CommentThreadState {
Unresolved = 0,
Resolved = 1
}
/**
* A collection of {@link Comment comments} representing a conversation at a particular range in a document.
*/
@ -15279,6 +15287,11 @@ declare module 'vscode' {
*/
label?: string;
/**
* The optional state of a comment thread, which may affect how the comment is displayed.
*/
state?: CommentThreadState;
/**
* Dispose this comment thread.
*

View file

@ -1,24 +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 module 'vscode' {
// https://github.com/microsoft/vscode/issues/127473
/**
* The state of a comment thread.
*/
export enum CommentThreadState {
Unresolved = 0,
Resolved = 1
}
export interface CommentThread {
/**
* The optional state of a comment thread, which may affect how the comment is displayed.
*/
state?: CommentThreadState;
}
}

View file

@ -1321,10 +1321,10 @@
resolved "https://registry.yarnpkg.com/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.21.tgz#89b48f293f6aa3341bb888c1118d16ff13b032d3"
integrity sha512-zSUH9HYCw5qsCtd7b31yqkpaCU6jhtkKLkvOOA8yTrIRfBSOFb8PPhgmMicD7B/m+t4PwOJXzU1XDtrM9Fd3/g==
"@vscode/vscode-perf@^0.0.1":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@vscode/vscode-perf/-/vscode-perf-0.0.1.tgz#8378057d86003d8823d7404734adc64cfae80780"
integrity sha512-7xzVgkWAqFAFMTbHNGY6WiIKHEn0X0ARvIJmDEv2fDKjIB9W76R67Ft25jn3rf2/Gi0HfTPeJwjPTXm6ih5juw==
"@vscode/vscode-perf@^0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@vscode/vscode-perf/-/vscode-perf-0.0.2.tgz#d5a1c506c5ff57ab2b9cb74d349f66c5e5e98fdf"
integrity sha512-C8RrB+aRGXE5iSjm69zLRpLMMsoti+MonciR9xjzSj4lW9/NWNmQY2kH3Ktkoyci2zhUrTN+0OSmmuyDhhFDVg==
dependencies:
chalk "^4.x"
commander "^9.4.0"