Merge from vscode 1a81711a85e38ccf784110568ebf3784ab9094a5 (#9161)

* Merge from vscode 1a81711a85e38ccf784110568ebf3784ab9094a5

* small spacing fix
This commit is contained in:
Anthony Dresser
2020-02-15 00:43:09 -06:00
committed by GitHub
parent 74b89a0a85
commit 873c6a39fe
78 changed files with 1474 additions and 1011 deletions

View File

@@ -447,6 +447,22 @@
"command": "git.stashDrop", "command": "git.stashDrop",
"title": "%command.stashDrop%", "title": "%command.stashDrop%",
"category": "Git" "category": "Git"
},
{
"command": "git.timeline.openDiff",
"title": "%command.timelineOpenDiff%",
"icon": "$(compare-changes)",
"category": "Git"
},
{
"command": "git.timeline.copyCommitId",
"title": "%command.timelineCopyCommitId%",
"category": "Git"
},
{
"command": "git.timeline.copyCommitMessage",
"title": "%command.timelineCopyCommitMessage%",
"category": "Git"
} }
], ],
"menus": { "menus": {
@@ -718,6 +734,18 @@
{ {
"command": "git.stashDrop", "command": "git.stashDrop",
"when": "config.git.enabled && gitOpenRepositoryCount != 0" "when": "config.git.enabled && gitOpenRepositoryCount != 0"
},
{
"command": "git.timeline.openDiff",
"when": "false"
},
{
"command": "git.timeline.copyCommitId",
"when": "false"
},
{
"command": "git.timeline.copyCommitMessage",
"when": "false"
} }
], ],
"scm/title": [ "scm/title": [
@@ -1248,6 +1276,28 @@
"command": "git.revertChange", "command": "git.revertChange",
"when": "originalResourceScheme == git" "when": "originalResourceScheme == git"
} }
],
"timeline/item/context": [
{
"command": "git.timeline.openDiff",
"group": "inline",
"when": "timelineItem =~ /git:file\\b/"
},
{
"command": "git.timeline.openDiff",
"group": "1_timeline",
"when": "timelineItem =~ /git:file\\b/"
},
{
"command": "git.timeline.copyCommitId",
"group": "2_timeline@1",
"when": "timelineItem =~ /git:file:commit\\b/"
},
{
"command": "git.timeline.copyCommitMessage",
"group": "2_timeline@2",
"when": "timelineItem =~ /git:file:commit\\b/"
}
] ]
}, },
"configuration": { "configuration": {
@@ -1779,10 +1829,11 @@
"@types/file-type": "^5.2.1", "@types/file-type": "^5.2.1",
"@types/mocha": "2.2.43", "@types/mocha": "2.2.43",
"@types/node": "^12.11.7", "@types/node": "^12.11.7",
"@types/vscode": "^1.42",
"@types/which": "^1.0.28", "@types/which": "^1.0.28",
"mocha": "^3.2.0", "mocha": "^3.2.0",
"mocha-junit-reporter": "^1.23.3", "mocha-junit-reporter": "^1.23.3",
"mocha-multi-reporters": "^1.1.7", "mocha-multi-reporters": "^1.1.7",
"vscode": "^1.1.36" "vscode-test": "^1.3.0"
} }
} }

View File

@@ -70,6 +70,9 @@
"command.stashApply": "Apply Stash...", "command.stashApply": "Apply Stash...",
"command.stashApplyLatest": "Apply Latest Stash", "command.stashApplyLatest": "Apply Latest Stash",
"command.stashDrop": "Drop Stash...", "command.stashDrop": "Drop Stash...",
"command.timelineOpenDiff": "Open Changes",
"command.timelineCopyCommitId": "Copy Commit ID",
"command.timelineCopyCommitMessage": "Copy Commit Message",
"config.enabled": "Whether git is enabled.", "config.enabled": "Whether git is enabled.",
"config.path": "Path and filename of the git executable, e.g. `C:\\Program Files\\Git\\bin\\git.exe` (Windows).", "config.path": "Path and filename of the git executable, e.g. `C:\\Program Files\\Git\\bin\\git.exe` (Windows).",
"config.autoRepositoryDetection": "Configures when repositories should be automatically detected.", "config.autoRepositoryDetection": "Configures when repositories should be automatically detected.",
@@ -127,7 +130,7 @@
"config.showProgress": "Controls whether git actions should show progress.", "config.showProgress": "Controls whether git actions should show progress.",
"config.rebaseWhenSync": "Force git to use rebase when running the sync command.", "config.rebaseWhenSync": "Force git to use rebase when running the sync command.",
"config.confirmEmptyCommits": "Always confirm the creation of empty commits for the 'Git: Commit Empty' command.", "config.confirmEmptyCommits": "Always confirm the creation of empty commits for the 'Git: Commit Empty' command.",
"config.fetchOnPull": "Fetch all branches when pulling or just the current one.", "config.fetchOnPull": "When enabled, fetch all branches when pulling. Otherwise, fetch just the current one.",
"config.pullTags": "Fetch all tags when pulling.", "config.pullTags": "Fetch all tags when pulling.",
"config.autoStash": "Stash any changes before pulling and restore them after successful pull.", "config.autoStash": "Stash any changes before pulling and restore them after successful pull.",
"config.allowForcePush": "Controls whether force push (with or without lease) is enabled.", "config.allowForcePush": "Controls whether force push (with or without lease) is enabled.",

View File

@@ -6,7 +6,7 @@
import { lstat, Stats } from 'fs'; import { lstat, Stats } from 'fs';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder } from 'vscode'; import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env } from 'vscode';
import TelemetryReporter from 'vscode-extension-telemetry'; import TelemetryReporter from 'vscode-extension-telemetry';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { Branch, GitErrorCodes, Ref, RefType, Status, CommitOptions } from './api/git'; import { Branch, GitErrorCodes, Ref, RefType, Status, CommitOptions } from './api/git';
@@ -17,6 +17,7 @@ import { applyLineChanges, getModifiedRange, intersectDiffWithRange, invertLineC
import { fromGitUri, toGitUri, isGitUri } from './uri'; import { fromGitUri, toGitUri, isGitUri } from './uri';
import { grep, isDescendant, pathEquals } from './util'; import { grep, isDescendant, pathEquals } from './util';
import { Log, LogLevel } from './log'; import { Log, LogLevel } from './log';
import { GitTimelineItem } from './timelineProvider';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -2331,23 +2332,47 @@ export class CommandCenter {
return result && result.stash; return result && result.stash;
} }
@command('git.openDiff', { repository: false }) @command('git.timeline.openDiff', { repository: false })
async openDiff(uri: Uri, lhs: string, rhs: string) { async timelineOpenDiff(item: TimelineItem, uri: Uri | undefined, _source: string) {
// eslint-disable-next-line eqeqeq
if (uri == null || !GitTimelineItem.is(item)) {
return undefined;
}
const basename = path.basename(uri.fsPath); const basename = path.basename(uri.fsPath);
let title; let title;
if ((lhs === 'HEAD' || lhs === '~') && rhs === '') { if ((item.previousRef === 'HEAD' || item.previousRef === '~') && item.ref === '') {
title = `${basename} (Working Tree)`; title = `${basename} (Working Tree)`;
} }
else if (lhs === 'HEAD' && rhs === '~') { else if (item.previousRef === 'HEAD' && item.ref === '~') {
title = `${basename} (Index)`; title = `${basename} (Index)`;
} else { } else {
title = `${basename} (${lhs.endsWith('^') ? `${lhs.substr(0, 8)}^` : lhs.substr(0, 8)}) \u27f7 ${basename} (${rhs.endsWith('^') ? `${rhs.substr(0, 8)}^` : rhs.substr(0, 8)})`; title = `${basename} (${item.shortPreviousRef}) \u27f7 ${basename} (${item.shortRef})`;
} }
return commands.executeCommand('vscode.diff', toGitUri(uri, lhs), rhs === '' ? uri : toGitUri(uri, rhs), title); return commands.executeCommand('vscode.diff', toGitUri(uri, item.previousRef), item.ref === '' ? uri : toGitUri(uri, item.ref), title);
} }
@command('git.timeline.copyCommitId', { repository: false })
async timelineCopyCommitId(item: TimelineItem, _uri: Uri | undefined, _source: string) {
if (!GitTimelineItem.is(item)) {
return;
}
env.clipboard.writeText(item.ref);
}
@command('git.timeline.copyCommitMessage', { repository: false })
async timelineCopyCommitMessage(item: TimelineItem, _uri: Uri | undefined, _source: string) {
if (!GitTimelineItem.is(item)) {
return;
}
env.clipboard.writeText(item.message);
}
private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any { private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any {
const result = (...args: any[]) => { const result = (...args: any[]) => {
let result: Promise<any>; let result: Promise<any>;

View File

@@ -5,19 +5,62 @@
import * as dayjs from 'dayjs'; import * as dayjs from 'dayjs';
import * as advancedFormat from 'dayjs/plugin/advancedFormat'; import * as advancedFormat from 'dayjs/plugin/advancedFormat';
import * as relativeTime from 'dayjs/plugin/relativeTime'; import { CancellationToken, Disposable, Event, EventEmitter, ThemeIcon, Timeline, TimelineChangeEvent, TimelineCursor, TimelineItem, TimelineProvider, Uri, workspace } from 'vscode';
import { CancellationToken, Disposable, Event, EventEmitter, ThemeIcon, TimelineItem, TimelineProvider, Uri, workspace, TimelineChangeEvent } from 'vscode';
import { Model } from './model'; import { Model } from './model';
import { Repository } from './repository'; import { Repository } from './repository';
import { debounce } from './decorators'; import { debounce } from './decorators';
import { Status } from './api/git'; import { Status } from './api/git';
dayjs.extend(advancedFormat); dayjs.extend(advancedFormat);
dayjs.extend(relativeTime);
// TODO[ECA]: Localize all the strings // TODO[ECA]: Localize all the strings
// TODO[ECA]: Localize or use a setting for date format // TODO[ECA]: Localize or use a setting for date format
export class GitTimelineItem extends TimelineItem {
static is(item: TimelineItem): item is GitTimelineItem {
return item instanceof GitTimelineItem;
}
readonly ref: string;
readonly previousRef: string;
readonly message: string;
constructor(
ref: string,
previousRef: string,
message: string,
timestamp: number,
id: string,
contextValue: string
) {
const index = message.indexOf('\n');
const label = index !== -1 ? `${message.substring(0, index)} \u2026` : message;
super(label, timestamp);
this.ref = ref;
this.previousRef = previousRef;
this.message = message;
this.id = id;
this.contextValue = contextValue;
}
get shortRef() {
return this.shortenRef(this.ref);
}
get shortPreviousRef() {
return this.shortenRef(this.previousRef);
}
private shortenRef(ref: string): string {
if (ref === '' || ref === '~' || ref === 'HEAD') {
return ref;
}
return ref.endsWith('^') ? `${ref.substr(0, 8)}^` : ref.substr(0, 8);
}
}
export class GitTimelineProvider implements TimelineProvider { export class GitTimelineProvider implements TimelineProvider {
private _onDidChange = new EventEmitter<TimelineChangeEvent>(); private _onDidChange = new EventEmitter<TimelineChangeEvent>();
get onDidChange(): Event<TimelineChangeEvent> { get onDidChange(): Event<TimelineChangeEvent> {
@@ -44,7 +87,7 @@ export class GitTimelineProvider implements TimelineProvider {
this._disposable.dispose(); this._disposable.dispose();
} }
async provideTimeline(uri: Uri, _token: CancellationToken): Promise<TimelineItem[]> { async provideTimeline(uri: Uri, _cursor: TimelineCursor, _token: CancellationToken): Promise<Timeline> {
// console.log(`GitTimelineProvider.provideTimeline: uri=${uri} state=${this._model.state}`); // console.log(`GitTimelineProvider.provideTimeline: uri=${uri} state=${this._model.state}`);
const repo = this._model.getRepository(uri); const repo = this._model.getRepository(uri);
@@ -53,7 +96,7 @@ export class GitTimelineProvider implements TimelineProvider {
this._repoStatusDate = undefined; this._repoStatusDate = undefined;
this._repo = undefined; this._repo = undefined;
return []; return { items: [] };
} }
if (this._repo?.root !== repo.root) { if (this._repo?.root !== repo.root) {
@@ -72,25 +115,17 @@ export class GitTimelineProvider implements TimelineProvider {
const commits = await repo.logFile(uri); const commits = await repo.logFile(uri);
let dateFormatter: dayjs.Dayjs; let dateFormatter: dayjs.Dayjs;
const items = commits.map<TimelineItem>(c => { const items = commits.map<GitTimelineItem>(c => {
let message = c.message;
const index = message.indexOf('\n');
if (index !== -1) {
message = `${message.substring(0, index)} \u2026`;
}
dateFormatter = dayjs(c.authorDate); dateFormatter = dayjs(c.authorDate);
const item = new TimelineItem(message, c.authorDate?.getTime() ?? 0); const item = new GitTimelineItem(c.hash, `${c.hash}^`, c.message, c.authorDate?.getTime() ?? 0, c.hash, 'git:file:commit');
item.id = c.hash;
item.iconPath = new (ThemeIcon as any)('git-commit'); item.iconPath = new (ThemeIcon as any)('git-commit');
item.description = `${dateFormatter.fromNow()} \u2022 ${c.authorName}`; item.description = c.authorName;
item.detail = `${c.authorName} (${c.authorEmail}) \u2014 ${c.hash.substr(0, 8)}\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n\n${c.message}`; item.detail = `${c.authorName} (${c.authorEmail}) \u2014 ${c.hash.substr(0, 8)}\n${dateFormatter.format('MMMM Do, YYYY h:mma')}\n\n${c.message}`;
item.command = { item.command = {
title: 'Open Diff', title: 'Open Comparison',
command: 'git.openDiff', command: 'git.timeline.openDiff',
arguments: [uri, `${c.hash}^`, c.hash] arguments: [uri, this.id, item]
}; };
return item; return item;
@@ -123,16 +158,15 @@ export class GitTimelineProvider implements TimelineProvider {
break; break;
} }
const item = new TimelineItem('Staged Changes', date.getTime()); const item = new GitTimelineItem('~', 'HEAD', 'Staged Changes', date.getTime(), 'index', 'git:file:index');
item.id = 'index';
// TODO[ECA]: Replace with a better icon -- reflecting its status maybe? // TODO[ECA]: Replace with a better icon -- reflecting its status maybe?
item.iconPath = new (ThemeIcon as any)('git-commit'); item.iconPath = new (ThemeIcon as any)('git-commit');
item.description = `${dateFormatter.fromNow()} \u2022 You`; item.description = 'You';
item.detail = `You \u2014 Index\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n${status}`; item.detail = `You \u2014 Index\n${dateFormatter.format('MMMM Do, YYYY h:mma')}\n${status}`;
item.command = { item.command = {
title: 'Open Comparison', title: 'Open Comparison',
command: 'git.openDiff', command: 'git.timeline.openDiff',
arguments: [uri, 'HEAD', '~'] arguments: [uri, this.id, item]
}; };
items.push(item); items.push(item);
@@ -166,22 +200,21 @@ export class GitTimelineProvider implements TimelineProvider {
break; break;
} }
const item = new TimelineItem('Uncommited Changes', date.getTime()); const item = new GitTimelineItem('', index ? '~' : 'HEAD', 'Uncommited Changes', date.getTime(), 'working', 'git:file:working');
item.id = 'working';
// TODO[ECA]: Replace with a better icon -- reflecting its status maybe? // TODO[ECA]: Replace with a better icon -- reflecting its status maybe?
item.iconPath = new (ThemeIcon as any)('git-commit'); item.iconPath = new (ThemeIcon as any)('git-commit');
item.description = `${dateFormatter.fromNow()} \u2022 You`; item.description = 'You';
item.detail = `You \u2014 Working Tree\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n${status}`; item.detail = `You \u2014 Working Tree\n${dateFormatter.format('MMMM Do, YYYY h:mma')}\n${status}`;
item.command = { item.command = {
title: 'Open Comparison', title: 'Open Comparison',
command: 'git.openDiff', command: 'git.timeline.openDiff',
arguments: [uri, index ? '~' : 'HEAD', ''] arguments: [uri, this.id, item]
}; };
items.push(item); items.push(item);
} }
return items; return { items: items };
} }
private onRepositoriesChanged(_repo: Repository) { private onRepositoriesChanged(_repo: Repository) {
@@ -208,6 +241,6 @@ export class GitTimelineProvider implements TimelineProvider {
@debounce(500) @debounce(500)
private fireChanged() { private fireChanged() {
this._onDidChange.fire(); this._onDidChange.fire({});
} }
} }

View File

@@ -31,6 +31,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a"
integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==
"@types/vscode@^1.42":
version "1.42.0"
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.42.0.tgz#0ad891a9487e91e34be7c56985058a179031eb76"
integrity sha512-ds6TceMsh77Fs0Mq0Vap6Y72JbGWB8Bay4DrnJlf5d9ui2RSe1wis13oQm+XhguOeH1HUfLGzaDAoupTUtgabw==
"@types/which@^1.0.28": "@types/which@^1.0.28":
version "1.0.28" version "1.0.28"
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.0.28.tgz#016e387629b8817bed653fe32eab5d11279c8df6" resolved "https://registry.yarnpkg.com/@types/which/-/which-1.0.28.tgz#016e387629b8817bed653fe32eab5d11279c8df6"
@@ -43,16 +48,6 @@ agent-base@4, agent-base@^4.3.0:
dependencies: dependencies:
es6-promisify "^5.0.0" es6-promisify "^5.0.0"
ajv@^6.5.5:
version "6.11.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ansi-regex@^3.0.0: ansi-regex@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
@@ -67,45 +62,11 @@ applicationinsights@1.0.8:
diagnostic-channel-publishers "0.2.1" diagnostic-channel-publishers "0.2.1"
zone.js "0.7.6" zone.js "0.7.6"
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
dependencies:
safer-buffer "~2.1.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
balanced-match@^1.0.0: balanced-match@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
dependencies:
tweetnacl "^0.14.3"
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.8" version "1.1.8"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
@@ -119,43 +80,16 @@ browser-stdout@1.3.0:
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f"
integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8=
browser-stdout@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
byline@^5.0.0: byline@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
charenc@~0.0.1: charenc@~0.0.1:
version "0.0.2" version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
commander@2.15.1:
version "2.15.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==
commander@2.9.0: commander@2.9.0:
version "2.9.0" version "2.9.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
@@ -168,23 +102,11 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
core-util-is@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
crypt@~0.0.1: crypt@~0.0.1:
version "0.0.2" version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
dependencies:
assert-plus "^1.0.0"
dayjs@1.8.19: dayjs@1.8.19:
version "1.8.19" version "1.8.19"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.19.tgz#5117dc390d8f8e586d53891dbff3fa308f51abfe" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.19.tgz#5117dc390d8f8e586d53891dbff3fa308f51abfe"
@@ -218,11 +140,6 @@ debug@^3.1.0:
dependencies: dependencies:
ms "^2.1.1" ms "^2.1.1"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
diagnostic-channel-publishers@0.2.1: diagnostic-channel-publishers@0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3" resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
@@ -240,19 +157,6 @@ diff@3.2.0:
resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k= integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k=
diff@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
dependencies:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
es6-promise@^4.0.3: es6-promise@^4.0.3:
version "4.2.8" version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
@@ -270,62 +174,16 @@ escape-string-regexp@1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
file-type@^7.2.0: file-type@^7.2.0:
version "7.2.0" version "7.2.0"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-7.2.0.tgz#113cfed52e1d6959ab80248906e2f25a8cdccb74" resolved "https://registry.yarnpkg.com/file-type/-/file-type-7.2.0.tgz#113cfed52e1d6959ab80248906e2f25a8cdccb74"
integrity sha1-ETz+1S4daVmrgCSJBuLyWozcy3Q= integrity sha1-ETz+1S4daVmrgCSJBuLyWozcy3Q=
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.6"
mime-types "^2.1.12"
fs.realpath@^1.0.0: fs.realpath@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
dependencies:
assert-plus "^1.0.0"
glob@7.1.1: glob@7.1.1:
version "7.1.1" version "7.1.1"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
@@ -338,19 +196,7 @@ glob@7.1.1:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
glob@7.1.2: glob@^7.1.3:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.2:
version "7.1.6" version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -367,39 +213,16 @@ glob@^7.1.2:
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
growl@1.10.5:
version "1.10.5"
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
growl@1.9.2: growl@1.9.2:
version "1.9.2" version "1.9.2"
resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@~5.1.0:
version "5.1.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
dependencies:
ajv "^6.5.5"
har-schema "^2.0.0"
has-flag@^1.0.0: has-flag@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
he@1.1.1: he@1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
@@ -413,16 +236,7 @@ http-proxy-agent@^2.1.0:
agent-base "4" agent-base "4"
debug "3.1.0" debug "3.1.0"
http-signature@~1.2.0: https-proxy-agent@^2.2.4:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
https-proxy-agent@^2.2.1:
version "2.2.4" version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
@@ -455,61 +269,21 @@ is-buffer@~1.1.1:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
isexe@^2.0.0: isexe@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
jschardet@2.1.1: jschardet@2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184" resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184"
integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q== integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q==
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
json3@3.3.2: json3@3.3.2:
version "3.3.2" version "3.3.2"
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
verror "1.10.0"
lodash._baseassign@^3.0.0: lodash._baseassign@^3.0.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
@@ -580,19 +354,7 @@ md5@^2.1.0:
crypt "~0.0.1" crypt "~0.0.1"
is-buffer "~1.1.1" is-buffer "~1.1.1"
mime-db@1.43.0: minimatch@^3.0.2, minimatch@^3.0.4:
version "1.43.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
mime-types@^2.1.12, mime-types@~2.1.19:
version "2.1.26"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
dependencies:
mime-db "1.43.0"
minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -648,23 +410,6 @@ mocha@^3.2.0:
mkdirp "0.5.1" mkdirp "0.5.1"
supports-color "3.1.2" supports-color "3.1.2"
mocha@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6"
integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==
dependencies:
browser-stdout "1.3.1"
commander "2.15.1"
debug "3.1.0"
diff "3.5.0"
escape-string-regexp "1.0.5"
glob "7.1.2"
growl "1.10.5"
he "1.1.1"
minimatch "3.0.4"
mkdirp "0.5.1"
supports-color "5.4.0"
ms@2.0.0: ms@2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -675,11 +420,6 @@ ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
once@^1.3.0: once@^1.3.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -692,73 +432,14 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
performance-now@^2.1.0: rimraf@^2.6.3:
version "2.1.0" version "2.7.1"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
psl@^1.1.24:
version "1.7.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c"
integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
querystringify@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
request@^2.88.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
dependencies: dependencies:
aws-sign2 "~0.7.0" glob "^7.1.3"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.0"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.4.3"
tunnel-agent "^0.6.0"
uuid "^3.3.2"
requires-port@^1.0.0: "safer-buffer@>= 2.1.2 < 3":
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
safe-buffer@^5.0.1, safe-buffer@^5.1.2:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -768,39 +449,6 @@ semver@^5.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
semver@^5.4.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
source-map-support@^0.5.0:
version "0.5.16"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
bcrypt-pbkdf "^1.0.0"
dashdash "^1.12.0"
ecc-jsbn "~0.1.1"
getpass "^0.1.1"
jsbn "~0.1.0"
safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
strip-ansi@^4.0.0: strip-ansi@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
@@ -815,62 +463,6 @@ supports-color@3.1.2:
dependencies: dependencies:
has-flag "^1.0.0" has-flag "^1.0.0"
supports-color@5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==
dependencies:
has-flag "^3.0.0"
tough-cookie@~2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
dependencies:
psl "^1.1.24"
punycode "^1.4.1"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
dependencies:
safe-buffer "^5.0.1"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
uri-js@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
dependencies:
punycode "^2.1.0"
url-parse@^1.4.4:
version "1.4.7"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
dependencies:
querystringify "^2.1.1"
requires-port "^1.0.0"
uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
vscode-extension-telemetry@0.1.1: vscode-extension-telemetry@0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b" resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b"
@@ -883,32 +475,20 @@ vscode-nls@^4.0.0:
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002"
integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw==
vscode-test@^0.4.1: vscode-test@^1.3.0:
version "0.4.3" version "1.3.0"
resolved "https://registry.yarnpkg.com/vscode-test/-/vscode-test-0.4.3.tgz#461ebf25fc4bc93d77d982aed556658a2e2b90b8" resolved "https://registry.yarnpkg.com/vscode-test/-/vscode-test-1.3.0.tgz#3310ab385d9b887b4c82e8f52be1030e7cf9493d"
integrity sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w== integrity sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==
dependencies: dependencies:
http-proxy-agent "^2.1.0" http-proxy-agent "^2.1.0"
https-proxy-agent "^2.2.1" https-proxy-agent "^2.2.4"
rimraf "^2.6.3"
vscode-uri@^2.0.0: vscode-uri@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.0.tgz#2df704222f72b8a71ff266ba0830ed6c51ac1542" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.0.tgz#2df704222f72b8a71ff266ba0830ed6c51ac1542"
integrity sha512-lWXWofDSYD8r/TIyu64MdwB4FaSirQ608PP/TzUyslyOeHGwQ0eTHUZeJrK1ILOmwUHaJtV693m2JoUYroUDpw== integrity sha512-lWXWofDSYD8r/TIyu64MdwB4FaSirQ608PP/TzUyslyOeHGwQ0eTHUZeJrK1ILOmwUHaJtV693m2JoUYroUDpw==
vscode@^1.1.36:
version "1.1.36"
resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.36.tgz#5e1a0d1bf4977d0c7bc5159a9a13d5b104d4b1b6"
integrity sha512-cGFh9jmGLcTapCpPCKvn8aG/j9zVQ+0x5hzYJq5h5YyUXVGa1iamOaB2M2PZXoumQPES4qeAP1FwkI0b6tL4bQ==
dependencies:
glob "^7.1.2"
mocha "^5.2.0"
request "^2.88.0"
semver "^5.4.1"
source-map-support "^0.5.0"
url-parse "^1.4.4"
vscode-test "^0.4.1"
which@^1.3.0: which@^1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"

View File

@@ -165,7 +165,7 @@
"opn": "^6.0.0", "opn": "^6.0.0",
"optimist": "0.3.5", "optimist": "0.3.5",
"p-all": "^1.0.0", "p-all": "^1.0.0",
"playwright": "^0.10.0", "playwright": "0.11.0",
"pump": "^1.0.1", "pump": "^1.0.1",
"queue": "3.0.6", "queue": "3.0.6",
"rcedit": "^1.1.0", "rcedit": "^1.1.0",

View File

@@ -140,6 +140,9 @@ function configureCommandlineSwitchesSync(cliArgs) {
// provided by Electron // provided by Electron
'disable-color-correct-rendering' 'disable-color-correct-rendering'
]; ];
if (process.platform === 'linux') {
SUPPORTED_ELECTRON_SWITCHES.push('force-renderer-accessibility');
}
// Read argv config // Read argv config
const argvConfig = readArgvConfigSync(); const argvConfig = readArgvConfigSync();

View File

@@ -5,6 +5,53 @@
import { pad } from './strings'; import { pad } from './strings';
const minute = 60;
const hour = minute * 60;
const day = hour * 24;
const week = day * 7;
const month = day * 30;
const year = day * 365;
// TODO[ECA]: Localize strings
export function fromNow(date: number | Date) {
if (typeof date !== 'number') {
date = date.getTime();
}
const seconds = Math.round((new Date().getTime() - date) / 1000);
if (seconds < 30) {
return 'now';
}
let value: number;
let unit: string;
if (seconds < minute) {
value = seconds;
unit = 'sec';
} else if (seconds < hour) {
value = Math.floor(seconds / minute);
unit = 'min';
} else if (seconds < day) {
value = Math.floor(seconds / hour);
unit = 'hr';
} else if (seconds < week) {
value = Math.floor(seconds / day);
unit = 'day';
} else if (seconds < month) {
value = Math.floor(seconds / week);
unit = 'wk';
} else if (seconds < year) {
value = Math.floor(seconds / month);
unit = 'mo';
} else {
value = Math.floor(seconds / year);
unit = 'yr';
}
return `${value} ${unit}${value === 1 ? '' : 's'}`;
}
export function toLocalISOString(date: Date): string { export function toLocalISOString(date: Date): string {
return date.getFullYear() + return date.getFullYear() +
'-' + pad(date.getMonth() + 1, 2) + '-' + pad(date.getMonth() + 1, 2) +

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IWorkbenchConstructionOptions, create, URI, Event, Emitter, UriComponents, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IApplicationLinkProvider, IApplicationLink } from 'vs/workbench/workbench.web.api'; import { IWorkbenchConstructionOptions, create, URI, Event, Emitter, UriComponents, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IApplicationLink } from 'vs/workbench/workbench.web.api';
import { generateUuid } from 'vs/base/common/uuid'; import { generateUuid } from 'vs/base/common/uuid';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { streamToBuffer } from 'vs/base/common/buffer'; import { streamToBuffer } from 'vs/base/common/buffer';
@@ -279,39 +279,6 @@ class WorkspaceProvider implements IWorkspaceProvider {
} }
} }
class ApplicationLinkProvider {
private links: IApplicationLink[] | undefined = undefined;
constructor(workspace: IWorkspace) {
this.computeLink(workspace);
}
private computeLink(workspace: IWorkspace): void {
if (!workspace) {
return; // not for empty workspaces
}
const workspaceUri = isWorkspaceToOpen(workspace) ? workspace.workspaceUri : isFolderToOpen(workspace) ? workspace.folderUri : undefined;
if (workspaceUri) {
this.links = [{
uri: URI.from({
scheme: product.quality === 'stable' ? 'vscode' : 'vscode-insiders',
authority: Schemas.vscodeRemote,
path: posix.join(posix.sep, workspaceUri.authority, workspaceUri.path),
query: workspaceUri.query,
fragment: workspaceUri.fragment,
}),
label: localize('openInDesktop', "Open in Desktop")
}];
}
}
get provider(): IApplicationLinkProvider {
return () => this.links;
}
}
(function () { (function () {
// Find config by checking for DOM // Find config by checking for DOM
@@ -375,12 +342,30 @@ class ApplicationLinkProvider {
} }
} }
// Application links ("Open in Desktop")
let applicationLinks: IApplicationLink[] | undefined = undefined;
if (workspace) {
const workspaceUri = isWorkspaceToOpen(workspace) ? workspace.workspaceUri : isFolderToOpen(workspace) ? workspace.folderUri : undefined;
if (workspaceUri) {
applicationLinks = [{
uri: URI.from({
scheme: product.quality === 'stable' ? 'vscode' : 'vscode-insiders',
authority: Schemas.vscodeRemote,
path: posix.join(posix.sep, workspaceUri.authority, workspaceUri.path),
query: workspaceUri.query,
fragment: workspaceUri.fragment,
}),
label: localize('openInDesktop', "Open in Desktop")
}];
}
}
// Finally create workbench // Finally create workbench
create(document.body, { create(document.body, {
...config, ...config,
workspaceProvider: new WorkspaceProvider(workspace, payload), workspaceProvider: new WorkspaceProvider(workspace, payload),
urlCallbackProvider: new PollingURLCallbackProvider(), urlCallbackProvider: new PollingURLCallbackProvider(),
credentialsProvider: new LocalStorageCredentialsProvider(), credentialsProvider: new LocalStorageCredentialsProvider(),
applicationLinkProvider: new ApplicationLinkProvider(workspace).provider applicationLinks: applicationLinks
}); });
})(); })();

View File

@@ -265,6 +265,34 @@ export interface HoverProvider {
provideHover(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<Hover>; provideHover(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<Hover>;
} }
/**
* An evaluatable expression represents additional information for an expression in a document. Evaluatable expression are
* evaluated by a debugger or runtime and their result is rendered in a tooltip-like widget.
*/
export interface EvaluatableExpression {
/**
* The range to which this expression applies.
*/
range: IRange;
/*
* This expression overrides the expression extracted from the range.
*/
expression?: string;
}
/**
* The hover provider interface defines the contract between extensions and
* the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature.
*/
export interface EvaluatableExpressionProvider {
/**
* Provide a hover for the given position and document. Multiple hovers at the same
* position will be merged by the editor. A hover can have a range which defaults
* to the word range at the position when omitted.
*/
provideEvaluatableExpression(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<EvaluatableExpression>;
}
export const enum CompletionItemKind { export const enum CompletionItemKind {
Method, Method,
Function, Function,
@@ -1595,6 +1623,11 @@ export const SignatureHelpProviderRegistry = new LanguageFeatureRegistry<Signatu
*/ */
export const HoverProviderRegistry = new LanguageFeatureRegistry<HoverProvider>(); export const HoverProviderRegistry = new LanguageFeatureRegistry<HoverProvider>();
/**
* @internal
*/
export const EvaluatableExpressionProviderRegistry = new LanguageFeatureRegistry<EvaluatableExpressionProvider>();
/** /**
* @internal * @internal
*/ */

25
src/vs/monaco.d.ts vendored
View File

@@ -5242,6 +5242,31 @@ declare namespace monaco.languages {
provideHover(model: editor.ITextModel, position: Position, token: CancellationToken): ProviderResult<Hover>; provideHover(model: editor.ITextModel, position: Position, token: CancellationToken): ProviderResult<Hover>;
} }
/**
* An evaluatable expression represents additional information for an expression in a document. Evaluatable expression are
* evaluated by a debugger or runtime and their result is rendered in a tooltip-like widget.
*/
export interface EvaluatableExpression {
/**
* The range to which this expression applies.
*/
range: IRange;
expression?: string;
}
/**
* The hover provider interface defines the contract between extensions and
* the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature.
*/
export interface EvaluatableExpressionProvider {
/**
* Provide a hover for the given position and document. Multiple hovers at the same
* position will be merged by the editor. A hover can have a range which defaults
* to the word range at the position when omitted.
*/
provideEvaluatableExpression(model: editor.ITextModel, position: Position, token: CancellationToken): ProviderResult<EvaluatableExpression>;
}
export enum CompletionItemKind { export enum CompletionItemKind {
Method = 0, Method = 0,
Function = 1, Function = 1,

View File

@@ -119,7 +119,9 @@ export class MenuId {
static readonly DataExplorerContext = new MenuId('DataExplorerContext'); // {{SQL CARBON EDIT}} static readonly DataExplorerContext = new MenuId('DataExplorerContext'); // {{SQL CARBON EDIT}}
static readonly DataExplorerAction = new MenuId('DataExplorerAction'); // {{SQL CARBON EDIT}} static readonly DataExplorerAction = new MenuId('DataExplorerAction'); // {{SQL CARBON EDIT}}
static readonly ExplorerWidgetContext = new MenuId('ExplorerWidgetContext'); // {{SQL CARBON EDIT}} static readonly ExplorerWidgetContext = new MenuId('ExplorerWidgetContext'); // {{SQL CARBON EDIT}}
static readonly TimelineItemContext = new MenuId('TimelineItemContext');
static readonly TimelineTitle = new MenuId('TimelineTitle');
static readonly TimelineTitleContext = new MenuId('TimelineTitleContext');
readonly id: number; readonly id: number;
readonly _debugName: string; readonly _debugName: string;

View File

@@ -29,7 +29,7 @@ export interface IConstructorSignature0<T> {
} }
export interface IConstructorSignature1<A1, T> { export interface IConstructorSignature1<A1, T> {
new(first: A1, ...services: BrandedService[]): T; new <Services extends BrandedService[]>(first: A1, ...services: Services): T;
} }
export interface IConstructorSignature2<A1, A2, T> { export interface IConstructorSignature2<A1, A2, T> {

View File

@@ -98,7 +98,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto
async triggerAutoSync(): Promise<void> { async triggerAutoSync(): Promise<void> {
if (this.enabled) { if (this.enabled) {
return this.syncDelayer.trigger(() => { return this.syncDelayer.trigger(() => {
this.logService.info('Auto Sync: Triggerred.'); this.logService.info('Auto Sync: Triggered.');
return this.sync(false, true); return this.sync(false, true);
}, this.successiveFailures }, this.successiveFailures
? 1000 * 1 * Math.min(this.successiveFailures, 60) /* Delay by number of seconds as number of failures up to 1 minute */ ? 1000 * 1 * Math.min(this.successiveFailures, 60) /* Delay by number of seconds as number of failures up to 1 minute */

View File

@@ -876,7 +876,65 @@ declare module 'vscode' {
//#endregion //#endregion
//#region Debug: //#region locate evaluatable expressions for debug hover: https://github.com/microsoft/vscode/issues/89084
/**
* An EvaluatableExpression represents an expression in a document that can be evaluated by an active debugger or runtime.
* The result of this evaluation is shown in a tooltip-like widget.
* If only a range is specified, the expression will be extracted from the underlying document.
* An optional expression can be used to override the extracted expression.
* In this case the range is still used to highlight the range in the document.
*/
export class EvaluatableExpression {
/*
* The range is used to extract the evaluatable expression from the underlying document and to highlight it.
*/
readonly range: Range;
/*
* If specified the expression overrides the extracted expression.
*/
readonly expression?: string;
/**
* Creates a new evaluatable expression object.
*
* @param range The range in the underlying document from which the evaluatable expression is extracted.
* @param expression If specified overrides the extracted expression.
*/
constructor(range: Range, expression?: string);
}
/**
* The evaluatable expression provider interface defines the contract between extensions and
* the debug hover.
*/
export interface EvaluatableExpressionProvider {
/**
* Provide an evaluatable expression for the given document and position.
* The expression can be implicitly specified by the range in the underlying document or by explicitly returning an expression.
*
* @param document The document in which the command was invoked.
* @param position The position where the command was invoked.
* @param token A cancellation token.
* @return An EvaluatableExpression or a thenable that resolves to such. The lack of a result can be
* signaled by returning `undefined` or `null`.
*/
provideEvaluatableExpression(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<EvaluatableExpression>;
}
export namespace languages {
/**
* Register a provider that locates evaluatable expressions in text documents.
*
* If multiple providers are registered for a language an arbitrary provider will be used.
*
* @param selector A selector that defines the documents this provider is applicable to.
* @param provider An evaluatable expression provider.
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/
export function registerEvaluatableExpressionProvider(selector: DocumentSelector, provider: EvaluatableExpressionProvider): Disposable;
}
// deprecated // deprecated
@@ -1553,6 +1611,40 @@ declare module 'vscode' {
uri?: Uri; uri?: Uri;
} }
export interface TimelineCursor {
/**
* A provider-defined cursor specifing the range of timeline items to be returned. Must be serializable.
*/
cursor?: any;
/**
* A flag to specify whether the timeline items requested are before or after (default) the provided cursor.
*/
before?: boolean;
/**
* The maximum number of timeline items that should be returned.
*/
limit?: number;
}
export interface Timeline {
/**
* A provider-defined cursor specifing the range of timeline items returned. Must be serializable.
*/
cursor?: any;
/**
* A flag which indicates whether there are any more items that weren't returned.
*/
more?: boolean;
/**
* An array of [timeline items](#TimelineItem).
*/
items: TimelineItem[];
}
export interface TimelineProvider { export interface TimelineProvider {
/** /**
* An optional event to signal that the timeline for a source has changed. * An optional event to signal that the timeline for a source has changed.
@@ -1575,10 +1667,11 @@ declare module 'vscode' {
* *
* @param uri The [uri](#Uri) of the file to provide the timeline for. * @param uri The [uri](#Uri) of the file to provide the timeline for.
* @param token A cancellation token. * @param token A cancellation token.
* @return An array of timeline items or a thenable that resolves to such. The lack of a result * @param cursor TBD
* @return The [timeline result](#TimelineResult) or a thenable that resolves to such. The lack of a result
* can be signaled by returning `undefined`, `null`, or an empty array. * can be signaled by returning `undefined`, `null`, or an empty array.
*/ */
provideTimeline(uri: Uri, token: CancellationToken): ProviderResult<TimelineItem[]>; provideTimeline(uri: Uri, cursor: TimelineCursor, token: CancellationToken): ProviderResult<Timeline>;
} }
export namespace workspace { export namespace workspace {

View File

@@ -213,6 +213,16 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
})); }));
} }
// --- debug hover
$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void {
this._registrations.set(handle, modes.EvaluatableExpressionProviderRegistry.register(selector, <modes.EvaluatableExpressionProvider>{
provideEvaluatableExpression: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined> => {
return this._proxy.$provideEvaluatableExpression(handle, model.uri, position, token);
}
}));
}
// --- occurrences // --- occurrences
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void { $registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void {

View File

@@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { MainContext, MainThreadTimelineShape, IExtHostContext, ExtHostTimelineShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { MainContext, MainThreadTimelineShape, IExtHostContext, ExtHostTimelineShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ITimelineService, TimelineItem, TimelineProviderDescriptor, TimelineChangeEvent } from 'vs/workbench/contrib/timeline/common/timeline'; import { TimelineChangeEvent, TimelineCursor, TimelineProviderDescriptor, ITimelineService } from 'vs/workbench/contrib/timeline/common/timeline';
@extHostNamedCustomer(MainContext.MainThreadTimeline) @extHostNamedCustomer(MainContext.MainThreadTimeline)
export class MainThreadTimeline implements MainThreadTimelineShape { export class MainThreadTimeline implements MainThreadTimelineShape {
@@ -24,10 +24,6 @@ export class MainThreadTimeline implements MainThreadTimelineShape {
this._proxy = context.getProxy(ExtHostContext.ExtHostTimeline); this._proxy = context.getProxy(ExtHostContext.ExtHostTimeline);
} }
$getTimeline(uri: URI, token: CancellationToken): Promise<TimelineItem[]> {
return this._timelineService.getTimeline(uri, token);
}
$registerTimelineProvider(provider: TimelineProviderDescriptor): void { $registerTimelineProvider(provider: TimelineProviderDescriptor): void {
this.logService.trace(`MainThreadTimeline#registerTimelineProvider: id=${provider.id}`); this.logService.trace(`MainThreadTimeline#registerTimelineProvider: id=${provider.id}`);
@@ -43,8 +39,8 @@ export class MainThreadTimeline implements MainThreadTimelineShape {
this._timelineService.registerTimelineProvider({ this._timelineService.registerTimelineProvider({
...provider, ...provider,
onDidChange: onDidChange.event, onDidChange: onDidChange.event,
provideTimeline(uri: URI, token: CancellationToken) { provideTimeline(uri: URI, cursor: TimelineCursor, token: CancellationToken, options?: { cacheResults?: boolean }) {
return proxy.$getTimeline(provider.id, uri, token); return proxy.$getTimeline(provider.id, uri, cursor, token, options);
}, },
dispose() { dispose() {
emitters.delete(provider.id); emitters.delete(provider.id);

View File

@@ -134,7 +134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHostLabelService, new ExtHostLabelService(rpcProtocol)); const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHostLabelService, new ExtHostLabelService(rpcProtocol));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol)); const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol)); const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol)); const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
// Check that no named customers are missing // Check that no named customers are missing
// {{SQL CARBON EDIT}} filter out the services we don't expose // {{SQL CARBON EDIT}} filter out the services we don't expose
@@ -348,6 +348,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable { registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
return extHostLanguageFeatures.registerHoverProvider(extension, checkSelector(selector), provider, extension.identifier); return extHostLanguageFeatures.registerHoverProvider(extension, checkSelector(selector), provider, extension.identifier);
}, },
registerEvaluatableExpressionProvider(selector: vscode.DocumentSelector, provider: vscode.EvaluatableExpressionProvider): vscode.Disposable {
return extHostLanguageFeatures.registerEvaluatableExpressionProvider(extension, checkSelector(selector), provider, extension.identifier);
},
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable { registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider); return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
}, },
@@ -928,6 +931,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
DocumentLink: extHostTypes.DocumentLink, DocumentLink: extHostTypes.DocumentLink,
DocumentSymbol: extHostTypes.DocumentSymbol, DocumentSymbol: extHostTypes.DocumentSymbol,
EndOfLine: extHostTypes.EndOfLine, EndOfLine: extHostTypes.EndOfLine,
EvaluatableExpression: extHostTypes.EvaluatableExpression,
EventEmitter: Emitter, EventEmitter: Emitter,
ExtensionKind: extHostTypes.ExtensionKind, ExtensionKind: extHostTypes.ExtensionKind,
CustomExecution: extHostTypes.CustomExecution, CustomExecution: extHostTypes.CustomExecution,

View File

@@ -49,7 +49,7 @@ import { SaveReason } from 'vs/workbench/common/editor';
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelOptions } from 'vs/platform/remote/common/tunnel'; import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { TimelineItem, TimelineProviderDescriptor, TimelineChangeEvent, TimelineItemWithSource } from 'vs/workbench/contrib/timeline/common/timeline'; import { Timeline, TimelineChangeEvent, TimelineCursor, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views'; import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
@@ -357,6 +357,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerImplementationSupport(handle: number, selector: IDocumentFilterDto[]): void; $registerImplementationSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void; $registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void; $registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto): void; $registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto): void;
@@ -806,8 +807,6 @@ export interface MainThreadTimelineShape extends IDisposable {
$registerTimelineProvider(provider: TimelineProviderDescriptor): void; $registerTimelineProvider(provider: TimelineProviderDescriptor): void;
$unregisterTimelineProvider(source: string): void; $unregisterTimelineProvider(source: string): void;
$emitTimelineChangeEvent(e: TimelineChangeEvent): void; $emitTimelineChangeEvent(e: TimelineChangeEvent): void;
$getTimeline(uri: UriComponents, token: CancellationToken): Promise<TimelineItem[]>;
} }
// -- extension host // -- extension host
@@ -1213,6 +1212,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IDefinitionLinkDto[]>; $provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IDefinitionLinkDto[]>;
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IDefinitionLinkDto[]>; $provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IDefinitionLinkDto[]>;
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.Hover | undefined>; $provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.Hover | undefined>;
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined>;
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined>; $provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined>;
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<ILocationDto[] | undefined>; $provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<ILocationDto[] | undefined>;
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>; $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>;
@@ -1461,7 +1461,7 @@ export interface ExtHostTunnelServiceShape {
} }
export interface ExtHostTimelineShape { export interface ExtHostTimelineShape {
$getTimeline(source: string, uri: UriComponents, token: CancellationToken): Promise<TimelineItemWithSource[]>; $getTimeline(source: string, uri: UriComponents, cursor: TimelineCursor, token: CancellationToken, options?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
} }
// --- proxy identifiers // --- proxy identifiers

View File

@@ -276,6 +276,27 @@ class HoverAdapter {
} }
} }
class EvaluatableExpressionAdapter {
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.EvaluatableExpressionProvider,
) { }
public provideEvaluatableExpression(resource: URI, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined> {
const doc = this._documents.getDocument(resource);
const pos = typeConvert.Position.to(position);
return asPromise(() => this._provider.provideEvaluatableExpression(doc, pos, token)).then(value => {
if (value) {
return typeConvert.EvaluatableExpression.from(value);
}
return undefined;
});
}
}
class DocumentHighlightAdapter { class DocumentHighlightAdapter {
constructor( constructor(
@@ -1329,7 +1350,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter | TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter; | SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter;
class AdapterData { class AdapterData {
constructor( constructor(
@@ -1549,6 +1570,18 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return this._withAdapter(handle, HoverAdapter, adapter => adapter.provideHover(URI.revive(resource), position, token), undefined); return this._withAdapter(handle, HoverAdapter, adapter => adapter.provideHover(URI.revive(resource), position, token), undefined);
} }
// --- debug hover
registerEvaluatableExpressionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.EvaluatableExpressionProvider, extensionId?: ExtensionIdentifier): vscode.Disposable {
const handle = this._addNewAdapter(new EvaluatableExpressionAdapter(this._documents, provider), extension);
this._proxy.$registerEvaluatableExpressionProvider(handle, this._transformDocumentSelector(selector));
return this._createDisposable(handle);
}
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined> {
return this._withAdapter(handle, EvaluatableExpressionAdapter, adapter => adapter.provideEvaluatableExpression(URI.revive(resource), position, token), undefined);
}
// --- occurrences // --- occurrences
registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable { registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {

View File

@@ -7,61 +7,91 @@ import * as vscode from 'vscode';
import { UriComponents, URI } from 'vs/base/common/uri'; import { UriComponents, URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ExtHostTimelineShape, MainThreadTimelineShape, IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostTimelineShape, MainThreadTimelineShape, IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { TimelineItemWithSource, TimelineProvider } from 'vs/workbench/contrib/timeline/common/timeline'; import { Timeline, TimelineCursor, TimelineItem, TimelineProvider } from 'vs/workbench/contrib/timeline/common/timeline';
import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ThemeIcon } from 'vs/workbench/api/common/extHostTypes'; import { ThemeIcon } from 'vs/workbench/api/common/extHostTypes';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
export interface IExtHostTimeline extends ExtHostTimelineShape { export interface IExtHostTimeline extends ExtHostTimelineShape {
readonly _serviceBrand: undefined; readonly _serviceBrand: undefined;
$getTimeline(id: string, uri: UriComponents, token: vscode.CancellationToken): Promise<TimelineItemWithSource[]>; $getTimeline(id: string, uri: UriComponents, cursor: vscode.TimelineCursor, token: vscode.CancellationToken, options?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
} }
export const IExtHostTimeline = createDecorator<IExtHostTimeline>('IExtHostTimeline'); export const IExtHostTimeline = createDecorator<IExtHostTimeline>('IExtHostTimeline');
export class ExtHostTimeline implements IExtHostTimeline { export class ExtHostTimeline implements IExtHostTimeline {
private static handlePool = 0;
_serviceBrand: undefined; _serviceBrand: undefined;
private _proxy: MainThreadTimelineShape; private _proxy: MainThreadTimelineShape;
private _providers = new Map<string, TimelineProvider>(); private _providers = new Map<string, TimelineProvider>();
private _itemsBySourceByUriMap = new Map<string | undefined, Map<string, Map<string, vscode.TimelineItem>>>();
constructor( constructor(
mainContext: IMainContext, mainContext: IMainContext,
commands: ExtHostCommands,
) { ) {
this._proxy = mainContext.getProxy(MainContext.MainThreadTimeline); this._proxy = mainContext.getProxy(MainContext.MainThreadTimeline);
commands.registerArgumentProcessor({
processArgument: arg => {
if (arg && arg.$mid === 11) {
const uri = arg.uri === undefined ? undefined : URI.revive(arg.uri);
return this._itemsBySourceByUriMap.get(getUriKey(uri))?.get(arg.source)?.get(arg.handle);
}
return arg;
}
});
} }
async $getTimeline(id: string, uri: UriComponents, token: vscode.CancellationToken): Promise<TimelineItemWithSource[]> { async $getTimeline(id: string, uri: UriComponents, cursor: vscode.TimelineCursor, token: vscode.CancellationToken, options?: { cacheResults?: boolean }): Promise<Timeline | undefined> {
const provider = this._providers.get(id); const provider = this._providers.get(id);
return provider?.provideTimeline(URI.revive(uri), token) ?? []; return provider?.provideTimeline(URI.revive(uri), cursor, token, options);
} }
registerTimelineProvider(scheme: string | string[], provider: vscode.TimelineProvider, extensionId: ExtensionIdentifier, commandConverter: CommandsConverter): IDisposable { registerTimelineProvider(scheme: string | string[], provider: vscode.TimelineProvider, _extensionId: ExtensionIdentifier, commandConverter: CommandsConverter): IDisposable {
const timelineDisposables = new DisposableStore(); const timelineDisposables = new DisposableStore();
const convertTimelineItem = this.convertTimelineItem(provider.id, commandConverter, timelineDisposables); const convertTimelineItem = this.convertTimelineItem(provider.id, commandConverter, timelineDisposables).bind(this);
let disposable: IDisposable | undefined; let disposable: IDisposable | undefined;
if (provider.onDidChange) { if (provider.onDidChange) {
disposable = provider.onDidChange(this.emitTimelineChangeEvent(provider.id), this); disposable = provider.onDidChange(this.emitTimelineChangeEvent(provider.id), this);
} }
const itemsBySourceByUriMap = this._itemsBySourceByUriMap;
return this.registerTimelineProviderCore({ return this.registerTimelineProviderCore({
...provider, ...provider,
scheme: scheme, scheme: scheme,
onDidChange: undefined, onDidChange: undefined,
async provideTimeline(uri: URI, token: CancellationToken) { async provideTimeline(uri: URI, cursor: TimelineCursor, token: CancellationToken, options?: { cacheResults?: boolean }) {
timelineDisposables.clear(); timelineDisposables.clear();
const results = await provider.provideTimeline(uri, token); // For now, only allow the caching of a single Uri
if (options?.cacheResults && !itemsBySourceByUriMap.has(getUriKey(uri))) {
itemsBySourceByUriMap.clear();
}
const result = await provider.provideTimeline(uri, cursor, token);
// Intentional == we don't know how a provider will respond // Intentional == we don't know how a provider will respond
// eslint-disable-next-line eqeqeq // eslint-disable-next-line eqeqeq
return results != null if (result == null) {
? results.map(item => convertTimelineItem(item)) return undefined;
: []; }
// TODO: Determine if we should cache dependent on who calls us (internal vs external)
const convertItem = convertTimelineItem(uri, options?.cacheResults ?? false);
return {
...result,
source: provider.id,
items: result.items.map(convertItem)
};
}, },
dispose() { dispose() {
disposable?.dispose(); disposable?.dispose();
@@ -70,39 +100,72 @@ export class ExtHostTimeline implements IExtHostTimeline {
}); });
} }
private convertTimelineItem(source: string, commandConverter: CommandsConverter, disposables: DisposableStore): (item: vscode.TimelineItem) => TimelineItemWithSource { private convertTimelineItem(source: string, commandConverter: CommandsConverter, disposables: DisposableStore) {
return (item: vscode.TimelineItem) => { return (uri: URI, cacheResults: boolean) => {
const { iconPath, ...props } = item; let itemsMap: Map<string, vscode.TimelineItem> | undefined;
if (cacheResults) {
const uriKey = getUriKey(uri);
let icon; let sourceMap = this._itemsBySourceByUriMap.get(uriKey);
let iconDark; if (sourceMap === undefined) {
let themeIcon; sourceMap = new Map();
if (item.iconPath) { this._itemsBySourceByUriMap.set(uriKey, sourceMap);
if (iconPath instanceof ThemeIcon) {
themeIcon = { id: iconPath.id };
} }
else if (URI.isUri(iconPath)) {
icon = iconPath; itemsMap = sourceMap.get(source);
iconDark = iconPath; if (itemsMap === undefined) {
} itemsMap = new Map();
else { sourceMap.set(source, itemsMap);
({ light: icon, dark: iconDark } = iconPath as { light: URI; dark: URI });
} }
} }
return { return (item: vscode.TimelineItem): TimelineItem => {
...props, const { iconPath, ...props } = item;
source: source,
command: item.command ? commandConverter.toInternal(item.command, disposables) : undefined, const handle = `${source}|${item.id ?? `${item.timestamp}-${ExtHostTimeline.handlePool++}`}`;
icon: icon, itemsMap?.set(handle, item);
iconDark: iconDark,
themeIcon: themeIcon let icon;
let iconDark;
let themeIcon;
if (item.iconPath) {
if (iconPath instanceof ThemeIcon) {
themeIcon = { id: iconPath.id };
}
else if (URI.isUri(iconPath)) {
icon = iconPath;
iconDark = iconPath;
}
else {
({ light: icon, dark: iconDark } = iconPath as { light: URI; dark: URI });
}
}
return {
...props,
handle: handle,
source: source,
command: item.command ? commandConverter.toInternal(item.command, disposables) : undefined,
icon: icon,
iconDark: iconDark,
themeIcon: themeIcon
};
}; };
}; };
} }
private emitTimelineChangeEvent(id: string) { private emitTimelineChangeEvent(id: string) {
return (e: vscode.TimelineChangeEvent) => { return (e: vscode.TimelineChangeEvent) => {
// Clear caches
if (e?.uri === undefined) {
for (const sourceMap of this._itemsBySourceByUriMap.values()) {
sourceMap.get(id)?.clear();
}
}
else {
this._itemsBySourceByUriMap.get(getUriKey(e.uri))?.clear();
}
this._proxy.$emitTimelineChangeEvent({ ...e, id: id }); this._proxy.$emitTimelineChangeEvent({ ...e, id: id });
}; };
} }
@@ -123,9 +186,18 @@ export class ExtHostTimeline implements IExtHostTimeline {
this._providers.set(provider.id, provider); this._providers.set(provider.id, provider);
return toDisposable(() => { return toDisposable(() => {
for (const sourceMap of this._itemsBySourceByUriMap.values()) {
sourceMap.get(provider.id)?.clear();
}
this._providers.delete(provider.id); this._providers.delete(provider.id);
this._proxy.$unregisterTimelineProvider(provider.id); this._proxy.$unregisterTimelineProvider(provider.id);
provider.dispose(); provider.dispose();
}); });
} }
} }
function getUriKey(uri: URI | undefined): string | undefined {
return uri?.toString();
}

View File

@@ -257,7 +257,7 @@ export namespace MarkdownString {
} else if (htmlContent.isMarkdownString(markup)) { } else if (htmlContent.isMarkdownString(markup)) {
res = markup; res = markup;
} else if (typeof markup === 'string') { } else if (typeof markup === 'string') {
res = { value: <string>markup }; res = { value: markup };
} else { } else {
res = { value: '' }; res = { value: '' };
} }
@@ -737,6 +737,20 @@ export namespace Hover {
return new types.Hover(info.contents.map(MarkdownString.to), Range.to(info.range)); return new types.Hover(info.contents.map(MarkdownString.to), Range.to(info.range));
} }
} }
export namespace EvaluatableExpression {
export function from(expression: vscode.EvaluatableExpression): modes.EvaluatableExpression {
return <modes.EvaluatableExpression>{
range: Range.from(expression.range),
expression: expression.expression
};
}
export function to(info: modes.EvaluatableExpression): types.EvaluatableExpression {
return new types.EvaluatableExpression(Range.to(info.range), info.expression);
}
}
export namespace DocumentHighlight { export namespace DocumentHighlight {
export function from(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight { export function from(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight {
return { return {

View File

@@ -2283,6 +2283,17 @@ export class DebugAdapterInlineImplementation implements vscode.DebugAdapterInli
} }
} }
@es5ClassCompat
export class EvaluatableExpression implements vscode.EvaluatableExpression {
readonly range: vscode.Range;
readonly expression?: string;
constructor(range: vscode.Range, expression?: string) {
this.range = range;
this.expression = expression;
}
}
export enum LogLevel { export enum LogLevel {
Trace = 1, Trace = 1,
Debug = 2, Debug = 2,

View File

@@ -57,6 +57,8 @@ namespace schema {
case 'comments/comment/title': return MenuId.CommentTitle; case 'comments/comment/title': return MenuId.CommentTitle;
case 'comments/comment/context': return MenuId.CommentActions; case 'comments/comment/context': return MenuId.CommentActions;
case 'extension/context': return MenuId.ExtensionContext; case 'extension/context': return MenuId.ExtensionContext;
case 'timeline/title': return MenuId.TimelineTitle;
case 'timeline/item/context': return MenuId.TimelineItemContext;
} }
return undefined; return undefined;
@@ -220,6 +222,16 @@ namespace schema {
type: 'array', type: 'array',
items: menuItem items: menuItem
}, },
'timeline/title': {
description: localize('view.timelineTitle', "The Timeline view title menu"),
type: 'array',
items: menuItem
},
'timeline/item/context': {
description: localize('view.timelineContext', "The Timeline view item context menu"),
type: 'array',
items: menuItem
},
} }
}; };

View File

@@ -56,7 +56,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
//#region IView //#region IView
readonly minimumWidth: number = 420; readonly minimumWidth: number = 300;
readonly maximumWidth: number = Number.POSITIVE_INFINITY; readonly maximumWidth: number = Number.POSITIVE_INFINITY;
readonly minimumHeight: number = 77; readonly minimumHeight: number = 77;
readonly maximumHeight: number = Number.POSITIVE_INFINITY; readonly maximumHeight: number = Number.POSITIVE_INFINITY;

View File

@@ -57,12 +57,12 @@ export interface IViewContainerDescriptor {
export interface IViewContainersRegistry { export interface IViewContainersRegistry {
/** /**
* An event that is triggerred when a view container is registered. * An event that is triggered when a view container is registered.
*/ */
readonly onDidRegister: Event<{ viewContainer: ViewContainer, viewContainerLocation: ViewContainerLocation }>; readonly onDidRegister: Event<{ viewContainer: ViewContainer, viewContainerLocation: ViewContainerLocation }>;
/** /**
* An event that is triggerred when a view container is deregistered. * An event that is triggered when a view container is deregistered.
*/ */
readonly onDidDeregister: Event<{ viewContainer: ViewContainer, viewContainerLocation: ViewContainerLocation }>; readonly onDidDeregister: Event<{ viewContainer: ViewContainer, viewContainerLocation: ViewContainerLocation }>;

View File

@@ -6,7 +6,7 @@
import 'vs/css!./bulkEdit'; import 'vs/css!./bulkEdit';
import { WorkbenchAsyncDataTree, TreeResourceNavigator, IOpenEvent } from 'vs/platform/list/browser/listService'; import { WorkbenchAsyncDataTree, TreeResourceNavigator, IOpenEvent } from 'vs/platform/list/browser/listService';
import { WorkspaceEdit } from 'vs/editor/common/modes'; import { WorkspaceEdit } from 'vs/editor/common/modes';
import { BulkEditElement, BulkEditDelegate, TextEditElementRenderer, FileElementRenderer, BulkEditDataSource, BulkEditIdentityProvider, FileElement, TextEditElement, BulkEditAccessibilityProvider, BulkEditAriaProvider, CategoryElementRenderer, BulkEditNaviLabelProvider, CategoryElement } from 'vs/workbench/contrib/bulkEdit/browser/bulkEditTree'; import { BulkEditElement, BulkEditDelegate, TextEditElementRenderer, FileElementRenderer, BulkEditDataSource, BulkEditIdentityProvider, FileElement, TextEditElement, BulkEditAccessibilityProvider, BulkEditAriaProvider, CategoryElementRenderer, BulkEditNaviLabelProvider, CategoryElement, BulkEditSorter } from 'vs/workbench/contrib/bulkEdit/browser/bulkEditTree';
import { FuzzyScore } from 'vs/base/common/filters'; import { FuzzyScore } from 'vs/base/common/filters';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService'; import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService';
@@ -135,6 +135,7 @@ export class BulkEditPane extends ViewPane {
expandOnlyOnTwistieClick: true, expandOnlyOnTwistieClick: true,
multipleSelectionSupport: false, multipleSelectionSupport: false,
keyboardNavigationLabelProvider: new BulkEditNaviLabelProvider(), keyboardNavigationLabelProvider: new BulkEditNaviLabelProvider(),
sorter: new BulkEditSorter()
} }
); );

View File

@@ -99,6 +99,15 @@ export class BulkFileOperation {
this.newUri = edit.newUri; this.newUri = edit.newUri;
} }
} }
needsConfirmation(): boolean {
for (let [, edit] of this.originalEdits) {
if (!this.parent.checked.isChecked(edit)) {
return true;
}
}
return false;
}
} }
export class BulkCategory { export class BulkCategory {
@@ -230,7 +239,7 @@ export class BulkFileOperations {
} }
operationByResource.forEach(value => this.fileOperations.push(value)); operationByResource.forEach(value => this.fileOperations.push(value));
operationByCategory.forEach(value => value.metadata.needsConfirmation ? this.categories.unshift(value) : this.categories.push(value)); operationByCategory.forEach(value => this.categories.push(value));
// "correct" invalid parent-check child states that is // "correct" invalid parent-check child states that is
// unchecked file edits (rename, create, delete) uncheck // unchecked file edits (rename, create, delete) uncheck

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IAsyncDataSource, ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeSorter } from 'vs/base/browser/ui/tree/tree';
import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
@@ -24,6 +24,7 @@ import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { basename } from 'vs/base/common/resources'; import { basename } from 'vs/base/common/resources';
import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { WorkspaceFileEdit } from 'vs/editor/common/modes'; import { WorkspaceFileEdit } from 'vs/editor/common/modes';
import { compare } from 'vs/base/common/strings';
// --- VIEW MODEL // --- VIEW MODEL
@@ -248,6 +249,39 @@ export class BulkEditDataSource implements IAsyncDataSource<BulkFileOperations,
} }
} }
export class BulkEditSorter implements ITreeSorter<BulkEditElement> {
compare(a: BulkEditElement, b: BulkEditElement): number {
if (a instanceof CategoryElement && b instanceof CategoryElement) {
//
const aConfirm = BulkEditSorter._needsConfirmation(a.category);
const bConfirm = BulkEditSorter._needsConfirmation(b.category);
if (aConfirm === bConfirm) {
return a.category.metadata.label.localeCompare(b.category.metadata.label);
} else if (aConfirm) {
return -1;
} else {
return 1;
}
}
if (a instanceof FileElement && b instanceof FileElement) {
return compare(a.edit.uri.toString(), b.edit.uri.toString());
}
if (a instanceof TextEditElement && b instanceof TextEditElement) {
return Range.compareRangesUsingStarts(a.edit.textEdit.edit.range, b.edit.textEdit.edit.range);
}
return 0;
}
private static _needsConfirmation(a: BulkCategory): boolean {
return a.fileOperations.some(ops => ops.needsConfirmation());
}
}
// --- ACCESSI // --- ACCESSI
export class BulkEditAccessibilityProvider implements IAccessibilityProvider<BulkEditElement> { export class BulkEditAccessibilityProvider implements IAccessibilityProvider<BulkEditElement> {

View File

@@ -40,7 +40,7 @@ CommandsRegistry.registerCommand('_workbench.openWith', (accessor: ServicesAcces
// #region Reopen With // #region Reopen With
const REOPEN_WITH_COMMAND_ID = 'reOpenWith'; const REOPEN_WITH_COMMAND_ID = 'reOpenWith';
const REOPEN_WITH_TITLE = { value: nls.localize('reopenWith.title', 'Reopen With'), original: 'Reopen With' }; const REOPEN_WITH_TITLE = { value: nls.localize('reopenWith.title', 'Reopen With...'), original: 'Reopen With' };
KeybindingsRegistry.registerCommandAndKeybindingRule({ KeybindingsRegistry.registerCommandAndKeybindingRule({
id: REOPEN_WITH_COMMAND_ID, id: REOPEN_WITH_COMMAND_ID,
@@ -83,6 +83,17 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
when: CONTEXT_HAS_CUSTOM_EDITORS, when: CONTEXT_HAS_CUSTOM_EDITORS,
}); });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
command: {
id: REOPEN_WITH_COMMAND_ID,
title: REOPEN_WITH_TITLE,
category: viewCategory,
},
group: '3_open',
order: 20,
when: CONTEXT_HAS_CUSTOM_EDITORS,
});
// #endregion // #endregion

View File

@@ -19,7 +19,6 @@ import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel'; import { ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
import { once } from 'vs/base/common/functional'; import { once } from 'vs/base/common/functional';
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
export const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024; export const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
export const twistiePixels = 20; export const twistiePixels = 20;
@@ -233,11 +232,3 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
templateData.toDispose.dispose(); templateData.toDispose.dispose();
} }
} }
export abstract class BaseDebugViewPane extends ViewPane {
render(): void {
super.render();
dom.addClass(this.element, 'debug-pane');
}
}

View File

@@ -28,14 +28,13 @@ import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { ILabelService } from 'vs/platform/label/common/label'; import { ILabelService } from 'vs/platform/label/common/label';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Gesture } from 'vs/base/browser/touch'; import { Gesture } from 'vs/base/browser/touch';
import { IViewDescriptorService } from 'vs/workbench/common/views'; import { IViewDescriptorService } from 'vs/workbench/common/views';
import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor'; import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IOpenerService } from 'vs/platform/opener/common/opener';
import { BaseDebugViewPane } from 'vs/workbench/contrib/debug/browser/baseDebugView';
const $ = dom.$; const $ = dom.$;
@@ -54,7 +53,7 @@ export function getExpandedBodySize(model: IDebugModel): number {
return Math.min(MAX_VISIBLE_BREAKPOINTS, length) * 22; return Math.min(MAX_VISIBLE_BREAKPOINTS, length) * 22;
} }
export class BreakpointsView extends BaseDebugViewPane { export class BreakpointsView extends ViewPane {
private list!: WorkbenchList<IEnablement>; private list!: WorkbenchList<IEnablement>;
private needsRefresh = false; private needsRefresh = false;
@@ -82,6 +81,7 @@ export class BreakpointsView extends BaseDebugViewPane {
public renderBody(container: HTMLElement): void { public renderBody(container: HTMLElement): void {
super.renderBody(container); super.renderBody(container);
dom.addClass(this.element, 'debug-pane');
dom.addClass(container, 'debug-breakpoints'); dom.addClass(container, 'debug-breakpoints');
const delegate = new BreakpointsDelegate(this.debugService); const delegate = new BreakpointsDelegate(this.debugService);

View File

@@ -13,12 +13,12 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions'; import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { renderViewTree, BaseDebugViewPane } from 'vs/workbench/contrib/debug/browser/baseDebugView'; import { renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { IAction, Action } from 'vs/base/common/actions'; import { IAction, Action } from 'vs/base/common/actions';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { ILabelService } from 'vs/platform/label/common/label'; import { ILabelService } from 'vs/platform/label/common/label';
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
@@ -74,7 +74,7 @@ export function getContextForContributedActions(element: CallStackItem | null):
return ''; return '';
} }
export class CallStackView extends BaseDebugViewPane { export class CallStackView extends ViewPane {
private pauseMessage!: HTMLSpanElement; private pauseMessage!: HTMLSpanElement;
private pauseMessageLabel!: HTMLSpanElement; private pauseMessageLabel!: HTMLSpanElement;
private onCallStackChangeScheduler: RunOnceScheduler; private onCallStackChangeScheduler: RunOnceScheduler;
@@ -158,7 +158,7 @@ export class CallStackView extends BaseDebugViewPane {
renderBody(container: HTMLElement): void { renderBody(container: HTMLElement): void {
super.renderBody(container); super.renderBody(container);
dom.addClass(this.element, 'debug-pane');
dom.addClass(container, 'debug-call-stack'); dom.addClass(container, 'debug-call-stack');
const treeContainer = renderViewTree(container); const treeContainer = renderViewTree(container);

View File

@@ -136,17 +136,19 @@ function getWordToLineNumbersMap(model: ITextModel | null): Map<string, number[]
model.forceTokenization(lineNumber); model.forceTokenization(lineNumber);
const lineTokens = model.getLineTokens(lineNumber); const lineTokens = model.getLineTokens(lineNumber);
for (let tokenIndex = 0, tokenCount = lineTokens.getCount(); tokenIndex < tokenCount; tokenIndex++) { for (let tokenIndex = 0, tokenCount = lineTokens.getCount(); tokenIndex < tokenCount; tokenIndex++) {
const tokenStartOffset = lineTokens.getStartOffset(tokenIndex);
const tokenEndOffset = lineTokens.getEndOffset(tokenIndex);
const tokenType = lineTokens.getStandardTokenType(tokenIndex); const tokenType = lineTokens.getStandardTokenType(tokenIndex);
const tokenStr = lineContent.substring(tokenStartOffset, tokenEndOffset);
// Token is a word and not a comment // Token is a word and not a comment
if (tokenType === StandardTokenType.Other) { if (tokenType === StandardTokenType.Other) {
DEFAULT_WORD_REGEXP.lastIndex = 0; // We assume tokens will usually map 1:1 to words if they match DEFAULT_WORD_REGEXP.lastIndex = 0; // We assume tokens will usually map 1:1 to words if they match
const tokenStartOffset = lineTokens.getStartOffset(tokenIndex);
const tokenEndOffset = lineTokens.getEndOffset(tokenIndex);
const tokenStr = lineContent.substring(tokenStartOffset, tokenEndOffset);
const wordMatch = DEFAULT_WORD_REGEXP.exec(tokenStr); const wordMatch = DEFAULT_WORD_REGEXP.exec(tokenStr);
if (wordMatch) { if (wordMatch) {
const word = wordMatch[0]; const word = wordMatch[0];
if (!result.has(word)) { if (!result.has(word)) {
result.set(word, []); result.set(word, []);

View File

@@ -11,7 +11,7 @@ import * as dom from 'vs/base/browser/dom';
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
import { Position } from 'vs/editor/common/core/position'; import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range'; import { Range, IRange } from 'vs/editor/common/core/range';
import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDebugService, IExpression, IExpressionContainer, IStackFrame } from 'vs/workbench/contrib/debug/common/debug'; import { IDebugService, IExpression, IExpressionContainer, IStackFrame } from 'vs/workbench/contrib/debug/common/debug';
@@ -30,6 +30,8 @@ import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
import { coalesce } from 'vs/base/common/arrays'; import { coalesce } from 'vs/base/common/arrays';
import { IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; import { IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView'; import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
import { EvaluatableExpressionProviderRegistry } from 'vs/editor/common/modes';
import { CancellationToken } from 'vs/base/common/cancellation';
const $ = dom.$; const $ = dom.$;
const MAX_TREE_HEIGHT = 324; const MAX_TREE_HEIGHT = 324;
@@ -107,6 +109,7 @@ export class DebugHoverWidget implements IContentWidget {
accessibilityProvider: new DebugHoverAccessibilityProvider(), accessibilityProvider: new DebugHoverAccessibilityProvider(),
mouseSupport: false, mouseSupport: false,
horizontalScrolling: true, horizontalScrolling: true,
useShadows: false,
overrideStyles: { overrideStyles: {
listBackground: editorHoverBackground listBackground: editorHoverBackground
} }
@@ -174,18 +177,52 @@ export class DebugHoverWidget implements IContentWidget {
} }
async showAt(range: Range, focus: boolean): Promise<void> { async showAt(range: Range, focus: boolean): Promise<void> {
const pos = range.getStartPosition();
const session = this.debugService.getViewModel().focusedSession; const session = this.debugService.getViewModel().focusedSession;
if (!this.editor.hasModel()) {
if (!session || !this.editor.hasModel()) {
return Promise.resolve(this.hide()); return Promise.resolve(this.hide());
} }
const lineContent = this.editor.getModel().getLineContent(pos.lineNumber); const model = this.editor.getModel();
const { start, end } = getExactExpressionStartAndEnd(lineContent, range.startColumn, range.endColumn); const pos = range.getStartPosition();
// use regex to extract the sub-expression #9821
const matchingExpression = lineContent.substring(start - 1, end); let rng: IRange | undefined = undefined;
if (!matchingExpression || !session) { let matchingExpression: string | undefined;
if (EvaluatableExpressionProviderRegistry.has(model)) {
const supports = EvaluatableExpressionProviderRegistry.ordered(model);
const promises = supports.map(support => {
return Promise.resolve(support.provideEvaluatableExpression(model, pos, CancellationToken.None)).then(expression => {
return expression;
}, err => {
//onUnexpectedExternalError(err);
return undefined;
});
});
const results = await Promise.all(promises).then(coalesce);
if (results.length > 0) {
matchingExpression = results[0].expression;
rng = results[0].range;
if (!matchingExpression) {
const lineContent = model.getLineContent(pos.lineNumber);
matchingExpression = lineContent.substring(rng.startColumn - 1, rng.endColumn);
}
}
} else { // old one-size-fits-all strategy
const lineContent = model.getLineContent(pos.lineNumber);
const { start, end } = getExactExpressionStartAndEnd(lineContent, range.startColumn, range.endColumn);
// use regex to extract the sub-expression #9821
matchingExpression = lineContent.substring(start - 1, end);
rng = new Range(pos.lineNumber, start, pos.lineNumber, start + matchingExpression.length);
}
if (!matchingExpression) {
return Promise.resolve(this.hide()); return Promise.resolve(this.hide());
} }
@@ -202,13 +239,15 @@ export class DebugHoverWidget implements IContentWidget {
if (!expression || (expression instanceof Expression && !expression.available)) { if (!expression || (expression instanceof Expression && !expression.available)) {
this.hide(); this.hide();
return undefined; return;
} }
this.highlightDecorations = this.editor.deltaDecorations(this.highlightDecorations, [{ if (rng) {
range: new Range(pos.lineNumber, start, pos.lineNumber, start + matchingExpression.length), this.highlightDecorations = this.editor.deltaDecorations(this.highlightDecorations, [{
options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS range: rng,
}]); options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS
}]);
}
return this.doShow(pos, expression, focus); return this.doShow(pos, expression, focus);
} }

View File

@@ -7,12 +7,12 @@ import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom'; import * as dom from 'vs/base/browser/dom';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { normalize, isAbsolute, posix } from 'vs/base/common/path'; import { normalize, isAbsolute, posix } from 'vs/base/common/path';
import { IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { renderViewTree, BaseDebugViewPane } from 'vs/workbench/contrib/debug/browser/baseDebugView'; import { renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { IDebugSession, IDebugService, CONTEXT_LOADED_SCRIPTS_ITEM_TYPE } from 'vs/workbench/contrib/debug/common/debug'; import { IDebugSession, IDebugService, CONTEXT_LOADED_SCRIPTS_ITEM_TYPE } from 'vs/workbench/contrib/debug/common/debug';
import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
@@ -402,7 +402,7 @@ function asTreeElement(item: BaseTreeItem, viewState?: IViewState): ITreeElement
}; };
} }
export class LoadedScriptsView extends BaseDebugViewPane { export class LoadedScriptsView extends ViewPane {
private treeContainer!: HTMLElement; private treeContainer!: HTMLElement;
private loadedScriptsItemType: IContextKey<string>; private loadedScriptsItemType: IContextKey<string>;
@@ -435,6 +435,7 @@ export class LoadedScriptsView extends BaseDebugViewPane {
renderBody(container: HTMLElement): void { renderBody(container: HTMLElement): void {
super.renderBody(container); super.renderBody(container);
dom.addClass(this.element, 'debug-pane');
dom.addClass(container, 'debug-loaded-scripts'); dom.addClass(container, 'debug-loaded-scripts');
dom.addClass(container, 'show-file-icons'); dom.addClass(container, 'show-file-icons');

View File

@@ -75,7 +75,7 @@
/* Expressions */ /* Expressions */
.monaco-workbench .debug-viewlet .monaco-list-row .expression, .monaco-workbench .debug-pane .monaco-list-row .expression,
.monaco-workbench .debug-hover-widget .monaco-list-row .expression { .monaco-workbench .debug-hover-widget .monaco-list-row .expression {
font-size: 13px; font-size: 13px;
overflow: hidden; overflow: hidden;
@@ -84,7 +84,7 @@
white-space: pre; white-space: pre;
} }
.monaco-workbench.mac .debug-viewlet .monaco-list-row .expression, .monaco-workbench.mac .debug-pane .monaco-list-row .expression,
.monaco-workbench.mac .debug-hover-widget .monaco-list-row .expression { .monaco-workbench.mac .debug-hover-widget .monaco-list-row .expression {
font-size: 11px; font-size: 11px;
} }

View File

@@ -12,7 +12,6 @@
user-select: text; user-select: text;
-webkit-user-select: text; -webkit-user-select: text;
word-break: break-all; word-break: break-all;
padding: 4px 5px;
} }
.monaco-editor .debug-hover-widget .complex-value { .monaco-editor .debug-hover-widget .complex-value {
@@ -62,6 +61,7 @@
overflow: auto; overflow: auto;
font-family: var(--monaco-monospace-font); font-family: var(--monaco-monospace-font);
max-height: 500px; max-height: 500px;
padding: 4px 5px;
} }
.monaco-editor .debug-hover-widget .error { .monaco-editor .debug-hover-widget .error {

View File

@@ -601,7 +601,7 @@ export class RawDebugSession implements IDisposable {
private send<R extends DebugProtocol.Response>(command: string, args: any, token?: CancellationToken, timeout?: number): Promise<R> { private send<R extends DebugProtocol.Response>(command: string, args: any, token?: CancellationToken, timeout?: number): Promise<R> {
return new Promise<DebugProtocol.Response>((completeDispatch, errorDispatch) => { return new Promise<DebugProtocol.Response>((completeDispatch, errorDispatch) => {
if (!this.debugAdapter) { if (!this.debugAdapter) {
errorDispatch(new Error('no debug adapter found')); errorDispatch(new Error(nls.localize('noDebugAdapter', "No debug adapter found. Can not send '{0}'.", command)));
return; return;
} }
let cancelationListener: IDisposable; let cancelationListener: IDisposable;

View File

@@ -20,7 +20,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { equals } from 'vs/base/common/arrays'; import { equals } from 'vs/base/common/arrays';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes'; import { KeyCode } from 'vs/base/common/keyCodes';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -170,6 +170,7 @@ export class StartView extends ViewPane {
})); }));
attachButtonStyler(this.debugButton, this.themeService); attachButtonStyler(this.debugButton, this.themeService);
dom.addClass(this.element, 'debug-pane');
dom.addClass(container, 'debug-start-view'); dom.addClass(container, 'debug-start-view');
this.secondMessageContainer = $('.section'); this.secondMessageContainer = $('.section');

View File

@@ -12,12 +12,12 @@ import { IDebugService, IExpression, IScope, CONTEXT_VARIABLES_FOCUSED, IViewMod
import { Variable, Scope } from 'vs/workbench/contrib/debug/common/debugModel'; import { Variable, Scope } from 'vs/workbench/contrib/debug/common/debugModel';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { renderViewTree, renderVariable, IInputBoxOptions, AbstractExpressionsRenderer, IExpressionTemplateData, BaseDebugViewPane } from 'vs/workbench/contrib/debug/browser/baseDebugView'; import { renderViewTree, renderVariable, IInputBoxOptions, AbstractExpressionsRenderer, IExpressionTemplateData } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { IAction, Action } from 'vs/base/common/actions'; import { IAction, Action } from 'vs/base/common/actions';
import { CopyValueAction } from 'vs/workbench/contrib/debug/browser/debugActions'; import { CopyValueAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ITreeRenderer, ITreeNode, ITreeMouseEvent, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree'; import { ITreeRenderer, ITreeNode, ITreeMouseEvent, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
@@ -39,7 +39,7 @@ let forgetScopes = true;
export const variableSetEmitter = new Emitter<void>(); export const variableSetEmitter = new Emitter<void>();
export class VariablesView extends BaseDebugViewPane { export class VariablesView extends ViewPane {
private onFocusStackFrameScheduler: RunOnceScheduler; private onFocusStackFrameScheduler: RunOnceScheduler;
private needsRefresh = false; private needsRefresh = false;
@@ -90,6 +90,7 @@ export class VariablesView extends BaseDebugViewPane {
renderBody(container: HTMLElement): void { renderBody(container: HTMLElement): void {
super.renderBody(container); super.renderBody(container);
dom.addClass(this.element, 'debug-pane');
dom.addClass(container, 'debug-variables'); dom.addClass(container, 'debug-variables');
const treeContainer = renderViewTree(container); const treeContainer = renderViewTree(container);

View File

@@ -16,9 +16,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IAction, Action } from 'vs/base/common/actions'; import { IAction, Action } from 'vs/base/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { renderExpressionValue, renderViewTree, IInputBoxOptions, AbstractExpressionsRenderer, IExpressionTemplateData, BaseDebugViewPane } from 'vs/workbench/contrib/debug/browser/baseDebugView'; import { renderExpressionValue, renderViewTree, IInputBoxOptions, AbstractExpressionsRenderer, IExpressionTemplateData } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
@@ -38,7 +38,7 @@ const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
let ignoreVariableSetEmitter = false; let ignoreVariableSetEmitter = false;
let useCachedEvaluation = false; let useCachedEvaluation = false;
export class WatchExpressionsView extends BaseDebugViewPane { export class WatchExpressionsView extends ViewPane {
private onWatchExpressionsUpdatedScheduler: RunOnceScheduler; private onWatchExpressionsUpdatedScheduler: RunOnceScheduler;
private needsRefresh = false; private needsRefresh = false;
@@ -67,6 +67,7 @@ export class WatchExpressionsView extends BaseDebugViewPane {
renderBody(container: HTMLElement): void { renderBody(container: HTMLElement): void {
super.renderBody(container); super.renderBody(container);
dom.addClass(this.element, 'debug-pane');
dom.addClass(container, 'debug-watch'); dom.addClass(container, 'debug-watch');
const treeContainer = renderViewTree(container); const treeContainer = renderViewTree(container);

View File

@@ -676,7 +676,11 @@ export class ExplorerView extends ViewPane {
if (item.isDisposed) { if (item.isDisposed) {
return this.onSelectResource(resource, reveal, retry + 1); return this.onSelectResource(resource, reveal, retry + 1);
} }
this.tree.reveal(item, 0.5);
// Don't scroll to the item if it's already visible
if (this.tree.getRelativeTop(item) === null) {
this.tree.reveal(item, 0.5);
}
} }
this.tree.setFocus([item]); this.tree.setFocus([item]);

View File

@@ -29,13 +29,13 @@ export class OpenInDesktopIndicator extends Disposable implements IWorkbenchCont
) { ) {
super(); super();
const links = environmentService.options?.applicationLinkProvider?.(); const links = environmentService.options?.applicationLinks;
if (Array.isArray(links) && links?.length > 0) { if (Array.isArray(links) && links?.length > 0) {
this.installOpenInDesktopIndicator(links); this.installOpenInDesktopIndicator(links);
} }
} }
private installOpenInDesktopIndicator(links: IApplicationLink[]): void { private installOpenInDesktopIndicator(links: readonly IApplicationLink[]): void {
// Register action to trigger "Open In Desktop" // Register action to trigger "Open In Desktop"
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions); const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
@@ -71,7 +71,7 @@ export class OpenInDesktopAction extends Action {
} }
async run(): Promise<boolean> { async run(): Promise<boolean> {
const links = this.environmentService.options?.applicationLinkProvider?.(); const links = this.environmentService.options?.applicationLinks;
if (Array.isArray(links)) { if (Array.isArray(links)) {
if (links.length === 1) { if (links.length === 1) {
return this.openApplicationLink(links[0]); return this.openApplicationLink(links[0]);
@@ -83,7 +83,7 @@ export class OpenInDesktopAction extends Action {
return true; return true;
} }
private async runWithPicker(links: IApplicationLink[]): Promise<boolean> { private async runWithPicker(links: readonly IApplicationLink[]): Promise<boolean> {
// Show a picker with choices // Show a picker with choices
const quickPick = this.quickInputService.createQuickPick<IApplicationLink>(); const quickPick = this.quickInputService.createQuickPick<IApplicationLink>();

View File

@@ -27,7 +27,7 @@ import { localize } from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IResourceInput, TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor'; import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { WorkbenchDataTree } from 'vs/platform/list/browser/listService'; import { WorkbenchDataTree } from 'vs/platform/list/browser/listService';
@@ -37,7 +37,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { CollapseAction } from 'vs/workbench/browser/viewlet'; import { CollapseAction } from 'vs/workbench/browser/viewlet';
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { OutlineConfigKeys, OutlineViewFocused, OutlineViewFiltered } from 'vs/editor/contrib/documentSymbols/outline'; import { OutlineConfigKeys, OutlineViewFocused, OutlineViewFiltered } from 'vs/editor/contrib/documentSymbols/outline';
import { FuzzyScore } from 'vs/base/common/filters'; import { FuzzyScore } from 'vs/base/common/filters';
import { OutlineDataSource, OutlineItemComparator, OutlineSortOrder, OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItem, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineFilter } from 'vs/editor/contrib/documentSymbols/outlineTree'; import { OutlineDataSource, OutlineItemComparator, OutlineSortOrder, OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItem, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineFilter } from 'vs/editor/contrib/documentSymbols/outlineTree';
@@ -49,6 +49,7 @@ import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDeco
import { MarkerSeverity } from 'vs/platform/markers/common/markers'; import { MarkerSeverity } from 'vs/platform/markers/common/markers';
import { IViewDescriptorService } from 'vs/workbench/common/views'; import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
class RequestState { class RequestState {
@@ -261,7 +262,7 @@ export class OutlinePane extends ViewPane {
@IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IThemeService private readonly _themeService: IThemeService, @IThemeService private readonly _themeService: IThemeService,
@IStorageService private readonly _storageService: IStorageService, @IStorageService private readonly _storageService: IStorageService,
@IEditorService private readonly _editorService: IEditorService, @ICodeEditorService private readonly _editorService: ICodeEditorService,
@IMarkerDecorationsService private readonly _markerDecorationService: IMarkerDecorationsService, @IMarkerDecorationsService private readonly _markerDecorationService: IMarkerDecorationsService,
@IConfigurationService private readonly _configurationService: IConfigurationService, @IConfigurationService private readonly _configurationService: IConfigurationService,
@IKeybindingService keybindingService: IKeybindingService, @IKeybindingService keybindingService: IKeybindingService,
@@ -347,7 +348,7 @@ export class OutlinePane extends ViewPane {
this._disposables.push(this._tree); this._disposables.push(this._tree);
this._disposables.push(this._outlineViewState.onDidChange(this._onDidChangeUserState, this)); this._disposables.push(this._outlineViewState.onDidChange(this._onDidChangeUserState, this));
this._disposables.push(this.viewDescriptorService.onDidChangeLocation(({ views, from, to }) => { this._disposables.push(this.viewDescriptorService.onDidChangeLocation(({ views }) => {
if (views.some(v => v.id === this.id)) { if (views.some(v => v.id === this.id)) {
this._tree.updateOptions({ overrideStyles: { listBackground: this.getBackgroundColor() } }); this._tree.updateOptions({ overrideStyles: { listBackground: this.getBackgroundColor() } });
} }
@@ -629,15 +630,18 @@ export class OutlinePane extends ViewPane {
} }
private async _revealTreeSelection(model: OutlineModel, element: OutlineElement, focus: boolean, aside: boolean): Promise<void> { private async _revealTreeSelection(model: OutlineModel, element: OutlineElement, focus: boolean, aside: boolean): Promise<void> {
await this._editorService.openCodeEditor(
await this._editorService.openEditor({ {
resource: model.textModel.uri, resource: model.textModel.uri,
options: { options: {
preserveFocus: !focus, preserveFocus: !focus,
selection: Range.collapseToStart(element.symbol.selectionRange), selection: Range.collapseToStart(element.symbol.selectionRange),
selectionRevealType: TextEditorSelectionRevealType.NearTop, selectionRevealType: TextEditorSelectionRevealType.NearTop,
} }
} as IResourceInput, aside ? SIDE_GROUP : ACTIVE_GROUP); },
this._editorService.getActiveCodeEditor(),
aside
);
} }
private _revealEditorSelection(model: OutlineModel, selection: Selection): void { private _revealEditorSelection(model: OutlineModel, selection: Selection): void {

View File

@@ -29,7 +29,7 @@ import { SelectionHighlighter } from 'vs/editor/contrib/multicursor/multicursor'
import * as nls from 'vs/nls'; import * as nls from 'vs/nls';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService, IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
@@ -984,7 +984,7 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
private static _getContributions(): IEditorContributionDescription[] { private static _getContributions(): IEditorContributionDescription[] {
const skipContributions = [FoldingController.ID, SelectionHighlighter.ID, FindController.ID]; const skipContributions = [FoldingController.ID, SelectionHighlighter.ID, FindController.ID];
const contributions = EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1); const contributions = EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1);
contributions.push({ id: DefaultSettingsEditorContribution.ID, ctor: DefaultSettingsEditorContribution }); contributions.push({ id: DefaultSettingsEditorContribution.ID, ctor: DefaultSettingsEditorContribution as IConstructorSignature1<ICodeEditor, editorCommon.IEditorContribution> });
return contributions; return contributions;
} }

View File

@@ -15,7 +15,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { RunOnceScheduler } from 'vs/base/common/async'; import { RunOnceScheduler } from 'vs/base/common/async';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { isEqual } from 'vs/base/common/resources'; import { isEqual } from 'vs/base/common/resources';
import { isMacintosh, isNative } from 'vs/base/common/platform'; import { isMacintosh, isNative, isLinux } from 'vs/base/common/platform';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
@@ -26,6 +26,7 @@ interface IConfiguration extends IWindowsConfiguration {
telemetry: { enableCrashReporter: boolean }; telemetry: { enableCrashReporter: boolean };
workbench: { list: { horizontalScrolling: boolean } }; workbench: { list: { horizontalScrolling: boolean } };
debug: { console: { wordWrap: boolean } }; debug: { console: { wordWrap: boolean } };
editor: { accessibilitySupport: 'on' | 'off' | 'auto' };
} }
export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution { export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution {
@@ -38,6 +39,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo
private enableCrashReporter: boolean | undefined; private enableCrashReporter: boolean | undefined;
private treeHorizontalScrolling: boolean | undefined; private treeHorizontalScrolling: boolean | undefined;
private debugConsoleWordWrap: boolean | undefined; private debugConsoleWordWrap: boolean | undefined;
private accessibilitySupport: 'on' | 'off' | 'auto' | undefined;
constructor( constructor(
@IHostService private readonly hostService: IHostService, @IHostService private readonly hostService: IHostService,
@@ -103,6 +105,14 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo
this.enableCrashReporter = config.telemetry.enableCrashReporter; this.enableCrashReporter = config.telemetry.enableCrashReporter;
changed = true; changed = true;
} }
// On linux turning on accessibility support will also pass this flag to the chrome renderer, thus a restart is required
if (isLinux && typeof config.editor?.accessibilitySupport === 'string' && config.editor.accessibilitySupport !== this.accessibilitySupport) {
this.accessibilitySupport = config.editor.accessibilitySupport;
if (this.accessibilitySupport === 'on') {
changed = true;
}
}
} }
// Notify only when changed and we are the focused window (avoids notification spam across windows) // Notify only when changed and we are the focused window (avoids notification spam across windows)

View File

@@ -13,3 +13,20 @@
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
} }
.timeline-tree-view .monaco-list .monaco-list-row .custom-view-tree-node-item .monaco-icon-label {
flex: 1;
text-overflow: ellipsis;
overflow: hidden;
}
.timeline-tree-view .monaco-list .monaco-list-row .custom-view-tree-node-item .timeline-timestamp-container {
margin-left: 2px;
margin-right: 4px;
text-overflow: ellipsis;
overflow: hidden;
}
.timeline-tree-view .monaco-list .monaco-list-row .custom-view-tree-node-item .timeline-timestamp-container .timeline-timestamp {
opacity: 0.5;
}

View File

@@ -8,11 +8,11 @@ import { localize } from 'vs/nls';
import * as DOM from 'vs/base/browser/dom'; import * as DOM from 'vs/base/browser/dom';
import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { DisposableStore } from 'vs/base/common/lifecycle'; import { DisposableStore, IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { IListVirtualDelegate, IIdentityProvider, IKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/list/list'; import { IListVirtualDelegate, IIdentityProvider, IKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/list/list';
import { ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; import { ITreeNode, ITreeRenderer, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { TreeResourceNavigator, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; import { TreeResourceNavigator, WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -20,7 +20,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TimelineItem, ITimelineService, TimelineChangeEvent, TimelineProvidersChangeEvent, TimelineRequest, TimelineItemWithSource } from 'vs/workbench/contrib/timeline/common/timeline'; import { ITimelineService, TimelineChangeEvent, TimelineProvidersChangeEvent, TimelineRequest, TimelineItem } from 'vs/workbench/contrib/timeline/common/timeline';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { SideBySideEditor, toResource } from 'vs/workbench/common/editor'; import { SideBySideEditor, toResource } from 'vs/workbench/common/editor';
import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommandService } from 'vs/platform/commands/common/commands';
@@ -31,10 +31,20 @@ import { IProgressService } from 'vs/platform/progress/common/progress';
import { VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; import { VIEWLET_ID } from 'vs/workbench/contrib/files/common/files';
import { debounce } from 'vs/base/common/decorators'; import { debounce } from 'vs/base/common/decorators';
import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IActionViewItemProvider, ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, ActionRunner } from 'vs/base/common/actions';
import { ContextAwareMenuEntryActionViewItem, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { MenuItemAction, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { fromNow } from 'vs/base/common/date';
// TODO[ECA]: Localize all the strings
type TreeElement = TimelineItem; type TreeElement = TimelineItem;
// TODO[ECA]: Localize all the strings interface TimelineActionContext {
uri: URI | undefined;
item: TreeElement;
}
export class TimelinePane extends ViewPane { export class TimelinePane extends ViewPane {
static readonly ID = 'timeline'; static readonly ID = 'timeline';
@@ -44,10 +54,12 @@ export class TimelinePane extends ViewPane {
private _messageElement!: HTMLDivElement; private _messageElement!: HTMLDivElement;
private _treeElement!: HTMLDivElement; private _treeElement!: HTMLDivElement;
private _tree!: WorkbenchObjectTree<TreeElement, FuzzyScore>; private _tree!: WorkbenchObjectTree<TreeElement, FuzzyScore>;
private _treeRenderer: TimelineTreeRenderer | undefined;
private _menus: TimelineMenus;
private _visibilityDisposables: DisposableStore | undefined; private _visibilityDisposables: DisposableStore | undefined;
// private _excludedSources: Set<string> | undefined; // private _excludedSources: Set<string> | undefined;
private _items: TimelineItemWithSource[] = []; private _items: TimelineItem[] = [];
private _loadingMessageTimer: any | undefined; private _loadingMessageTimer: any | undefined;
private _pendingRequests = new Map<string, TimelineRequest>(); private _pendingRequests = new Map<string, TimelineRequest>();
private _uri: URI | undefined; private _uri: URI | undefined;
@@ -67,7 +79,9 @@ export class TimelinePane extends ViewPane {
@IOpenerService openerService: IOpenerService, @IOpenerService openerService: IOpenerService,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
) { ) {
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService); super({ ...options, titleMenuId: MenuId.TimelineTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService);
this._menus = this._register(this.instantiationService.createInstance(TimelineMenus, this.id));
const scopedContextKeyService = this._register(this.contextKeyService.createScoped()); const scopedContextKeyService = this._register(this.contextKeyService.createScoped());
scopedContextKeyService.createKey('view', TimelinePane.ID); scopedContextKeyService.createKey('view', TimelinePane.ID);
@@ -88,6 +102,7 @@ export class TimelinePane extends ViewPane {
} }
this._uri = uri; this._uri = uri;
this._treeRenderer?.setUri(uri);
this.loadTimeline(); this.loadTimeline();
} }
@@ -187,7 +202,7 @@ export class TimelinePane extends ViewPane {
let request = this._pendingRequests.get(source); let request = this._pendingRequests.get(source);
request?.tokenSource.dispose(true); request?.tokenSource.dispose(true);
request = this.timelineService.getTimelineRequest(source, this._uri, new CancellationTokenSource())!; request = this.timelineService.getTimeline(source, this._uri, {}, new CancellationTokenSource(), { cacheResults: true })!;
this._pendingRequests.set(source, request); this._pendingRequests.set(source, request);
request.tokenSource.token.onCancellationRequested(() => this._pendingRequests.delete(source)); request.tokenSource.token.onCancellationRequested(() => this._pendingRequests.delete(source));
@@ -199,7 +214,7 @@ export class TimelinePane extends ViewPane {
private async handleRequest(request: TimelineRequest) { private async handleRequest(request: TimelineRequest) {
let items; let items;
try { try {
items = await this.progressService.withProgress({ location: VIEWLET_ID }, () => request.items); items = await this.progressService.withProgress({ location: VIEWLET_ID }, () => request.result.then(r => r?.items ?? []));
} }
catch { } catch { }
@@ -211,7 +226,7 @@ export class TimelinePane extends ViewPane {
this.replaceItems(request.source, items); this.replaceItems(request.source, items);
} }
private replaceItems(source: string, items?: TimelineItemWithSource[]) { private replaceItems(source: string, items?: TimelineItem[]) {
const hasItems = this._items.length !== 0; const hasItems = this._items.length !== 0;
if (items?.length) { if (items?.length) {
@@ -291,17 +306,20 @@ export class TimelinePane extends ViewPane {
// DOM.addClass(this._treeElement, 'show-file-icons'); // DOM.addClass(this._treeElement, 'show-file-icons');
container.appendChild(this._treeElement); container.appendChild(this._treeElement);
const renderer = this.instantiationService.createInstance(TimelineTreeRenderer); this._treeRenderer = this.instantiationService.createInstance(TimelineTreeRenderer, this._menus);
this._tree = <WorkbenchObjectTree<TreeElement, FuzzyScore>>this.instantiationService.createInstance(WorkbenchObjectTree, 'TimelinePane', this._treeElement, new TimelineListVirtualDelegate(), [renderer], { this._tree = <WorkbenchObjectTree<TreeElement, FuzzyScore>>this.instantiationService.createInstance(WorkbenchObjectTree, 'TimelinePane',
this._treeElement, new TimelineListVirtualDelegate(), [this._treeRenderer], {
identityProvider: new TimelineIdentityProvider(), identityProvider: new TimelineIdentityProvider(),
keyboardNavigationLabelProvider: new TimelineKeyboardNavigationLabelProvider(), keyboardNavigationLabelProvider: new TimelineKeyboardNavigationLabelProvider(),
overrideStyles: { overrideStyles: {
listBackground: this.getBackgroundColor() listBackground: this.getBackgroundColor(),
} }
}); });
const customTreeNavigator = new TreeResourceNavigator(this._tree, { openOnFocus: false, openOnSelection: false }); const customTreeNavigator = new TreeResourceNavigator(this._tree, { openOnFocus: false, openOnSelection: false });
this._register(customTreeNavigator); this._register(customTreeNavigator);
this._register(this._tree.onContextMenu(e => this.onContextMenu(this._menus, e)));
this._register( this._register(
customTreeNavigator.onDidOpenResource(e => { customTreeNavigator.onDidOpenResource(e => {
if (!e.browserEvent) { if (!e.browserEvent) {
@@ -316,36 +334,112 @@ export class TimelinePane extends ViewPane {
}) })
); );
} }
}
export class TimelineElementTemplate { private onContextMenu(menus: TimelineMenus, treeEvent: ITreeContextMenuEvent<TreeElement | null>): void {
static readonly id = 'TimelineElementTemplate'; const item = treeEvent.element;
if (item === null) {
return;
}
const event: UIEvent = treeEvent.browserEvent;
constructor( event.preventDefault();
readonly container: HTMLElement, event.stopPropagation();
readonly iconLabel: IconLabel,
readonly icon: HTMLElement
) { }
}
export class TimelineIdentityProvider implements IIdentityProvider<TimelineItem> { this._tree.setFocus([item]);
getId(item: TimelineItem): { toString(): string } { const actions = menus.getResourceContextActions(item);
return `${item.id}|${item.timestamp}`; if (!actions.length) {
return;
}
this.contextMenuService.showContextMenu({
getAnchor: () => treeEvent.anchor,
getActions: () => actions,
getActionViewItem: (action) => {
const keybinding = this.keybindingService.lookupKeybinding(action.id);
if (keybinding) {
return new ActionViewItem(action, action, { label: true, keybinding: keybinding.getLabel() });
}
return undefined;
},
onHide: (wasCancelled?: boolean) => {
if (wasCancelled) {
this._tree.domFocus();
}
},
getActionsContext: (): TimelineActionContext => ({ uri: this._uri, item: item }),
actionRunner: new TimelineActionRunner()
});
} }
} }
export class TimelineKeyboardNavigationLabelProvider implements IKeyboardNavigationLabelProvider<TimelineItem> { export class TimelineElementTemplate implements IDisposable {
getKeyboardNavigationLabel(element: TimelineItem): { toString(): string } { static readonly id = 'TimelineElementTemplate';
readonly actionBar: ActionBar;
readonly icon: HTMLElement;
readonly iconLabel: IconLabel;
readonly timestamp: HTMLSpanElement;
constructor(
readonly container: HTMLElement,
actionViewItemProvider: IActionViewItemProvider
) {
DOM.addClass(container, 'custom-view-tree-node-item');
this.icon = DOM.append(container, DOM.$('.custom-view-tree-node-item-icon'));
this.iconLabel = new IconLabel(container, { supportHighlights: true, supportCodicons: true });
const timestampContainer = DOM.append(this.iconLabel.element, DOM.$('.timeline-timestamp-container'));
this.timestamp = DOM.append(timestampContainer, DOM.$('span.timeline-timestamp'));
const actionsContainer = DOM.append(this.iconLabel.element, DOM.$('.actions'));
this.actionBar = new ActionBar(actionsContainer, { actionViewItemProvider: actionViewItemProvider });
}
dispose() {
this.iconLabel.dispose();
this.actionBar.dispose();
}
reset() {
this.actionBar.clear();
}
}
export class TimelineIdentityProvider implements IIdentityProvider<TreeElement> {
getId(item: TreeElement): { toString(): string } {
return item.handle;
}
}
class TimelineActionRunner extends ActionRunner {
runAction(action: IAction, { uri, item }: TimelineActionContext): Promise<any> {
return action.run(...[
{
$mid: 11,
handle: item.handle,
source: item.source,
uri: uri
},
uri,
item.source,
]);
}
}
export class TimelineKeyboardNavigationLabelProvider implements IKeyboardNavigationLabelProvider<TreeElement> {
getKeyboardNavigationLabel(element: TreeElement): { toString(): string } {
return element.label; return element.label;
} }
} }
export class TimelineListVirtualDelegate implements IListVirtualDelegate<TimelineItem> { export class TimelineListVirtualDelegate implements IListVirtualDelegate<TreeElement> {
getHeight(_element: TimelineItem): number { getHeight(_element: TreeElement): number {
return 22; return 22;
} }
getTemplateId(element: TimelineItem): string { getTemplateId(element: TreeElement): string {
return TimelineElementTemplate.id; return TimelineElementTemplate.id;
} }
} }
@@ -353,14 +447,25 @@ export class TimelineListVirtualDelegate implements IListVirtualDelegate<Timelin
class TimelineTreeRenderer implements ITreeRenderer<TreeElement, FuzzyScore, TimelineElementTemplate> { class TimelineTreeRenderer implements ITreeRenderer<TreeElement, FuzzyScore, TimelineElementTemplate> {
readonly templateId: string = TimelineElementTemplate.id; readonly templateId: string = TimelineElementTemplate.id;
constructor(@IThemeService private _themeService: IThemeService) { } private _actionViewItemProvider: IActionViewItemProvider;
constructor(
private readonly _menus: TimelineMenus,
@IInstantiationService protected readonly instantiationService: IInstantiationService,
@IThemeService private _themeService: IThemeService
) {
this._actionViewItemProvider = (action: IAction) => action instanceof MenuItemAction
? this.instantiationService.createInstance(ContextAwareMenuEntryActionViewItem, action)
: undefined;
}
private _uri: URI | undefined;
setUri(uri: URI | undefined) {
this._uri = uri;
}
renderTemplate(container: HTMLElement): TimelineElementTemplate { renderTemplate(container: HTMLElement): TimelineElementTemplate {
DOM.addClass(container, 'custom-view-tree-node-item'); return new TimelineElementTemplate(container, this._actionViewItemProvider);
const icon = DOM.append(container, DOM.$('.custom-view-tree-node-item-icon'));
const iconLabel = new IconLabel(container, { supportHighlights: true, supportCodicons: true });
return new TimelineElementTemplate(container, iconLabel, icon);
} }
renderElement( renderElement(
@@ -369,30 +474,74 @@ class TimelineTreeRenderer implements ITreeRenderer<TreeElement, FuzzyScore, Tim
template: TimelineElementTemplate, template: TimelineElementTemplate,
height: number | undefined height: number | undefined
): void { ): void {
const { element } = node; template.reset();
const icon = this._themeService.getTheme().type === LIGHT ? element.icon : element.iconDark; const { element: item } = node;
const icon = this._themeService.getTheme().type === LIGHT ? item.icon : item.iconDark;
const iconUrl = icon ? URI.revive(icon) : null; const iconUrl = icon ? URI.revive(icon) : null;
if (iconUrl) { if (iconUrl) {
template.icon.className = 'custom-view-tree-node-item-icon'; template.icon.className = 'custom-view-tree-node-item-icon';
template.icon.style.backgroundImage = DOM.asCSSUrl(iconUrl); template.icon.style.backgroundImage = DOM.asCSSUrl(iconUrl);
} else { } else {
let iconClass: string | undefined; let iconClass: string | undefined;
if (element.themeIcon /*&& !this.isFileKindThemeIcon(element.themeIcon)*/) { if (item.themeIcon /*&& !this.isFileKindThemeIcon(element.themeIcon)*/) {
iconClass = ThemeIcon.asClassName(element.themeIcon); iconClass = ThemeIcon.asClassName(item.themeIcon);
} }
template.icon.className = iconClass ? `custom-view-tree-node-item-icon ${iconClass}` : ''; template.icon.className = iconClass ? `custom-view-tree-node-item-icon ${iconClass}` : '';
} }
template.iconLabel.setLabel(element.label, element.description, { template.iconLabel.setLabel(item.label, item.description, {
title: element.detail, title: item.detail,
matches: createMatches(node.filterData) matches: createMatches(node.filterData)
}); });
template.timestamp.textContent = fromNow(item.timestamp);
template.actionBar.context = { uri: this._uri, item: item } as TimelineActionContext;
template.actionBar.actionRunner = new TimelineActionRunner();
template.actionBar.push(this._menus.getResourceActions(item), { icon: true, label: false });
} }
disposeTemplate(template: TimelineElementTemplate): void { disposeTemplate(template: TimelineElementTemplate): void {
template.iconLabel.dispose(); template.iconLabel.dispose();
} }
} }
class TimelineMenus extends Disposable {
constructor(
private id: string,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IMenuService private readonly menuService: IMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService
) {
super();
}
getResourceActions(element: TreeElement): IAction[] {
return this.getActions(MenuId.TimelineItemContext, { key: 'timelineItem', value: element.contextValue }).primary;
}
getResourceContextActions(element: TreeElement): IAction[] {
return this.getActions(MenuId.TimelineItemContext, { key: 'timelineItem', value: element.contextValue }).secondary;
}
private getActions(menuId: MenuId, context: { key: string, value?: string }): { primary: IAction[]; secondary: IAction[]; } {
const contextKeyService = this.contextKeyService.createScoped();
contextKeyService.createKey('view', this.id);
contextKeyService.createKey(context.key, context.value);
const menu = this.menuService.createMenu(menuId, contextKeyService);
const primary: IAction[] = [];
const secondary: IAction[] = [];
const result = { primary, secondary };
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => /^inline/.test(g));
menu.dispose();
contextKeyService.dispose();
return result;
}
}

View File

@@ -16,9 +16,11 @@ export function toKey(extension: ExtensionIdentifier | string, source: string) {
} }
export interface TimelineItem { export interface TimelineItem {
handle: string;
source: string;
timestamp: number; timestamp: number;
label: string; label: string;
id?: string;
icon?: URI, icon?: URI,
iconDark?: URI, iconDark?: URI,
themeIcon?: { id: string }, themeIcon?: { id: string },
@@ -28,19 +30,29 @@ export interface TimelineItem {
contextValue?: string; contextValue?: string;
} }
export interface TimelineItemWithSource extends TimelineItem {
source: string;
}
export interface TimelineChangeEvent { export interface TimelineChangeEvent {
id: string; id: string;
uri?: URI; uri?: URI;
} }
export interface TimelineCursor {
cursor?: any;
before?: boolean;
limit?: number;
}
export interface Timeline {
source: string;
items: TimelineItem[];
cursor?: any;
more?: boolean;
}
export interface TimelineProvider extends TimelineProviderDescriptor, IDisposable { export interface TimelineProvider extends TimelineProviderDescriptor, IDisposable {
onDidChange?: Event<TimelineChangeEvent>; onDidChange?: Event<TimelineChangeEvent>;
provideTimeline(uri: URI, token: CancellationToken): Promise<TimelineItemWithSource[]>; provideTimeline(uri: URI, cursor: TimelineCursor, token: CancellationToken, options?: { cacheResults?: boolean }): Promise<Timeline | undefined>;
} }
export interface TimelineProviderDescriptor { export interface TimelineProviderDescriptor {
@@ -55,7 +67,7 @@ export interface TimelineProvidersChangeEvent {
} }
export interface TimelineRequest { export interface TimelineRequest {
readonly items: Promise<TimelineItemWithSource[]>; readonly result: Promise<Timeline | undefined>;
readonly source: string; readonly source: string;
readonly tokenSource: CancellationTokenSource; readonly tokenSource: CancellationTokenSource;
readonly uri: URI; readonly uri: URI;
@@ -72,9 +84,7 @@ export interface ITimelineService {
getSources(): string[]; getSources(): string[];
getTimeline(uri: URI, token: CancellationToken): Promise<TimelineItem[]>; getTimeline(id: string, uri: URI, cursor: TimelineCursor, tokenSource: CancellationTokenSource, options?: { cacheResults?: boolean }): TimelineRequest | undefined;
getTimelineRequest(id: string, uri: URI, tokenSource: CancellationTokenSource): TimelineRequest | undefined;
} }
const TIMELINE_SERVICE_ID = 'timeline'; const TIMELINE_SERVICE_ID = 'timeline';

View File

@@ -3,13 +3,13 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle'; import { IDisposable } from 'vs/base/common/lifecycle';
// import { basename } from 'vs/base/common/path'; // import { basename } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { ITimelineService, TimelineProvider, TimelineItem, TimelineChangeEvent, TimelineProvidersChangeEvent } from './timeline'; import { ITimelineService, TimelineChangeEvent, TimelineCursor, TimelineProvidersChangeEvent, TimelineProvider } from './timeline';
export class TimelineService implements ITimelineService { export class TimelineService implements ITimelineService {
_serviceBrand: undefined; _serviceBrand: undefined;
@@ -81,42 +81,7 @@ export class TimelineService implements ITimelineService {
return [...this._providers.keys()]; return [...this._providers.keys()];
} }
async getTimeline(uri: URI, token: CancellationToken, predicate?: (provider: TimelineProvider) => boolean) { getTimeline(id: string, uri: URI, cursor: TimelineCursor, tokenSource: CancellationTokenSource, options?: { cacheResults?: boolean }) {
this.logService.trace(`TimelineService#getTimeline(${uri.toString(true)})`);
const requests: Promise<[string, TimelineItem[]]>[] = [];
for (const provider of this._providers.values()) {
if (typeof provider.scheme === 'string') {
if (provider.scheme !== '*' && provider.scheme !== uri.scheme) {
continue;
}
} else if (!provider.scheme.includes(uri.scheme)) {
continue;
}
if (!(predicate?.(provider) ?? true)) {
continue;
}
requests.push(provider.provideTimeline(uri, token).then(p => [provider.id, p]));
}
const timelines = await Promise.all(requests);
const timeline = [];
for (const [source, items] of timelines) {
if (items.length === 0) {
continue;
}
timeline.push(...items.map(item => ({ ...item, source: source })));
}
timeline.sort((a, b) => b.timestamp - a.timestamp);
return timeline;
}
getTimelineRequest(id: string, uri: URI, tokenSource: CancellationTokenSource) {
this.logService.trace(`TimelineService#getTimeline(${id}): uri=${uri.toString(true)}`); this.logService.trace(`TimelineService#getTimeline(${id}): uri=${uri.toString(true)}`);
const provider = this._providers.get(id); const provider = this._providers.get(id);
@@ -133,12 +98,16 @@ export class TimelineService implements ITimelineService {
} }
return { return {
items: provider.provideTimeline(uri, tokenSource.token) result: provider.provideTimeline(uri, cursor, tokenSource.token, options)
.then(items => { .then(result => {
items = items.map(item => ({ ...item, source: provider.id })); if (result === undefined) {
items.sort((a, b) => (b.timestamp - a.timestamp) || b.source.localeCompare(a.source, undefined, { numeric: true, sensitivity: 'base' })); return undefined;
}
return items; result.items = result.items.map(item => ({ ...item, source: provider.id }));
result.items.sort((a, b) => (b.timestamp - a.timestamp) || b.source.localeCompare(a.source, undefined, { numeric: true, sensitivity: 'base' }));
return result;
}), }),
source: provider.id, source: provider.id,
tokenSource: tokenSource, tokenSource: tokenSource,

View File

@@ -127,41 +127,41 @@ export class ProductContribution implements IWorkbenchContribution {
@IHostService hostService: IHostService, @IHostService hostService: IHostService,
@IProductService productService: IProductService @IProductService productService: IProductService
) { ) {
if (!hostService.hasFocus) { hostService.hadLastFocus().then(hadLastFocus => {
return; if (!hadLastFocus) {
} return;
}
const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, '');
const shouldShowReleaseNotes = configurationService.getValue<boolean>('update.showReleaseNotes'); const shouldShowReleaseNotes = configurationService.getValue<boolean>('update.showReleaseNotes');
// was there an update? if so, open release notes // was there an update? if so, open release notes
const releaseNotesUrl = productService.releaseNotesUrl; const releaseNotesUrl = productService.releaseNotesUrl;
if (shouldShowReleaseNotes && !environmentService.args['skip-release-notes'] && releaseNotesUrl && lastVersion && productService.version !== lastVersion && productService.quality === 'stable') { // {{SQL CARBON EDIT}} Only show release notes for stable build if (shouldShowReleaseNotes && !environmentService.args['skip-release-notes'] && releaseNotesUrl && lastVersion && productService.version !== lastVersion && productService.quality === 'stable') { // {{SQL CARBON EDIT}} Only show release notes for stable build) {
/* // {{SQL CARBON EDIT}} Prompt user to open release notes in browser until we can get ADS release notes from the web /*showReleaseNotes(instantiationService, productService.version) {{SQL CARBON EDIT}} Prompt user to open release notes in browser until we can get ADS release notes from the web
showReleaseNotes(instantiationService, productService.version) .then(undefined, () => {*/
.then(undefined, () => { notificationService.prompt(
*/ severity.Info,
notificationService.prompt( nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", productService.nameLong, productService.version),
severity.Info, [{
nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", productService.nameLong, productService.version), label: nls.localize('releaseNotes', "Release Notes"),
[{ run: () => {
label: nls.localize('releaseNotes', "Release Notes"), const uri = URI.parse(releaseNotesUrl);
run: () => { openerService.open(uri);
const uri = URI.parse(releaseNotesUrl); }
openerService.open(uri); }],
} { sticky: true }
}], );
{ sticky: true } }/*);
); }*/
// }); // {{SQL CARBON EDIT}}
}
// should we show the new license? // should we show the new license?
if (productService.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(productService.version, '>=1.0.0')) { if (productService.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(productService.version, '>=1.0.0')) {
notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", productService.licenseUrl)); notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", productService.licenseUrl));
} }
storageService.store(ProductContribution.KEY, productService.version, StorageScope.GLOBAL); storageService.store(ProductContribution.KEY, productService.version, StorageScope.GLOBAL);
});
} }
} }

View File

@@ -286,4 +286,10 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
this.element.style.pointerEvents = ''; this.element.style.pointerEvents = '';
} }
} }
public selectAll() {
if (this.element) {
this._send('execCommand', 'selectAll');
}
}
} }

View File

@@ -187,6 +187,7 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd
showFind(): void { this.withWebview(webview => webview.showFind()); } showFind(): void { this.withWebview(webview => webview.showFind()); }
hideFind(): void { this.withWebview(webview => webview.hideFind()); } hideFind(): void { this.withWebview(webview => webview.hideFind()); }
runFindAction(previous: boolean): void { this.withWebview(webview => webview.runFindAction(previous)); } runFindAction(previous: boolean): void { this.withWebview(webview => webview.runFindAction(previous)); }
selectAll(): void { this.withWebview(webview => webview.selectAll()); }
public getInnerWebview() { public getInnerWebview() {
return this._webview.value; return this._webview.value;

View File

@@ -232,23 +232,23 @@
* @param {MouseEvent} event * @param {MouseEvent} event
*/ */
const handleAuxClick = const handleAuxClick =
(event) => { (event) => {
// Prevent middle clicks opening a broken link in the browser // Prevent middle clicks opening a broken link in the browser
if (!event.view || !event.view.document) { if (!event.view || !event.view.document) {
return; return;
}
if (event.button === 1) {
let node = /** @type {any} */ (event.target);
while (node) {
if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) {
event.preventDefault();
break;
}
node = node.parentNode;
} }
}
}; if (event.button === 1) {
let node = /** @type {any} */ (event.target);
while (node) {
if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) {
event.preventDefault();
break;
}
node = node.parentNode;
}
}
};
/** /**
* @param {KeyboardEvent} e * @param {KeyboardEvent} e
@@ -449,6 +449,10 @@
}, 0); }, 0);
}); });
/**
* @param {Document} contentDocument
* @param {Window} contentWindow
*/
const onLoad = (contentDocument, contentWindow) => { const onLoad = (contentDocument, contentWindow) => {
if (contentDocument && contentDocument.body) { if (contentDocument && contentDocument.body) {
// Workaround for https://github.com/Microsoft/vscode/issues/12865 // Workaround for https://github.com/Microsoft/vscode/issues/12865
@@ -492,10 +496,12 @@
}, 200); }, 200);
newFrame.contentWindow.addEventListener('load', function (e) { newFrame.contentWindow.addEventListener('load', function (e) {
const contentDocument = /** @type {Document} */ (e.target);
if (loadTimeout) { if (loadTimeout) {
clearTimeout(loadTimeout); clearTimeout(loadTimeout);
loadTimeout = undefined; loadTimeout = undefined;
onLoad(e.target, this); onLoad(contentDocument, this);
} }
}); });
@@ -539,6 +545,13 @@
initData.initialScrollProgress = progress; initData.initialScrollProgress = progress;
}); });
host.onMessage('execCommand', (_event, data) => {
const target = getActiveFrame();
if (!target) {
return;
}
target.contentDocument.execCommand(data);
});
trackFocus({ trackFocus({
onFocus: () => host.postMessage('did-focus'), onFocus: () => host.postMessage('did-focus'),

View File

@@ -14,7 +14,7 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
import { webviewDeveloperCategory } from 'vs/workbench/contrib/webview/browser/webview'; import { webviewDeveloperCategory } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory'; import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory';
import { HideWebViewEditorFindCommand, ReloadWebviewAction, ShowWebViewEditorFindWidgetAction, WebViewEditorFindNextCommand, WebViewEditorFindPreviousCommand } from '../browser/webviewCommands'; import { HideWebViewEditorFindCommand, ReloadWebviewAction, ShowWebViewEditorFindWidgetAction, WebViewEditorFindNextCommand, WebViewEditorFindPreviousCommand, SelectAllWebviewEditorCommand } from '../browser/webviewCommands';
import { WebviewEditor } from './webviewEditor'; import { WebviewEditor } from './webviewEditor';
import { WebviewInput } from './webviewEditorInput'; import { WebviewInput } from './webviewEditorInput';
import { IWebviewWorkbenchService, WebviewEditorService } from './webviewWorkbenchService'; import { IWebviewWorkbenchService, WebviewEditorService } from './webviewWorkbenchService';
@@ -50,6 +50,11 @@ registerAction2(class extends WebViewEditorFindPreviousCommand {
constructor() { super(webviewActiveContextKeyExpr); } constructor() { super(webviewActiveContextKeyExpr); }
}); });
registerAction2(class extends SelectAllWebviewEditorCommand {
constructor() { super(webviewActiveContextKeyExpr); }
});
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions); const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
actionRegistry.registerWorkbenchAction( actionRegistry.registerWorkbenchAction(
SyncActionDescriptor.create(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL), SyncActionDescriptor.create(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL),

View File

@@ -93,6 +93,8 @@ export interface Webview extends IDisposable {
hideFind(): void; hideFind(): void;
runFindAction(previous: boolean): void; runFindAction(previous: boolean): void;
selectAll(): void;
windowDidDragStart(): void; windowDidDragStart(): void;
windowDidDragEnd(): void; windowDidDragEnd(): void;
} }

View File

@@ -13,6 +13,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/contrib/webview/browser/webview'; import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor'; import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
export class ShowWebViewEditorFindWidgetAction extends Action2 { export class ShowWebViewEditorFindWidgetAction extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.showFind'; public static readonly ID = 'editor.action.webvieweditor.showFind';
@@ -97,6 +98,29 @@ export class WebViewEditorFindPreviousCommand extends Action2 {
getActiveWebviewEditor(accessor)?.find(true); getActiveWebviewEditor(accessor)?.find(true);
} }
} }
export class SelectAllWebviewEditorCommand extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.selectAll';
public static readonly LABEL = nls.localize('editor.action.webvieweditor.selectAll', 'Select all');
constructor(contextKeyExpr: ContextKeyExpr) {
const precondition = ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey));
super({
id: SelectAllWebviewEditorCommand.ID,
title: SelectAllWebviewEditorCommand.LABEL,
keybinding: {
when: precondition,
primary: KeyMod.CtrlCmd | KeyCode.KEY_A,
weight: KeybindingWeight.EditorContrib
}
});
}
public run(accessor: ServicesAccessor, args: any): void {
getActiveWebviewEditor(accessor)?.selectAll();
}
}
export class ReloadWebviewAction extends Action { export class ReloadWebviewAction extends Action {
static readonly ID = 'workbench.action.webview.reloadWebviewAction'; static readonly ID = 'workbench.action.webview.reloadWebviewAction';
static readonly LABEL = nls.localize('refreshWebviewLabel', "Reload Webviews"); static readonly LABEL = nls.localize('refreshWebviewLabel', "Reload Webviews");

View File

@@ -15,7 +15,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, Webview, WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview'; import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -71,31 +71,33 @@ export class WebviewEditor extends BaseEditor {
} }
public showFind() { public showFind() {
this.withWebview(webview => { if (this.webview) {
webview.showFind(); this.webview.showFind();
this._findWidgetVisible.set(true); this._findWidgetVisible.set(true);
}); }
} }
public hideFind() { public hideFind() {
this._findWidgetVisible.reset(); this._findWidgetVisible.reset();
this.withWebview(webview => webview.hideFind()); this.webview?.hideFind();
} }
public find(previous: boolean) { public find(previous: boolean) {
this.withWebview(webview => { this.webview?.runFindAction(previous);
webview.runFindAction(previous); }
});
public selectAll() {
this.webview?.selectAll();
} }
public reload() { public reload() {
this.withWebview(webview => webview.reload()); this.webview?.reload();
} }
public layout(dimension: DOM.Dimension): void { public layout(dimension: DOM.Dimension): void {
this._dimension = dimension; this._dimension = dimension;
if (this.input && this.input instanceof WebviewInput) { if (this.webview) {
this.synchronizeWebviewContainerDimensions(this.input.webview, dimension); this.synchronizeWebviewContainerDimensions(this.webview, dimension);
} }
} }
@@ -109,22 +111,19 @@ export class WebviewEditor extends BaseEditor {
} }
}); });
} }
this.withWebview(webview => webview.focus()); this.webview?.focus();
} }
public withWebview(f: (element: Webview) => void): void { public get webview(): WebviewEditorOverlay | undefined {
if (this.input && this.input instanceof WebviewInput) { return this.input instanceof WebviewInput ? this.input.webview : undefined;
f(this.input.webview);
}
} }
protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void { protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void {
if (this.input instanceof WebviewInput) { if (this.input instanceof WebviewInput && this.webview) {
const webview = this.input.webview;
if (visible) { if (visible) {
webview.claim(this); this.webview.claim(this);
} else { } else {
webview.release(this); this.webview.release(this);
} }
this.claimWebview(this.input); this.claimWebview(this.input);
} }
@@ -132,8 +131,8 @@ export class WebviewEditor extends BaseEditor {
} }
public clearInput() { public clearInput() {
if (this.input && this.input instanceof WebviewInput) { if (this.webview) {
this.input.webview.release(this); this.webview.release(this);
this._webviewVisibleDisposables.clear(); this._webviewVisibleDisposables.clear();
} }
@@ -145,8 +144,8 @@ export class WebviewEditor extends BaseEditor {
return; return;
} }
if (this.input && this.input instanceof WebviewInput) { if (this.webview) {
this.input.webview.release(this); this.webview.release(this);
} }
await super.setInput(input, options, token); await super.setInput(input, options, token);
@@ -189,15 +188,11 @@ export class WebviewEditor extends BaseEditor {
} }
this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.DRAG_START, () => { this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.DRAG_START, () => {
if (this.input instanceof WebviewInput) { this.webview?.windowDidDragStart();
this.input.webview.windowDidDragStart();
}
})); }));
const onDragEnd = () => { const onDragEnd = () => {
if (this.input instanceof WebviewInput) { this.webview?.windowDidDragEnd();
this.input.webview.windowDidDragEnd();
}
}; };
this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.DRAG_END, onDragEnd)); this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.DRAG_END, onDragEnd));
this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.MOUSE_MOVE, currentEvent => { this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.MOUSE_MOVE, currentEvent => {

View File

@@ -26,8 +26,6 @@ actionRegistry.registerWorkbenchAction(
function registerWebViewCommands(editorId: string): void { function registerWebViewCommands(editorId: string): void {
const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', editorId), ContextKeyExpr.not('editorFocus') /* https://github.com/Microsoft/vscode/issues/58668 */)!; const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', editorId), ContextKeyExpr.not('editorFocus') /* https://github.com/Microsoft/vscode/issues/58668 */)!;
registerAction2(class extends webviewCommands.SelectAllWebviewEditorCommand { constructor() { super(contextKeyExpr); } });
// These commands are only needed on MacOS where we have to disable the menu bar commands // These commands are only needed on MacOS where we have to disable the menu bar commands
if (isMacintosh) { if (isMacintosh) {
registerAction2(class extends webviewCommands.CopyWebviewEditorCommand { constructor() { super(contextKeyExpr); } }); registerAction2(class extends webviewCommands.CopyWebviewEditorCommand { constructor() { super(contextKeyExpr); } });

View File

@@ -38,28 +38,6 @@ export class OpenWebviewDeveloperToolsAction extends Action {
} }
} }
export class SelectAllWebviewEditorCommand extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.selectAll';
public static readonly LABEL = nls.localize('editor.action.webvieweditor.selectAll', 'Select all');
constructor(contextKeyExpr: ContextKeyExpr) {
const precondition = ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey));
super({
id: SelectAllWebviewEditorCommand.ID,
title: SelectAllWebviewEditorCommand.LABEL,
keybinding: {
when: precondition,
primary: KeyMod.CtrlCmd | KeyCode.KEY_A,
weight: KeybindingWeight.EditorContrib
}
});
}
public run(accessor: ServicesAccessor, args: any): void {
withActiveWebviewBasedWebview(accessor, webview => webview.selectAll());
}
}
export class CopyWebviewEditorCommand extends Action2 { export class CopyWebviewEditorCommand extends Action2 {
public static readonly ID = 'editor.action.webvieweditor.copy'; public static readonly ID = 'editor.action.webvieweditor.copy';
public static readonly LABEL = nls.localize('editor.action.webvieweditor.copy', "Copy2"); public static readonly LABEL = nls.localize('editor.action.webvieweditor.copy', "Copy2");
@@ -77,7 +55,7 @@ export class CopyWebviewEditorCommand extends Action2 {
} }
public run(accessor: ServicesAccessor): void { public run(accessor: ServicesAccessor): void {
withActiveWebviewBasedWebview(accessor, webview => webview.copy()); getActiveWebviewBasedWebview(accessor)?.copy();
} }
} }
@@ -98,7 +76,7 @@ export class PasteWebviewEditorCommand extends Action2 {
} }
public run(accessor: ServicesAccessor): void { public run(accessor: ServicesAccessor): void {
withActiveWebviewBasedWebview(accessor, webview => webview.paste()); getActiveWebviewBasedWebview(accessor)?.paste();
} }
} }
@@ -119,7 +97,7 @@ export class CutWebviewEditorCommand extends Action2 {
} }
public run(accessor: ServicesAccessor): void { public run(accessor: ServicesAccessor): void {
withActiveWebviewBasedWebview(accessor, webview => webview.cut()); getActiveWebviewBasedWebview(accessor)?.cut();
} }
} }
@@ -140,7 +118,7 @@ export class UndoWebviewEditorCommand extends Action2 {
} }
public run(accessor: ServicesAccessor, args: any): void { public run(accessor: ServicesAccessor, args: any): void {
withActiveWebviewBasedWebview(accessor, webview => webview.undo()); getActiveWebviewBasedWebview(accessor)?.undo();
} }
} }
@@ -163,22 +141,24 @@ export class RedoWebviewEditorCommand extends Action2 {
} }
public run(accessor: ServicesAccessor, args: any): void { public run(accessor: ServicesAccessor, args: any): void {
withActiveWebviewBasedWebview(accessor, webview => webview.redo()); getActiveWebviewBasedWebview(accessor)?.redo();
} }
} }
function withActiveWebviewBasedWebview(accessor: ServicesAccessor, f: (webview: ElectronWebviewBasedWebview) => void): void { function getActiveWebviewBasedWebview(accessor: ServicesAccessor): ElectronWebviewBasedWebview | undefined {
const webViewEditor = getActiveWebviewEditor(accessor); const webview = getActiveWebviewEditor(accessor)?.webview;
if (webViewEditor) { if (!webview) {
webViewEditor.withWebview(webview => { return undefined;
if (webview instanceof ElectronWebviewBasedWebview) {
f(webview);
} else if ((webview as WebviewEditorOverlay).getInnerWebview) {
const innerWebview = (webview as WebviewEditorOverlay).getInnerWebview();
if (innerWebview instanceof ElectronWebviewBasedWebview) {
f(innerWebview);
}
}
});
} }
if (webview instanceof ElectronWebviewBasedWebview) {
return webview;
} else if ((webview as WebviewEditorOverlay).getInnerWebview) {
const innerWebview = (webview as WebviewEditorOverlay).getInnerWebview();
if (innerWebview instanceof ElectronWebviewBasedWebview) {
return innerWebview;
}
}
return undefined;
} }

View File

@@ -22,6 +22,7 @@ import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench
import { IElectronService } from 'vs/platform/electron/node/electron'; import { IElectronService } from 'vs/platform/electron/node/electron';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import product from 'vs/platform/product/common/product'; import product from 'vs/platform/product/common/product';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; // {{SQL CARBON EDIT}} add import import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; // {{SQL CARBON EDIT}} add import
@@ -333,8 +334,7 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten
(function registerJSONSchemas(): void { (function registerJSONSchemas(): void {
const argvDefinitionFileSchemaId = 'vscode://schemas/argv'; const argvDefinitionFileSchemaId = 'vscode://schemas/argv';
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution); const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
const schema: IJSONSchema = {
jsonRegistry.registerSchema(argvDefinitionFileSchemaId, {
id: argvDefinitionFileSchemaId, id: argvDefinitionFileSchemaId,
allowComments: true, allowComments: true,
allowTrailingCommas: true, allowTrailingCommas: true,
@@ -355,5 +355,13 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten
description: nls.localize('argv.disableColorCorrectRendering', 'Resolves issues around color profile selection. ONLY change this option if you encounter graphic issues.') description: nls.localize('argv.disableColorCorrectRendering', 'Resolves issues around color profile selection. ONLY change this option if you encounter graphic issues.')
} }
} }
}); };
if (isLinux) {
schema.properties!['force-renderer-accessibility'] = {
type: 'boolean',
description: nls.localize('argv.force-renderer-accessibility', 'Forces the renderer to be accessible. ONLY change this if you are using a screen reader on Linux. On other platforms the renderer will automatically be accessible. This flag is automatically set if you have editor.accessibilitySupport: on.'),
};
}
jsonRegistry.registerSchema(argvDefinitionFileSchemaId, schema);
})(); })();

View File

@@ -4,13 +4,18 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { isWindows } from 'vs/base/common/platform'; import { isWindows, isLinux } from 'vs/base/common/platform';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { AccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; import { AccessibilityService } from 'vs/platform/accessibility/common/accessibilityService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
interface AccessibilityMetrics { interface AccessibilityMetrics {
enabled: boolean; enabled: boolean;
@@ -65,3 +70,22 @@ export class NodeAccessibilityService extends AccessibilityService implements IA
} }
registerSingleton(IAccessibilityService, NodeAccessibilityService, true); registerSingleton(IAccessibilityService, NodeAccessibilityService, true);
// On linux we do not automatically detect that a screen reader is detected, thus we have to implicitly notify the renderer to enable accessibility when user configures it in settings
class LinuxAccessibilityContribution implements IWorkbenchContribution {
constructor(
@IJSONEditingService jsonEditingService: IJSONEditingService,
@IAccessibilityService accessibilityService: AccessibilityService,
@IEnvironmentService environmentService: IEnvironmentService
) {
accessibilityService.onDidChangeScreenReaderOptimized(async () => {
if (accessibilityService.isScreenReaderOptimized()) {
await jsonEditingService.write(environmentService.argvResource, [{ key: 'force-renderer-accessibility', value: true }], true);
}
});
}
}
if (isLinux) {
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LinuxAccessibilityContribution, LifecyclePhase.Ready);
}

View File

@@ -95,6 +95,10 @@ export class BrowserHostService extends Disposable implements IHostService {
return document.hasFocus(); return document.hasFocus();
} }
async hadLastFocus(): Promise<boolean> {
return true;
}
async focus(): Promise<void> { async focus(): Promise<void> {
window.focus(); window.focus();
} }

View File

@@ -25,6 +25,11 @@ export interface IHostService {
*/ */
readonly hasFocus: boolean; readonly hasFocus: boolean;
/**
* Find out if the window had the last focus.
*/
hadLastFocus(): Promise<boolean>;
/** /**
* Attempt to bring the window to the foreground and focus it. * Attempt to bring the window to the foreground and focus it.
*/ */

View File

@@ -36,6 +36,16 @@ export class DesktopHostService extends Disposable implements IHostService {
return document.hasFocus(); return document.hasFocus();
} }
async hadLastFocus(): Promise<boolean> {
const activeWindowId = await this.electronService.getActiveWindowId();
if (typeof activeWindowId === 'undefined') {
return false;
}
return activeWindowId === this.electronEnvironmentService.windowId;
}
openWindow(options?: IOpenEmptyWindowOptions): Promise<void>; openWindow(options?: IOpenEmptyWindowOptions): Promise<void>;
openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise<void>; openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise<void>;
openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise<void> { openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise<void> {

View File

@@ -79,7 +79,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
private lastResolvedFileStat: IFileStatWithMetadata | undefined; private lastResolvedFileStat: IFileStatWithMetadata | undefined;
private readonly saveSequentializer = new TaskSequentializer(); private readonly saveSequentializer = new TaskSequentializer();
private lastSaveAttemptTime = 0;
private dirty = false; private dirty = false;
private inConflictMode = false; private inConflictMode = false;
@@ -553,16 +552,15 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
return false; // if model is in save conflict or error, do not save unless save reason is explicit return false; // if model is in save conflict or error, do not save unless save reason is explicit
} }
// Actually do save and log
this.logService.trace('[text file model] save() - enter', this.resource.toString()); this.logService.trace('[text file model] save() - enter', this.resource.toString());
await this.doSave(options); await this.doSave(options);
this.logService.trace('[text file model] save() - exit', this.resource.toString()); this.logService.trace('[text file model] save() - exit', this.resource.toString());
return true; return true;
} }
private doSave(options: ITextFileSaveOptions): Promise<void> { private async doSave(options: ITextFileSaveOptions): Promise<void> {
if (typeof options.reason !== 'number') { if (typeof options.reason !== 'number') {
options.reason = SaveReason.EXPLICIT; options.reason = SaveReason.EXPLICIT;
} }
@@ -587,7 +585,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
if (!options.force && !this.dirty) { if (!options.force && !this.dirty) {
this.logService.trace(`[text file model] doSave(${versionId}) - exit - because not dirty and/or versionId is different (this.isDirty: ${this.dirty}, this.versionId: ${this.versionId})`, this.resource.toString()); this.logService.trace(`[text file model] doSave(${versionId}) - exit - because not dirty and/or versionId is different (this.isDirty: ${this.dirty}, this.versionId: ${this.versionId})`, this.resource.toString());
return Promise.resolve(); return;
} }
// Return if currently saving by storing this save request as the next save that should happen. // Return if currently saving by storing this save request as the next save that should happen.
@@ -618,26 +616,22 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
this.textEditorModel.pushStackElement(); this.textEditorModel.pushStackElement();
} }
// A save participant can still change the model now and since we are so close to saving
// we do not want to trigger another auto save or similar, so we block this
// In addition we update our version right after in case it changed because of a model change
//
// Save participants can also be skipped through API.
const saveParticipantCancellation = new CancellationTokenSource(); const saveParticipantCancellation = new CancellationTokenSource();
let saveParticipantPromise: Promise<number> = Promise.resolve(versionId);
if (this.isResolved() && this.textFileService.saveParticipant && !options.skipSaveParticipants) {
const onCompleteOrError = () => {
this.ignoreDirtyOnModelContentChange = false;
return this.versionId; return (this.saveSequentializer as TaskSequentializer).setPending(versionId, (async () => { // {{SQL CARBON EDIT}} strict-null-checks
};
this.ignoreDirtyOnModelContentChange = true; // A save participant can still change the model now and since we are so close to saving
saveParticipantPromise = this.textFileService.saveParticipant.participate(this, { reason: options.reason }, saveParticipantCancellation.token).then(onCompleteOrError, onCompleteOrError); // we do not want to trigger another auto save or similar, so we block this
} // In addition we update our version right after in case it changed because of a model change
//
// mark the save participant as current pending save operation // Save participants can also be skipped through API.
return (this.saveSequentializer as TaskSequentializer).setPending(versionId, saveParticipantPromise.then(newVersionId => { // {{SQL CARBON EDIT}} strict-null-check if (this.isResolved() && this.textFileService.saveParticipant && !options.skipSaveParticipants) {
try {
await this.textFileService.saveParticipant.participate(this, { reason: options.reason ?? SaveReason.EXPLICIT }, saveParticipantCancellation.token);
} catch (error) {
// Ignore
}
}
// We have to protect against being disposed at this point. It could be that the save() operation // We have to protect against being disposed at this point. It could be that the save() operation
// was triggerd followed by a dispose() operation right after without waiting. Typically we cannot // was triggerd followed by a dispose() operation right after without waiting. Typically we cannot
@@ -661,32 +655,39 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
// - the model is not dirty (otherwise we know there are changed which needs to go to the file) // - the model is not dirty (otherwise we know there are changed which needs to go to the file)
// - the model is not in orphan mode (because in that case we know the file does not exist on disk) // - the model is not in orphan mode (because in that case we know the file does not exist on disk)
// - the model version did not change due to save participants running // - the model version did not change due to save participants running
if (options.force && !this.dirty && !this.inOrphanMode && options.reason === SaveReason.EXPLICIT && versionId === newVersionId) { if (options.force && !this.dirty && !this.inOrphanMode && options.reason === SaveReason.EXPLICIT && versionId === this.versionId) {
return this.doTouch(newVersionId, options.reason); return this.doTouch(this.versionId, options.reason);
} }
// update versionId with its new value (if pre-save changes happened) // update versionId with its new value (if pre-save changes happened)
versionId = newVersionId; versionId = this.versionId;
// Clear error flag since we are trying to save again // Clear error flag since we are trying to save again
this.inErrorMode = false; this.inErrorMode = false;
// Remember when this model was saved last // Save to Disk. We mark the save operation as currently pending with
this.lastSaveAttemptTime = Date.now(); // the latest versionId because it might have changed from a save
// participant triggering
// Save to Disk
// mark the save operation as currently pending with the versionId (it might have changed from a save participant triggering)
this.logService.trace(`[text file model] doSave(${versionId}) - before write()`, this.resource.toString()); this.logService.trace(`[text file model] doSave(${versionId}) - before write()`, this.resource.toString());
const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat); const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat);
return this.saveSequentializer.setPending(newVersionId, this.textFileService.write(lastResolvedFileStat.resource, this.createSnapshot(), { const textFileEdiorModel = this;
overwriteReadonly: options.overwriteReadonly, return this.saveSequentializer.setPending(versionId, (async () => {
overwriteEncoding: options.overwriteEncoding, try {
mtime: lastResolvedFileStat.mtime, const stat = await this.textFileService.write(lastResolvedFileStat.resource, textFileEdiorModel.createSnapshot(), {
encoding: this.getEncoding(), overwriteReadonly: options.overwriteReadonly,
etag: (options.ignoreModifiedSince || !this.filesConfigurationService.preventSaveConflicts(lastResolvedFileStat.resource, this.getMode())) ? ETAG_DISABLED : lastResolvedFileStat.etag, overwriteEncoding: options.overwriteEncoding,
writeElevated: options.writeElevated mtime: lastResolvedFileStat.mtime,
}).then(stat => this.handleSaveSuccess(stat, versionId, options), error => this.handleSaveError(error, versionId, options))); encoding: this.getEncoding(),
}), () => saveParticipantCancellation.cancel()); etag: (options.ignoreModifiedSince || !this.filesConfigurationService.preventSaveConflicts(lastResolvedFileStat.resource, textFileEdiorModel.getMode())) ? ETAG_DISABLED : lastResolvedFileStat.etag,
writeElevated: options.writeElevated
});
this.handleSaveSuccess(stat, versionId, options);
} catch (error) {
this.handleSaveError(error, versionId, options);
}
})());
})(), () => saveParticipantCancellation.cancel());
} }
private handleSaveSuccess(stat: IFileStatWithMetadata, versionId: number, options: ITextFileSaveOptions): void { private handleSaveSuccess(stat: IFileStatWithMetadata, versionId: number, options: ITextFileSaveOptions): void {
@@ -733,19 +734,24 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
private doTouch(this: TextFileEditorModel & IResolvedTextFileEditorModel, versionId: number, reason: SaveReason): Promise<void> { private doTouch(this: TextFileEditorModel & IResolvedTextFileEditorModel, versionId: number, reason: SaveReason): Promise<void> {
const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat); const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat);
return this.saveSequentializer.setPending(versionId, this.textFileService.write(lastResolvedFileStat.resource, this.createSnapshot(), {
mtime: lastResolvedFileStat.mtime,
encoding: this.getEncoding(),
etag: lastResolvedFileStat.etag
}).then(stat => {
// Updated resolved stat with updated stat since touching it might have changed mtime return this.saveSequentializer.setPending(versionId, (async () => {
this.updateLastResolvedFileStat(stat); try {
const stat = await this.textFileService.write(lastResolvedFileStat.resource, this.createSnapshot(), {
mtime: lastResolvedFileStat.mtime,
encoding: this.getEncoding(),
etag: lastResolvedFileStat.etag
});
// Emit File Saved Event // Updated resolved stat with updated stat since touching it might have changed mtime
this._onDidSave.fire(reason); this.updateLastResolvedFileStat(stat);
}, error => onUnexpectedError(error) /* just log any error but do not notify the user since the file was not dirty */)); // Emit File Saved Event
this._onDidSave.fire(reason);
} catch (error) {
onUnexpectedError(error); // just log any error but do not notify the user since the file was not dirty
}
})());
} }
private updateSavedVersionId(): void { private updateSavedVersionId(): void {
@@ -776,10 +782,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
//#endregion //#endregion
getLastSaveAttemptTime(): number {
return this.lastSaveAttemptTime;
}
hasState(state: ModelState): boolean { hasState(state: ModelState): boolean {
switch (state) { switch (state) {
case ModelState.CONFLICT: case ModelState.CONFLICT:

View File

@@ -84,7 +84,13 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
// to have a size of 2 (1 running load and 1 queued load). // to have a size of 2 (1 running load and 1 queued load).
const queue = this.modelLoadQueue.queueFor(model.resource); const queue = this.modelLoadQueue.queueFor(model.resource);
if (queue.size <= 1) { if (queue.size <= 1) {
queue.queue(() => model.load().then(undefined, onUnexpectedError)); queue.queue(async () => {
try {
await model.load();
} catch (error) {
onUnexpectedError(error);
}
});
} }
} }

View File

@@ -120,7 +120,6 @@ suite('Files - TextFileEditorModel', () => {
await pendingSave; await pendingSave;
assert.ok(model.getLastSaveAttemptTime() <= Date.now());
assert.ok(model.hasState(ModelState.SAVED)); assert.ok(model.hasState(ModelState.SAVED));
assert.ok(!model.isDirty()); assert.ok(!model.isDirty());
assert.ok(savedEvent); assert.ok(savedEvent);
@@ -488,8 +487,6 @@ suite('Files - TextFileEditorModel', () => {
assert.ok(!accessor.textFileService.isDirty(toResource.call(this, '/path/index_async2.txt'))); assert.ok(!accessor.textFileService.isDirty(toResource.call(this, '/path/index_async2.txt')));
assert.ok(assertIsDefined(model1.getStat()).mtime > m1Mtime); assert.ok(assertIsDefined(model1.getStat()).mtime > m1Mtime);
assert.ok(assertIsDefined(model2.getStat()).mtime > m2Mtime); assert.ok(assertIsDefined(model2.getStat()).mtime > m2Mtime);
assert.ok(model1.getLastSaveAttemptTime() > m1Mtime);
assert.ok(model2.getLastSaveAttemptTime() > m2Mtime);
model1.dispose(); model1.dispose();
model2.dispose(); model2.dispose();
@@ -506,12 +503,11 @@ suite('Files - TextFileEditorModel', () => {
}); });
accessor.textFileService.saveParticipant = { accessor.textFileService.saveParticipant = {
participate: model => { participate: async model => {
assert.ok(model.isDirty()); assert.ok(model.isDirty());
model.textEditorModel!.setValue('bar'); model.textEditorModel!.setValue('bar');
assert.ok(model.isDirty()); assert.ok(model.isDirty());
eventCounter++; eventCounter++;
return Promise.resolve();
} }
}; };
@@ -545,8 +541,8 @@ suite('Files - TextFileEditorModel', () => {
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
accessor.textFileService.saveParticipant = { accessor.textFileService.saveParticipant = {
participate: (model) => { participate: async model => {
return Promise.reject(new Error('boom')); new Error('boom');
} }
}; };
@@ -563,10 +559,9 @@ suite('Files - TextFileEditorModel', () => {
let participations: boolean[] = []; let participations: boolean[] = [];
accessor.textFileService.saveParticipant = { accessor.textFileService.saveParticipant = {
participate: (model) => { participate: async model => {
return timeout(10).then(() => { await timeout(10);
participations.push(true); participations.push(true);
});
} }
}; };
@@ -586,4 +581,49 @@ suite('Files - TextFileEditorModel', () => {
assert.equal(participations.length, 1); assert.equal(participations.length, 1);
model.dispose(); model.dispose();
}); });
test('Save Participant, calling save from within is unsupported but does not explode (sync save)', async function () {
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
await testSaveFromSaveParticipant(model, false);
model.dispose();
});
test('Save Participant, calling save from within is unsupported but does not explode (async save)', async function () {
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
await testSaveFromSaveParticipant(model, true);
model.dispose();
});
async function testSaveFromSaveParticipant(model: TextFileEditorModel, async: boolean): Promise<void> {
let savePromise: Promise<boolean>;
let breakLoop = false;
accessor.textFileService.saveParticipant = {
participate: async model => {
if (breakLoop) {
return;
}
breakLoop = true;
if (async) {
await timeout(10);
}
const newSavePromise = model.save();
// assert that this is the same promise as the outer one
assert.equal(savePromise, newSavePromise);
}
};
await model.load();
model.textEditorModel!.setValue('foo');
savePromise = model.save();
await savePromise;
}
}); });

View File

@@ -537,6 +537,22 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
} }
} }
// If a value is not present in the cache, it must be reset to default
this.viewContainersRegistry.all.forEach(viewContainer => {
const viewDescriptorCollection = this.getViewDescriptors(viewContainer);
viewDescriptorCollection.allViewDescriptors.forEach(viewDescriptor => {
if (!newCachedPositions.has(viewDescriptor.id)) {
const currentContainer = this.getViewContainer(viewDescriptor.id);
const defaultContainer = this.getDefaultContainer(viewDescriptor.id);
if (currentContainer && defaultContainer && currentContainer !== defaultContainer) {
this.moveViews([viewDescriptor], currentContainer, defaultContainer);
}
this.cachedViewInfo.delete(viewDescriptor.id);
}
});
});
this.cachedViewInfo = this.getCachedViewPositions(); this.cachedViewInfo = this.getCachedViewPositions();
} }
} }
@@ -571,6 +587,16 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
}); });
}); });
// Do no save default positions to the cache
// so that default changes can be recognized
// https://github.com/microsoft/vscode/issues/90414
for (const [viewId, containerInfo] of this.cachedViewInfo) {
const defaultContainer = this.getDefaultContainer(viewId);
if (defaultContainer?.id === containerInfo.containerId) {
this.cachedViewInfo.delete(viewId);
}
}
this.cachedViewPositionsValue = JSON.stringify([...this.cachedViewInfo]); this.cachedViewPositionsValue = JSON.stringify([...this.cachedViewInfo]);
} }

View File

@@ -865,6 +865,7 @@ export class TestHostService implements IHostService {
_serviceBrand: undefined; _serviceBrand: undefined;
readonly hasFocus: boolean = true; readonly hasFocus: boolean = true;
async hadLastFocus(): Promise<boolean> { return true; }
readonly onDidChangeFocus: Event<boolean> = Event.None; readonly onDidChangeFocus: Event<boolean> = Event.None;
async restart(): Promise<void> { } async restart(): Promise<void> { }

View File

@@ -80,17 +80,29 @@ interface IApplicationLink {
uri: URI; uri: URI;
/** /**
* A label for the link to display. * A label for the application link to display.
*/ */
label: string; label: string;
} }
interface IApplicationLinkProvider { interface ICommand {
(): IApplicationLink[] | undefined
/**
* An identifier for the command. Commands can be executed from extensions
* using the `vscode.commands.executeCommand` API using that command ID.
*/
id: string,
/**
* A function that is being executed with any arguments passed over.
*/
handler: (...args: any[]) => void;
} }
interface IWorkbenchConstructionOptions { interface IWorkbenchConstructionOptions {
//#region Connection related configuration
/** /**
* The remote authority is the IP:PORT from where the workbench is served * The remote authority is the IP:PORT from where the workbench is served
* from. It is for example being used for the websocket connections as address. * from. It is for example being used for the websocket connections as address.
@@ -108,6 +120,36 @@ interface IWorkbenchConstructionOptions {
*/ */
readonly webviewEndpoint?: string; readonly webviewEndpoint?: string;
/**
* A factory for web sockets.
*/
readonly webSocketFactory?: IWebSocketFactory;
/**
* A provider for resource URIs.
*/
readonly resourceUriProvider?: IResourceUriProvider;
/**
* Resolves an external uri before it is opened.
*/
readonly resolveExternalUri?: IExternalUriResolver;
/**
* Support for creating tunnels.
*/
readonly tunnelFactory?: ITunnelFactory;
/**
* Support for filtering candidate ports
*/
readonly showCandidate?: IShowCandidate;
//#endregion
//#region Workbench configuration
/** /**
* A handler for opening workspaces and providing the initial workspace. * A handler for opening workspaces and providing the initial workspace.
*/ */
@@ -119,16 +161,6 @@ interface IWorkbenchConstructionOptions {
*/ */
userDataProvider?: IFileSystemProvider; userDataProvider?: IFileSystemProvider;
/**
* A factory for web sockets.
*/
readonly webSocketFactory?: IWebSocketFactory;
/**
* A provider for resource URIs.
*/
readonly resourceUriProvider?: IResourceUriProvider;
/** /**
* The credentials provider to store and retrieve secrets. * The credentials provider to store and retrieve secrets.
*/ */
@@ -154,21 +186,6 @@ interface IWorkbenchConstructionOptions {
*/ */
readonly resolveCommonTelemetryProperties?: ICommontTelemetryPropertiesResolver; readonly resolveCommonTelemetryProperties?: ICommontTelemetryPropertiesResolver;
/**
* Resolves an external uri before it is opened.
*/
readonly resolveExternalUri?: IExternalUriResolver;
/**
* Support for creating tunnels.
*/
readonly tunnelFactory?: ITunnelFactory;
/**
* Support for filtering candidate ports
*/
readonly showCandidate?: IShowCandidate;
/** /**
* Provide entries for the "Open in Desktop" feature. * Provide entries for the "Open in Desktop" feature.
* *
@@ -179,7 +196,20 @@ interface IWorkbenchConstructionOptions {
* - N elements: there will be a "Open in Desktop" affordance that opens * - N elements: there will be a "Open in Desktop" affordance that opens
* a picker on click to select which application to open. * a picker on click to select which application to open.
*/ */
readonly applicationLinkProvider?: IApplicationLinkProvider; readonly applicationLinks?: readonly IApplicationLink[];
/**
* A set of optional commands that should be registered with the commands
* registry.
*
* Note: commands can be called from extensions if the identifier is known!
*/
readonly commands?: readonly ICommand[];
//#endregion
//#region Diagnostics
/** /**
* Current logging level. Default is `LogLevel.Info`. * Current logging level. Default is `LogLevel.Info`.
@@ -190,20 +220,8 @@ interface IWorkbenchConstructionOptions {
* Whether to enable the smoke test driver. * Whether to enable the smoke test driver.
*/ */
readonly driver?: boolean; readonly driver?: boolean;
}
interface ICommandHandler { //#endregion
(...args: any[]): void;
}
interface IWorkbench {
/**
* Register a command with the provided identifier and handler with
* the workbench. The command can be called from extensions using the
* `vscode.commands.executeCommand` API.
*/
registerCommand(id: string, command: ICommandHandler): IDisposable;
} }
/** /**
@@ -211,24 +229,22 @@ interface IWorkbench {
* *
* @param domElement the container to create the workbench in * @param domElement the container to create the workbench in
* @param options for setting up the workbench * @param options for setting up the workbench
*
* @returns the workbench facade with additional methods to call on.
*/ */
async function create(domElement: HTMLElement, options: IWorkbenchConstructionOptions): Promise<IWorkbench> { async function create(domElement: HTMLElement, options: IWorkbenchConstructionOptions): Promise<void> {
// Startup workbench // Startup workbench
await main(domElement, options); await main(domElement, options);
// Return facade // Register commands if any
return { if (Array.isArray(options.commands)) {
registerCommand: (id: string, command: ICommandHandler): IDisposable => { for (const command of options.commands) {
return CommandsRegistry.registerCommand(id, (accessor, ...args: any[]) => { CommandsRegistry.registerCommand(command.id, (accessor, ...args: any[]) => {
// we currently only pass on the arguments but not the accessor // we currently only pass on the arguments but not the accessor
// to the command to reduce our exposure of internal API. // to the command to reduce our exposure of internal API.
command(...args); command.handler(...args);
}); });
} }
}; }
} }
export { export {
@@ -237,9 +253,6 @@ export {
create, create,
IWorkbenchConstructionOptions, IWorkbenchConstructionOptions,
// Workbench Facade
IWorkbench,
ICommandHandler,
// Basic Types // Basic Types
URI, URI,
@@ -291,5 +304,7 @@ export {
// Protocol Links // Protocol Links
IApplicationLink, IApplicationLink,
IApplicationLinkProvider
// Commands
ICommand
}; };

View File

@@ -141,10 +141,12 @@ export function connect(engine: 'chromium' | 'webkit' | 'firefox' = 'chromium'):
return new Promise(async (c) => { return new Promise(async (c) => {
const browser = await playwright[engine].launch({ const browser = await playwright[engine].launch({
// Run in Edge dev on macOS // Run in Edge dev on macOS
// executablePath: '/Applications/Microsoft\ Edge\ Dev.app/Contents/MacOS/Microsoft\ Edge\ Dev' // executablePath: '/Applications/Microsoft\ Edge\ Dev.app/Contents/MacOS/Microsoft\ Edge\ Dev',
headless: false
}); });
const page = (await browser.defaultContext().pages())[0]; const context = await browser.newContext();
await page.setViewport({ width, height }); const page = await context.newPage();
await page.setViewportSize({ width, height });
await page.goto(`${endpoint}&folder=vscode-remote://localhost:9888${URI.file(workspacePath!).path}`); await page.goto(`${endpoint}&folder=vscode-remote://localhost:9888${URI.file(workspacePath!).path}`);
const result = { const result = {
client: { dispose: () => browser.close() && teardown() }, client: { dispose: () => browser.close() && teardown() },

View File

@@ -9,6 +9,7 @@
"devDependencies": { "devDependencies": {
"@types/mkdirp": "0.5.1", "@types/mkdirp": "0.5.1",
"@types/node": "^12.11.7", "@types/node": "^12.11.7",
"@types/optimist": "0.0.29",
"@types/rimraf": "2.0.2", "@types/rimraf": "2.0.2",
"@types/tmp": "^0.1.0", "@types/tmp": "^0.1.0",
"rimraf": "^2.6.1", "rimraf": "^2.6.1",

View File

@@ -11,8 +11,9 @@ import * as tmp from 'tmp';
import * as rimraf from 'rimraf'; import * as rimraf from 'rimraf';
import { URI } from 'vscode-uri'; import { URI } from 'vscode-uri';
import * as kill from 'tree-kill'; import * as kill from 'tree-kill';
import * as optimistLib from 'optimist';
const optimist = require('optimist') const optimist = optimistLib
.describe('workspacePath', 'path to the workspace to open in the test').string('workspacePath') .describe('workspacePath', 'path to the workspace to open in the test').string('workspacePath')
.describe('extensionDevelopmentPath', 'path to the extension to test').string('extensionDevelopmentPath') .describe('extensionDevelopmentPath', 'path to the extension to test').string('extensionDevelopmentPath')
.describe('extensionTestsPath', 'path to the extension tests').string('extensionTestsPath') .describe('extensionTestsPath', 'path to the extension tests').string('extensionTestsPath')
@@ -28,11 +29,12 @@ if (optimist.argv.help) {
const width = 1200; const width = 1200;
const height = 800; const height = 800;
async function runTestsInBrowser(browserType: string, endpoint: url.UrlWithStringQuery, server: cp.ChildProcess): Promise<void> { async function runTestsInBrowser(browserType: 'chromium' | 'firefox' | 'webkit', endpoint: url.UrlWithStringQuery, server: cp.ChildProcess): Promise<void> {
const args = process.platform === 'linux' && browserType === 'chromium' ? ['--no-sandbox'] : undefined; // disable sandbox to run chrome on certain Linux distros const args = process.platform === 'linux' && browserType === 'chromium' ? ['--no-sandbox'] : undefined; // disable sandbox to run chrome on certain Linux distros
const browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug), dumpio: true, args }); const browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug), dumpio: true, args });
const page = (await browser.defaultContext().pages())[0]; const context = await browser.newContext();
await page.setViewport({ width, height }); const page = await context.newPage();
await page.setViewportSize({ width, height });
const host = endpoint.host; const host = endpoint.host;
const protocol = 'vscode-remote'; const protocol = 'vscode-remote';

View File

@@ -38,6 +38,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.26.tgz#213e153babac0ed169d44a6d919501e68f59dea9" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.26.tgz#213e153babac0ed169d44a6d919501e68f59dea9"
integrity sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA== integrity sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA==
"@types/optimist@0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/optimist/-/optimist-0.0.29.tgz#a8873580b3a84b69ac1e687323b15fbbeb90479a"
integrity sha1-qIc1gLOoS2msHmhzI7Ffu+uQR5o=
"@types/rimraf@2.0.2": "@types/rimraf@2.0.2":
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e"

View File

@@ -120,7 +120,8 @@ const testModules = (async function () {
async function runTestsInBrowser(testModules, browserType) { async function runTestsInBrowser(testModules, browserType) {
const args = process.platform === 'linux' && browserType === 'chromium' ? ['--no-sandbox'] : undefined; // disable sandbox to run chrome on certain Linux distros const args = process.platform === 'linux' && browserType === 'chromium' ? ['--no-sandbox'] : undefined; // disable sandbox to run chrome on certain Linux distros
const browser = await playwright[browserType].launch({ headless: !Boolean(argv.debug), dumpio: true, args }); const browser = await playwright[browserType].launch({ headless: !Boolean(argv.debug), dumpio: true, args });
const page = (await browser.defaultContext().pages())[0] const context = await browser.newContext();
const page = await context.newPage();
const target = url.pathToFileURL(path.join(__dirname, 'renderer.html')); const target = url.pathToFileURL(path.join(__dirname, 'renderer.html'));
if (argv.build) { if (argv.build) {
target.search = `?build=true`; target.search = `?build=true`;

View File

@@ -6046,11 +6046,6 @@ mime@^1.4.1:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^2.0.3:
version "2.4.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
mimic-fn@^1.0.0: mimic-fn@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
@@ -7107,29 +7102,28 @@ pkg-dir@^3.0.0:
dependencies: dependencies:
find-up "^3.0.0" find-up "^3.0.0"
playwright-core@=0.10.0: playwright-core@=0.11.0:
version "0.10.0" version "0.11.0"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-0.10.0.tgz#86699c9cc3e613d733e6635a54aceea1993013d5" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-0.11.0.tgz#a2372833f6ec4e7886c4409e3da93df997aee61b"
integrity sha512-yernA6yrrBhmb8M5eO6GZsJOrBKWOZszlu65Luz8LP7ryaDExN1sE9XjQBNbiwJ5Gfs8cehtAO7GfTDJt+Z2cQ== integrity sha512-9UPP/Max65PMiZJz9DNWB3ZRWtTlYlceLFnm6JO8aU7m6Vw3gwCvuSGoC5W69H67q98jH0VPSPp546+EnkiR2g==
dependencies: dependencies:
debug "^4.1.0" debug "^4.1.0"
extract-zip "^1.6.6" extract-zip "^1.6.6"
https-proxy-agent "^3.0.0" https-proxy-agent "^3.0.0"
jpeg-js "^0.3.6" jpeg-js "^0.3.6"
mime "^2.0.3"
pngjs "^3.4.0" pngjs "^3.4.0"
progress "^2.0.3" progress "^2.0.3"
proxy-from-env "^1.0.0" proxy-from-env "^1.0.0"
rimraf "^2.6.1" rimraf "^3.0.2"
uuid "^3.4.0" uuid "^3.4.0"
ws "^6.1.0" ws "^6.1.0"
playwright@^0.10.0: playwright@0.11.0:
version "0.10.0" version "0.11.0"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-0.10.0.tgz#d37f7e42e0e868dcc4ec35cb0a8dbc6248457642" resolved "https://registry.yarnpkg.com/playwright/-/playwright-0.11.0.tgz#2abec99ea278b220bcd3902d7520ec22abc2d97e"
integrity sha512-f3VRME/PIO5NbcWnlCDfXwPC0DAZJ7ETkcAdE+sensLCOkfDtLh97E71ZuxNCaPYsUA6FIPi5syD8pHJW/4hQQ== integrity sha512-cTJZ06OhwseMC9+D6KX1NmZXyEoaJl0o6GLkDhwmou3IFTrUFVOw7KYMBpcbJz0Rhb/de5ZPFlDTffLfEy/9lg==
dependencies: dependencies:
playwright-core "=0.10.0" playwright-core "=0.11.0"
plist@^3.0.1: plist@^3.0.1:
version "3.0.1" version "3.0.1"
@@ -8160,6 +8154,13 @@ rimraf@^2.4.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
dependencies: dependencies:
glob "^7.0.5" glob "^7.0.5"
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
rimraf@~2.2.6: rimraf@~2.2.6:
version "2.2.8" version "2.2.8"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"