mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
Merge from vscode 1a81711a85e38ccf784110568ebf3784ab9094a5 (#9161)
* Merge from vscode 1a81711a85e38ccf784110568ebf3784ab9094a5 * small spacing fix
This commit is contained in:
@@ -447,6 +447,22 @@
|
||||
"command": "git.stashDrop",
|
||||
"title": "%command.stashDrop%",
|
||||
"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": {
|
||||
@@ -718,6 +734,18 @@
|
||||
{
|
||||
"command": "git.stashDrop",
|
||||
"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": [
|
||||
@@ -1248,6 +1276,28 @@
|
||||
"command": "git.revertChange",
|
||||
"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": {
|
||||
@@ -1779,10 +1829,11 @@
|
||||
"@types/file-type": "^5.2.1",
|
||||
"@types/mocha": "2.2.43",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/vscode": "^1.42",
|
||||
"@types/which": "^1.0.28",
|
||||
"mocha": "^3.2.0",
|
||||
"mocha-junit-reporter": "^1.23.3",
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"vscode": "^1.1.36"
|
||||
"vscode-test": "^1.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,9 @@
|
||||
"command.stashApply": "Apply Stash...",
|
||||
"command.stashApplyLatest": "Apply Latest 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.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.",
|
||||
@@ -127,7 +130,7 @@
|
||||
"config.showProgress": "Controls whether git actions should show progress.",
|
||||
"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.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.autoStash": "Stash any changes before pulling and restore them after successful pull.",
|
||||
"config.allowForcePush": "Controls whether force push (with or without lease) is enabled.",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { lstat, Stats } from 'fs';
|
||||
import * as os from 'os';
|
||||
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 * as nls from 'vscode-nls';
|
||||
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 { grep, isDescendant, pathEquals } from './util';
|
||||
import { Log, LogLevel } from './log';
|
||||
import { GitTimelineItem } from './timelineProvider';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -2331,23 +2332,47 @@ export class CommandCenter {
|
||||
return result && result.stash;
|
||||
}
|
||||
|
||||
@command('git.openDiff', { repository: false })
|
||||
async openDiff(uri: Uri, lhs: string, rhs: string) {
|
||||
@command('git.timeline.openDiff', { repository: false })
|
||||
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);
|
||||
|
||||
let title;
|
||||
if ((lhs === 'HEAD' || lhs === '~') && rhs === '') {
|
||||
if ((item.previousRef === 'HEAD' || item.previousRef === '~') && item.ref === '') {
|
||||
title = `${basename} (Working Tree)`;
|
||||
}
|
||||
else if (lhs === 'HEAD' && rhs === '~') {
|
||||
else if (item.previousRef === 'HEAD' && item.ref === '~') {
|
||||
title = `${basename} (Index)`;
|
||||
} 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 {
|
||||
const result = (...args: any[]) => {
|
||||
let result: Promise<any>;
|
||||
|
||||
@@ -5,19 +5,62 @@
|
||||
|
||||
import * as dayjs from 'dayjs';
|
||||
import * as advancedFormat from 'dayjs/plugin/advancedFormat';
|
||||
import * as relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import { CancellationToken, Disposable, Event, EventEmitter, ThemeIcon, TimelineItem, TimelineProvider, Uri, workspace, TimelineChangeEvent } from 'vscode';
|
||||
import { CancellationToken, Disposable, Event, EventEmitter, ThemeIcon, Timeline, TimelineChangeEvent, TimelineCursor, TimelineItem, TimelineProvider, Uri, workspace } from 'vscode';
|
||||
import { Model } from './model';
|
||||
import { Repository } from './repository';
|
||||
import { debounce } from './decorators';
|
||||
import { Status } from './api/git';
|
||||
|
||||
dayjs.extend(advancedFormat);
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
// TODO[ECA]: Localize all the strings
|
||||
// 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 {
|
||||
private _onDidChange = new EventEmitter<TimelineChangeEvent>();
|
||||
get onDidChange(): Event<TimelineChangeEvent> {
|
||||
@@ -44,7 +87,7 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
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}`);
|
||||
|
||||
const repo = this._model.getRepository(uri);
|
||||
@@ -53,7 +96,7 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
this._repoStatusDate = undefined;
|
||||
this._repo = undefined;
|
||||
|
||||
return [];
|
||||
return { items: [] };
|
||||
}
|
||||
|
||||
if (this._repo?.root !== repo.root) {
|
||||
@@ -72,25 +115,17 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
const commits = await repo.logFile(uri);
|
||||
|
||||
let dateFormatter: dayjs.Dayjs;
|
||||
const items = commits.map<TimelineItem>(c => {
|
||||
let message = c.message;
|
||||
|
||||
const index = message.indexOf('\n');
|
||||
if (index !== -1) {
|
||||
message = `${message.substring(0, index)} \u2026`;
|
||||
}
|
||||
|
||||
const items = commits.map<GitTimelineItem>(c => {
|
||||
dateFormatter = dayjs(c.authorDate);
|
||||
|
||||
const item = new TimelineItem(message, c.authorDate?.getTime() ?? 0);
|
||||
item.id = c.hash;
|
||||
const item = new GitTimelineItem(c.hash, `${c.hash}^`, c.message, c.authorDate?.getTime() ?? 0, c.hash, 'git:file:commit');
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.description = `${dateFormatter.fromNow()} \u2022 ${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.description = c.authorName;
|
||||
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 = {
|
||||
title: 'Open Diff',
|
||||
command: 'git.openDiff',
|
||||
arguments: [uri, `${c.hash}^`, c.hash]
|
||||
title: 'Open Comparison',
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [uri, this.id, item]
|
||||
};
|
||||
|
||||
return item;
|
||||
@@ -123,16 +158,15 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
break;
|
||||
}
|
||||
|
||||
const item = new TimelineItem('Staged Changes', date.getTime());
|
||||
item.id = 'index';
|
||||
const item = new GitTimelineItem('~', 'HEAD', 'Staged Changes', date.getTime(), 'index', 'git:file:index');
|
||||
// TODO[ECA]: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.description = `${dateFormatter.fromNow()} \u2022 You`;
|
||||
item.detail = `You \u2014 Index\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n${status}`;
|
||||
item.description = 'You';
|
||||
item.detail = `You \u2014 Index\n${dateFormatter.format('MMMM Do, YYYY h:mma')}\n${status}`;
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.openDiff',
|
||||
arguments: [uri, 'HEAD', '~']
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [uri, this.id, item]
|
||||
};
|
||||
|
||||
items.push(item);
|
||||
@@ -166,22 +200,21 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
break;
|
||||
}
|
||||
|
||||
const item = new TimelineItem('Uncommited Changes', date.getTime());
|
||||
item.id = 'working';
|
||||
const item = new GitTimelineItem('', index ? '~' : 'HEAD', 'Uncommited Changes', date.getTime(), 'working', 'git:file:working');
|
||||
// TODO[ECA]: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.description = `${dateFormatter.fromNow()} \u2022 You`;
|
||||
item.detail = `You \u2014 Working Tree\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n${status}`;
|
||||
item.description = 'You';
|
||||
item.detail = `You \u2014 Working Tree\n${dateFormatter.format('MMMM Do, YYYY h:mma')}\n${status}`;
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.openDiff',
|
||||
arguments: [uri, index ? '~' : 'HEAD', '']
|
||||
command: 'git.timeline.openDiff',
|
||||
arguments: [uri, this.id, item]
|
||||
};
|
||||
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
return { items: items };
|
||||
}
|
||||
|
||||
private onRepositoriesChanged(_repo: Repository) {
|
||||
@@ -208,6 +241,6 @@ export class GitTimelineProvider implements TimelineProvider {
|
||||
|
||||
@debounce(500)
|
||||
private fireChanged() {
|
||||
this._onDidChange.fire();
|
||||
this._onDidChange.fire({});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a"
|
||||
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":
|
||||
version "1.0.28"
|
||||
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:
|
||||
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:
|
||||
version "3.0.0"
|
||||
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"
|
||||
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:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
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:
|
||||
version "1.1.8"
|
||||
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"
|
||||
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:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
|
||||
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:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||
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:
|
||||
version "2.9.0"
|
||||
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"
|
||||
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:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
|
||||
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:
|
||||
version "1.8.19"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.19.tgz#5117dc390d8f8e586d53891dbff3fa308f51abfe"
|
||||
@@ -218,11 +140,6 @@ debug@^3.1.0:
|
||||
dependencies:
|
||||
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:
|
||||
version "0.2.1"
|
||||
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"
|
||||
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:
|
||||
version "4.2.8"
|
||||
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"
|
||||
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:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-7.2.0.tgz#113cfed52e1d6959ab80248906e2f25a8cdccb74"
|
||||
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:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
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:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
|
||||
@@ -338,19 +196,7 @@ glob@7.1.1:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@7.1.2:
|
||||
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:
|
||||
glob@^7.1.3:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
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"
|
||||
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:
|
||||
version "1.9.2"
|
||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
|
||||
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:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
|
||||
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:
|
||||
version "1.1.1"
|
||||
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"
|
||||
debug "3.1.0"
|
||||
|
||||
http-signature@~1.2.0:
|
||||
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:
|
||||
https-proxy-agent@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
|
||||
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"
|
||||
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:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
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:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184"
|
||||
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:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
|
||||
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:
|
||||
version "3.2.0"
|
||||
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"
|
||||
is-buffer "~1.1.1"
|
||||
|
||||
mime-db@1.43.0:
|
||||
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:
|
||||
minimatch@^3.0.2, minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
@@ -648,23 +410,6 @@ mocha@^3.2.0:
|
||||
mkdirp "0.5.1"
|
||||
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:
|
||||
version "2.0.0"
|
||||
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"
|
||||
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:
|
||||
version "1.4.0"
|
||||
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"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
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==
|
||||
rimraf@^2.6.3:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
||||
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
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"
|
||||
glob "^7.1.3"
|
||||
|
||||
requires-port@^1.0.0:
|
||||
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:
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
@@ -768,39 +449,6 @@ semver@^5.3.0:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
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:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
@@ -815,62 +463,6 @@ supports-color@3.1.2:
|
||||
dependencies:
|
||||
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:
|
||||
version "0.1.1"
|
||||
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"
|
||||
integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw==
|
||||
|
||||
vscode-test@^0.4.1:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-test/-/vscode-test-0.4.3.tgz#461ebf25fc4bc93d77d982aed556658a2e2b90b8"
|
||||
integrity sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==
|
||||
vscode-test@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-test/-/vscode-test-1.3.0.tgz#3310ab385d9b887b4c82e8f52be1030e7cf9493d"
|
||||
integrity sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==
|
||||
dependencies:
|
||||
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:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.0.tgz#2df704222f72b8a71ff266ba0830ed6c51ac1542"
|
||||
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:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
"opn": "^6.0.0",
|
||||
"optimist": "0.3.5",
|
||||
"p-all": "^1.0.0",
|
||||
"playwright": "^0.10.0",
|
||||
"playwright": "0.11.0",
|
||||
"pump": "^1.0.1",
|
||||
"queue": "3.0.6",
|
||||
"rcedit": "^1.1.0",
|
||||
|
||||
@@ -140,6 +140,9 @@ function configureCommandlineSwitchesSync(cliArgs) {
|
||||
// provided by Electron
|
||||
'disable-color-correct-rendering'
|
||||
];
|
||||
if (process.platform === 'linux') {
|
||||
SUPPORTED_ELECTRON_SWITCHES.push('force-renderer-accessibility');
|
||||
}
|
||||
|
||||
// Read argv config
|
||||
const argvConfig = readArgvConfigSync();
|
||||
|
||||
@@ -5,6 +5,53 @@
|
||||
|
||||
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 {
|
||||
return date.getFullYear() +
|
||||
'-' + pad(date.getMonth() + 1, 2) +
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* 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 { CancellationToken } from 'vs/base/common/cancellation';
|
||||
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 () {
|
||||
|
||||
// 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
|
||||
create(document.body, {
|
||||
...config,
|
||||
workspaceProvider: new WorkspaceProvider(workspace, payload),
|
||||
urlCallbackProvider: new PollingURLCallbackProvider(),
|
||||
credentialsProvider: new LocalStorageCredentialsProvider(),
|
||||
applicationLinkProvider: new ApplicationLinkProvider(workspace).provider
|
||||
applicationLinks: applicationLinks
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -265,6 +265,34 @@ export interface HoverProvider {
|
||||
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 {
|
||||
Method,
|
||||
Function,
|
||||
@@ -1595,6 +1623,11 @@ export const SignatureHelpProviderRegistry = new LanguageFeatureRegistry<Signatu
|
||||
*/
|
||||
export const HoverProviderRegistry = new LanguageFeatureRegistry<HoverProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const EvaluatableExpressionProviderRegistry = new LanguageFeatureRegistry<EvaluatableExpressionProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
||||
25
src/vs/monaco.d.ts
vendored
25
src/vs/monaco.d.ts
vendored
@@ -5242,6 +5242,31 @@ declare namespace monaco.languages {
|
||||
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 {
|
||||
Method = 0,
|
||||
Function = 1,
|
||||
|
||||
@@ -119,7 +119,9 @@ export class MenuId {
|
||||
static readonly DataExplorerContext = new MenuId('DataExplorerContext'); // {{SQL CARBON EDIT}}
|
||||
static readonly DataExplorerAction = new MenuId('DataExplorerAction'); // {{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 _debugName: string;
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface IConstructorSignature0<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> {
|
||||
|
||||
@@ -98,7 +98,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto
|
||||
async triggerAutoSync(): Promise<void> {
|
||||
if (this.enabled) {
|
||||
return this.syncDelayer.trigger(() => {
|
||||
this.logService.info('Auto Sync: Triggerred.');
|
||||
this.logService.info('Auto Sync: Triggered.');
|
||||
return this.sync(false, true);
|
||||
}, this.successiveFailures
|
||||
? 1000 * 1 * Math.min(this.successiveFailures, 60) /* Delay by number of seconds as number of failures up to 1 minute */
|
||||
|
||||
99
src/vs/vscode.proposed.d.ts
vendored
99
src/vs/vscode.proposed.d.ts
vendored
@@ -876,7 +876,65 @@ declare module 'vscode' {
|
||||
|
||||
//#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
|
||||
|
||||
@@ -1553,6 +1611,40 @@ declare module 'vscode' {
|
||||
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 {
|
||||
/**
|
||||
* 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 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.
|
||||
*/
|
||||
provideTimeline(uri: Uri, token: CancellationToken): ProviderResult<TimelineItem[]>;
|
||||
provideTimeline(uri: Uri, cursor: TimelineCursor, token: CancellationToken): ProviderResult<Timeline>;
|
||||
}
|
||||
|
||||
export namespace workspace {
|
||||
|
||||
@@ -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
|
||||
|
||||
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { MainContext, MainThreadTimelineShape, IExtHostContext, ExtHostTimelineShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
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)
|
||||
export class MainThreadTimeline implements MainThreadTimelineShape {
|
||||
@@ -24,10 +24,6 @@ export class MainThreadTimeline implements MainThreadTimelineShape {
|
||||
this._proxy = context.getProxy(ExtHostContext.ExtHostTimeline);
|
||||
}
|
||||
|
||||
$getTimeline(uri: URI, token: CancellationToken): Promise<TimelineItem[]> {
|
||||
return this._timelineService.getTimeline(uri, token);
|
||||
}
|
||||
|
||||
$registerTimelineProvider(provider: TimelineProviderDescriptor): void {
|
||||
this.logService.trace(`MainThreadTimeline#registerTimelineProvider: id=${provider.id}`);
|
||||
|
||||
@@ -43,8 +39,8 @@ export class MainThreadTimeline implements MainThreadTimelineShape {
|
||||
this._timelineService.registerTimelineProvider({
|
||||
...provider,
|
||||
onDidChange: onDidChange.event,
|
||||
provideTimeline(uri: URI, token: CancellationToken) {
|
||||
return proxy.$getTimeline(provider.id, uri, token);
|
||||
provideTimeline(uri: URI, cursor: TimelineCursor, token: CancellationToken, options?: { cacheResults?: boolean }) {
|
||||
return proxy.$getTimeline(provider.id, uri, cursor, token, options);
|
||||
},
|
||||
dispose() {
|
||||
emitters.delete(provider.id);
|
||||
|
||||
@@ -134,7 +134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHostLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(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
|
||||
// {{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 {
|
||||
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 {
|
||||
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
@@ -928,6 +931,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
DocumentLink: extHostTypes.DocumentLink,
|
||||
DocumentSymbol: extHostTypes.DocumentSymbol,
|
||||
EndOfLine: extHostTypes.EndOfLine,
|
||||
EvaluatableExpression: extHostTypes.EvaluatableExpression,
|
||||
EventEmitter: Emitter,
|
||||
ExtensionKind: extHostTypes.ExtensionKind,
|
||||
CustomExecution: extHostTypes.CustomExecution,
|
||||
|
||||
@@ -49,7 +49,7 @@ import { SaveReason } from 'vs/workbench/common/editor';
|
||||
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
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}}
|
||||
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
|
||||
@@ -357,6 +357,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerImplementationSupport(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto): void;
|
||||
@@ -806,8 +807,6 @@ export interface MainThreadTimelineShape extends IDisposable {
|
||||
$registerTimelineProvider(provider: TimelineProviderDescriptor): void;
|
||||
$unregisterTimelineProvider(source: string): void;
|
||||
$emitTimelineChangeEvent(e: TimelineChangeEvent): void;
|
||||
|
||||
$getTimeline(uri: UriComponents, token: CancellationToken): Promise<TimelineItem[]>;
|
||||
}
|
||||
|
||||
// -- extension host
|
||||
@@ -1213,6 +1212,7 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideImplementation(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>;
|
||||
$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>;
|
||||
$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>;
|
||||
@@ -1461,7 +1461,7 @@ export interface ExtHostTunnelServiceShape {
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
constructor(
|
||||
@@ -1329,7 +1350,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
|
||||
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
|
||||
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
|
||||
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
|
||||
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter;
|
||||
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter;
|
||||
|
||||
class AdapterData {
|
||||
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);
|
||||
}
|
||||
|
||||
// --- 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
|
||||
|
||||
registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
|
||||
|
||||
@@ -7,61 +7,91 @@ import * as vscode from 'vscode';
|
||||
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
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 { 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 { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
export interface IExtHostTimeline extends ExtHostTimelineShape {
|
||||
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 class ExtHostTimeline implements IExtHostTimeline {
|
||||
private static handlePool = 0;
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private _proxy: MainThreadTimelineShape;
|
||||
|
||||
private _providers = new Map<string, TimelineProvider>();
|
||||
|
||||
private _itemsBySourceByUriMap = new Map<string | undefined, Map<string, Map<string, vscode.TimelineItem>>>();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
commands: ExtHostCommands,
|
||||
) {
|
||||
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);
|
||||
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 convertTimelineItem = this.convertTimelineItem(provider.id, commandConverter, timelineDisposables);
|
||||
const convertTimelineItem = this.convertTimelineItem(provider.id, commandConverter, timelineDisposables).bind(this);
|
||||
|
||||
let disposable: IDisposable | undefined;
|
||||
if (provider.onDidChange) {
|
||||
disposable = provider.onDidChange(this.emitTimelineChangeEvent(provider.id), this);
|
||||
}
|
||||
|
||||
const itemsBySourceByUriMap = this._itemsBySourceByUriMap;
|
||||
return this.registerTimelineProviderCore({
|
||||
...provider,
|
||||
scheme: scheme,
|
||||
onDidChange: undefined,
|
||||
async provideTimeline(uri: URI, token: CancellationToken) {
|
||||
async provideTimeline(uri: URI, cursor: TimelineCursor, token: CancellationToken, options?: { cacheResults?: boolean }) {
|
||||
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
|
||||
// eslint-disable-next-line eqeqeq
|
||||
return results != null
|
||||
? results.map(item => convertTimelineItem(item))
|
||||
: [];
|
||||
if (result == null) {
|
||||
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() {
|
||||
disposable?.dispose();
|
||||
@@ -70,39 +100,72 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
});
|
||||
}
|
||||
|
||||
private convertTimelineItem(source: string, commandConverter: CommandsConverter, disposables: DisposableStore): (item: vscode.TimelineItem) => TimelineItemWithSource {
|
||||
return (item: vscode.TimelineItem) => {
|
||||
const { iconPath, ...props } = item;
|
||||
private convertTimelineItem(source: string, commandConverter: CommandsConverter, disposables: DisposableStore) {
|
||||
return (uri: URI, cacheResults: boolean) => {
|
||||
let itemsMap: Map<string, vscode.TimelineItem> | undefined;
|
||||
if (cacheResults) {
|
||||
const uriKey = getUriKey(uri);
|
||||
|
||||
let icon;
|
||||
let iconDark;
|
||||
let themeIcon;
|
||||
if (item.iconPath) {
|
||||
if (iconPath instanceof ThemeIcon) {
|
||||
themeIcon = { id: iconPath.id };
|
||||
let sourceMap = this._itemsBySourceByUriMap.get(uriKey);
|
||||
if (sourceMap === undefined) {
|
||||
sourceMap = new Map();
|
||||
this._itemsBySourceByUriMap.set(uriKey, sourceMap);
|
||||
}
|
||||
else if (URI.isUri(iconPath)) {
|
||||
icon = iconPath;
|
||||
iconDark = iconPath;
|
||||
}
|
||||
else {
|
||||
({ light: icon, dark: iconDark } = iconPath as { light: URI; dark: URI });
|
||||
|
||||
itemsMap = sourceMap.get(source);
|
||||
if (itemsMap === undefined) {
|
||||
itemsMap = new Map();
|
||||
sourceMap.set(source, itemsMap);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...props,
|
||||
source: source,
|
||||
command: item.command ? commandConverter.toInternal(item.command, disposables) : undefined,
|
||||
icon: icon,
|
||||
iconDark: iconDark,
|
||||
themeIcon: themeIcon
|
||||
return (item: vscode.TimelineItem): TimelineItem => {
|
||||
const { iconPath, ...props } = item;
|
||||
|
||||
const handle = `${source}|${item.id ?? `${item.timestamp}-${ExtHostTimeline.handlePool++}`}`;
|
||||
itemsMap?.set(handle, item);
|
||||
|
||||
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) {
|
||||
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 });
|
||||
};
|
||||
}
|
||||
@@ -123,9 +186,18 @@ export class ExtHostTimeline implements IExtHostTimeline {
|
||||
this._providers.set(provider.id, provider);
|
||||
|
||||
return toDisposable(() => {
|
||||
for (const sourceMap of this._itemsBySourceByUriMap.values()) {
|
||||
sourceMap.get(provider.id)?.clear();
|
||||
}
|
||||
|
||||
this._providers.delete(provider.id);
|
||||
this._proxy.$unregisterTimelineProvider(provider.id);
|
||||
provider.dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getUriKey(uri: URI | undefined): string | undefined {
|
||||
return uri?.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ export namespace MarkdownString {
|
||||
} else if (htmlContent.isMarkdownString(markup)) {
|
||||
res = markup;
|
||||
} else if (typeof markup === 'string') {
|
||||
res = { value: <string>markup };
|
||||
res = { value: markup };
|
||||
} else {
|
||||
res = { value: '' };
|
||||
}
|
||||
@@ -737,6 +737,20 @@ export namespace Hover {
|
||||
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 function from(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight {
|
||||
return {
|
||||
|
||||
@@ -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 {
|
||||
Trace = 1,
|
||||
Debug = 2,
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace schema {
|
||||
case 'comments/comment/title': return MenuId.CommentTitle;
|
||||
case 'comments/comment/context': return MenuId.CommentActions;
|
||||
case 'extension/context': return MenuId.ExtensionContext;
|
||||
case 'timeline/title': return MenuId.TimelineTitle;
|
||||
case 'timeline/item/context': return MenuId.TimelineItemContext;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@@ -220,6 +222,16 @@ namespace schema {
|
||||
type: 'array',
|
||||
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
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
|
||||
//#region IView
|
||||
|
||||
readonly minimumWidth: number = 420;
|
||||
readonly minimumWidth: number = 300;
|
||||
readonly maximumWidth: number = Number.POSITIVE_INFINITY;
|
||||
readonly minimumHeight: number = 77;
|
||||
readonly maximumHeight: number = Number.POSITIVE_INFINITY;
|
||||
|
||||
@@ -57,12 +57,12 @@ export interface IViewContainerDescriptor {
|
||||
|
||||
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 }>;
|
||||
|
||||
/**
|
||||
* 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 }>;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./bulkEdit';
|
||||
import { WorkbenchAsyncDataTree, TreeResourceNavigator, IOpenEvent } from 'vs/platform/list/browser/listService';
|
||||
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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
@@ -135,6 +135,7 @@ export class BulkEditPane extends ViewPane {
|
||||
expandOnlyOnTwistieClick: true,
|
||||
multipleSelectionSupport: false,
|
||||
keyboardNavigationLabelProvider: new BulkEditNaviLabelProvider(),
|
||||
sorter: new BulkEditSorter()
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -99,6 +99,15 @@ export class BulkFileOperation {
|
||||
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 {
|
||||
@@ -230,7 +239,7 @@ export class BulkFileOperations {
|
||||
}
|
||||
|
||||
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
|
||||
// unchecked file edits (rename, create, delete) uncheck
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* 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 { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
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 { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { WorkspaceFileEdit } from 'vs/editor/common/modes';
|
||||
import { compare } from 'vs/base/common/strings';
|
||||
|
||||
// --- 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
|
||||
|
||||
export class BulkEditAccessibilityProvider implements IAccessibilityProvider<BulkEditElement> {
|
||||
|
||||
@@ -40,7 +40,7 @@ CommandsRegistry.registerCommand('_workbench.openWith', (accessor: ServicesAcces
|
||||
// #region Reopen With
|
||||
|
||||
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({
|
||||
id: REOPEN_WITH_COMMAND_ID,
|
||||
@@ -83,6 +83,17 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
||||
import { ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
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 twistiePixels = 20;
|
||||
@@ -233,11 +232,3 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
|
||||
templateData.toDispose.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class BaseDebugViewPane extends ViewPane {
|
||||
|
||||
render(): void {
|
||||
super.render();
|
||||
dom.addClass(this.element, 'debug-pane');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,14 +28,13 @@ import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
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 { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Gesture } from 'vs/base/browser/touch';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { BaseDebugViewPane } from 'vs/workbench/contrib/debug/browser/baseDebugView';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -54,7 +53,7 @@ export function getExpandedBodySize(model: IDebugModel): number {
|
||||
return Math.min(MAX_VISIBLE_BREAKPOINTS, length) * 22;
|
||||
}
|
||||
|
||||
export class BreakpointsView extends BaseDebugViewPane {
|
||||
export class BreakpointsView extends ViewPane {
|
||||
|
||||
private list!: WorkbenchList<IEnablement>;
|
||||
private needsRefresh = false;
|
||||
@@ -82,6 +81,7 @@ export class BreakpointsView extends BaseDebugViewPane {
|
||||
public renderBody(container: HTMLElement): void {
|
||||
super.renderBody(container);
|
||||
|
||||
dom.addClass(this.element, 'debug-pane');
|
||||
dom.addClass(container, 'debug-breakpoints');
|
||||
const delegate = new BreakpointsDelegate(this.debugService);
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
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 { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
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 { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
@@ -74,7 +74,7 @@ export function getContextForContributedActions(element: CallStackItem | null):
|
||||
return '';
|
||||
}
|
||||
|
||||
export class CallStackView extends BaseDebugViewPane {
|
||||
export class CallStackView extends ViewPane {
|
||||
private pauseMessage!: HTMLSpanElement;
|
||||
private pauseMessageLabel!: HTMLSpanElement;
|
||||
private onCallStackChangeScheduler: RunOnceScheduler;
|
||||
@@ -158,7 +158,7 @@ export class CallStackView extends BaseDebugViewPane {
|
||||
|
||||
renderBody(container: HTMLElement): void {
|
||||
super.renderBody(container);
|
||||
|
||||
dom.addClass(this.element, 'debug-pane');
|
||||
dom.addClass(container, 'debug-call-stack');
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
|
||||
@@ -136,17 +136,19 @@ function getWordToLineNumbersMap(model: ITextModel | null): Map<string, number[]
|
||||
model.forceTokenization(lineNumber);
|
||||
const lineTokens = model.getLineTokens(lineNumber);
|
||||
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 tokenStr = lineContent.substring(tokenStartOffset, tokenEndOffset);
|
||||
|
||||
// Token is a word and not a comment
|
||||
if (tokenType === StandardTokenType.Other) {
|
||||
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);
|
||||
|
||||
if (wordMatch) {
|
||||
|
||||
const word = wordMatch[0];
|
||||
if (!result.has(word)) {
|
||||
result.set(word, []);
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as dom from 'vs/base/browser/dom';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
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 { IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
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 MAX_TREE_HEIGHT = 324;
|
||||
@@ -107,6 +109,7 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
accessibilityProvider: new DebugHoverAccessibilityProvider(),
|
||||
mouseSupport: false,
|
||||
horizontalScrolling: true,
|
||||
useShadows: false,
|
||||
overrideStyles: {
|
||||
listBackground: editorHoverBackground
|
||||
}
|
||||
@@ -174,18 +177,52 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
}
|
||||
|
||||
async showAt(range: Range, focus: boolean): Promise<void> {
|
||||
const pos = range.getStartPosition();
|
||||
|
||||
const session = this.debugService.getViewModel().focusedSession;
|
||||
if (!this.editor.hasModel()) {
|
||||
|
||||
if (!session || !this.editor.hasModel()) {
|
||||
return Promise.resolve(this.hide());
|
||||
}
|
||||
|
||||
const lineContent = this.editor.getModel().getLineContent(pos.lineNumber);
|
||||
const { start, end } = getExactExpressionStartAndEnd(lineContent, range.startColumn, range.endColumn);
|
||||
// use regex to extract the sub-expression #9821
|
||||
const matchingExpression = lineContent.substring(start - 1, end);
|
||||
if (!matchingExpression || !session) {
|
||||
const model = this.editor.getModel();
|
||||
const pos = range.getStartPosition();
|
||||
|
||||
let rng: IRange | undefined = undefined;
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -202,13 +239,15 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
|
||||
if (!expression || (expression instanceof Expression && !expression.available)) {
|
||||
this.hide();
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
this.highlightDecorations = this.editor.deltaDecorations(this.highlightDecorations, [{
|
||||
range: new Range(pos.lineNumber, start, pos.lineNumber, start + matchingExpression.length),
|
||||
options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS
|
||||
}]);
|
||||
if (rng) {
|
||||
this.highlightDecorations = this.editor.deltaDecorations(this.highlightDecorations, [{
|
||||
range: rng,
|
||||
options: DebugHoverWidget._HOVER_HIGHLIGHT_DECORATION_OPTIONS
|
||||
}]);
|
||||
}
|
||||
|
||||
return this.doShow(pos, expression, focus);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
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 { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
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 { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
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 loadedScriptsItemType: IContextKey<string>;
|
||||
@@ -435,6 +435,7 @@ export class LoadedScriptsView extends BaseDebugViewPane {
|
||||
renderBody(container: HTMLElement): void {
|
||||
super.renderBody(container);
|
||||
|
||||
dom.addClass(this.element, 'debug-pane');
|
||||
dom.addClass(container, 'debug-loaded-scripts');
|
||||
dom.addClass(container, 'show-file-icons');
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
/* 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 {
|
||||
font-size: 13px;
|
||||
overflow: hidden;
|
||||
@@ -84,7 +84,7 @@
|
||||
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 {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
word-break: break-all;
|
||||
padding: 4px 5px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .complex-value {
|
||||
@@ -62,6 +61,7 @@
|
||||
overflow: auto;
|
||||
font-family: var(--monaco-monospace-font);
|
||||
max-height: 500px;
|
||||
padding: 4px 5px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .error {
|
||||
|
||||
@@ -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> {
|
||||
return new Promise<DebugProtocol.Response>((completeDispatch, errorDispatch) => {
|
||||
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;
|
||||
}
|
||||
let cancelationListener: IDisposable;
|
||||
|
||||
@@ -20,7 +20,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
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 { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -170,6 +170,7 @@ export class StartView extends ViewPane {
|
||||
}));
|
||||
attachButtonStyler(this.debugButton, this.themeService);
|
||||
|
||||
dom.addClass(this.element, 'debug-pane');
|
||||
dom.addClass(container, 'debug-start-view');
|
||||
|
||||
this.secondMessageContainer = $('.section');
|
||||
|
||||
@@ -12,12 +12,12 @@ import { IDebugService, IExpression, IScope, CONTEXT_VARIABLES_FOCUSED, IViewMod
|
||||
import { Variable, Scope } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
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 { CopyValueAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
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 { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
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 class VariablesView extends BaseDebugViewPane {
|
||||
export class VariablesView extends ViewPane {
|
||||
|
||||
private onFocusStackFrameScheduler: RunOnceScheduler;
|
||||
private needsRefresh = false;
|
||||
@@ -90,6 +90,7 @@ export class VariablesView extends BaseDebugViewPane {
|
||||
renderBody(container: HTMLElement): void {
|
||||
super.renderBody(container);
|
||||
|
||||
dom.addClass(this.element, 'debug-pane');
|
||||
dom.addClass(container, 'debug-variables');
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
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 { 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 { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
@@ -38,7 +38,7 @@ const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
|
||||
let ignoreVariableSetEmitter = false;
|
||||
let useCachedEvaluation = false;
|
||||
|
||||
export class WatchExpressionsView extends BaseDebugViewPane {
|
||||
export class WatchExpressionsView extends ViewPane {
|
||||
|
||||
private onWatchExpressionsUpdatedScheduler: RunOnceScheduler;
|
||||
private needsRefresh = false;
|
||||
@@ -67,6 +67,7 @@ export class WatchExpressionsView extends BaseDebugViewPane {
|
||||
renderBody(container: HTMLElement): void {
|
||||
super.renderBody(container);
|
||||
|
||||
dom.addClass(this.element, 'debug-pane');
|
||||
dom.addClass(container, 'debug-watch');
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
|
||||
@@ -676,7 +676,11 @@ export class ExplorerView extends ViewPane {
|
||||
if (item.isDisposed) {
|
||||
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]);
|
||||
|
||||
@@ -29,13 +29,13 @@ export class OpenInDesktopIndicator extends Disposable implements IWorkbenchCont
|
||||
) {
|
||||
super();
|
||||
|
||||
const links = environmentService.options?.applicationLinkProvider?.();
|
||||
const links = environmentService.options?.applicationLinks;
|
||||
if (Array.isArray(links) && links?.length > 0) {
|
||||
this.installOpenInDesktopIndicator(links);
|
||||
}
|
||||
}
|
||||
|
||||
private installOpenInDesktopIndicator(links: IApplicationLink[]): void {
|
||||
private installOpenInDesktopIndicator(links: readonly IApplicationLink[]): void {
|
||||
|
||||
// Register action to trigger "Open In Desktop"
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
@@ -71,7 +71,7 @@ export class OpenInDesktopAction extends Action {
|
||||
}
|
||||
|
||||
async run(): Promise<boolean> {
|
||||
const links = this.environmentService.options?.applicationLinkProvider?.();
|
||||
const links = this.environmentService.options?.applicationLinks;
|
||||
if (Array.isArray(links)) {
|
||||
if (links.length === 1) {
|
||||
return this.openApplicationLink(links[0]);
|
||||
@@ -83,7 +83,7 @@ export class OpenInDesktopAction extends Action {
|
||||
return true;
|
||||
}
|
||||
|
||||
private async runWithPicker(links: IApplicationLink[]): Promise<boolean> {
|
||||
private async runWithPicker(links: readonly IApplicationLink[]): Promise<boolean> {
|
||||
|
||||
// Show a picker with choices
|
||||
const quickPick = this.quickInputService.createQuickPick<IApplicationLink>();
|
||||
|
||||
@@ -27,7 +27,7 @@ import { localize } from 'vs/nls';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
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 { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
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 { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
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 { FuzzyScore } from 'vs/base/common/filters';
|
||||
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 { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
|
||||
class RequestState {
|
||||
|
||||
@@ -261,7 +262,7 @@ export class OutlinePane extends ViewPane {
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@IStorageService private readonly _storageService: IStorageService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
@IMarkerDecorationsService private readonly _markerDecorationService: IMarkerDecorationsService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@@ -347,7 +348,7 @@ export class OutlinePane extends ViewPane {
|
||||
|
||||
this._disposables.push(this._tree);
|
||||
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)) {
|
||||
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> {
|
||||
|
||||
await this._editorService.openEditor({
|
||||
resource: model.textModel.uri,
|
||||
options: {
|
||||
preserveFocus: !focus,
|
||||
selection: Range.collapseToStart(element.symbol.selectionRange),
|
||||
selectionRevealType: TextEditorSelectionRevealType.NearTop,
|
||||
}
|
||||
} as IResourceInput, aside ? SIDE_GROUP : ACTIVE_GROUP);
|
||||
await this._editorService.openCodeEditor(
|
||||
{
|
||||
resource: model.textModel.uri,
|
||||
options: {
|
||||
preserveFocus: !focus,
|
||||
selection: Range.collapseToStart(element.symbol.selectionRange),
|
||||
selectionRevealType: TextEditorSelectionRevealType.NearTop,
|
||||
}
|
||||
},
|
||||
this._editorService.getActiveCodeEditor(),
|
||||
aside
|
||||
);
|
||||
}
|
||||
|
||||
private _revealEditorSelection(model: OutlineModel, selection: Selection): void {
|
||||
|
||||
@@ -29,7 +29,7 @@ import { SelectionHighlighter } from 'vs/editor/contrib/multicursor/multicursor'
|
||||
import * as nls from 'vs/nls';
|
||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
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 { IEditorProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -984,7 +984,7 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
|
||||
private static _getContributions(): IEditorContributionDescription[] {
|
||||
const skipContributions = [FoldingController.ID, SelectionHighlighter.ID, FindController.ID];
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
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 { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
@@ -26,6 +26,7 @@ interface IConfiguration extends IWindowsConfiguration {
|
||||
telemetry: { enableCrashReporter: boolean };
|
||||
workbench: { list: { horizontalScrolling: boolean } };
|
||||
debug: { console: { wordWrap: boolean } };
|
||||
editor: { accessibilitySupport: 'on' | 'off' | 'auto' };
|
||||
}
|
||||
|
||||
export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution {
|
||||
@@ -38,6 +39,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo
|
||||
private enableCrashReporter: boolean | undefined;
|
||||
private treeHorizontalScrolling: boolean | undefined;
|
||||
private debugConsoleWordWrap: boolean | undefined;
|
||||
private accessibilitySupport: 'on' | 'off' | 'auto' | undefined;
|
||||
|
||||
constructor(
|
||||
@IHostService private readonly hostService: IHostService,
|
||||
@@ -103,6 +105,14 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo
|
||||
this.enableCrashReporter = config.telemetry.enableCrashReporter;
|
||||
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)
|
||||
|
||||
@@ -13,3 +13,20 @@
|
||||
position: absolute;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ import { localize } from 'vs/nls';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
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 { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
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 { TreeResourceNavigator, WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
|
||||
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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
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 { SideBySideEditor, toResource } from 'vs/workbench/common/editor';
|
||||
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 { debounce } from 'vs/base/common/decorators';
|
||||
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;
|
||||
|
||||
// TODO[ECA]: Localize all the strings
|
||||
interface TimelineActionContext {
|
||||
uri: URI | undefined;
|
||||
item: TreeElement;
|
||||
}
|
||||
|
||||
export class TimelinePane extends ViewPane {
|
||||
static readonly ID = 'timeline';
|
||||
@@ -44,10 +54,12 @@ export class TimelinePane extends ViewPane {
|
||||
private _messageElement!: HTMLDivElement;
|
||||
private _treeElement!: HTMLDivElement;
|
||||
private _tree!: WorkbenchObjectTree<TreeElement, FuzzyScore>;
|
||||
private _treeRenderer: TimelineTreeRenderer | undefined;
|
||||
private _menus: TimelineMenus;
|
||||
private _visibilityDisposables: DisposableStore | undefined;
|
||||
|
||||
// private _excludedSources: Set<string> | undefined;
|
||||
private _items: TimelineItemWithSource[] = [];
|
||||
private _items: TimelineItem[] = [];
|
||||
private _loadingMessageTimer: any | undefined;
|
||||
private _pendingRequests = new Map<string, TimelineRequest>();
|
||||
private _uri: URI | undefined;
|
||||
@@ -67,7 +79,9 @@ export class TimelinePane extends ViewPane {
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@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());
|
||||
scopedContextKeyService.createKey('view', TimelinePane.ID);
|
||||
@@ -88,6 +102,7 @@ export class TimelinePane extends ViewPane {
|
||||
}
|
||||
|
||||
this._uri = uri;
|
||||
this._treeRenderer?.setUri(uri);
|
||||
this.loadTimeline();
|
||||
}
|
||||
|
||||
@@ -187,7 +202,7 @@ export class TimelinePane extends ViewPane {
|
||||
let request = this._pendingRequests.get(source);
|
||||
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);
|
||||
request.tokenSource.token.onCancellationRequested(() => this._pendingRequests.delete(source));
|
||||
@@ -199,7 +214,7 @@ export class TimelinePane extends ViewPane {
|
||||
private async handleRequest(request: TimelineRequest) {
|
||||
let items;
|
||||
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 { }
|
||||
|
||||
@@ -211,7 +226,7 @@ export class TimelinePane extends ViewPane {
|
||||
this.replaceItems(request.source, items);
|
||||
}
|
||||
|
||||
private replaceItems(source: string, items?: TimelineItemWithSource[]) {
|
||||
private replaceItems(source: string, items?: TimelineItem[]) {
|
||||
const hasItems = this._items.length !== 0;
|
||||
|
||||
if (items?.length) {
|
||||
@@ -291,17 +306,20 @@ export class TimelinePane extends ViewPane {
|
||||
// DOM.addClass(this._treeElement, 'show-file-icons');
|
||||
container.appendChild(this._treeElement);
|
||||
|
||||
const renderer = this.instantiationService.createInstance(TimelineTreeRenderer);
|
||||
this._tree = <WorkbenchObjectTree<TreeElement, FuzzyScore>>this.instantiationService.createInstance(WorkbenchObjectTree, 'TimelinePane', this._treeElement, new TimelineListVirtualDelegate(), [renderer], {
|
||||
this._treeRenderer = this.instantiationService.createInstance(TimelineTreeRenderer, this._menus);
|
||||
this._tree = <WorkbenchObjectTree<TreeElement, FuzzyScore>>this.instantiationService.createInstance(WorkbenchObjectTree, 'TimelinePane',
|
||||
this._treeElement, new TimelineListVirtualDelegate(), [this._treeRenderer], {
|
||||
identityProvider: new TimelineIdentityProvider(),
|
||||
keyboardNavigationLabelProvider: new TimelineKeyboardNavigationLabelProvider(),
|
||||
overrideStyles: {
|
||||
listBackground: this.getBackgroundColor()
|
||||
listBackground: this.getBackgroundColor(),
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
const customTreeNavigator = new TreeResourceNavigator(this._tree, { openOnFocus: false, openOnSelection: false });
|
||||
this._register(customTreeNavigator);
|
||||
this._register(this._tree.onContextMenu(e => this.onContextMenu(this._menus, e)));
|
||||
this._register(
|
||||
customTreeNavigator.onDidOpenResource(e => {
|
||||
if (!e.browserEvent) {
|
||||
@@ -316,36 +334,112 @@ export class TimelinePane extends ViewPane {
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class TimelineElementTemplate {
|
||||
static readonly id = 'TimelineElementTemplate';
|
||||
private onContextMenu(menus: TimelineMenus, treeEvent: ITreeContextMenuEvent<TreeElement | null>): void {
|
||||
const item = treeEvent.element;
|
||||
if (item === null) {
|
||||
return;
|
||||
}
|
||||
const event: UIEvent = treeEvent.browserEvent;
|
||||
|
||||
constructor(
|
||||
readonly container: HTMLElement,
|
||||
readonly iconLabel: IconLabel,
|
||||
readonly icon: HTMLElement
|
||||
) { }
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
export class TimelineIdentityProvider implements IIdentityProvider<TimelineItem> {
|
||||
getId(item: TimelineItem): { toString(): string } {
|
||||
return `${item.id}|${item.timestamp}`;
|
||||
this._tree.setFocus([item]);
|
||||
const actions = menus.getResourceContextActions(item);
|
||||
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> {
|
||||
getKeyboardNavigationLabel(element: TimelineItem): { toString(): string } {
|
||||
export class TimelineElementTemplate implements IDisposable {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
export class TimelineListVirtualDelegate implements IListVirtualDelegate<TimelineItem> {
|
||||
getHeight(_element: TimelineItem): number {
|
||||
export class TimelineListVirtualDelegate implements IListVirtualDelegate<TreeElement> {
|
||||
getHeight(_element: TreeElement): number {
|
||||
return 22;
|
||||
}
|
||||
|
||||
getTemplateId(element: TimelineItem): string {
|
||||
getTemplateId(element: TreeElement): string {
|
||||
return TimelineElementTemplate.id;
|
||||
}
|
||||
}
|
||||
@@ -353,14 +447,25 @@ export class TimelineListVirtualDelegate implements IListVirtualDelegate<Timelin
|
||||
class TimelineTreeRenderer implements ITreeRenderer<TreeElement, FuzzyScore, TimelineElementTemplate> {
|
||||
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 {
|
||||
DOM.addClass(container, 'custom-view-tree-node-item');
|
||||
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);
|
||||
return new TimelineElementTemplate(container, this._actionViewItemProvider);
|
||||
}
|
||||
|
||||
renderElement(
|
||||
@@ -369,30 +474,74 @@ class TimelineTreeRenderer implements ITreeRenderer<TreeElement, FuzzyScore, Tim
|
||||
template: TimelineElementTemplate,
|
||||
height: number | undefined
|
||||
): 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;
|
||||
|
||||
if (iconUrl) {
|
||||
template.icon.className = 'custom-view-tree-node-item-icon';
|
||||
template.icon.style.backgroundImage = DOM.asCSSUrl(iconUrl);
|
||||
|
||||
} else {
|
||||
let iconClass: string | undefined;
|
||||
if (element.themeIcon /*&& !this.isFileKindThemeIcon(element.themeIcon)*/) {
|
||||
iconClass = ThemeIcon.asClassName(element.themeIcon);
|
||||
if (item.themeIcon /*&& !this.isFileKindThemeIcon(element.themeIcon)*/) {
|
||||
iconClass = ThemeIcon.asClassName(item.themeIcon);
|
||||
}
|
||||
template.icon.className = iconClass ? `custom-view-tree-node-item-icon ${iconClass}` : '';
|
||||
}
|
||||
|
||||
template.iconLabel.setLabel(element.label, element.description, {
|
||||
title: element.detail,
|
||||
template.iconLabel.setLabel(item.label, item.description, {
|
||||
title: item.detail,
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@ export function toKey(extension: ExtensionIdentifier | string, source: string) {
|
||||
}
|
||||
|
||||
export interface TimelineItem {
|
||||
handle: string;
|
||||
source: string;
|
||||
|
||||
timestamp: number;
|
||||
label: string;
|
||||
id?: string;
|
||||
icon?: URI,
|
||||
iconDark?: URI,
|
||||
themeIcon?: { id: string },
|
||||
@@ -28,19 +30,29 @@ export interface TimelineItem {
|
||||
contextValue?: string;
|
||||
}
|
||||
|
||||
export interface TimelineItemWithSource extends TimelineItem {
|
||||
source: string;
|
||||
}
|
||||
|
||||
export interface TimelineChangeEvent {
|
||||
id: string;
|
||||
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 {
|
||||
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 {
|
||||
@@ -55,7 +67,7 @@ export interface TimelineProvidersChangeEvent {
|
||||
}
|
||||
|
||||
export interface TimelineRequest {
|
||||
readonly items: Promise<TimelineItemWithSource[]>;
|
||||
readonly result: Promise<Timeline | undefined>;
|
||||
readonly source: string;
|
||||
readonly tokenSource: CancellationTokenSource;
|
||||
readonly uri: URI;
|
||||
@@ -72,9 +84,7 @@ export interface ITimelineService {
|
||||
|
||||
getSources(): string[];
|
||||
|
||||
getTimeline(uri: URI, token: CancellationToken): Promise<TimelineItem[]>;
|
||||
|
||||
getTimelineRequest(id: string, uri: URI, tokenSource: CancellationTokenSource): TimelineRequest | undefined;
|
||||
getTimeline(id: string, uri: URI, cursor: TimelineCursor, tokenSource: CancellationTokenSource, options?: { cacheResults?: boolean }): TimelineRequest | undefined;
|
||||
}
|
||||
|
||||
const TIMELINE_SERVICE_ID = 'timeline';
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
* 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 { IDisposable } from 'vs/base/common/lifecycle';
|
||||
// import { basename } from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
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 {
|
||||
_serviceBrand: undefined;
|
||||
@@ -81,42 +81,7 @@ export class TimelineService implements ITimelineService {
|
||||
return [...this._providers.keys()];
|
||||
}
|
||||
|
||||
async getTimeline(uri: URI, token: CancellationToken, predicate?: (provider: TimelineProvider) => 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) {
|
||||
getTimeline(id: string, uri: URI, cursor: TimelineCursor, tokenSource: CancellationTokenSource, options?: { cacheResults?: boolean }) {
|
||||
this.logService.trace(`TimelineService#getTimeline(${id}): uri=${uri.toString(true)}`);
|
||||
|
||||
const provider = this._providers.get(id);
|
||||
@@ -133,12 +98,16 @@ export class TimelineService implements ITimelineService {
|
||||
}
|
||||
|
||||
return {
|
||||
items: provider.provideTimeline(uri, tokenSource.token)
|
||||
.then(items => {
|
||||
items = items.map(item => ({ ...item, source: provider.id }));
|
||||
items.sort((a, b) => (b.timestamp - a.timestamp) || b.source.localeCompare(a.source, undefined, { numeric: true, sensitivity: 'base' }));
|
||||
result: provider.provideTimeline(uri, cursor, tokenSource.token, options)
|
||||
.then(result => {
|
||||
if (result === undefined) {
|
||||
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,
|
||||
tokenSource: tokenSource,
|
||||
|
||||
@@ -127,41 +127,41 @@ export class ProductContribution implements IWorkbenchContribution {
|
||||
@IHostService hostService: IHostService,
|
||||
@IProductService productService: IProductService
|
||||
) {
|
||||
if (!hostService.hasFocus) {
|
||||
return;
|
||||
}
|
||||
hostService.hadLastFocus().then(hadLastFocus => {
|
||||
if (!hadLastFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, '');
|
||||
const shouldShowReleaseNotes = configurationService.getValue<boolean>('update.showReleaseNotes');
|
||||
const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, '');
|
||||
const shouldShowReleaseNotes = configurationService.getValue<boolean>('update.showReleaseNotes');
|
||||
|
||||
// was there an update? if so, open release notes
|
||||
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
|
||||
/* // {{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, () => {
|
||||
*/
|
||||
notificationService.prompt(
|
||||
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: () => {
|
||||
const uri = URI.parse(releaseNotesUrl);
|
||||
openerService.open(uri);
|
||||
}
|
||||
}],
|
||||
{ sticky: true }
|
||||
);
|
||||
// }); // {{SQL CARBON EDIT}}
|
||||
}
|
||||
// was there an update? if so, open release notes
|
||||
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) {
|
||||
/*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
|
||||
.then(undefined, () => {*/
|
||||
notificationService.prompt(
|
||||
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: () => {
|
||||
const uri = URI.parse(releaseNotesUrl);
|
||||
openerService.open(uri);
|
||||
}
|
||||
}],
|
||||
{ sticky: true }
|
||||
);
|
||||
}/*);
|
||||
}*/
|
||||
|
||||
// should we show the new license?
|
||||
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));
|
||||
}
|
||||
// should we show the new license?
|
||||
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));
|
||||
}
|
||||
|
||||
storageService.store(ProductContribution.KEY, productService.version, StorageScope.GLOBAL);
|
||||
storageService.store(ProductContribution.KEY, productService.version, StorageScope.GLOBAL);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -286,4 +286,10 @@ export abstract class BaseWebview<T extends HTMLElement> extends Disposable {
|
||||
this.element.style.pointerEvents = '';
|
||||
}
|
||||
}
|
||||
|
||||
public selectAll() {
|
||||
if (this.element) {
|
||||
this._send('execCommand', 'selectAll');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +187,7 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd
|
||||
showFind(): void { this.withWebview(webview => webview.showFind()); }
|
||||
hideFind(): void { this.withWebview(webview => webview.hideFind()); }
|
||||
runFindAction(previous: boolean): void { this.withWebview(webview => webview.runFindAction(previous)); }
|
||||
selectAll(): void { this.withWebview(webview => webview.selectAll()); }
|
||||
|
||||
public getInnerWebview() {
|
||||
return this._webview.value;
|
||||
|
||||
@@ -232,23 +232,23 @@
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
const handleAuxClick =
|
||||
(event) => {
|
||||
// Prevent middle clicks opening a broken link in the browser
|
||||
if (!event.view || !event.view.document) {
|
||||
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;
|
||||
(event) => {
|
||||
// Prevent middle clicks opening a broken link in the browser
|
||||
if (!event.view || !event.view.document) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {KeyboardEvent} e
|
||||
@@ -449,6 +449,10 @@
|
||||
}, 0);
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {Document} contentDocument
|
||||
* @param {Window} contentWindow
|
||||
*/
|
||||
const onLoad = (contentDocument, contentWindow) => {
|
||||
if (contentDocument && contentDocument.body) {
|
||||
// Workaround for https://github.com/Microsoft/vscode/issues/12865
|
||||
@@ -492,10 +496,12 @@
|
||||
}, 200);
|
||||
|
||||
newFrame.contentWindow.addEventListener('load', function (e) {
|
||||
const contentDocument = /** @type {Document} */ (e.target);
|
||||
|
||||
if (loadTimeout) {
|
||||
clearTimeout(loadTimeout);
|
||||
loadTimeout = undefined;
|
||||
onLoad(e.target, this);
|
||||
onLoad(contentDocument, this);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -539,6 +545,13 @@
|
||||
initData.initialScrollProgress = progress;
|
||||
});
|
||||
|
||||
host.onMessage('execCommand', (_event, data) => {
|
||||
const target = getActiveFrame();
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
target.contentDocument.execCommand(data);
|
||||
});
|
||||
|
||||
trackFocus({
|
||||
onFocus: () => host.postMessage('did-focus'),
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
|
||||
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
||||
import { webviewDeveloperCategory } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
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 { WebviewInput } from './webviewEditorInput';
|
||||
import { IWebviewWorkbenchService, WebviewEditorService } from './webviewWorkbenchService';
|
||||
@@ -50,6 +50,11 @@ registerAction2(class extends WebViewEditorFindPreviousCommand {
|
||||
constructor() { super(webviewActiveContextKeyExpr); }
|
||||
});
|
||||
|
||||
registerAction2(class extends SelectAllWebviewEditorCommand {
|
||||
constructor() { super(webviewActiveContextKeyExpr); }
|
||||
});
|
||||
|
||||
|
||||
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
SyncActionDescriptor.create(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL),
|
||||
|
||||
@@ -93,6 +93,8 @@ export interface Webview extends IDisposable {
|
||||
hideFind(): void;
|
||||
runFindAction(previous: boolean): void;
|
||||
|
||||
selectAll(): void;
|
||||
|
||||
windowDidDragStart(): void;
|
||||
windowDidDragEnd(): void;
|
||||
}
|
||||
|
||||
@@ -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 { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
|
||||
|
||||
export class ShowWebViewEditorFindWidgetAction extends Action2 {
|
||||
public static readonly ID = 'editor.action.webvieweditor.showFind';
|
||||
@@ -97,6 +98,29 @@ export class WebViewEditorFindPreviousCommand extends Action2 {
|
||||
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 {
|
||||
static readonly ID = 'workbench.action.webview.reloadWebviewAction';
|
||||
static readonly LABEL = nls.localize('refreshWebviewLabel', "Reload Webviews");
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
|
||||
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 { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -71,31 +71,33 @@ export class WebviewEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
public showFind() {
|
||||
this.withWebview(webview => {
|
||||
webview.showFind();
|
||||
if (this.webview) {
|
||||
this.webview.showFind();
|
||||
this._findWidgetVisible.set(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public hideFind() {
|
||||
this._findWidgetVisible.reset();
|
||||
this.withWebview(webview => webview.hideFind());
|
||||
this.webview?.hideFind();
|
||||
}
|
||||
|
||||
public find(previous: boolean) {
|
||||
this.withWebview(webview => {
|
||||
webview.runFindAction(previous);
|
||||
});
|
||||
this.webview?.runFindAction(previous);
|
||||
}
|
||||
|
||||
public selectAll() {
|
||||
this.webview?.selectAll();
|
||||
}
|
||||
|
||||
public reload() {
|
||||
this.withWebview(webview => webview.reload());
|
||||
this.webview?.reload();
|
||||
}
|
||||
|
||||
public layout(dimension: DOM.Dimension): void {
|
||||
this._dimension = dimension;
|
||||
if (this.input && this.input instanceof WebviewInput) {
|
||||
this.synchronizeWebviewContainerDimensions(this.input.webview, dimension);
|
||||
if (this.webview) {
|
||||
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 {
|
||||
if (this.input && this.input instanceof WebviewInput) {
|
||||
f(this.input.webview);
|
||||
}
|
||||
public get webview(): WebviewEditorOverlay | undefined {
|
||||
return this.input instanceof WebviewInput ? this.input.webview : undefined;
|
||||
}
|
||||
|
||||
protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void {
|
||||
if (this.input instanceof WebviewInput) {
|
||||
const webview = this.input.webview;
|
||||
if (this.input instanceof WebviewInput && this.webview) {
|
||||
if (visible) {
|
||||
webview.claim(this);
|
||||
this.webview.claim(this);
|
||||
} else {
|
||||
webview.release(this);
|
||||
this.webview.release(this);
|
||||
}
|
||||
this.claimWebview(this.input);
|
||||
}
|
||||
@@ -132,8 +131,8 @@ export class WebviewEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
public clearInput() {
|
||||
if (this.input && this.input instanceof WebviewInput) {
|
||||
this.input.webview.release(this);
|
||||
if (this.webview) {
|
||||
this.webview.release(this);
|
||||
this._webviewVisibleDisposables.clear();
|
||||
}
|
||||
|
||||
@@ -145,8 +144,8 @@ export class WebviewEditor extends BaseEditor {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.input && this.input instanceof WebviewInput) {
|
||||
this.input.webview.release(this);
|
||||
if (this.webview) {
|
||||
this.webview.release(this);
|
||||
}
|
||||
|
||||
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, () => {
|
||||
if (this.input instanceof WebviewInput) {
|
||||
this.input.webview.windowDidDragStart();
|
||||
}
|
||||
this.webview?.windowDidDragStart();
|
||||
}));
|
||||
|
||||
const onDragEnd = () => {
|
||||
if (this.input instanceof WebviewInput) {
|
||||
this.input.webview.windowDidDragEnd();
|
||||
}
|
||||
this.webview?.windowDidDragEnd();
|
||||
};
|
||||
this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.DRAG_END, onDragEnd));
|
||||
this._webviewVisibleDisposables.add(DOM.addDisposableListener(window, DOM.EventType.MOUSE_MOVE, currentEvent => {
|
||||
|
||||
@@ -26,8 +26,6 @@ actionRegistry.registerWorkbenchAction(
|
||||
function registerWebViewCommands(editorId: string): void {
|
||||
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
|
||||
if (isMacintosh) {
|
||||
registerAction2(class extends webviewCommands.CopyWebviewEditorCommand { constructor() { super(contextKeyExpr); } });
|
||||
|
||||
@@ -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 {
|
||||
public static readonly ID = 'editor.action.webvieweditor.copy';
|
||||
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 {
|
||||
withActiveWebviewBasedWebview(accessor, webview => webview.copy());
|
||||
getActiveWebviewBasedWebview(accessor)?.copy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +76,7 @@ export class PasteWebviewEditorCommand extends Action2 {
|
||||
}
|
||||
|
||||
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 {
|
||||
withActiveWebviewBasedWebview(accessor, webview => webview.cut());
|
||||
getActiveWebviewBasedWebview(accessor)?.cut();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +118,7 @@ export class UndoWebviewEditorCommand extends Action2 {
|
||||
}
|
||||
|
||||
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 {
|
||||
withActiveWebviewBasedWebview(accessor, webview => webview.redo());
|
||||
getActiveWebviewBasedWebview(accessor)?.redo();
|
||||
}
|
||||
}
|
||||
|
||||
function withActiveWebviewBasedWebview(accessor: ServicesAccessor, f: (webview: ElectronWebviewBasedWebview) => void): void {
|
||||
const webViewEditor = getActiveWebviewEditor(accessor);
|
||||
if (webViewEditor) {
|
||||
webViewEditor.withWebview(webview => {
|
||||
if (webview instanceof ElectronWebviewBasedWebview) {
|
||||
f(webview);
|
||||
} else if ((webview as WebviewEditorOverlay).getInnerWebview) {
|
||||
const innerWebview = (webview as WebviewEditorOverlay).getInnerWebview();
|
||||
if (innerWebview instanceof ElectronWebviewBasedWebview) {
|
||||
f(innerWebview);
|
||||
}
|
||||
}
|
||||
});
|
||||
function getActiveWebviewBasedWebview(accessor: ServicesAccessor): ElectronWebviewBasedWebview | undefined {
|
||||
const webview = getActiveWebviewEditor(accessor)?.webview;
|
||||
if (!webview) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
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
|
||||
|
||||
@@ -333,8 +334,7 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten
|
||||
(function registerJSONSchemas(): void {
|
||||
const argvDefinitionFileSchemaId = 'vscode://schemas/argv';
|
||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||
|
||||
jsonRegistry.registerSchema(argvDefinitionFileSchemaId, {
|
||||
const schema: IJSONSchema = {
|
||||
id: argvDefinitionFileSchemaId,
|
||||
allowComments: 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.')
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
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);
|
||||
})();
|
||||
|
||||
@@ -4,13 +4,18 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
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 { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
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 {
|
||||
enabled: boolean;
|
||||
@@ -65,3 +70,22 @@ export class NodeAccessibilityService extends AccessibilityService implements IA
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -95,6 +95,10 @@ export class BrowserHostService extends Disposable implements IHostService {
|
||||
return document.hasFocus();
|
||||
}
|
||||
|
||||
async hadLastFocus(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
async focus(): Promise<void> {
|
||||
window.focus();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ export interface IHostService {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -36,6 +36,16 @@ export class DesktopHostService extends Disposable implements IHostService {
|
||||
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(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise<void>;
|
||||
openWindow(arg1?: IOpenEmptyWindowOptions | IWindowOpenable[], arg2?: IOpenWindowOptions): Promise<void> {
|
||||
|
||||
@@ -79,7 +79,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
private lastResolvedFileStat: IFileStatWithMetadata | undefined;
|
||||
|
||||
private readonly saveSequentializer = new TaskSequentializer();
|
||||
private lastSaveAttemptTime = 0;
|
||||
|
||||
private dirty = 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
|
||||
}
|
||||
|
||||
// Actually do save and log
|
||||
this.logService.trace('[text file model] save() - enter', this.resource.toString());
|
||||
|
||||
await this.doSave(options);
|
||||
|
||||
this.logService.trace('[text file model] save() - exit', this.resource.toString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private doSave(options: ITextFileSaveOptions): Promise<void> {
|
||||
private async doSave(options: ITextFileSaveOptions): Promise<void> {
|
||||
if (typeof options.reason !== 'number') {
|
||||
options.reason = SaveReason.EXPLICIT;
|
||||
}
|
||||
@@ -587,7 +585,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
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());
|
||||
|
||||
return Promise.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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();
|
||||
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;
|
||||
saveParticipantPromise = this.textFileService.saveParticipant.participate(this, { reason: options.reason }, saveParticipantCancellation.token).then(onCompleteOrError, onCompleteOrError);
|
||||
}
|
||||
|
||||
// mark the save participant as current pending save operation
|
||||
return (this.saveSequentializer as TaskSequentializer).setPending(versionId, saveParticipantPromise.then(newVersionId => { // {{SQL CARBON EDIT}} strict-null-check
|
||||
// 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.
|
||||
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
|
||||
// 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 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
|
||||
if (options.force && !this.dirty && !this.inOrphanMode && options.reason === SaveReason.EXPLICIT && versionId === newVersionId) {
|
||||
return this.doTouch(newVersionId, options.reason);
|
||||
if (options.force && !this.dirty && !this.inOrphanMode && options.reason === SaveReason.EXPLICIT && versionId === this.versionId) {
|
||||
return this.doTouch(this.versionId, options.reason);
|
||||
}
|
||||
|
||||
// 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
|
||||
this.inErrorMode = false;
|
||||
|
||||
// Remember when this model was saved last
|
||||
this.lastSaveAttemptTime = Date.now();
|
||||
|
||||
// Save to Disk
|
||||
// mark the save operation as currently pending with the versionId (it might have changed from a save participant triggering)
|
||||
// Save to Disk. We mark the save operation as currently pending with
|
||||
// the latest versionId because it might have changed from a save
|
||||
// participant triggering
|
||||
this.logService.trace(`[text file model] doSave(${versionId}) - before write()`, this.resource.toString());
|
||||
const lastResolvedFileStat = assertIsDefined(this.lastResolvedFileStat);
|
||||
return this.saveSequentializer.setPending(newVersionId, this.textFileService.write(lastResolvedFileStat.resource, this.createSnapshot(), {
|
||||
overwriteReadonly: options.overwriteReadonly,
|
||||
overwriteEncoding: options.overwriteEncoding,
|
||||
mtime: lastResolvedFileStat.mtime,
|
||||
encoding: this.getEncoding(),
|
||||
etag: (options.ignoreModifiedSince || !this.filesConfigurationService.preventSaveConflicts(lastResolvedFileStat.resource, this.getMode())) ? ETAG_DISABLED : lastResolvedFileStat.etag,
|
||||
writeElevated: options.writeElevated
|
||||
}).then(stat => this.handleSaveSuccess(stat, versionId, options), error => this.handleSaveError(error, versionId, options)));
|
||||
}), () => saveParticipantCancellation.cancel());
|
||||
const textFileEdiorModel = this;
|
||||
return this.saveSequentializer.setPending(versionId, (async () => {
|
||||
try {
|
||||
const stat = await this.textFileService.write(lastResolvedFileStat.resource, textFileEdiorModel.createSnapshot(), {
|
||||
overwriteReadonly: options.overwriteReadonly,
|
||||
overwriteEncoding: options.overwriteEncoding,
|
||||
mtime: lastResolvedFileStat.mtime,
|
||||
encoding: this.getEncoding(),
|
||||
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 {
|
||||
@@ -733,19 +734,24 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
|
||||
private doTouch(this: TextFileEditorModel & IResolvedTextFileEditorModel, versionId: number, reason: SaveReason): Promise<void> {
|
||||
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
|
||||
this.updateLastResolvedFileStat(stat);
|
||||
return this.saveSequentializer.setPending(versionId, (async () => {
|
||||
try {
|
||||
const stat = await this.textFileService.write(lastResolvedFileStat.resource, this.createSnapshot(), {
|
||||
mtime: lastResolvedFileStat.mtime,
|
||||
encoding: this.getEncoding(),
|
||||
etag: lastResolvedFileStat.etag
|
||||
});
|
||||
|
||||
// Emit File Saved Event
|
||||
this._onDidSave.fire(reason);
|
||||
// Updated resolved stat with updated stat since touching it might have changed mtime
|
||||
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 {
|
||||
@@ -776,10 +782,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
||||
|
||||
//#endregion
|
||||
|
||||
getLastSaveAttemptTime(): number {
|
||||
return this.lastSaveAttemptTime;
|
||||
}
|
||||
|
||||
hasState(state: ModelState): boolean {
|
||||
switch (state) {
|
||||
case ModelState.CONFLICT:
|
||||
|
||||
@@ -84,7 +84,13 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
|
||||
// to have a size of 2 (1 running load and 1 queued load).
|
||||
const queue = this.modelLoadQueue.queueFor(model.resource);
|
||||
if (queue.size <= 1) {
|
||||
queue.queue(() => model.load().then(undefined, onUnexpectedError));
|
||||
queue.queue(async () => {
|
||||
try {
|
||||
await model.load();
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,6 @@ suite('Files - TextFileEditorModel', () => {
|
||||
|
||||
await pendingSave;
|
||||
|
||||
assert.ok(model.getLastSaveAttemptTime() <= Date.now());
|
||||
assert.ok(model.hasState(ModelState.SAVED));
|
||||
assert.ok(!model.isDirty());
|
||||
assert.ok(savedEvent);
|
||||
@@ -488,8 +487,6 @@ suite('Files - TextFileEditorModel', () => {
|
||||
assert.ok(!accessor.textFileService.isDirty(toResource.call(this, '/path/index_async2.txt')));
|
||||
assert.ok(assertIsDefined(model1.getStat()).mtime > m1Mtime);
|
||||
assert.ok(assertIsDefined(model2.getStat()).mtime > m2Mtime);
|
||||
assert.ok(model1.getLastSaveAttemptTime() > m1Mtime);
|
||||
assert.ok(model2.getLastSaveAttemptTime() > m2Mtime);
|
||||
|
||||
model1.dispose();
|
||||
model2.dispose();
|
||||
@@ -506,12 +503,11 @@ suite('Files - TextFileEditorModel', () => {
|
||||
});
|
||||
|
||||
accessor.textFileService.saveParticipant = {
|
||||
participate: model => {
|
||||
participate: async model => {
|
||||
assert.ok(model.isDirty());
|
||||
model.textEditorModel!.setValue('bar');
|
||||
assert.ok(model.isDirty());
|
||||
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);
|
||||
|
||||
accessor.textFileService.saveParticipant = {
|
||||
participate: (model) => {
|
||||
return Promise.reject(new Error('boom'));
|
||||
participate: async model => {
|
||||
new Error('boom');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -563,10 +559,9 @@ suite('Files - TextFileEditorModel', () => {
|
||||
let participations: boolean[] = [];
|
||||
|
||||
accessor.textFileService.saveParticipant = {
|
||||
participate: (model) => {
|
||||
return timeout(10).then(() => {
|
||||
participations.push(true);
|
||||
});
|
||||
participate: async model => {
|
||||
await timeout(10);
|
||||
participations.push(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -586,4 +581,49 @@ suite('Files - TextFileEditorModel', () => {
|
||||
assert.equal(participations.length, 1);
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -865,6 +865,7 @@ export class TestHostService implements IHostService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
readonly hasFocus: boolean = true;
|
||||
async hadLastFocus(): Promise<boolean> { return true; }
|
||||
readonly onDidChangeFocus: Event<boolean> = Event.None;
|
||||
|
||||
async restart(): Promise<void> { }
|
||||
|
||||
@@ -80,17 +80,29 @@ interface IApplicationLink {
|
||||
uri: URI;
|
||||
|
||||
/**
|
||||
* A label for the link to display.
|
||||
* A label for the application link to display.
|
||||
*/
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface IApplicationLinkProvider {
|
||||
(): IApplicationLink[] | undefined
|
||||
interface ICommand {
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
//#region Connection related configuration
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -108,6 +120,36 @@ interface IWorkbenchConstructionOptions {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -119,16 +161,6 @@ interface IWorkbenchConstructionOptions {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -154,21 +186,6 @@ interface IWorkbenchConstructionOptions {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -179,7 +196,20 @@ interface IWorkbenchConstructionOptions {
|
||||
* - N elements: there will be a "Open in Desktop" affordance that opens
|
||||
* 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`.
|
||||
@@ -190,20 +220,8 @@ interface IWorkbenchConstructionOptions {
|
||||
* Whether to enable the smoke test driver.
|
||||
*/
|
||||
readonly driver?: boolean;
|
||||
}
|
||||
|
||||
interface ICommandHandler {
|
||||
(...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;
|
||||
//#endregion
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,24 +229,22 @@ interface IWorkbench {
|
||||
*
|
||||
* @param domElement the container to create the workbench in
|
||||
* @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
|
||||
await main(domElement, options);
|
||||
|
||||
// Return facade
|
||||
return {
|
||||
registerCommand: (id: string, command: ICommandHandler): IDisposable => {
|
||||
return CommandsRegistry.registerCommand(id, (accessor, ...args: any[]) => {
|
||||
// Register commands if any
|
||||
if (Array.isArray(options.commands)) {
|
||||
for (const command of options.commands) {
|
||||
CommandsRegistry.registerCommand(command.id, (accessor, ...args: any[]) => {
|
||||
// we currently only pass on the arguments but not the accessor
|
||||
// to the command to reduce our exposure of internal API.
|
||||
command(...args);
|
||||
command.handler(...args);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
@@ -237,9 +253,6 @@ export {
|
||||
create,
|
||||
IWorkbenchConstructionOptions,
|
||||
|
||||
// Workbench Facade
|
||||
IWorkbench,
|
||||
ICommandHandler,
|
||||
|
||||
// Basic Types
|
||||
URI,
|
||||
@@ -291,5 +304,7 @@ export {
|
||||
|
||||
// Protocol Links
|
||||
IApplicationLink,
|
||||
IApplicationLinkProvider
|
||||
|
||||
// Commands
|
||||
ICommand
|
||||
};
|
||||
|
||||
@@ -141,10 +141,12 @@ export function connect(engine: 'chromium' | 'webkit' | 'firefox' = 'chromium'):
|
||||
return new Promise(async (c) => {
|
||||
const browser = await playwright[engine].launch({
|
||||
// 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];
|
||||
await page.setViewport({ width, height });
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
await page.setViewportSize({ width, height });
|
||||
await page.goto(`${endpoint}&folder=vscode-remote://localhost:9888${URI.file(workspacePath!).path}`);
|
||||
const result = {
|
||||
client: { dispose: () => browser.close() && teardown() },
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"devDependencies": {
|
||||
"@types/mkdirp": "0.5.1",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/optimist": "0.0.29",
|
||||
"@types/rimraf": "2.0.2",
|
||||
"@types/tmp": "^0.1.0",
|
||||
"rimraf": "^2.6.1",
|
||||
|
||||
@@ -11,8 +11,9 @@ import * as tmp from 'tmp';
|
||||
import * as rimraf from 'rimraf';
|
||||
import { URI } from 'vscode-uri';
|
||||
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('extensionDevelopmentPath', 'path to the extension to test').string('extensionDevelopmentPath')
|
||||
.describe('extensionTestsPath', 'path to the extension tests').string('extensionTestsPath')
|
||||
@@ -28,11 +29,12 @@ if (optimist.argv.help) {
|
||||
const width = 1200;
|
||||
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 browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug), dumpio: true, args });
|
||||
const page = (await browser.defaultContext().pages())[0];
|
||||
await page.setViewport({ width, height });
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
await page.setViewportSize({ width, height });
|
||||
|
||||
const host = endpoint.host;
|
||||
const protocol = 'vscode-remote';
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.26.tgz#213e153babac0ed169d44a6d919501e68f59dea9"
|
||||
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":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e"
|
||||
|
||||
@@ -120,7 +120,8 @@ const testModules = (async function () {
|
||||
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 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'));
|
||||
if (argv.build) {
|
||||
target.search = `?build=true`;
|
||||
|
||||
33
yarn.lock
33
yarn.lock
@@ -6046,11 +6046,6 @@ mime@^1.4.1:
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
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:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
|
||||
@@ -7107,29 +7102,28 @@ pkg-dir@^3.0.0:
|
||||
dependencies:
|
||||
find-up "^3.0.0"
|
||||
|
||||
playwright-core@=0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-0.10.0.tgz#86699c9cc3e613d733e6635a54aceea1993013d5"
|
||||
integrity sha512-yernA6yrrBhmb8M5eO6GZsJOrBKWOZszlu65Luz8LP7ryaDExN1sE9XjQBNbiwJ5Gfs8cehtAO7GfTDJt+Z2cQ==
|
||||
playwright-core@=0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-0.11.0.tgz#a2372833f6ec4e7886c4409e3da93df997aee61b"
|
||||
integrity sha512-9UPP/Max65PMiZJz9DNWB3ZRWtTlYlceLFnm6JO8aU7m6Vw3gwCvuSGoC5W69H67q98jH0VPSPp546+EnkiR2g==
|
||||
dependencies:
|
||||
debug "^4.1.0"
|
||||
extract-zip "^1.6.6"
|
||||
https-proxy-agent "^3.0.0"
|
||||
jpeg-js "^0.3.6"
|
||||
mime "^2.0.3"
|
||||
pngjs "^3.4.0"
|
||||
progress "^2.0.3"
|
||||
proxy-from-env "^1.0.0"
|
||||
rimraf "^2.6.1"
|
||||
rimraf "^3.0.2"
|
||||
uuid "^3.4.0"
|
||||
ws "^6.1.0"
|
||||
|
||||
playwright@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-0.10.0.tgz#d37f7e42e0e868dcc4ec35cb0a8dbc6248457642"
|
||||
integrity sha512-f3VRME/PIO5NbcWnlCDfXwPC0DAZJ7ETkcAdE+sensLCOkfDtLh97E71ZuxNCaPYsUA6FIPi5syD8pHJW/4hQQ==
|
||||
playwright@0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-0.11.0.tgz#2abec99ea278b220bcd3902d7520ec22abc2d97e"
|
||||
integrity sha512-cTJZ06OhwseMC9+D6KX1NmZXyEoaJl0o6GLkDhwmou3IFTrUFVOw7KYMBpcbJz0Rhb/de5ZPFlDTffLfEy/9lg==
|
||||
dependencies:
|
||||
playwright-core "=0.10.0"
|
||||
playwright-core "=0.11.0"
|
||||
|
||||
plist@^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:
|
||||
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:
|
||||
version "2.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
|
||||
|
||||
Reference in New Issue
Block a user