Merge from vscode 27ada910e121e23a6d95ecca9cae595fb98ab568

This commit is contained in:
ADS Merger
2020-04-30 00:53:43 +00:00
parent 87e5239713
commit 93f35ca321
413 changed files with 7190 additions and 8756 deletions
+4 -2
View File
@@ -485,7 +485,8 @@
"**/{vs,sql}/workbench/services/**/common/**", "**/{vs,sql}/workbench/services/**/common/**",
"**/{vs,sql}/workbench/api/**/common/**", "**/{vs,sql}/workbench/api/**/common/**",
"vs/workbench/contrib/files/common/editors/fileEditorInput", // this should be fine, it only accesses constants from contrib "vs/workbench/contrib/files/common/editors/fileEditorInput", // this should be fine, it only accesses constants from contrib
"vscode-textmate" "vscode-textmate",
"vscode-oniguruma"
] ]
}, },
{ {
@@ -519,7 +520,8 @@
"onigasm-umd", "onigasm-umd",
"sanitize-html", "sanitize-html",
"@angular/*", "@angular/*",
"rxjs/**" "rxjs/**",
"vscode-oniguruma"
] ]
}, },
{ {
-1
View File
@@ -79,7 +79,6 @@
"type": "pwa-chrome", "type": "pwa-chrome",
"request": "launch", "request": "launch",
"name": "Launch azuredatastudio", "name": "Launch azuredatastudio",
"browserLaunchLocation": "workspace",
"windows": { "windows": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.bat" "runtimeExecutable": "${workspaceFolder}/scripts/sql.bat"
}, },
+16 -6
View File
@@ -1,9 +1,19 @@
# Query: \\w+\\?\\..+![(.[] # Query: \\w+\\?\\.\\w+![(.[]
# Flags: RegExp # Flags: RegExp
# ContextLines: 2 # ContextLines: 2
2 results - 2 files
src/vs/base/browser/ui/tree/asyncDataTree.ts: src/vs/base/browser/ui/tree/asyncDataTree.ts:
270 } : undefined, 243 } : () => 'treeitem',
271 isChecked: options.ariaProvider!.isChecked ? (e) => { 244 isChecked: options.accessibilityProvider!.isChecked ? (e) => {
272: return options.ariaProvider?.isChecked!(e.element as T); 245: return !!(options.accessibilityProvider?.isChecked!(e.element as T));
273 } : undefined 246 } : undefined,
274 }, 247 getAriaLabel(e) {
src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts:
254
255 return debugDynamicExtensions.map(e => {
256: const type = e.contributes?.debuggers![0].type!;
257 return {
258 label: this.getDebuggerLabel(type)!,
+4 -2
View File
@@ -7,7 +7,8 @@
"**/.DS_Store": true, "**/.DS_Store": true,
"build/**/*.js": { "build/**/*.js": {
"when": "$(basename).ts" "when": "$(basename).ts"
} },
"src/vs/server": false
}, },
"files.associations": { "files.associations": {
"cglicenses.json": "jsonc" "cglicenses.json": "jsonc"
@@ -24,7 +25,8 @@
"test/smoke/out/**": true, "test/smoke/out/**": true,
"test/automation/out/**": true, "test/automation/out/**": true,
"test/integration/browser/out/**": true, "test/integration/browser/out/**": true,
"src/vs/base/test/node/uri.test.data.txt": true "src/vs/base/test/node/uri.test.data.txt": true,
"src/vs/server": false
}, },
"lcov.path": [ "lcov.path": [
"./.build/coverage/lcov.info", "./.build/coverage/lcov.info",
-7
View File
@@ -19,13 +19,6 @@ vscode-sqlite3/build/**
vscode-sqlite3/src/** vscode-sqlite3/src/**
!vscode-sqlite3/build/Release/*.node !vscode-sqlite3/build/Release/*.node
oniguruma/binding.gyp
oniguruma/build/**
oniguruma/src/**
oniguruma/deps/**
!oniguruma/build/Release/*.node
!oniguruma/src/*.js
windows-mutex/binding.gyp windows-mutex/binding.gyp
windows-mutex/build/** windows-mutex/build/**
windows-mutex/src/** windows-mutex/src/**
+1 -1
View File
@@ -244,7 +244,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
const deps = gulp.src(dependenciesSrc, { base: '.', dot: true }) const deps = gulp.src(dependenciesSrc, { base: '.', dot: true })
.pipe(filter(['**', '!**/package-lock.json'])) .pipe(filter(['**', '!**/package-lock.json']))
.pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore'))) .pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore')))
.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar')); .pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*', '**/*.wasm'], 'app/node_modules.asar'));
let all = es.merge( let all = es.merge(
packageJsonStream, packageJsonStream,
+1
View File
@@ -187,6 +187,7 @@ const excludedExtensions = [
'vscode-test-resolver', 'vscode-test-resolver',
'ms-vscode.node-debug', 'ms-vscode.node-debug',
'ms-vscode.node-debug2', 'ms-vscode.node-debug2',
'vscode-notebook-tests',
'integration-tests', 'integration-tests',
]; ];
// {{SQL CARBON EDIT}} // {{SQL CARBON EDIT}}
+1
View File
@@ -221,6 +221,7 @@ const excludedExtensions = [
'vscode-test-resolver', 'vscode-test-resolver',
'ms-vscode.node-debug', 'ms-vscode.node-debug',
'ms-vscode.node-debug2', 'ms-vscode.node-debug2',
'vscode-notebook-tests',
'integration-tests', // {{SQL CARBON EDIT}} 'integration-tests', // {{SQL CARBON EDIT}}
]; ];
+1 -6
View File
@@ -69,12 +69,7 @@ function loader(src, bundledFileHeader, bundleLoader) {
this.emit('data', data); this.emit('data', data);
} }
})) }))
.pipe(util.loadSourcemaps()) .pipe(concat('vs/loader.js')));
.pipe(concat('vs/loader.js'))
.pipe(es.mapSync(function (f) {
f.sourceMap.sourceRoot = util.toFileUri(path.join(REPO_ROOT_PATH, 'src'));
return f;
})));
} }
function toConcatStream(src, bundledFileHeader, sources, dest) { function toConcatStream(src, bundledFileHeader, sources, dest) {
const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest); const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
-5
View File
@@ -81,12 +81,7 @@ function loader(src: string, bundledFileHeader: string, bundleLoader: boolean):
this.emit('data', data); this.emit('data', data);
} }
})) }))
.pipe(util.loadSourcemaps())
.pipe(concat('vs/loader.js')) .pipe(concat('vs/loader.js'))
.pipe(es.mapSync<FileSourceMap, FileSourceMap>(function (f) {
f.sourceMap.sourceRoot = util.toFileUri(path.join(REPO_ROOT_PATH, 'src'));
return f;
}))
); );
} }
+1 -1
View File
@@ -48,7 +48,7 @@
"rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-node-resolve": "^5.2.0",
"terser": "4.3.8", "terser": "4.3.8",
"typescript": "^3.9.0-dev.20200420", "typescript": "^3.9.0-dev.20200427",
"vsce": "1.48.0", "vsce": "1.48.0",
"vscode-telemetry-extractor": "^1.5.4", "vscode-telemetry-extractor": "^1.5.4",
"xml2js": "^0.4.17" "xml2js": "^0.4.17"
+4 -4
View File
@@ -3462,10 +3462,10 @@ typescript@^3.0.1:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
typescript@^3.9.0-dev.20200420: typescript@^3.9.0-dev.20200427:
version "3.9.0-dev.20200420" version "3.9.0-dev.20200427"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200420.tgz#99c2bc0936dbf4479b0b5260d80475ed494b1532" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200427.tgz#e42d606d938575dfb7b0b66f04a31b5f0eb0be57"
integrity sha512-36MW6V+oXNnsSgliSjUWvtOkO21g9+iFGHPFv+O06HsCl3dcuqzBac17m8xuOuWo1LUlEgS6yAnD9fiVgvmCfg== integrity sha512-ja/GhL7BHT+VQZiLoYMGJt2CP1Pdr0EhYefv4LLw4tVooSuCDB8SDKT/i/HwsoPgQ4ZaYfg1vPl+1RhiO3bwJg==
typical@^4.0.0: typical@^4.0.0:
version "4.0.0" version "4.0.0"
+32
View File
@@ -169,5 +169,37 @@
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE", "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
"SOFTWARE." "SOFTWARE."
] ]
},
{
// Reason: The license at https://github.com/floatdrop/pinkie/blob/master/license
// cannot be found by the OSS tool automatically.
"name": "pinkie",
"fullLicenseText": [
"The MIT License (MIT)",
"",
"Copyright (c) Vsevolod Strukchinsky <floatdrop@gmail.com> (github.com/floatdrop)",
"",
"Permission is hereby granted, free of charge, to any person obtaining a copy",
"of this software and associated documentation files (the \"Software\"), to deal",
"in the Software without restriction, including without limitation the rights",
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell",
"copies of the Software, and to permit persons to whom the Software is",
"furnished to do so, subject to the following conditions:",
"",
"The above copyright notice and this permission notice shall be included in",
"all copies or substantial portions of the Software.",
"",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR",
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN",
"THE SOFTWARE."
]
},
{
"name": "big-integer",
"prependLicenseText": ["Copyright released to public domain"]
} }
] ]
+8 -1
View File
@@ -21,6 +21,13 @@
"language": "dockerfile", "language": "dockerfile",
"scopeName": "source.dockerfile", "scopeName": "source.dockerfile",
"path": "./syntaxes/docker.tmLanguage.json" "path": "./syntaxes/docker.tmLanguage.json"
}] }],
"configurationDefaults": {
"[dockerfile]": {
"editor.quickSuggestions": {
"strings": true
}
}
}
} }
} }
+13 -4
View File
@@ -609,10 +609,6 @@
"command": "git.pullRebase", "command": "git.pullRebase",
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0" "when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
}, },
{
"command": "git.pullFrom",
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
},
{ {
"command": "git.merge", "command": "git.merge",
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0" "when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
@@ -1669,6 +1665,18 @@
"scope": "resource", "scope": "resource",
"default": true, "default": true,
"description": "%config.showCommitInput%" "description": "%config.showCommitInput%"
},
"git.terminalAuthentication": {
"type": "boolean",
"scope": "resource",
"default": true,
"description": "%config.terminalAuthentication%"
},
"git.githubAuthentication": {
"type": "boolean",
"scope": "resource",
"default": true,
"description": "%config.githubAuthentication%"
} }
} }
}, },
@@ -1781,6 +1789,7 @@
"ignore" "ignore"
], ],
"filenames": [ "filenames": [
".gitignore_global",
".gitignore" ".gitignore"
], ],
"configuration": "./languages/ignore.language-configuration.json" "configuration": "./languages/ignore.language-configuration.json"
+2
View File
@@ -144,6 +144,8 @@
"config.untrackedChanges.separate": "Untracked changes appear separately in the Source Control view. They are also excluded from several actions.", "config.untrackedChanges.separate": "Untracked changes appear separately in the Source Control view. They are also excluded from several actions.",
"config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.", "config.untrackedChanges.hidden": "Untracked changes are hidden and excluded from several actions.",
"config.showCommitInput": "Controls whether to show the commit input in the Git source control panel.", "config.showCommitInput": "Controls whether to show the commit input in the Git source control panel.",
"config.terminalAuthentication": "Controls whether to enable VS Code to be the authentication handler for git processes spawned in the integrated terminal. Note: terminals need to be restarted to pick up a change in this setting.",
"config.githubAuthentication": "Controls whether to enable automatic GitHub authentication for git commands within VS Code.",
"colors.added": "Color for added resources.", "colors.added": "Color for added resources.",
"colors.modified": "Color for modified resources.", "colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.", "colors.deleted": "Color for deleted resources.",
+16 -1
View File
@@ -5,7 +5,7 @@
import { Model } from '../model'; import { Model } from '../model';
import { Repository as BaseRepository, Resource } from '../repository'; import { Repository as BaseRepository, Resource } from '../repository';
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, GitExtension, RefType, RemoteSourceProvider } from './git'; import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, GitExtension, RefType, RemoteSourceProvider, CredentialsProvider } from './git';
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands } from 'vscode'; import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands } from 'vscode';
import { mapEvent } from '../util'; import { mapEvent } from '../util';
import { toGitUri } from '../uri'; import { toGitUri } from '../uri';
@@ -183,6 +183,10 @@ export class ApiRepository implements Repository {
return this._repository.removeRemote(name); return this._repository.removeRemote(name);
} }
renameRemote(name: string, newName: string): Promise<void> {
return this._repository.renameRemote(name, newName);
}
fetch(remote?: string | undefined, ref?: string | undefined, depth?: number | undefined): Promise<void> { fetch(remote?: string | undefined, ref?: string | undefined, depth?: number | undefined): Promise<void> {
return this._repository.fetch(remote, ref, depth); return this._repository.fetch(remote, ref, depth);
} }
@@ -248,10 +252,21 @@ export class ApiImpl implements API {
return result ? new ApiRepository(result) : null; return result ? new ApiRepository(result) : null;
} }
async init(root: Uri): Promise<Repository | null> {
const path = root.fsPath;
await this._model.git.init(path);
await this._model.openRepository(path);
return this.getRepository(root) || null;
}
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable { registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable {
return this._model.registerRemoteSourceProvider(provider); return this._model.registerRemoteSourceProvider(provider);
} }
registerCredentialsProvider(provider: CredentialsProvider): Disposable {
return this._model.registerCredentialsProvider(provider);
}
constructor(private _model: Model) { } constructor(private _model: Model) { }
} }
+13
View File
@@ -179,6 +179,7 @@ export interface Repository {
addRemote(name: string, url: string): Promise<void>; addRemote(name: string, url: string): Promise<void>;
removeRemote(name: string): Promise<void>; removeRemote(name: string): Promise<void>;
renameRemote(name: string, newName: string): Promise<void>;
fetch(remote?: string, ref?: string, depth?: number): Promise<void>; fetch(remote?: string, ref?: string, depth?: number): Promise<void>;
pull(unshallow?: boolean): Promise<void>; pull(unshallow?: boolean): Promise<void>;
@@ -203,6 +204,15 @@ export interface RemoteSourceProvider {
getRemoteSources(query?: string): ProviderResult<RemoteSource[]>; getRemoteSources(query?: string): ProviderResult<RemoteSource[]>;
} }
export interface Credentials {
readonly username: string;
readonly password: string;
}
export interface CredentialsProvider {
getCredentials(host: Uri): ProviderResult<Credentials>;
}
export type APIState = 'uninitialized' | 'initialized'; export type APIState = 'uninitialized' | 'initialized';
export interface API { export interface API {
@@ -215,7 +225,10 @@ export interface API {
toGitUri(uri: Uri, ref: string): Uri; toGitUri(uri: Uri, ref: string): Uri;
getRepository(uri: Uri): Repository | null; getRepository(uri: Uri): Repository | null;
init(root: Uri): Promise<Repository | null>;
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable; registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable;
registerCredentialsProvider(provider: CredentialsProvider): Disposable;
} }
export interface GitExtension { export interface GitExtension {
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
VSCODE_GIT_ASKPASS_PIPE=`mktemp` VSCODE_GIT_ASKPASS_PIPE=`mktemp`
VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $* ELECTRON_RUN_AS_NODE="1" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_MAIN" $*
cat $VSCODE_GIT_ASKPASS_PIPE cat $VSCODE_GIT_ASKPASS_PIPE
rm $VSCODE_GIT_ASKPASS_PIPE rm $VSCODE_GIT_ASKPASS_PIPE
+55 -20
View File
@@ -3,36 +3,60 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { window, InputBoxOptions } from 'vscode'; import { window, InputBoxOptions, Uri, OutputChannel, Disposable } from 'vscode';
import { IDisposable } from './util'; import { IDisposable, EmptyDisposable, toDisposable } from './util';
import * as path from 'path'; import * as path from 'path';
import { IIPCHandler, IIPCServer } from './ipc/ipcServer'; import { IIPCHandler, IIPCServer, createIPCServer } from './ipc/ipcServer';
import { CredentialsProvider, Credentials } from './api/git';
export interface AskpassEnvironment {
GIT_ASKPASS: string;
ELECTRON_RUN_AS_NODE?: string;
VSCODE_GIT_ASKPASS_NODE?: string;
VSCODE_GIT_ASKPASS_MAIN?: string;
VSCODE_GIT_ASKPASS_HANDLE?: string;
}
export class Askpass implements IIPCHandler { export class Askpass implements IIPCHandler {
private disposable: IDisposable; private disposable: IDisposable = EmptyDisposable;
private cache = new Map<string, Credentials>();
private credentialsProviders = new Set<CredentialsProvider>();
static getDisabledEnv(): AskpassEnvironment { static async create(outputChannel: OutputChannel, context?: string): Promise<Askpass> {
return { try {
GIT_ASKPASS: path.join(__dirname, 'askpass-empty.sh') return new Askpass(await createIPCServer(context));
}; } catch (err) {
outputChannel.appendLine(`[error] Failed to create git askpass IPC: ${err}`);
return new Askpass();
}
} }
constructor(ipc: IIPCServer) { private constructor(private ipc?: IIPCServer) {
if (ipc) {
this.disposable = ipc.registerHandler('askpass', this); this.disposable = ipc.registerHandler('askpass', this);
} }
}
async handle({ request, host }: { request: string, host: string }): Promise<string> { async handle({ request, host }: { request: string, host: string }): Promise<string> {
const uri = Uri.parse(host);
const authority = uri.authority.replace(/^.*@/, '');
const password = /password/i.test(request);
const cached = this.cache.get(authority);
if (cached && password) {
this.cache.delete(authority);
return cached.password;
}
if (!password) {
for (const credentialsProvider of this.credentialsProviders) {
try {
const credentials = await credentialsProvider.getCredentials(uri);
if (credentials) {
this.cache.set(authority, credentials);
setTimeout(() => this.cache.delete(authority), 60_000);
return credentials.username;
}
} catch { }
}
}
const options: InputBoxOptions = { const options: InputBoxOptions = {
password: /password/i.test(request), password,
placeHolder: request, placeHolder: request,
prompt: `Git: ${host}`, prompt: `Git: ${host}`,
ignoreFocusOut: true ignoreFocusOut: true
@@ -41,15 +65,26 @@ export class Askpass implements IIPCHandler {
return await window.showInputBox(options) || ''; return await window.showInputBox(options) || '';
} }
getEnv(): AskpassEnvironment { getEnv(): { [key: string]: string; } {
if (!this.ipc) {
return { return {
ELECTRON_RUN_AS_NODE: '1', GIT_ASKPASS: path.join(__dirname, 'askpass-empty.sh')
};
}
return {
...this.ipc.getEnv(),
GIT_ASKPASS: path.join(__dirname, 'askpass.sh'), GIT_ASKPASS: path.join(__dirname, 'askpass.sh'),
VSCODE_GIT_ASKPASS_NODE: process.execPath, VSCODE_GIT_ASKPASS_NODE: process.execPath,
VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js') VSCODE_GIT_ASKPASS_MAIN: path.join(__dirname, 'askpass-main.js')
}; };
} }
registerCredentialsProvider(provider: CredentialsProvider): Disposable {
this.credentialsProviders.add(provider);
return toDisposable(() => this.credentialsProviders.delete(provider));
}
dispose(): void { dispose(): void {
this.disposable.dispose(); this.disposable.dispose();
} }
+9 -1
View File
@@ -524,7 +524,7 @@ export class CommandCenter {
quickpick.ignoreFocusOut = true; quickpick.ignoreFocusOut = true;
const providers = this.model.getRemoteProviders() const providers = this.model.getRemoteProviders()
.map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + localize('clonefrom', "Clone from {1}", provider.name), alwaysShow: true, provider })); .map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + localize('clonefrom', "Clone from {0}", provider.name), alwaysShow: true, provider }));
quickpick.placeholder = providers.length === 0 quickpick.placeholder = providers.length === 0
? localize('provide url', "Provide repository URL.") ? localize('provide url', "Provide repository URL.")
@@ -2560,6 +2560,14 @@ export class CommandCenter {
type = 'warning'; type = 'warning';
options.modal = false; options.modal = false;
break; break;
case GitErrorCodes.AuthenticationFailed:
const regex = /Authentication failed for '(.*)'/i;
const match = regex.exec(err.stderr || String(err));
message = match
? localize('auth failed specific', "Failed to authenticate to git remote:\n\n{0}", match[1])
: localize('auth failed', "Failed to authenticate to git remote.");
break;
case GitErrorCodes.NoUserNameConfigured: case GitErrorCodes.NoUserNameConfigured:
case GitErrorCodes.NoUserEmailConfigured: case GitErrorCodes.NoUserEmailConfigured:
message = localize('missing user info', "Make sure you configure your 'user.name' and 'user.email' in git."); message = localize('missing user info', "Make sure you configure your 'user.name' and 'user.email' in git.");
+7 -2
View File
@@ -306,7 +306,7 @@ export interface IGitOptions {
function getGitErrorCode(stderr: string): string | undefined { function getGitErrorCode(stderr: string): string | undefined {
if (/Another git process seems to be running in this repository|If no other git process is currently running/.test(stderr)) { if (/Another git process seems to be running in this repository|If no other git process is currently running/.test(stderr)) {
return GitErrorCodes.RepositoryIsLocked; return GitErrorCodes.RepositoryIsLocked;
} else if (/Authentication failed/.test(stderr)) { } else if (/Authentication failed/i.test(stderr)) {
return GitErrorCodes.AuthenticationFailed; return GitErrorCodes.AuthenticationFailed;
} else if (/Not a git repository/i.test(stderr)) { } else if (/Not a git repository/i.test(stderr)) {
return GitErrorCodes.NotAGitRepository; return GitErrorCodes.NotAGitRepository;
@@ -1498,7 +1498,12 @@ export class Repository {
} }
async removeRemote(name: string): Promise<void> { async removeRemote(name: string): Promise<void> {
const args = ['remote', 'rm', name]; const args = ['remote', 'remove', name];
await this.run(args);
}
async renameRemote(name: string, newName: string): Promise<void> {
const args = ['remote', 'rename', name, newName];
await this.run(args); await this.run(args);
} }
+66
View File
@@ -0,0 +1,66 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CredentialsProvider, Credentials } from './api/git';
import { IDisposable, filterEvent, EmptyDisposable } from './util';
import { workspace, Uri, AuthenticationSession, authentication } from 'vscode';
import { Askpass } from './askpass';
export class GitHubCredentialProvider implements CredentialsProvider {
async getCredentials(host: Uri): Promise<Credentials | undefined> {
if (!/github\.com/i.test(host.authority)) {
return;
}
const session = await this.getSession();
return { username: session.account.id, password: await session.getAccessToken() };
}
private async getSession(): Promise<AuthenticationSession> {
const authenticationSessions = await authentication.getSessions('github', ['repo']);
if (authenticationSessions.length) {
return await authenticationSessions[0];
} else {
return await authentication.login('github', ['repo']);
}
}
}
export class GithubCredentialProviderManager {
private providerDisposable: IDisposable = EmptyDisposable;
private readonly disposable: IDisposable;
private _enabled = false;
private set enabled(enabled: boolean) {
if (this._enabled === enabled) {
return;
}
this._enabled = enabled;
if (enabled) {
this.providerDisposable = this.askpass.registerCredentialsProvider(new GitHubCredentialProvider());
} else {
this.providerDisposable.dispose();
}
}
constructor(private readonly askpass: Askpass) {
this.disposable = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git'))(this.refresh, this);
this.refresh();
}
private refresh(): void {
this.enabled = workspace.getConfiguration('git', null).get('githubAuthentication', true);
}
dispose(): void {
this.enabled = false;
this.disposable.dispose();
}
}
+24 -9
View File
@@ -11,27 +11,42 @@ import * as os from 'os';
import * as fs from 'fs'; import * as fs from 'fs';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
function getIPCHandlePath(nonce: string): string { function getIPCHandlePath(id: string): string {
if (process.platform === 'win32') { if (process.platform === 'win32') {
return `\\\\.\\pipe\\vscode-git-ipc-${nonce}-sock`; return `\\\\.\\pipe\\vscode-git-${id}-sock`;
} }
if (process.env['XDG_RUNTIME_DIR']) { if (process.env['XDG_RUNTIME_DIR']) {
return path.join(process.env['XDG_RUNTIME_DIR'] as string, `vscode-git-ipc-${nonce}.sock`); return path.join(process.env['XDG_RUNTIME_DIR'] as string, `vscode-git-${id}.sock`);
} }
return path.join(os.tmpdir(), `vscode-git-ipc-${nonce}.sock`); return path.join(os.tmpdir(), `vscode-git-${id}.sock`);
} }
export interface IIPCHandler { export interface IIPCHandler {
handle(request: any): Promise<any>; handle(request: any): Promise<any>;
} }
export async function createIPCServer(): Promise<IIPCServer> { export async function createIPCServer(context?: string): Promise<IIPCServer> {
const server = http.createServer(); const server = http.createServer();
const hash = crypto.createHash('sha1');
if (!context) {
const buffer = await new Promise<Buffer>((c, e) => crypto.randomBytes(20, (err, buf) => err ? e(err) : c(buf))); const buffer = await new Promise<Buffer>((c, e) => crypto.randomBytes(20, (err, buf) => err ? e(err) : c(buf)));
const nonce = buffer.toString('hex'); hash.update(buffer);
const ipcHandlePath = getIPCHandlePath(nonce); } else {
hash.update(context);
}
const ipcHandlePath = getIPCHandlePath(hash.digest('hex').substr(0, 10));
if (process.platform !== 'win32') {
try {
await fs.promises.unlink(ipcHandlePath);
} catch {
// noop
}
}
return new Promise((c, e) => { return new Promise((c, e) => {
try { try {
@@ -46,7 +61,7 @@ export async function createIPCServer(): Promise<IIPCServer> {
export interface IIPCServer extends Disposable { export interface IIPCServer extends Disposable {
readonly ipcHandlePath: string | undefined; readonly ipcHandlePath: string | undefined;
getEnv(): any; getEnv(): { [key: string]: string; };
registerHandler(name: string, handler: IIPCHandler): Disposable; registerHandler(name: string, handler: IIPCHandler): Disposable;
} }
@@ -91,7 +106,7 @@ class IPCServer implements IIPCServer, Disposable {
}); });
} }
getEnv(): any { getEnv(): { [key: string]: string; } {
return { VSCODE_GIT_IPC_HANDLE: this.ipcHandlePath }; return { VSCODE_GIT_IPC_HANDLE: this.ipcHandlePath };
} }
+11 -19
View File
@@ -20,9 +20,10 @@ import { GitProtocolHandler } from './protocolHandler';
import { GitExtensionImpl } from './api/extension'; import { GitExtensionImpl } from './api/extension';
// import * as path from 'path'; // import * as path from 'path';
// import * as fs from 'fs'; // import * as fs from 'fs';
import { createIPCServer, IIPCServer } from './ipc/ipcServer';
import { GitTimelineProvider } from './timelineProvider'; import { GitTimelineProvider } from './timelineProvider';
import { registerAPICommands } from './api/api1'; import { registerAPICommands } from './api/api1';
import { GithubCredentialProviderManager } from './github';
import { TerminalEnvironmentManager } from './terminal';
const deactivateTasks: { (): Promise<any>; }[] = []; const deactivateTasks: { (): Promise<any>; }[] = [];
@@ -36,27 +37,18 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
const pathHint = workspace.getConfiguration('git').get<string>('path'); const pathHint = workspace.getConfiguration('git').get<string>('path');
const info = await findGit(pathHint, path => outputChannel.appendLine(localize('looking', "Looking for git in: {0}", path))); const info = await findGit(pathHint, path => outputChannel.appendLine(localize('looking', "Looking for git in: {0}", path)));
let env: any = {}; const askpass = await Askpass.create(outputChannel, context.storagePath);
let ipc: IIPCServer | undefined;
try {
ipc = await createIPCServer();
disposables.push(ipc);
env = { ...env, ...ipc.getEnv() };
} catch {
// noop
}
if (ipc) {
const askpass = new Askpass(ipc);
disposables.push(askpass); disposables.push(askpass);
env = { ...env, ...askpass.getEnv() };
} else { const env = askpass.getEnv();
env = { ...env, ...Askpass.getDisabledEnv() }; const terminalEnvironmentManager = new TerminalEnvironmentManager(context, env);
} disposables.push(terminalEnvironmentManager);
const githubCredentialProviderManager = new GithubCredentialProviderManager(askpass);
context.subscriptions.push(githubCredentialProviderManager);
const git = new Git({ gitPath: info.path, version: info.version, env }); const git = new Git({ gitPath: info.path, version: info.version, env });
const model = new Model(git, context.globalState, outputChannel); const model = new Model(git, askpass, context.globalState, outputChannel);
disposables.push(model); disposables.push(model);
const onRepository = () => commands.executeCommand('setContext', 'gitOpenRepositoryCount', `${model.repositories.length}`); const onRepository = () => commands.executeCommand('setContext', 'gitOpenRepositoryCount', `${model.repositories.length}`);
+7 -2
View File
@@ -12,7 +12,8 @@ import * as path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { fromGitUri } from './uri'; import { fromGitUri } from './uri';
import { GitErrorCodes, APIState as State, RemoteSourceProvider } from './api/git'; import { GitErrorCodes, APIState as State, RemoteSourceProvider, CredentialsProvider } from './api/git';
import { Askpass } from './askpass';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -78,7 +79,7 @@ export class Model {
private disposables: Disposable[] = []; private disposables: Disposable[] = [];
constructor(readonly git: Git, private globalState: Memento, private outputChannel: OutputChannel) { constructor(readonly git: Git, private readonly askpass: Askpass, private globalState: Memento, private outputChannel: OutputChannel) {
workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables); workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables);
window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables); window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables);
workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables); workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables);
@@ -454,6 +455,10 @@ export class Model {
return toDisposable(() => this.remoteProviders.delete(provider)); return toDisposable(() => this.remoteProviders.delete(provider));
} }
registerCredentialsProvider(provider: CredentialsProvider): Disposable {
return this.askpass.registerCredentialsProvider(provider);
}
getRemoteProviders(): RemoteSourceProvider[] { getRemoteProviders(): RemoteSourceProvider[] {
return [...this.remoteProviders.values()]; return [...this.remoteProviders.values()];
} }
+4
View File
@@ -1096,6 +1096,10 @@ export class Repository implements Disposable {
await this.run(Operation.Remote, () => this.repository.removeRemote(name)); await this.run(Operation.Remote, () => this.repository.removeRemote(name));
} }
async renameRemote(name: string, newName: string): Promise<void> {
await this.run(Operation.Remote, () => this.repository.renameRemote(name, newName));
}
@throttle @throttle
async fetchDefault(options: { silent?: boolean } = {}): Promise<void> { async fetchDefault(options: { silent?: boolean } = {}): Promise<void> {
await this.run(Operation.Fetch, () => this.repository.fetch(options)); await this.run(Operation.Fetch, () => this.repository.fetch(options));
+43
View File
@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtensionContext, workspace } from 'vscode';
import { filterEvent, IDisposable } from './util';
export class TerminalEnvironmentManager {
private readonly disposable: IDisposable;
private _enabled = false;
private set enabled(enabled: boolean) {
if (this._enabled === enabled) {
return;
}
this._enabled = enabled;
this.context.environmentVariableCollection.clear();
if (enabled) {
for (const name of Object.keys(this.env)) {
this.context.environmentVariableCollection.replace(name, this.env[name]);
}
}
}
constructor(private readonly context: ExtensionContext, private readonly env: { [key: string]: string }) {
this.disposable = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git'))
(this.refresh, this);
this.refresh();
}
private refresh(): void {
this.enabled = workspace.getConfiguration('git', null).get('terminalAuthentication', true);
}
dispose(): void {
this.disposable.dispose();
}
}
@@ -14,6 +14,22 @@
"activationEvents": [ "activationEvents": [
"*" "*"
], ],
"contributes": {
"commands": [
{
"command": "github.provide-token",
"title": "Manually Provide Token"
}
],
"menus": {
"commandPalette": [
{
"command": "github.provide-token",
"when": "false"
}
]
}
},
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"main": "./out/extension.js", "main": "./out/extension.js",
"scripts": { "scripts": {
@@ -18,6 +18,10 @@ export async function activate(context: vscode.ExtensionContext) {
await loginService.initialize(); await loginService.initialize();
context.subscriptions.push(vscode.commands.registerCommand('github.provide-token', () => {
return loginService.manuallyProvideToken();
}));
vscode.authentication.registerAuthenticationProvider({ vscode.authentication.registerAuthenticationProvider({
id: 'github', id: 'github',
displayName: 'GitHub', displayName: 'GitHub',
+37 -15
View File
@@ -6,7 +6,7 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
import { keychain } from './common/keychain'; import { keychain } from './common/keychain';
import { GitHubServer } from './githubServer'; import { GitHubServer, NETWORK_ERROR } from './githubServer';
import Logger from './common/logger'; import Logger from './common/logger';
export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationSessionsChangeEvent>(); export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationSessionsChangeEvent>();
@@ -38,13 +38,26 @@ export class GitHubAuthenticationProvider {
private _githubServer = new GitHubServer(); private _githubServer = new GitHubServer();
public async initialize(): Promise<void> { public async initialize(): Promise<void> {
try {
this._sessions = await this.readSessions(); this._sessions = await this.readSessions();
} catch (e) {
// Ignore, network request failed
}
// TODO revert Cannot validate tokens from auth server, no available clientId
// await this.validateSessions();
this.pollForChange(); this.pollForChange();
} }
private pollForChange() { private pollForChange() {
setTimeout(async () => { setTimeout(async () => {
const storedSessions = await this.readSessions(); let storedSessions: vscode.AuthenticationSession[];
try {
storedSessions = await this.readSessions();
} catch (e) {
// Ignore, network request failed
return;
}
const added: string[] = []; const added: string[] = [];
const removed: string[] = []; const removed: string[] = [];
@@ -53,6 +66,7 @@ export class GitHubAuthenticationProvider {
const matchesExisting = this._sessions.some(s => s.id === session.id); const matchesExisting = this._sessions.some(s => s.id === session.id);
// Another window added a session to the keychain, add it to our state as well // Another window added a session to the keychain, add it to our state as well
if (!matchesExisting) { if (!matchesExisting) {
Logger.info('Adding session found in keychain');
this._sessions.push(session); this._sessions.push(session);
added.push(session.id); added.push(session.id);
} }
@@ -62,6 +76,7 @@ export class GitHubAuthenticationProvider {
const matchesExisting = storedSessions.some(s => s.id === session.id); const matchesExisting = storedSessions.some(s => s.id === session.id);
// Another window has logged out, remove from our state // Another window has logged out, remove from our state
if (!matchesExisting) { if (!matchesExisting) {
Logger.info('Removing session no longer found in keychain');
const sessionIndex = this._sessions.findIndex(s => s.id === session.id); const sessionIndex = this._sessions.findIndex(s => s.id === session.id);
if (sessionIndex > -1) { if (sessionIndex > -1) {
this._sessions.splice(sessionIndex, 1); this._sessions.splice(sessionIndex, 1);
@@ -84,8 +99,7 @@ export class GitHubAuthenticationProvider {
if (storedSessions) { if (storedSessions) {
try { try {
const sessionData: (SessionData | OldSessionData)[] = JSON.parse(storedSessions); const sessionData: (SessionData | OldSessionData)[] = JSON.parse(storedSessions);
const sessionPromises = sessionData.map(async (session: SessionData | OldSessionData): Promise<vscode.AuthenticationSession | undefined> => { const sessionPromises = sessionData.map(async (session: SessionData | OldSessionData): Promise<vscode.AuthenticationSession> => {
try {
const needsUserInfo = isOldSessionData(session) || !session.account; const needsUserInfo = isOldSessionData(session) || !session.account;
let userInfo: { id: string, accountName: string }; let userInfo: { id: string, accountName: string };
if (needsUserInfo) { if (needsUserInfo) {
@@ -105,14 +119,16 @@ export class GitHubAuthenticationProvider {
scopes: session.scopes, scopes: session.scopes,
getAccessToken: () => Promise.resolve(session.accessToken) getAccessToken: () => Promise.resolve(session.accessToken)
}; };
} catch (e) {
return undefined;
}
}); });
return (await Promise.all(sessionPromises)).filter((x: vscode.AuthenticationSession | undefined): x is vscode.AuthenticationSession => !!x); return Promise.all(sessionPromises);
} catch (e) { } catch (e) {
if (e === NETWORK_ERROR) {
return [];
}
Logger.error(`Error reading sessions: ${e}`); Logger.error(`Error reading sessions: ${e}`);
await keychain.deleteToken();
} }
} }
@@ -154,6 +170,10 @@ export class GitHubAuthenticationProvider {
} }
} }
public async manuallyProvideToken(): Promise<void> {
this._githubServer.manuallyProvideToken();
}
private async tokenToSession(token: string, scopes: string[]): Promise<vscode.AuthenticationSession> { private async tokenToSession(token: string, scopes: string[]): Promise<vscode.AuthenticationSession> {
const userInfo = await this._githubServer.getUserInfo(token); const userInfo = await this._githubServer.getUserInfo(token);
return { return {
@@ -180,13 +200,15 @@ export class GitHubAuthenticationProvider {
public async logout(id: string) { public async logout(id: string) {
const sessionIndex = this._sessions.findIndex(session => session.id === id); const sessionIndex = this._sessions.findIndex(session => session.id === id);
if (sessionIndex > -1) { if (sessionIndex > -1) {
const session = this._sessions.splice(sessionIndex, 1)[0]; this._sessions.splice(sessionIndex, 1);
const token = await session.getAccessToken(); // TODO revert
try { // Cannot revoke tokens from auth server, no clientId available
await this._githubServer.revokeToken(token); // const token = await session.getAccessToken();
} catch (_) { // try {
// ignore, should still remove from keychain // await this._githubServer.revokeToken(token);
} // } catch (_) {
// // ignore, should still remove from keychain
// }
} }
await this.storeSessions(); await this.storeSessions();
@@ -4,11 +4,17 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as https from 'https'; import * as https from 'https';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
import { PromiseAdapter, promiseFromEvent } from './common/utils'; import { PromiseAdapter, promiseFromEvent } from './common/utils';
import Logger from './common/logger'; import Logger from './common/logger';
import ClientRegistrar, { ClientDetails } from './common/clientRegistrar'; import ClientRegistrar from './common/clientRegistrar';
const localize = nls.loadMessageBundle();
export const NETWORK_ERROR = 'network error';
const AUTH_RELAY_SERVER = 'vscode-auth.github.com';
class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler { class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler {
public handleUri(uri: vscode.Uri) { public handleUri(uri: vscode.Uri) {
@@ -18,8 +24,8 @@ class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.
export const uriHandler = new UriEventHandler; export const uriHandler = new UriEventHandler;
const exchangeCodeForToken: (state: string, clientDetails: ClientDetails) => PromiseAdapter<vscode.Uri, string> = const exchangeCodeForToken: (state: string, host: string, getPath: (code: string) => string) => PromiseAdapter<vscode.Uri, string> =
(state, clientDetails) => async (uri, resolve, reject) => { (state, host, getPath) => async (uri, resolve, reject) => {
Logger.info('Exchanging code for token...'); Logger.info('Exchanging code for token...');
const query = parseQuery(uri); const query = parseQuery(uri);
const code = query.code; const code = query.code;
@@ -30,8 +36,8 @@ const exchangeCodeForToken: (state: string, clientDetails: ClientDetails) => Pro
} }
const post = https.request({ const post = https.request({
host: 'github.com', host: host,
path: `/login/oauth/access_token?client_id=${clientDetails.id}&client_secret=${clientDetails.secret}&state=${query.state}&code=${code}`, path: getPath(code),
method: 'POST', method: 'POST',
headers: { headers: {
Accept: 'application/json' Accept: 'application/json'
@@ -67,15 +73,61 @@ function parseQuery(uri: vscode.Uri) {
} }
export class GitHubServer { export class GitHubServer {
private _statusBarItem: vscode.StatusBarItem | undefined;
public async login(scopes: string): Promise<string> { public async login(scopes: string): Promise<string> {
Logger.info('Logging in...'); Logger.info('Logging in...');
this.updateStatusBarItem(true);
const state = uuid(); const state = uuid();
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`)); const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
const clientDetails = scopes === 'vso' ? ClientRegistrar.getGitHubAppDetails() : ClientRegistrar.getClientDetails(callbackUri); let uri = vscode.Uri.parse(`https://${AUTH_RELAY_SERVER}/authorize/?callbackUri=${encodeURIComponent(callbackUri.toString())}&scope=${scopes}&state=${state}&responseType=code`);
const uri = vscode.Uri.parse(`https://github.com/login/oauth/authorize?redirect_uri=${encodeURIComponent(callbackUri.toString())}&scope=${scopes}&state=${state}&client_id=${clientDetails.id}`); if (scopes === 'vso') {
const clientDetails = ClientRegistrar.getGitHubAppDetails();
uri = vscode.Uri.parse(`https://github.com/login/oauth/authorize?redirect_uri=${encodeURIComponent(callbackUri.toString())}&scope=${scopes}&state=${state}&client_id=${clientDetails.id}`);
}
vscode.env.openExternal(uri); vscode.env.openExternal(uri);
return promiseFromEvent(uriHandler.event, exchangeCodeForToken(state, clientDetails));
return promiseFromEvent(uriHandler.event, exchangeCodeForToken(state,
scopes === 'vso' ? 'github.com' : AUTH_RELAY_SERVER,
(code) => {
if (scopes === 'vso') {
const clientDetails = ClientRegistrar.getGitHubAppDetails();
return `/login/oauth/access_token?client_id=${clientDetails.id}&client_secret=${clientDetails.secret}&state=${state}&code=${code}`;
} else {
return `/token?code=${code}&state=${state}`;
}
})).finally(() => {
this.updateStatusBarItem(false);
});
}
private updateStatusBarItem(isStart?: boolean) {
if (isStart && !this._statusBarItem) {
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
this._statusBarItem.text = localize('signingIn', "$(mark-github) Signing in to github.com...");
this._statusBarItem.command = 'github.provide-token';
this._statusBarItem.show();
}
if (!isStart && this._statusBarItem) {
this._statusBarItem.dispose();
this._statusBarItem = undefined;
}
}
public async manuallyProvideToken() {
const uriOrToken = await vscode.window.showInputBox({ prompt: 'Token', ignoreFocusOut: true });
if (!uriOrToken) { return; }
try {
const uri = vscode.Uri.parse(uriOrToken);
if (!uri.scheme || uri.scheme === 'file') { throw new Error; }
uriHandler.handleUri(uri);
} catch (e) {
Logger.error(e);
vscode.window.showErrorMessage(localize('unexpectedInput', "The input did not matched the expected format"));
}
} }
public async hasUserInstallation(token: string): Promise<boolean> { public async hasUserInstallation(token: string): Promise<boolean> {
@@ -120,7 +172,7 @@ export class GitHubServer {
const uri = vscode.Uri.parse(`https://github.com/apps/microsoft-visual-studio-code/installations/new?state=${state}`); const uri = vscode.Uri.parse(`https://github.com/apps/microsoft-visual-studio-code/installations/new?state=${state}`);
vscode.env.openExternal(uri); vscode.env.openExternal(uri);
return promiseFromEvent(uriHandler.event, exchangeCodeForToken(state, clientDetails)); return promiseFromEvent(uriHandler.event, exchangeCodeForToken(state, 'github.com', (code) => `/login/oauth/access_token?client_id=${clientDetails.id}&client_secret=${clientDetails.secret}&state=${state}&code=${code}`));
} }
public async getUserInfo(token: string): Promise<{ id: string, accountName: string }> { public async getUserInfo(token: string): Promise<{ id: string, accountName: string }> {
@@ -145,7 +197,7 @@ export class GitHubServer {
Logger.info('Got account info!'); Logger.info('Got account info!');
resolve({ id: json.id, accountName: json.login }); resolve({ id: json.id, accountName: json.login });
} else { } else {
Logger.error('Getting account info failed'); Logger.error(`Getting account info failed: ${result.statusMessage}`);
reject(new Error(result.statusMessage)); reject(new Error(result.statusMessage));
} }
}); });
@@ -153,7 +205,52 @@ export class GitHubServer {
post.end(); post.end();
post.on('error', err => { post.on('error', err => {
reject(err); Logger.error(err.message);
reject(new Error(NETWORK_ERROR));
});
});
}
public async validateToken(token: string): Promise<void> {
return new Promise(async (resolve, reject) => {
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
const clientDetails = ClientRegistrar.getClientDetails(callbackUri);
const detailsString = `${clientDetails.id}:${clientDetails.secret}`;
const payload = JSON.stringify({ access_token: token });
Logger.info('Validating token...');
const post = https.request({
host: 'api.github.com',
path: `/applications/${clientDetails.id}/token`,
method: 'POST',
headers: {
Authorization: `Basic ${Buffer.from(detailsString).toString('base64')}`,
'User-Agent': 'Visual-Studio-Code',
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload)
}
}, result => {
const buffer: Buffer[] = [];
result.on('data', (chunk: Buffer) => {
buffer.push(chunk);
});
result.on('end', () => {
if (result.statusCode === 200) {
Logger.info('Validated token!');
resolve();
} else {
Logger.info(`Validating token failed: ${result.statusMessage}`);
reject(new Error(result.statusMessage));
}
});
});
post.write(payload);
post.end();
post.on('error', err => {
Logger.error(err.message);
reject(new Error(NETWORK_ERROR));
}); });
}); });
} }
+1 -1
View File
@@ -24,7 +24,7 @@ export function activate(context: vscode.ExtensionContext) {
const previewManager = new PreviewManager(extensionRoot, sizeStatusBarEntry, binarySizeStatusBarEntry, zoomStatusBarEntry); const previewManager = new PreviewManager(extensionRoot, sizeStatusBarEntry, binarySizeStatusBarEntry, zoomStatusBarEntry);
context.subscriptions.push(vscode.window.registerCustomEditorProvider2(PreviewManager.viewType, previewManager, { context.subscriptions.push(vscode.window.registerCustomEditorProvider2(PreviewManager.viewType, previewManager, {
supportsMultipleEditorsPerResource: true, supportsMultipleEditorsPerDocument: true,
})); }));
context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => { context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => {
+1 -1
View File
@@ -13,7 +13,7 @@ import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
export class PreviewManager implements vscode.CustomEditorProvider { export class PreviewManager implements vscode.CustomReadonlyEditorProvider {
public static readonly viewType = 'imagePreview.previewEditor'; public static readonly viewType = 'imagePreview.previewEditor';
@@ -120,10 +120,10 @@
] ]
}, },
"dependencies": { "dependencies": {
"request-light": "^0.2.5", "request-light": "^0.3.0",
"vscode-extension-telemetry": "0.1.1", "vscode-extension-telemetry": "0.1.1",
"vscode-languageclient": "^6.1.1", "vscode-languageclient": "^6.1.3",
"vscode-nls": "^4.1.1" "vscode-nls": "^4.1.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.11.7" "@types/node": "^12.11.7"
@@ -23,6 +23,7 @@ The server implements the following capabilities of the language server protocol
- [Code Formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting) supporting ranges and formatting the whole document. - [Code Formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting) supporting ranges and formatting the whole document.
- [Folding Ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange) for all folding ranges in the document. - [Folding Ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange) for all folding ranges in the document.
- Semantic Selection for semantic selection for one or multiple cursor positions. - Semantic Selection for semantic selection for one or multiple cursor positions.
- [Goto Definition](https://microsoft.github.io/language-server-protocol/specification#textDocument_definition) for $ref references in JSON schemas
- [Diagnostics (Validation)](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics) are pushed for all open documents - [Diagnostics (Validation)](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics) are pushed for all open documents
- syntax errors - syntax errors
- structural validation based on the document's [JSON schema](http://json-schema.org/). - structural validation based on the document's [JSON schema](http://json-schema.org/).
@@ -13,8 +13,8 @@
"main": "./out/jsonServerMain", "main": "./out/jsonServerMain",
"dependencies": { "dependencies": {
"jsonc-parser": "^2.2.1", "jsonc-parser": "^2.2.1",
"request-light": "^0.2.5", "request-light": "^0.3.0",
"vscode-json-languageservice": "^3.5.2", "vscode-json-languageservice": "^3.6.0",
"vscode-languageserver": "^6.1.1", "vscode-languageserver": "^6.1.1",
"vscode-uri": "^2.1.1" "vscode-uri": "^2.1.1"
}, },
@@ -174,7 +174,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
documentRangeFormattingProvider: params.initializationOptions.provideFormatter === true, documentRangeFormattingProvider: params.initializationOptions.provideFormatter === true,
colorProvider: {}, colorProvider: {},
foldingRangeProvider: true, foldingRangeProvider: true,
selectionRangeProvider: true selectionRangeProvider: true,
definitionProvider: true
}; };
return { capabilities }; return { capabilities };
@@ -516,5 +517,16 @@ connection.onSelectionRanges((params, token) => {
}, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token); }, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token);
}); });
connection.onDefinition((params, token) => {
return runSafeAsync(async () => {
const document = documents.get(params.textDocument.uri);
if (document) {
const jsonDocument = getJSONDocument(document);
return languageService.findDefinition(document, params.position, jsonDocument);
}
return [];
}, [], `Error while computing definitions for ${params.textDocument.uri}`, token);
});
// Listen on the connection // Listen on the connection
connection.listen(); connection.listen();
@@ -53,7 +53,7 @@ http-proxy-agent@^2.1.0:
agent-base "4" agent-base "4"
debug "3.1.0" debug "3.1.0"
https-proxy-agent@^2.2.3: https-proxy-agent@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
@@ -71,24 +71,24 @@ ms@2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
request-light@^0.2.5: request-light@^0.3.0:
version "0.2.5" version "0.3.0"
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.5.tgz#38a3da7b2e56f7af8cbba57e8a94930ee2380746" resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.3.0.tgz#04daa783e7f0a70392328dda4b546f3e27845f2d"
integrity sha512-eBEh+GzJAftUnex6tcL6eV2JCifY0+sZMIUpUPOVXbs2nV5hla4ZMmO3icYKGuGVuQ2zHE9evh4OrRcH4iyYYw== integrity sha512-xlVlZVT0ZvCT+c3zm3SjeFCzchoQxsUUmx5fkal0I6RIDJK+lmb1UYyKJ7WM4dTfnzHP4ElWwAf8Dli8c0/tVA==
dependencies: dependencies:
http-proxy-agent "^2.1.0" http-proxy-agent "^2.1.0"
https-proxy-agent "^2.2.3" https-proxy-agent "^2.2.4"
vscode-nls "^4.1.1" vscode-nls "^4.1.1"
vscode-json-languageservice@^3.5.2: vscode-json-languageservice@^3.6.0:
version "3.5.2" version "3.6.0"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.5.2.tgz#4b898140a8e581359c10660845a4cae15dcbb4f9" resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.6.0.tgz#133a1e2c3a3dffe38564a1ba948516805c3c1869"
integrity sha512-9cUvBq00O08lpWVVOx6tQ1yLxCHss79nsUdEAVYGomRyMbnPBmc0AkYPcXI9WK1EM6HBo0R9Zo3NjFhcICpy4A== integrity sha512-dXzFywypUZ9T0tjr4fREZiknXDz6vAGx1zsxbQY1+9DOpjMfbz0VLP873KmcbuvL4K3nseKTxc4TKHu8kLXRMw==
dependencies: dependencies:
jsonc-parser "^2.2.1" jsonc-parser "^2.2.1"
vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-textdocument "^1.0.1"
vscode-languageserver-types "^3.15.1" vscode-languageserver-types "^3.15.1"
vscode-nls "^4.1.1" vscode-nls "^4.1.2"
vscode-uri "^2.1.1" vscode-uri "^2.1.1"
vscode-jsonrpc@^5.0.1: vscode-jsonrpc@^5.0.1:
@@ -126,6 +126,11 @@ vscode-nls@^4.1.1:
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"
integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A== integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A==
vscode-nls@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
vscode-uri@^2.1.1: vscode-uri@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.1.tgz#5aa1803391b6ebdd17d047f51365cf62c38f6e90" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.1.tgz#5aa1803391b6ebdd17d047f51365cf62c38f6e90"
+15 -10
View File
@@ -76,7 +76,7 @@ http-proxy-agent@^2.1.0:
agent-base "4" agent-base "4"
debug "3.1.0" debug "3.1.0"
https-proxy-agent@^2.2.3: https-proxy-agent@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
@@ -94,13 +94,13 @@ ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
request-light@^0.2.5: request-light@^0.3.0:
version "0.2.5" version "0.3.0"
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.5.tgz#38a3da7b2e56f7af8cbba57e8a94930ee2380746" resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.3.0.tgz#04daa783e7f0a70392328dda4b546f3e27845f2d"
integrity sha512-eBEh+GzJAftUnex6tcL6eV2JCifY0+sZMIUpUPOVXbs2nV5hla4ZMmO3icYKGuGVuQ2zHE9evh4OrRcH4iyYYw== integrity sha512-xlVlZVT0ZvCT+c3zm3SjeFCzchoQxsUUmx5fkal0I6RIDJK+lmb1UYyKJ7WM4dTfnzHP4ElWwAf8Dli8c0/tVA==
dependencies: dependencies:
http-proxy-agent "^2.1.0" http-proxy-agent "^2.1.0"
https-proxy-agent "^2.2.3" https-proxy-agent "^2.2.4"
vscode-nls "^4.1.1" vscode-nls "^4.1.1"
semver@^5.3.0: semver@^5.3.0:
@@ -125,10 +125,10 @@ vscode-jsonrpc@^5.0.1:
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz#9bab9c330d89f43fc8c1e8702b5c36e058a01794" resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz#9bab9c330d89f43fc8c1e8702b5c36e058a01794"
integrity sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A== integrity sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==
vscode-languageclient@^6.1.1: vscode-languageclient@^6.1.3:
version "6.1.1" version "6.1.3"
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-6.1.1.tgz#91b62e416c5abbf2013ae3726f314a19c22a8457" resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-6.1.3.tgz#c979c5bb5855714a0307e998c18ca827c1b3953a"
integrity sha512-mB6d8Tg+82l8EFUfR+SBu0+lCshyKVgC5E5+MQ0/BJa+9AgeBjtG5npoGaCo4/VvWzK0ZRGm85zU5iRp1RYPIA== integrity sha512-YciJxk08iU5LmWu7j5dUt9/1OLjokKET6rME3cI4BRpiF6HZlusm2ZwPt0MYJ0lV5y43sZsQHhyon2xBg4ZJVA==
dependencies: dependencies:
semver "^6.3.0" semver "^6.3.0"
vscode-languageserver-protocol "^3.15.3" vscode-languageserver-protocol "^3.15.3"
@@ -151,6 +151,11 @@ vscode-nls@^4.1.1:
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"
integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A== integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A==
vscode-nls@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
zone.js@0.7.6: zone.js@0.7.6:
version "0.7.6" version "0.7.6"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009" resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
@@ -313,7 +313,7 @@
"customEditors": [ "customEditors": [
{ {
"viewType": "vscode.markdown.preview.editor", "viewType": "vscode.markdown.preview.editor",
"displayName": "(Experimental) VS Code Markdown Preview", "displayName": "Markdown Preview (Experimental)",
"priority": "option", "priority": "option",
"selector": [ "selector": [
{ {
@@ -104,7 +104,7 @@
"variable.other.enummember" "variable.other.enummember"
], ],
"settings": { "settings": {
"foreground": "#D4D4D4", "foreground": "#51B6C4",
} }
}, },
{ {
@@ -104,7 +104,7 @@
"variable.other.enummember" "variable.other.enummember"
], ],
"settings": { "settings": {
"foreground": "#000000", "foreground": "#328267",
} }
}, },
{ {
-12
View File
@@ -17,18 +17,6 @@
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"main": "./out/extension.js", "main": "./out/extension.js",
"contributes": { "contributes": {
"commands": [
{
"command": "microsoft.signin",
"title": "%signIn%",
"category": "%displayName%"
},
{
"command": "microsoft.signout",
"title": "%signOut%",
"category": "%displayName%"
}
],
"configuration": { "configuration": {
"title": "Microsoft Account", "title": "Microsoft Account",
"properties": { "properties": {
@@ -5,11 +5,8 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { AzureActiveDirectoryService, onDidChangeSessions } from './AADHelper'; import { AzureActiveDirectoryService, onDidChangeSessions } from './AADHelper';
import * as nls from 'vscode-nls';
import TelemetryReporter from 'vscode-extension-telemetry'; import TelemetryReporter from 'vscode-extension-telemetry';
const localize = nls.loadMessageBundle();
export const DEFAULT_SCOPES = 'https://management.core.windows.net/.default offline_access'; export const DEFAULT_SCOPES = 'https://management.core.windows.net/.default offline_access';
export async function activate(context: vscode.ExtensionContext) { export async function activate(context: vscode.ExtensionContext) {
@@ -48,39 +45,6 @@ export async function activate(context: vscode.ExtensionContext) {
} }
})); }));
context.subscriptions.push(vscode.commands.registerCommand('microsoft.signin', () => {
return loginService.login(DEFAULT_SCOPES);
}));
context.subscriptions.push(vscode.commands.registerCommand('microsoft.signout', async () => {
const sessions = loginService.sessions;
if (sessions.length === 0) {
return;
}
if (sessions.length === 1) {
const id = loginService.sessions[0].id;
await loginService.logout(id);
onDidChangeSessions.fire({ added: [], removed: [id], changed: [] });
vscode.window.showInformationMessage(localize('signedOut', "Successfully signed out."));
return;
}
const selectedSession = await vscode.window.showQuickPick(sessions.map(session => {
return {
id: session.id,
label: session.account.displayName
};
}));
if (selectedSession) {
await loginService.logout(selectedSession.id);
onDidChangeSessions.fire({ added: [], removed: [selectedSession.id], changed: [] });
vscode.window.showInformationMessage(localize('signedOut', "Successfully signed out."));
return;
}
}));
return; return;
} }
@@ -1,2 +0,0 @@
out
node_modules
-17
View File
@@ -1,17 +0,0 @@
// A launch configuration that compiles the extension and then opens it inside a new window
{
"version": "0.1.0",
"configurations": [
{
"name": "Launch Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["${workspaceFolder}/../../", "${workspaceFolder}/test", "--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out" ],
"stopOnEntry": false,
"sourceMaps": true,
"outDir": "${workspaceFolder}/out",
"preLaunchTask": "npm"
}
]
}
-11
View File
@@ -1,11 +0,0 @@
{
"version": "2.0.0",
"command": "npm",
"type": "shell",
"presentation": {
"reveal": "silent"
},
"args": ["run", "compile"],
"isBackground": true,
"problemMatcher": "$tsc-watch"
}
@@ -1,59 +0,0 @@
{
"name": "vscode-colorize-tests",
"description": "Colorize tests for VS Code",
"version": "0.0.1",
"publisher": "vscode",
"license": "MIT",
"private": true,
"activationEvents": [
"onLanguage:json"
],
"main": "./out/colorizerTestMain",
"enableProposedApi": true,
"engines": {
"vscode": "*"
},
"scripts": {
"vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json"
},
"dependencies": {
"jsonc-parser": "2.2.1"
},
"devDependencies": {
"@types/node": "^12.11.7",
"mocha-junit-reporter": "^1.17.0",
"mocha-multi-reporters": "^1.1.7",
"vscode": "1.1.5"
},
"contributes": {
"semanticTokenTypes": [
{
"id": "testToken",
"description": "A test token"
}
],
"semanticTokenModifiers": [
{
"id": "testModifier",
"description": "A test modifier"
}
],
"semanticTokenScopes": [
{
"scopes": {
"testToken": [
"entity.name.function.special"
]
}
}
],
"productIconThemes": [
{
"id": "Test Product Icons",
"label": "The Test Product Icon Theme",
"path": "./producticons/test-product-icon-theme.json",
"_watch": true
}
]
}
}
File diff suppressed because it is too large Load Diff
@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) <2013> <Elegant Themes, Inc.>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@@ -1,43 +0,0 @@
{
// ElegantIcons from https://www.elegantthemes.com/icons/elegant_font.zip
"fonts": [
{
"id": "elegant",
"src": [
{
"path": "./ElegantIcons.woff",
"format": "woff"
}
],
"weight": "normal",
"style": "normal",
}
],
"iconDefinitions": {
"chevron-down": {
"fontCharacter": "\\43",
},
"chevron-right": {
"fontCharacter": "\\45"
},
"error": {
"fontCharacter": "\\e062"
},
"warning": {
"fontCharacter": "\\e063"
},
"settings-gear": {
"fontCharacter": "\\e030"
},
"files": {
"fontCharacter": "\\e056"
},
"extensions": {
"fontCharacter": "\\e015"
},
"debug-alt-2": {
"fontCharacter": "\\e072"
}
}
}
@@ -1,76 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { commands, Uri } from 'vscode';
import { join, basename, normalize, dirname } from 'path';
import * as fs from 'fs';
function assertUnchangedTokens(testFixurePath: string, done: any) {
let fileName = basename(testFixurePath);
return commands.executeCommand('_workbench.captureSyntaxTokens', Uri.file(testFixurePath)).then(data => {
try {
let resultsFolderPath = join(dirname(dirname(testFixurePath)), 'colorize-results');
if (!fs.existsSync(resultsFolderPath)) {
fs.mkdirSync(resultsFolderPath);
}
let resultPath = join(resultsFolderPath, fileName.replace('.', '_') + '.json');
if (fs.existsSync(resultPath)) {
let previousData = JSON.parse(fs.readFileSync(resultPath).toString());
try {
assert.deepEqual(data, previousData);
} catch (e) {
fs.writeFileSync(resultPath, JSON.stringify(data, null, '\t'), { flag: 'w' });
if (Array.isArray(data) && Array.isArray(previousData) && data.length === previousData.length) {
for (let i= 0; i < data.length; i++) {
let d = data[i];
let p = previousData[i];
if (d.c !== p.c || hasThemeChange(d.r, p.r)) {
throw e;
}
}
// different but no tokenization ot color change: no failure
} else {
throw e;
}
}
} else {
fs.writeFileSync(resultPath, JSON.stringify(data, null, '\t'));
}
done();
} catch (e) {
done(e);
}
}, done);
}
function hasThemeChange(d: any, p: any) : boolean {
let keys = Object.keys(d);
for (let key of keys) {
if (d[key] !== p[key]) {
return true;
}
}
return false;
}
suite('colorization', () => {
let extensionsFolder = normalize(join(__dirname, '../../'));
let extensions = fs.readdirSync(extensionsFolder);
extensions.forEach(extension => {
let extensionColorizeFixturePath = join(extensionsFolder, extension, 'test', 'colorize-fixtures');
if (fs.existsSync(extensionColorizeFixturePath)) {
let fixturesFiles = fs.readdirSync(extensionColorizeFixturePath);
fixturesFiles.forEach(fixturesFile => {
// define a test for each fixture
test(extension + '-' + fixturesFile, function (done) {
assertUnchangedTokens(join(extensionColorizeFixturePath, fixturesFile), done);
});
});
}
});
});
@@ -1,66 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as jsoncParser from 'jsonc-parser';
export function activate(context: vscode.ExtensionContext): any {
const tokenTypes = ['type', 'struct', 'class', 'interface', 'enum', 'parameterType', 'function', 'variable', 'testToken'];
const tokenModifiers = ['static', 'abstract', 'deprecated', 'declaration', 'documentation', 'member', 'async', 'testModifier'];
const legend = new vscode.SemanticTokensLegend(tokenTypes, tokenModifiers);
const outputChannel = vscode.window.createOutputChannel('Semantic Tokens Test');
const documentSemanticHighlightProvider: vscode.DocumentSemanticTokensProvider = {
provideDocumentSemanticTokens(document: vscode.TextDocument): vscode.ProviderResult<vscode.SemanticTokens> {
const builder = new vscode.SemanticTokensBuilder();
function addToken(value: string, startLine: number, startCharacter: number, length: number) {
const [type, ...modifiers] = value.split('.');
let tokenType = legend.tokenTypes.indexOf(type);
if (tokenType === -1) {
return;
}
let tokenModifiers = 0;
for (let i = 0; i < modifiers.length; i++) {
const index = legend.tokenModifiers.indexOf(modifiers[i]);
if (index !== -1) {
tokenModifiers = tokenModifiers | 1 << index;
}
}
builder.push(startLine, startCharacter, length, tokenType, tokenModifiers);
const selectedModifiers = legend.tokenModifiers.filter((_val, bit) => tokenModifiers & (1 << bit)).join(' ');
outputChannel.appendLine(`line: ${startLine}, character: ${startCharacter}, length ${length}, ${legend.tokenTypes[tokenType]} (${tokenType}), ${selectedModifiers} ${tokenModifiers.toString(2)}`);
}
outputChannel.appendLine('---');
const visitor: jsoncParser.JSONVisitor = {
onObjectProperty: (property: string, _offset: number, _length: number, startLine: number, startCharacter: number) => {
addToken(property, startLine, startCharacter, property.length + 2);
},
onLiteralValue: (value: any, _offset: number, length: number, startLine: number, startCharacter: number) => {
if (typeof value === 'string') {
addToken(value, startLine, startCharacter, length);
}
}
};
jsoncParser.visit(document.getText(), visitor);
return builder.build();
}
};
context.subscriptions.push(vscode.languages.registerDocumentSemanticTokensProvider({ pattern: '**/*semantic-test.json' }, documentSemanticHighlightProvider, legend));
}
@@ -1,30 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
const testRunner = require('vscode/lib/testrunner');
const suite = 'Integration Colorize Tests';
const options: any = {
ui: 'tdd',
useColors: (!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY && process.platform !== 'win32'),
timeout: 60000
};
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
options.reporter = 'mocha-multi-reporters';
options.reporterOptions = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
testsuitesTitle: `${suite} ${process.platform}`,
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
}
};
}
testRunner.configure(options);
export = testRunner;
-9
View File
@@ -1,9 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path="../../../../src/vs/vscode.d.ts" />
/// <reference path="../../../../src/vs/vscode.proposed.d.ts" />
/// <reference types='@types/node'/>
@@ -1,13 +0,0 @@
{
"editor.tokenColorCustomizationsExperimental": {
"class": "#00b0b0",
"interface": "#845faf",
"function": "#ff00ff",
"*.declaration": {
"fontStyle": "underline"
},
"*.declaration.member": {
"fontStyle": "italic bold",
}
}
}
@@ -1,9 +0,0 @@
[
"class", "function.member.declaration",
"parameterType.declaration", "type", "parameterType.declaration", "type",
"variable.declaration", "parameterNames",
"function.member.declaration",
"interface.declaration",
"function.member.declaration", "testToken.testModifier"
]
@@ -1,9 +0,0 @@
{
"extends": "../shared.tsconfig.json",
"compilerOptions": {
"outDir": "./out"
},
"include": [
"src/**/*"
]
}
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -62,11 +62,10 @@
"keytar": "^5.5.0", "keytar": "^5.5.0",
"minimist": "^1.2.5", "minimist": "^1.2.5",
"native-is-elevated": "0.4.1", "native-is-elevated": "0.4.1",
"native-keymap": "2.1.1", "native-keymap": "2.1.2",
"native-watchdog": "1.3.0", "native-watchdog": "1.3.0",
"ng2-charts": "^1.6.0", "ng2-charts": "^1.6.0",
"node-pty": "0.10.0-beta8", "node-pty": "0.10.0-beta8",
"onigasm-umd": "2.2.5",
"plotly.js-dist-min": "^1.53.0", "plotly.js-dist-min": "^1.53.0",
"reflect-metadata": "^0.1.8", "reflect-metadata": "^0.1.8",
"rxjs": "5.4.0", "rxjs": "5.4.0",
@@ -77,15 +76,16 @@
"sudo-prompt": "9.1.1", "sudo-prompt": "9.1.1",
"v8-inspect-profiler": "^0.0.20", "v8-inspect-profiler": "^0.0.20",
"vscode-nsfw": "1.2.8", "vscode-nsfw": "1.2.8",
"vscode-oniguruma": "1.3.0",
"vscode-proxy-agent": "^0.5.2", "vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.8", "vscode-ripgrep": "^1.5.8",
"vscode-sqlite3": "4.0.10", "vscode-sqlite3": "4.0.10",
"vscode-textmate": "4.4.0", "vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.15", "xterm": "4.6.0-beta.25",
"xterm-addon-search": "0.6.0", "xterm-addon-search": "0.6.0",
"xterm-addon-unicode11": "0.2.0-beta.2", "xterm-addon-unicode11": "0.2.0-beta.2",
"xterm-addon-web-links": "0.3.0", "xterm-addon-web-links": "0.3.0",
"xterm-addon-webgl": "0.7.0-beta.6", "xterm-addon-webgl": "0.7.0-beta.8",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
"yazl": "^2.4.3", "yazl": "^2.4.3",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"
@@ -172,7 +172,7 @@
"opn": "^6.0.0", "opn": "^6.0.0",
"optimist": "0.3.5", "optimist": "0.3.5",
"p-all": "^1.0.0", "p-all": "^1.0.0",
"playwright": "0.12.1", "playwright": "0.15.0",
"pump": "^1.0.1", "pump": "^1.0.1",
"queue": "3.0.6", "queue": "3.0.6",
"rcedit": "^1.1.0", "rcedit": "^1.1.0",
@@ -183,7 +183,7 @@
"temp-write": "^3.4.0", "temp-write": "^3.4.0",
"ts-loader": "^4.4.2", "ts-loader": "^4.4.2",
"typemoq": "^0.3.2", "typemoq": "^0.3.2",
"typescript": "^3.9.0-dev.20200420", "typescript": "^3.9.0-dev.20200427",
"typescript-formatter": "7.1.0", "typescript-formatter": "7.1.0",
"underscore": "^1.8.2", "underscore": "^1.8.2",
"vinyl": "^2.0.0", "vinyl": "^2.0.0",
+1
View File
@@ -60,6 +60,7 @@
] ]
}, },
"extensionAllowedProposedApi": [ "extensionAllowedProposedApi": [
"ms-vscode.vscode-js-profile-table",
"ms-vscode.references-view" "ms-vscode.references-view"
], ],
"extensionsGallery": { "extensionsGallery": {
+4 -4
View File
@@ -27,7 +27,6 @@
"native-watchdog": "1.3.0", "native-watchdog": "1.3.0",
"ng2-charts": "^1.6.0", "ng2-charts": "^1.6.0",
"node-pty": "0.10.0-beta8", "node-pty": "0.10.0-beta8",
"onigasm-umd": "2.2.5",
"reflect-metadata": "^0.1.8", "reflect-metadata": "^0.1.8",
"rxjs": "5.4.0", "rxjs": "5.4.0",
"sanitize-html": "^1.19.1", "sanitize-html": "^1.19.1",
@@ -35,14 +34,15 @@
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33", "slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"spdlog": "^0.11.1", "spdlog": "^0.11.1",
"vscode-nsfw": "1.2.8", "vscode-nsfw": "1.2.8",
"vscode-oniguruma": "1.3.0",
"vscode-proxy-agent": "^0.5.2", "vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.8", "vscode-ripgrep": "^1.5.8",
"vscode-textmate": "4.4.0", "vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.15", "xterm": "4.6.0-beta.25",
"xterm-addon-search": "0.6.0", "xterm-addon-search": "0.6.0",
"xterm-addon-unicode11": "0.2.0-beta.2", "xterm-addon-unicode11": "0.2.0-beta.2",
"xterm-addon-web-links": "0.3.0", "xterm-addon-web-links": "0.3.0",
"xterm-addon-webgl": "0.7.0-beta.6", "xterm-addon-webgl": "0.7.0-beta.8",
"yauzl": "^2.9.2", "yauzl": "^2.9.2",
"yazl": "^2.4.3", "yazl": "^2.4.3",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"
+4 -4
View File
@@ -16,18 +16,18 @@
"html-query-plan": "git://github.com/anthonydresser/html-query-plan.git#2.6", "html-query-plan": "git://github.com/anthonydresser/html-query-plan.git#2.6",
"jquery": "3.4.0", "jquery": "3.4.0",
"ng2-charts": "^1.6.0", "ng2-charts": "^1.6.0",
"onigasm-umd": "2.2.5",
"reflect-metadata": "^0.1.8", "reflect-metadata": "^0.1.8",
"rxjs": "5.4.0", "rxjs": "5.4.0",
"sanitize-html": "^1.19.1", "sanitize-html": "^1.19.1",
"semver-umd": "^5.5.6", "semver-umd": "^5.5.6",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33", "slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"vscode-textmate": "4.4.0", "vscode-oniguruma": "1.3.0",
"xterm": "4.6.0-beta.15", "vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.25",
"xterm-addon-search": "0.6.0", "xterm-addon-search": "0.6.0",
"xterm-addon-unicode11": "0.2.0-beta.2", "xterm-addon-unicode11": "0.2.0-beta.2",
"xterm-addon-web-links": "0.3.0", "xterm-addon-web-links": "0.3.0",
"xterm-addon-webgl": "0.7.0-beta.6", "xterm-addon-webgl": "0.7.0-beta.8",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"
} }
} }
+17 -31
View File
@@ -222,11 +222,6 @@ moment@^2.10.2:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
nan@^2.14.0:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
ng2-charts@^1.6.0: ng2-charts@^1.6.0:
version "1.6.0" version "1.6.0"
resolved "https://registry.yarnpkg.com/ng2-charts/-/ng2-charts-1.6.0.tgz#108a2133ff62a8623895240fadbddbea2951f29d" resolved "https://registry.yarnpkg.com/ng2-charts/-/ng2-charts-1.6.0.tgz#108a2133ff62a8623895240fadbddbea2951f29d"
@@ -239,18 +234,6 @@ number-is-nan@^1.0.0:
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
onigasm-umd@2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.5.tgz#f104247334a543accd3f8d641a4d99b3d908d6a1"
integrity sha512-R3qD7hq6i2bBklF+QyjqZl/G4fe7GwtukI28YLH2vuiatqx52tb9vpg2sxwemKc3nF76SgkeyOKJLchBmTm0Aw==
oniguruma@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af"
integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA==
dependencies:
nan "^2.14.0"
postcss@^7.0.5: postcss@^7.0.5:
version "7.0.21" version "7.0.21"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17"
@@ -355,12 +338,15 @@ util-deprecate@^1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
vscode-textmate@4.4.0: vscode-oniguruma@1.3.0:
version "4.4.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.4.0.tgz#14032afeb50152e8f53258c95643e555f2948305" resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.0.tgz#6788a9db2f8b0781243b4eb8c7a1dd25f6c0e2c8"
integrity sha512-dFpm2eK0HwEjeFSD1DDh3j0q47bDSVuZt20RiJWxGqjtm73Wu2jip3C2KaZI3dQx/fSeeXCr/uEN4LNaNj7Ytw== integrity sha512-m4Br19v6XD4MRbVrgsLNSZgQrBzk1BCMCleL8+GrcoGxKEJJd62zOFcTaoQR3hCrSlLqoxWmJ7Cc0VieVV3iTQ==
dependencies:
oniguruma "^7.2.0" vscode-textmate@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.1.1.tgz#d88dbf271bee7cede455a21bd4894ba5724a4a7e"
integrity sha512-5VHjF+Fglf9d2JI5OyQ7FHutK6/29G0qYyD920K0SWO7uY8JTWbqyKAHEtfB/ZDk2fOe/E23n3wz9fHXKi63yg==
xtend@^4.0.1: xtend@^4.0.1:
version "4.0.2" version "4.0.2"
@@ -382,15 +368,15 @@ xterm-addon-web-links@0.3.0:
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.3.0.tgz#88affe9235c928b41bab660a65330f46d91c940e" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.3.0.tgz#88affe9235c928b41bab660a65330f46d91c940e"
integrity sha512-vGXiIDqNMyxK5S1IzOjDqcgeQrrv7TDcSHiOeCNAoWCI2f+Rap9d18gjgnMKPyR+AbG0KoKnaKA6Dc1du1vs5A== integrity sha512-vGXiIDqNMyxK5S1IzOjDqcgeQrrv7TDcSHiOeCNAoWCI2f+Rap9d18gjgnMKPyR+AbG0KoKnaKA6Dc1du1vs5A==
xterm-addon-webgl@0.7.0-beta.6: xterm-addon-webgl@0.7.0-beta.8:
version "0.7.0-beta.6" version "0.7.0-beta.8"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.6.tgz#340d728bae7456a1d67a7cb8996dfd51d96721b0" resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.8.tgz#546651958d740bf05d6a05555fbcacd2759b2ee7"
integrity sha512-IoR0hPtG5qBrcLG1B7GSzo4W2hYocP8UgG5LlyXkEkT/0BqVcGnICgR8Ck7EfMmU8ci4jNFiHYjK/Bgc4m2S4g== integrity sha512-2jxMtRR5zgAar1gPqt0iD/+GOlZ3cHyzzbIbC77EBIdZZFuhEDhJkucVPPS2KPcyqw3VROL1FgX7BSEV2rvdeA==
xterm@4.6.0-beta.15: xterm@4.6.0-beta.25:
version "4.6.0-beta.15" version "4.6.0-beta.25"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.15.tgz#93a0cb1ff047a452b03070499e2ccd0ba53e0678" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.25.tgz#2faea6cf8c677ed545792562165604ce7f314026"
integrity sha512-5G+3QSM/GKN/Tdq/IIU7FDivzh0eXsv3sNmZFDdtvNggnu2K56l4N5P0KZo0HdFztDfTyW/FLfqsPAwhrK4Khg== integrity sha512-63FLAUdJ8Bw9SMgLU3/r353P1WAtLxupbfvfddi4nMcz1WEGRq07O1CbmJn/bKHHkJw7gQQw0n1I8xnjFlLlTA==
zone.js@^0.8.4: zone.js@^0.8.4:
version "0.8.29" version "0.8.29"
+17 -26
View File
@@ -515,18 +515,6 @@ number-is-nan@^1.0.0:
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
onigasm-umd@2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.5.tgz#f104247334a543accd3f8d641a4d99b3d908d6a1"
integrity sha512-R3qD7hq6i2bBklF+QyjqZl/G4fe7GwtukI28YLH2vuiatqx52tb9vpg2sxwemKc3nF76SgkeyOKJLchBmTm0Aw==
oniguruma@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af"
integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA==
dependencies:
nan "^2.14.0"
pend@~1.2.0: pend@~1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
@@ -710,6 +698,11 @@ vscode-nsfw@1.2.8:
lodash.isundefined "^3.0.1" lodash.isundefined "^3.0.1"
nan "^2.10.0" nan "^2.10.0"
vscode-oniguruma@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.0.tgz#6788a9db2f8b0781243b4eb8c7a1dd25f6c0e2c8"
integrity sha512-m4Br19v6XD4MRbVrgsLNSZgQrBzk1BCMCleL8+GrcoGxKEJJd62zOFcTaoQR3hCrSlLqoxWmJ7Cc0VieVV3iTQ==
vscode-proxy-agent@^0.5.2: vscode-proxy-agent@^0.5.2:
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.2.tgz#0c90d24d353957b841d741da7b2701e3f0a044c4" resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.2.tgz#0c90d24d353957b841d741da7b2701e3f0a044c4"
@@ -725,12 +718,10 @@ vscode-ripgrep@^1.5.8:
resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.8.tgz#32cb33da6d1a9ca8f5de8c2813ed5114fd55fc11" resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.8.tgz#32cb33da6d1a9ca8f5de8c2813ed5114fd55fc11"
integrity sha512-l6Pv/t1Jk63RU+kEkMO04XxnNRYdyzuesizj9AzFpcfrUxxpAjEJBK1qO9Mov30UUGZl7uDUBn+uCv9koaHPPA== integrity sha512-l6Pv/t1Jk63RU+kEkMO04XxnNRYdyzuesizj9AzFpcfrUxxpAjEJBK1qO9Mov30UUGZl7uDUBn+uCv9koaHPPA==
vscode-textmate@4.4.0: vscode-textmate@5.1.1:
version "4.4.0" version "5.1.1"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.4.0.tgz#14032afeb50152e8f53258c95643e555f2948305" resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.1.1.tgz#d88dbf271bee7cede455a21bd4894ba5724a4a7e"
integrity sha512-dFpm2eK0HwEjeFSD1DDh3j0q47bDSVuZt20RiJWxGqjtm73Wu2jip3C2KaZI3dQx/fSeeXCr/uEN4LNaNj7Ytw== integrity sha512-5VHjF+Fglf9d2JI5OyQ7FHutK6/29G0qYyD920K0SWO7uY8JTWbqyKAHEtfB/ZDk2fOe/E23n3wz9fHXKi63yg==
dependencies:
oniguruma "^7.2.0"
vscode-windows-ca-certs@0.2.0: vscode-windows-ca-certs@0.2.0:
version "0.2.0" version "0.2.0"
@@ -764,15 +755,15 @@ xterm-addon-web-links@0.3.0:
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.3.0.tgz#88affe9235c928b41bab660a65330f46d91c940e" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.3.0.tgz#88affe9235c928b41bab660a65330f46d91c940e"
integrity sha512-vGXiIDqNMyxK5S1IzOjDqcgeQrrv7TDcSHiOeCNAoWCI2f+Rap9d18gjgnMKPyR+AbG0KoKnaKA6Dc1du1vs5A== integrity sha512-vGXiIDqNMyxK5S1IzOjDqcgeQrrv7TDcSHiOeCNAoWCI2f+Rap9d18gjgnMKPyR+AbG0KoKnaKA6Dc1du1vs5A==
xterm-addon-webgl@0.7.0-beta.6: xterm-addon-webgl@0.7.0-beta.8:
version "0.7.0-beta.6" version "0.7.0-beta.8"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.6.tgz#340d728bae7456a1d67a7cb8996dfd51d96721b0" resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.8.tgz#546651958d740bf05d6a05555fbcacd2759b2ee7"
integrity sha512-IoR0hPtG5qBrcLG1B7GSzo4W2hYocP8UgG5LlyXkEkT/0BqVcGnICgR8Ck7EfMmU8ci4jNFiHYjK/Bgc4m2S4g== integrity sha512-2jxMtRR5zgAar1gPqt0iD/+GOlZ3cHyzzbIbC77EBIdZZFuhEDhJkucVPPS2KPcyqw3VROL1FgX7BSEV2rvdeA==
xterm@4.6.0-beta.15: xterm@4.6.0-beta.25:
version "4.6.0-beta.15" version "4.6.0-beta.25"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.15.tgz#93a0cb1ff047a452b03070499e2ccd0ba53e0678" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.25.tgz#2faea6cf8c677ed545792562165604ce7f314026"
integrity sha512-5G+3QSM/GKN/Tdq/IIU7FDivzh0eXsv3sNmZFDdtvNggnu2K56l4N5P0KZo0HdFztDfTyW/FLfqsPAwhrK4Khg== integrity sha512-63FLAUdJ8Bw9SMgLU3/r353P1WAtLxupbfvfddi4nMcz1WEGRq07O1CbmJn/bKHHkJw7gQQw0n1I8xnjFlLlTA==
yauzl@^2.9.2: yauzl@^2.9.2:
version "2.10.0" version "2.10.0"
-1
View File
@@ -30,7 +30,6 @@ if not exist out yarn compile
set ELECTRON_RUN_AS_NODE=1 set ELECTRON_RUN_AS_NODE=1
set NODE_ENV=development set NODE_ENV=development
set VSCODE_DEV=1 set VSCODE_DEV=1
set ELECTRON_ENABLE_SECURITY_WARNINGS=1
REM set ELECTRON_DEFAULT_ERROR_MODE=1 TODO@ben to investigate if this helps with builds reporting stacks if renderer crashes REM set ELECTRON_DEFAULT_ERROR_MODE=1 TODO@ben to investigate if this helps with builds reporting stacks if renderer crashes
set ELECTRON_ENABLE_LOGGING=1 set ELECTRON_ENABLE_LOGGING=1
set ELECTRON_ENABLE_STACK_DUMPING=1 set ELECTRON_ENABLE_STACK_DUMPING=1
-1
View File
@@ -39,7 +39,6 @@ function code() {
ELECTRON_RUN_AS_NODE=1 \ ELECTRON_RUN_AS_NODE=1 \
NODE_ENV=development \ NODE_ENV=development \
VSCODE_DEV=1 \ VSCODE_DEV=1 \
ELECTRON_ENABLE_SECURITY_WARNINGS=1 \
ELECTRON_ENABLE_LOGGING=1 \ ELECTRON_ENABLE_LOGGING=1 \
ELECTRON_ENABLE_STACK_DUMPING=1 \ ELECTRON_ENABLE_STACK_DUMPING=1 \
"$CODE" --inspect=5874 "$ROOT/out/cli.js" . "$@" "$CODE" --inspect=5874 "$ROOT/out/cli.js" . "$@"
-1
View File
@@ -28,7 +28,6 @@ if not exist out yarn compile
:: Configuration :: Configuration
set NODE_ENV=development set NODE_ENV=development
set VSCODE_DEV=1 set VSCODE_DEV=1
set ELECTRON_ENABLE_SECURITY_WARNINGS=1
set VSCODE_CLI=1 set VSCODE_CLI=1
REM set ELECTRON_DEFAULT_ERROR_MODE=1 TODO@ben to investigate if this helps with builds reporting stacks if renderer crashes REM set ELECTRON_DEFAULT_ERROR_MODE=1 TODO@ben to investigate if this helps with builds reporting stacks if renderer crashes
set ELECTRON_ENABLE_LOGGING=1 set ELECTRON_ENABLE_LOGGING=1
-1
View File
@@ -44,7 +44,6 @@ function code() {
# Configuration # Configuration
export NODE_ENV=development export NODE_ENV=development
export VSCODE_DEV=1 export VSCODE_DEV=1
export ELECTRON_ENABLE_SECURITY_WARNINGS=1
export VSCODE_CLI=1 export VSCODE_CLI=1
export ELECTRON_ENABLE_STACK_DUMPING=1 export ELECTRON_ENABLE_STACK_DUMPING=1
export ELECTRON_ENABLE_LOGGING=1 export ELECTRON_ENABLE_LOGGING=1
+9 -7
View File
@@ -25,6 +25,7 @@ else
# and the build bundles extensions into .build webpacked # and the build bundles extensions into .build webpacked
yarn gulp compile-extension:vscode-api-tests \ yarn gulp compile-extension:vscode-api-tests \
compile-extension:vscode-colorize-tests \ compile-extension:vscode-colorize-tests \
compile-extension:vscode-notebook-tests \
compile-extension:markdown-language-features \ compile-extension:markdown-language-features \
compile-extension:emmet \ compile-extension:emmet \
compile-extension:css-language-features-server \ compile-extension:css-language-features-server \
@@ -44,14 +45,15 @@ fi
./scripts/test.sh --runGlob **/*.integrationTest.js "$@" ./scripts/test.sh --runGlob **/*.integrationTest.js "$@"
# Tests in the extension host # Tests in the extension host
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR # "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# Tests in commonJS # Tests in commonJS
cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js
@@ -67,7 +67,7 @@ export interface IInsightData {
export interface IInsightsView { export interface IInsightsView {
data: IInsightData; data: IInsightData;
setConfig?: (config: { [key: string]: any }) => void; setConfig?: (config: any) => void;
init?: () => void; init?: () => void;
} }
@@ -10,7 +10,7 @@ import { ModelViewInput } from 'sql/workbench/browser/modelComponents/modelViewI
import { ModelViewEditor } from 'sql/workbench/browser/modelComponents/modelViewEditor'; import { ModelViewEditor } from 'sql/workbench/browser/modelComponents/modelViewEditor';
// Model View editor registration // Model View editor registration
const viewModelEditorDescriptor = new EditorDescriptor( const viewModelEditorDescriptor = EditorDescriptor.create(
ModelViewEditor, ModelViewEditor,
ModelViewEditor.ID, ModelViewEditor.ID,
'ViewModel' 'ViewModel'
@@ -3,73 +3,69 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/views';
import { Event, Emitter } from 'vs/base/common/event'; import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, Disposable, toDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IAction, IActionViewItem, ActionRunner, Action } from 'vs/base/common/actions'; import { IAction, ActionRunner } from 'vs/base/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { IMenuService, MenuId, MenuItemAction, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { ContextAwareMenuEntryActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { ContextAwareMenuEntryActionViewItem, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService, ContextKeyExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, IViewsRegistry, ViewContainer, ITreeItemLabel, Extensions, IViewDescriptorService } from 'vs/workbench/common/views'; import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, IViewsRegistry, ITreeItemLabel, Extensions, IViewDescriptorService, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { IProgressService } from 'vs/platform/progress/common/progress'; import { IProgressService } from 'vs/platform/progress/common/progress';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommandService } from 'vs/platform/commands/common/commands';
import * as DOM from 'vs/base/browser/dom'; import * as DOM from 'vs/base/browser/dom';
import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels'; import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels';
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { dirname, basename } from 'vs/base/common/resources'; import { dirname, basename } from 'vs/base/common/resources';
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService'; import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon, IThemeService } from 'vs/platform/theme/common/themeService';
import { FileKind } from 'vs/platform/files/common/files'; import { FileKind } from 'vs/platform/files/common/files';
import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService'; import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { timeout } from 'vs/base/common/async'; import { timeout } from 'vs/base/common/async';
import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { textLinkForeground, textCodeBlockBackground, focusBorder, listFilterMatchHighlight, listFilterMatchHighlightBorder } from 'vs/platform/theme/common/colorRegistry';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { isString } from 'vs/base/common/types'; import { isString } from 'vs/base/common/types';
import { renderMarkdown, MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IMarkdownRenderResult } from 'vs/editor/contrib/markdown/markdownRenderer';
import { ILabelService } from 'vs/platform/label/common/label'; import { ILabelService } from 'vs/platform/label/common/label';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults'; import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { SIDE_BAR_BACKGROUND, PANEL_BACKGROUND } from 'vs/workbench/common/theme';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { firstIndex } from 'vs/base/common/arrays';
import { ITreeItem, ITreeView } from 'sql/workbench/common/views'; import { ITreeItem, ITreeView } from 'sql/workbench/common/views';
import { UserCancelledConnectionError } from 'sql/base/common/errors';
import { IOEShimService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerViewTreeShim'; import { IOEShimService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerViewTreeShim';
import { NodeContextKey } from 'sql/workbench/browser/parts/views/nodeContext'; import { NodeContextKey } from 'sql/workbench/browser/parts/views/nodeContext';
import { UserCancelledConnectionError } from 'sql/base/common/errors';
import { firstIndex } from 'vs/base/common/arrays';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export class CustomTreeViewPane extends ViewPane { export class TreeViewPane extends ViewPane {
private treeView: ITreeView; private treeView: ITreeView;
constructor( constructor(
options: IViewletViewOptions, options: IViewletViewOptions,
@INotificationService private readonly notificationService: INotificationService,
@IKeybindingService keybindingService: IKeybindingService, @IKeybindingService keybindingService: IKeybindingService,
@IContextMenuService contextMenuService: IContextMenuService, @IContextMenuService contextMenuService: IContextMenuService,
@IConfigurationService configurationService: IConfigurationService, @IConfigurationService configurationService: IConfigurationService,
@IContextKeyService contextKeyService: IContextKeyService, @IContextKeyService contextKeyService: IContextKeyService,
@IInstantiationService instantiationService: IInstantiationService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IOpenerService protected openerService: IOpenerService, @IInstantiationService instantiationService: IInstantiationService,
@IThemeService protected themeService: IThemeService, @IOpenerService openerService: IOpenerService,
@IThemeService themeService: IThemeService,
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
) { ) {
super({ ...(options as IViewPaneOptions) }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); super({ ...(options as IViewPaneOptions), titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id)); const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
this.treeView = treeView as ITreeView; this.treeView = treeView as ITreeView;
this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this)); this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this));
@@ -86,23 +82,22 @@ export class CustomTreeViewPane extends ViewPane {
} }
renderBody(container: HTMLElement): void { renderBody(container: HTMLElement): void {
if (this.treeView instanceof CustomTreeView) { super.renderBody(container);
if (this.treeView instanceof TreeView) {
this.treeView.show(container); this.treeView.show(container);
} }
} }
shouldShowWelcome(): boolean { shouldShowWelcome(): boolean {
return (this.treeView.dataProvider === undefined) && (this.treeView.message === undefined); return ((this.treeView.dataProvider === undefined) || !!this.treeView.dataProvider.isTreeEmpty) && (this.treeView.message === undefined);
} }
layoutBody(height: number, width: number): void { layoutBody(height: number, width: number): void {
super.layoutBody(height, width);
this.treeView.layout(height, width); this.treeView.layout(height, width);
} }
getActionViewItem(action: IAction): IActionViewItem | undefined {
return action instanceof MenuItemAction ? new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService) : undefined;
}
getOptimalWidth(): number { getOptimalWidth(): number {
return this.treeView.getOptimalWidth(); return this.treeView.getOptimalWidth();
} }
@@ -112,51 +107,6 @@ export class CustomTreeViewPane extends ViewPane {
} }
} }
class TitleMenus extends Disposable {
private titleActions: IAction[] = [];
private readonly titleActionsDisposable = this._register(new MutableDisposable());
private titleSecondaryActions: IAction[] = [];
private _onDidChangeTitle = this._register(new Emitter<void>());
readonly onDidChangeTitle: Event<void> = this._onDidChangeTitle.event;
constructor(
id: string,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IMenuService private readonly menuService: IMenuService,
) {
super();
const scopedContextKeyService = this._register(this.contextKeyService.createScoped());
scopedContextKeyService.createKey('view', id);
const titleMenu = this._register(this.menuService.createMenu(MenuId.ViewTitle, scopedContextKeyService));
const updateActions = () => {
this.titleActions = [];
this.titleSecondaryActions = [];
this.titleActionsDisposable.value = createAndFillInActionBarActions(titleMenu, undefined, { primary: this.titleActions, secondary: this.titleSecondaryActions });
this._onDidChangeTitle.fire();
};
this._register(titleMenu.onDidChange(updateActions));
updateActions();
this._register(toDisposable(() => {
this.titleActions = [];
this.titleSecondaryActions = [];
}));
}
getTitleActions(): IAction[] {
return this.titleActions;
}
getTitleSecondaryActions(): IAction[] {
return this.titleSecondaryActions;
}
}
class Root implements ITreeItem { class Root implements ITreeItem {
label = { label: 'root' }; label = { label: 'root' };
handle = '0'; handle = '0';
@@ -167,29 +117,30 @@ class Root implements ITreeItem {
const noDataProviderMessage = localize('no-dataprovider', "There is no data provider registered that can provide view data."); const noDataProviderMessage = localize('no-dataprovider', "There is no data provider registered that can provide view data.");
export class CustomTreeView extends Disposable implements ITreeView { class Tree extends WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> { }
export class TreeView extends Disposable implements ITreeView {
private isVisible: boolean = false; private isVisible: boolean = false;
private activated: boolean = false;
private _hasIconForParentNode = false; private _hasIconForParentNode = false;
private _hasIconForLeafNode = false; private _hasIconForLeafNode = false;
private _showCollapseAllAction = false;
private readonly collapseAllContextKey: RawContextKey<boolean>;
private readonly collapseAllContext: IContextKey<boolean>;
private readonly refreshContextKey: RawContextKey<boolean>;
private readonly refreshContext: IContextKey<boolean>;
private focused: boolean = false; private focused: boolean = false;
private domNode: HTMLElement; private domNode!: HTMLElement;
private treeContainer: HTMLElement; private treeContainer!: HTMLElement;
private _messageValue: string | IMarkdownString | undefined; private _messageValue: string | undefined;
private _canSelectMany: boolean = false; private _canSelectMany: boolean = false;
private messageElement: HTMLDivElement; private messageElement!: HTMLDivElement;
private tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>; private tree: Tree | undefined;
private treeLabels: ResourceLabels; private treeLabels: ResourceLabels | undefined;
private root: ITreeItem; private root: ITreeItem;
private elementsToRefresh: ITreeItem[] = []; private elementsToRefresh: ITreeItem[] = [];
private menus: TitleMenus;
private markdownRenderer: MarkdownRenderer;
private markdownResult: IMarkdownRenderResult | null;
private readonly _onDidExpandItem: Emitter<ITreeItem> = this._register(new Emitter<ITreeItem>()); private readonly _onDidExpandItem: Emitter<ITreeItem> = this._register(new Emitter<ITreeItem>());
readonly onDidExpandItem: Event<ITreeItem> = this._onDidExpandItem.event; readonly onDidExpandItem: Event<ITreeItem> = this._onDidExpandItem.event;
@@ -212,69 +163,109 @@ export class CustomTreeView extends Disposable implements ITreeView {
private readonly _onDidChangeTitle: Emitter<string> = this._register(new Emitter<string>()); private readonly _onDidChangeTitle: Emitter<string> = this._register(new Emitter<string>());
readonly onDidChangeTitle: Event<string> = this._onDidChangeTitle.event; readonly onDidChangeTitle: Event<string> = this._onDidChangeTitle.event;
private readonly _onDidCompleteRefresh: Emitter<void> = this._register(new Emitter<void>());
private nodeContext: NodeContextKey; private nodeContext: NodeContextKey;
constructor( constructor(
private id: string, protected readonly id: string,
private _title: string, private _title: string,
private viewContainer: ViewContainer, @IThemeService private readonly themeService: IThemeService,
@IExtensionService private readonly extensionService: IExtensionService,
@IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService,
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommandService private readonly commandService: ICommandService, @ICommandService private readonly commandService: ICommandService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IProgressService private readonly progressService: IProgressService, @IProgressService protected readonly progressService: IProgressService,
@IContextMenuService private readonly contextMenuService: IContextMenuService, @IContextMenuService private readonly contextMenuService: IContextMenuService,
@IKeybindingService private readonly keybindingService: IKeybindingService @IKeybindingService private readonly keybindingService: IKeybindingService,
@INotificationService private readonly notificationService: INotificationService,
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService
) { ) {
super(); super();
this.root = new Root(); this.root = new Root();
this.menus = this._register(instantiationService.createInstance(TitleMenus, this.id)); this.collapseAllContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableCollapseAll`, false);
this._register(this.menus.onDidChangeTitle(() => this._onDidChangeActions.fire())); this.collapseAllContext = this.collapseAllContextKey.bindTo(contextKeyService);
this.refreshContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableRefresh`, false);
this.refreshContext = this.refreshContextKey.bindTo(contextKeyService);
this._register(this.themeService.onDidFileIconThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/)); this._register(this.themeService.onDidFileIconThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/));
this._register(this.themeService.onDidColorThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/)); this._register(this.themeService.onDidColorThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/));
this._register(this.configurationService.onDidChangeConfiguration(e => { this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('explorer.decorations')) { if (e.affectsConfiguration('explorer.decorations')) {
this.doRefresh([this.root]).catch(onUnexpectedError); /** soft refresh **/ this.doRefresh([this.root]); /** soft refresh **/
} }
})); }));
this.markdownRenderer = instantiationService.createInstance(MarkdownRenderer); this._register(this.viewDescriptorService.onDidChangeLocation(({ views, from, to }) => {
this._register(toDisposable(() => { if (views.some(v => v.id === this.id)) {
if (this.markdownResult) { this.tree?.updateOptions({ overrideStyles: { listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND } });
this.markdownResult.dispose();
}
}));
this._register(Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).onDidChangeContainer(({ views, from, to }) => {
if (from === this.viewContainer && views.some(v => v.id === this.id)) {
this.viewContainer = to;
} }
})); }));
this.registerActions();
this.nodeContext = this._register(instantiationService.createInstance(NodeContextKey)); this.nodeContext = this._register(instantiationService.createInstance(NodeContextKey)); // tracked change
this.create(); this.create();
} }
private _dataProvider: ITreeViewDataProvider | null; collapse(element: ITreeItem): boolean {
get dataProvider(): ITreeViewDataProvider | null { if (this.tree) {
return this.tree.collapse(element);
}
return false;
}
get viewContainer(): ViewContainer {
return this.viewDescriptorService.getViewContainerByViewId(this.id)!;
}
get viewLocation(): ViewContainerLocation {
return this.viewDescriptorService.getViewLocationById(this.id)!;
}
private _dataProvider: ITreeViewDataProvider | undefined;
get dataProvider(): ITreeViewDataProvider | undefined {
return this._dataProvider; return this._dataProvider;
} }
set dataProvider(dataProvider: ITreeViewDataProvider | null) { set dataProvider(dataProvider: ITreeViewDataProvider | undefined) {
if (this.tree === undefined) {
this.createTree();
}
if (dataProvider) { if (dataProvider) {
this._dataProvider = new class implements ITreeViewDataProvider { this._dataProvider = new class implements ITreeViewDataProvider {
async getChildren(node: ITreeItem): Promise<ITreeItem[]> { private _isEmpty: boolean = true;
if (node && node.children) { private _onDidChangeEmpty: Emitter<void> = new Emitter();
return Promise.resolve(node.children); public onDidChangeEmpty: Event<void> = this._onDidChangeEmpty.event;
get isTreeEmpty(): boolean {
return this._isEmpty;
} }
const children = await (node instanceof Root ? dataProvider.getChildren() : dataProvider.getChildren(node));
async getChildren(node: ITreeItem): Promise<ITreeItem[]> {
let children: ITreeItem[];
if (node && node.children) {
children = node.children;
} else {
children = await (node instanceof Root ? dataProvider.getChildren() : dataProvider.getChildren(node));
node.children = children; node.children = children;
}
if (node instanceof Root) {
const oldEmpty = this._isEmpty;
this._isEmpty = children.length === 0;
if (oldEmpty !== this._isEmpty) {
this._onDidChangeEmpty.fire();
}
}
return children; return children;
} }
}; };
if (this._dataProvider.onDidChangeEmpty) {
this._register(this._dataProvider.onDidChangeEmpty(() => this._onDidChangeWelcomeState.fire()));
}
this.updateMessage(); this.updateMessage();
this.refresh().catch(onUnexpectedError); this.refresh();
} else { } else {
this._dataProvider = null; this._dataProvider = undefined;
this.updateMessage(); this.updateMessage();
} }
@@ -322,27 +313,61 @@ export class CustomTreeView extends Disposable implements ITreeView {
} }
get showCollapseAllAction(): boolean { get showCollapseAllAction(): boolean {
return this._showCollapseAllAction; return !!this.collapseAllContext.get();
} }
set showCollapseAllAction(showCollapseAllAction: boolean) { set showCollapseAllAction(showCollapseAllAction: boolean) {
if (this._showCollapseAllAction !== !!showCollapseAllAction) { this.collapseAllContext.set(showCollapseAllAction);
this._showCollapseAllAction = !!showCollapseAllAction;
this._onDidChangeActions.fire();
}
} }
getPrimaryActions(): IAction[] { get showRefreshAction(): boolean {
if (this.showCollapseAllAction) { return !!this.refreshContext.get();
const collapseAllAction = new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, () => this.tree ? new CollapseAllAction<ITreeItem, ITreeItem, FuzzyScore>(this.tree, true).run() : Promise.resolve());
return [...this.menus.getTitleActions(), collapseAllAction];
} else {
return this.menus.getTitleActions();
}
} }
getSecondaryActions(): IAction[] { set showRefreshAction(showRefreshAction: boolean) {
return this.menus.getTitleSecondaryActions(); this.refreshContext.set(showRefreshAction);
}
private registerActions() {
const that = this;
this._register(registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.actions.treeView.${that.id}.refresh`,
title: localize('refresh', "Refresh"),
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', that.id), that.refreshContextKey),
group: 'navigation',
order: Number.MAX_SAFE_INTEGER - 1,
},
icon: { id: 'codicon/refresh' }
});
}
async run(): Promise<void> {
return that.refresh();
}
}));
this._register(registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.actions.treeView.${that.id}.collapseAll`,
title: localize('collapseAll', "Collapse All"),
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', that.id), that.collapseAllContextKey),
group: 'navigation',
order: Number.MAX_SAFE_INTEGER,
},
icon: { id: 'codicon/collapse-all' }
});
}
async run(): Promise<void> {
if (that.tree) {
return new CollapseAllAction<ITreeItem, ITreeItem, FuzzyScore>(that.tree, true).run();
}
}
}));
} }
setVisibility(isVisible: boolean): void { setVisibility(isVisible: boolean): void {
@@ -352,9 +377,6 @@ export class CustomTreeView extends Disposable implements ITreeView {
} }
this.isVisible = isVisible; this.isVisible = isVisible;
if (this.isVisible) {
this.activate();
}
if (this.tree) { if (this.tree) {
if (this.isVisible) { if (this.isVisible) {
@@ -364,7 +386,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
} }
if (this.isVisible && this.elementsToRefresh.length) { if (this.isVisible && this.elementsToRefresh.length) {
this.doRefresh(this.elementsToRefresh).catch(onUnexpectedError); this.doRefresh(this.elementsToRefresh);
this.elementsToRefresh = []; this.elementsToRefresh = [];
} }
} }
@@ -372,16 +394,18 @@ export class CustomTreeView extends Disposable implements ITreeView {
this._onDidChangeVisibility.fire(this.isVisible); this._onDidChangeVisibility.fire(this.isVisible);
} }
focus(): void { focus(reveal: boolean = true): void {
if (this.tree && this.root.children && this.root.children.length > 0) { if (this.tree && this.root.children && this.root.children.length > 0) {
// Make sure the current selected element is revealed // Make sure the current selected element is revealed
const selectedElement = this.tree.getSelection()[0]; const selectedElement = this.tree.getSelection()[0];
if (selectedElement) { if (selectedElement && reveal) {
this.tree.reveal(selectedElement, 0.5); this.tree.reveal(selectedElement, 0.5);
} }
// Pass Focus to Viewer // Pass Focus to Viewer
this.tree.domFocus(); this.tree.domFocus();
} else if (this.tree) {
this.tree.domFocus();
} else { } else {
this.domNode.focus(); this.domNode.focus();
} }
@@ -406,18 +430,21 @@ export class CustomTreeView extends Disposable implements ITreeView {
const actionViewItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuEntryActionViewItem, action) : undefined; const actionViewItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuEntryActionViewItem, action) : undefined;
const treeMenus = this._register(this.instantiationService.createInstance(TreeMenus, this.id)); const treeMenus = this._register(this.instantiationService.createInstance(TreeMenus, this.id));
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this)); this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
const dataSource = this.instantiationService.createInstance(TreeDataSource, this, this.id, <T>(task: Promise<T>) => this.progressService.withProgress({ location: this.viewContainer.id }, () => task)); const dataSource = this.instantiationService.createInstance(TreeDataSource, this, this.id, <T>(task: Promise<T>) => this.progressService.withProgress({ location: this.id }, () => task));
const aligner = new Aligner(this.themeService); const aligner = new Aligner(this.themeService);
const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, treeMenus, this.treeLabels, actionViewItemProvider, aligner); const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, treeMenus, this.treeLabels, actionViewItemProvider, aligner);
const widgetAriaLabel = this._title;
this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'SqlCustomView', this.treeContainer, new CustomTreeDelegate(), [renderer], this.tree = this._register(this.instantiationService.createInstance(Tree, this.id, this.treeContainer, new TreeViewDelegate(), [renderer],
dataSource, { dataSource, {
identityProvider: new CustomViewIdentityProvider(), identityProvider: new TreeViewIdentityProvider(),
accessibilityProvider: { accessibilityProvider: {
getAriaLabel(element: ITreeItem): string { getAriaLabel(element: ITreeItem): string {
return element.label ? element.label.label : ''; return element.tooltip ? element.tooltip : element.label ? element.label.label : '';
}, },
getWidgetAriaLabel: () => this.title getWidgetAriaLabel(): string {
return widgetAriaLabel;
}
}, },
keyboardNavigationLabelProvider: { keyboardNavigationLabelProvider: {
getKeyboardNavigationLabel: (item: ITreeItem) => { getKeyboardNavigationLabel: (item: ITreeItem) => {
@@ -429,15 +456,22 @@ export class CustomTreeView extends Disposable implements ITreeView {
return e.collapsibleState !== TreeItemCollapsibleState.Expanded; return e.collapsibleState !== TreeItemCollapsibleState.Expanded;
}, },
multipleSelectionSupport: this.canSelectMany, multipleSelectionSupport: this.canSelectMany,
overrideStyles: {
listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND
}
}) as WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>); }) as WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>);
aligner.tree = this.tree; aligner.tree = this.tree;
const actionRunner = new MultipleSelectionActionRunner(() => this.tree!.getSelection()); const actionRunner = new MultipleSelectionActionRunner(this.notificationService, () => this.tree!.getSelection());
renderer.actionRunner = actionRunner; renderer.actionRunner = actionRunner;
this.tree.contextKeyService.createKey<boolean>(this.id, true); this.tree.contextKeyService.createKey<boolean>(this.id, true);
this._register(this.tree.onContextMenu(e => this.onContextMenu(treeMenus, e, actionRunner))); this._register(this.tree.onContextMenu(e => this.onContextMenu(treeMenus, e, actionRunner)));
this._register(this.tree.onDidChangeSelection(e => this._onDidChangeSelection.fire(e.elements))); this._register(this.tree.onDidChangeSelection(e => this._onDidChangeSelection.fire(e.elements)));
this._register(this.tree.onDidChangeCollapseState(e => { this._register(this.tree.onDidChangeCollapseState(e => {
if (!e.node.element) {
return;
}
const element: ITreeItem = Array.isArray(e.node.element.element) ? e.node.element.element[0] : e.node.element.element; const element: ITreeItem = Array.isArray(e.node.element.element) ? e.node.element.element[0] : e.node.element.element;
if (e.node.collapsed) { if (e.node.collapsed) {
this._onDidCollapseItem.fire(element); this._onDidCollapseItem.fire(element);
@@ -446,18 +480,18 @@ export class CustomTreeView extends Disposable implements ITreeView {
} }
})); }));
// Update resource context based on focused element // Update resource context based on focused element
this._register(this.tree.onDidChangeFocus(e => { this._register(this.tree.onDidChangeFocus(e => { // tracked change
this.nodeContext.set({ node: e.elements[0], viewId: this.id }); this.nodeContext.set({ node: e.elements[0], viewId: this.id });
})); }));
this.tree.setInput(this.root).then(() => this.updateContentAreas()); this.tree.setInput(this.root).then(() => this.updateContentAreas());
const customTreeNavigator = new TreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false }); const treeNavigator = new TreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
this._register(customTreeNavigator); this._register(treeNavigator);
this._register(customTreeNavigator.onDidOpenResource(e => { this._register(treeNavigator.onDidOpenResource(e => {
if (!e.browserEvent) { if (!e.browserEvent) {
return; return;
} }
const selection = this.tree.getSelection(); const selection = this.tree!.getSelection();
if ((selection.length === 1) && selection[0].command) { if ((selection.length === 1) && selection[0].command) {
this.commandService.executeCommand(selection[0].command.id, ...(selection[0].command.arguments || [])); this.commandService.executeCommand(selection[0].command.id, ...(selection[0].command.arguments || []));
} }
@@ -474,7 +508,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.tree.setFocus([node]); this.tree!.setFocus([node]);
const actions = treeMenus.getResourceContextActions(node); const actions = treeMenus.getResourceContextActions(node);
if (!actions.length) { if (!actions.length) {
return; return;
@@ -494,17 +528,17 @@ export class CustomTreeView extends Disposable implements ITreeView {
onHide: (wasCancelled?: boolean) => { onHide: (wasCancelled?: boolean) => {
if (wasCancelled) { if (wasCancelled) {
this.tree.domFocus(); this.tree!.domFocus();
} }
}, },
getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: this.id, $treeItemHandle: node.handle, $treeItem: node, $treeContainerId: this.treeContainer.id }), getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: this.id, $treeItemHandle: node.handle }),
actionRunner actionRunner
}); });
} }
private updateMessage(): void { protected updateMessage(): void {
if (this._message) { if (this._message) {
this.showMessage(this._message); this.showMessage(this._message);
} else if (!this.dataProvider) { } else if (!this.dataProvider) {
@@ -515,43 +549,36 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.updateContentAreas(); this.updateContentAreas();
} }
private showMessage(message: string | IMarkdownString): void { private showMessage(message: string): void {
DOM.removeClass(this.messageElement, 'hide'); DOM.removeClass(this.messageElement, 'hide');
if (this._messageValue !== message) {
this.resetMessageElement(); this.resetMessageElement();
this._messageValue = message; this._messageValue = message;
if (isString(this._messageValue)) { if (!isFalsyOrWhitespace(this._message)) {
this.messageElement.textContent = this._messageValue; this.messageElement.textContent = this._messageValue;
} else {
this.markdownResult = this.markdownRenderer.render(this._messageValue);
DOM.append(this.messageElement, this.markdownResult.element);
}
this.layout(this._size);
} }
this.layout(this._height, this._width);
} }
private hideMessage(): void { private hideMessage(): void {
this.resetMessageElement(); this.resetMessageElement();
DOM.addClass(this.messageElement, 'hide'); DOM.addClass(this.messageElement, 'hide');
this.layout(this._size); this.layout(this._height, this._width);
} }
private resetMessageElement(): void { private resetMessageElement(): void {
if (this.markdownResult) {
this.markdownResult.dispose();
this.markdownResult = null;
}
DOM.clearNode(this.messageElement); DOM.clearNode(this.messageElement);
} }
private _size: number; private _height: number = 0;
layout(size: number) { private _width: number = 0;
if (size) { layout(height: number, width: number) {
this._size = size; if (height && width) {
const treeSize = size - DOM.getTotalHeight(this.messageElement); this._height = height;
this.treeContainer.style.height = treeSize + 'px'; this._width = width;
const treeHeight = height - DOM.getTotalHeight(this.messageElement);
this.treeContainer.style.height = treeHeight + 'px';
if (this.tree) { if (this.tree) {
this.tree.layout(treeSize); this.tree.layout(treeHeight, width);
} }
} }
} }
@@ -565,8 +592,11 @@ export class CustomTreeView extends Disposable implements ITreeView {
return 0; return 0;
} }
refresh(elements?: ITreeItem[]): Promise<void> { async refresh(elements?: ITreeItem[]): Promise<void> {
if (this.dataProvider && this.tree) { if (this.dataProvider && this.tree) {
if (this.refreshing) {
await Event.toPromise(this._onDidCompleteRefresh.event);
}
if (!elements) { if (!elements) {
elements = [this.root]; elements = [this.root];
// remove all waiting elements to refresh if root is asked to refresh // remove all waiting elements to refresh if root is asked to refresh
@@ -591,24 +621,17 @@ export class CustomTreeView extends Disposable implements ITreeView {
} }
} }
} }
return Promise.resolve(undefined); return undefined;
}
collapse(element: ITreeItem): boolean {
if (this.tree) {
return this.tree.collapse(element);
}
return Promise.arguments(null);
} }
async expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void> { async expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void> {
if (this.tree) { const tree = this.tree;
if (tree) {
itemOrItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems]; itemOrItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
await Promise.all(itemOrItems.map(element => { await Promise.all(itemOrItems.map(element => {
return this.tree.expand(element, false); return tree.expand(element, false);
})); }));
} }
return Promise.resolve(undefined);
} }
setSelection(items: ITreeItem[]): void { setSelection(items: ITreeItem[]): void {
@@ -624,34 +647,23 @@ export class CustomTreeView extends Disposable implements ITreeView {
} }
} }
reveal(item: ITreeItem): Promise<void> { async reveal(item: ITreeItem): Promise<void> {
if (this.tree) { if (this.tree) {
return Promise.resolve(this.tree.reveal(item)); return this.tree.reveal(item);
}
return Promise.resolve();
}
private activate() {
if (!this.activated) {
this.createTree();
this.progressService.withProgress({ location: this.viewContainer.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`))
.then(() => timeout(2000))
.then(() => {
this.updateMessage();
});
this.activated = true;
} }
} }
private refreshing: boolean = false; private refreshing: boolean = false;
private async doRefresh(elements: ITreeItem[]): Promise<void> { private async doRefresh(elements: ITreeItem[]): Promise<void> {
if (this.tree) { const tree = this.tree;
if (tree && this.visible) {
this.refreshing = true; this.refreshing = true;
await Promise.all(elements.map(element => this.tree.updateChildren(element, true))); await Promise.all(elements.map(element => tree.updateChildren(element, true, true)));
this.refreshing = false; this.refreshing = false;
this._onDidCompleteRefresh.fire();
this.updateContentAreas(); this.updateContentAreas();
if (this.focused) { if (this.focused) {
this.focus(); this.focus(false);
} }
} }
} }
@@ -669,13 +681,13 @@ export class CustomTreeView extends Disposable implements ITreeView {
} }
} }
class CustomViewIdentityProvider implements IIdentityProvider<ITreeItem> { class TreeViewIdentityProvider implements IIdentityProvider<ITreeItem> {
getId(element: ITreeItem): { toString(): string; } { getId(element: ITreeItem): { toString(): string; } {
return element.handle; return element.handle;
} }
} }
class CustomTreeDelegate implements IListVirtualDelegate<ITreeItem> { class TreeViewDelegate implements IListVirtualDelegate<ITreeItem> {
getHeight(element: ITreeItem): number { getHeight(element: ITreeItem): number {
return TreeRenderer.ITEM_HEIGHT; return TreeRenderer.ITEM_HEIGHT;
@@ -704,7 +716,7 @@ class TreeDataSource implements IAsyncDataSource<ITreeItem, ITreeItem> {
} }
async getChildren(node: ITreeItem): Promise<any[]> { async getChildren(node: ITreeItem): Promise<any[]> {
if (node.childProvider) { if (node.childProvider) { // tracked change
try { try {
return await this.withProgress(this.objectExplorerService.getChildren(node, this.id)); return await this.withProgress(this.objectExplorerService.getChildren(node, this.id));
} catch (err) { } catch (err) {
@@ -728,19 +740,18 @@ class TreeDataSource implements IAsyncDataSource<ITreeItem, ITreeItem> {
} }
} }
// todo@joh,sandy make this proper and contributable from extensions // todo@joh,sandy make this proper and contributable from extensions
registerThemingParticipant((theme, collector) => { registerThemingParticipant((theme, collector) => {
const findMatchHighlightColor = theme.getColor(editorFindMatchHighlight); const matchBackgroundColor = theme.getColor(listFilterMatchHighlight);
if (findMatchHighlightColor) { if (matchBackgroundColor) {
collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; background-color: ${findMatchHighlightColor}; }`); collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; background-color: ${matchBackgroundColor}; }`);
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; background-color: ${findMatchHighlightColor}; }`); collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; background-color: ${matchBackgroundColor}; }`);
} }
const findMatchHighlightColorBorder = theme.getColor(editorFindMatchHighlightBorder); const matchBorderColor = theme.getColor(listFilterMatchHighlightBorder);
if (findMatchHighlightColorBorder) { if (matchBorderColor) {
collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${findMatchHighlightColorBorder}; box-sizing: border-box; }`); collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${matchBorderColor}; box-sizing: border-box; }`);
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${findMatchHighlightColorBorder}; box-sizing: border-box; }`); collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${matchBorderColor}; box-sizing: border-box; }`);
} }
const link = theme.getColor(textLinkForeground); const link = theme.getColor(textLinkForeground);
if (link) { if (link) {
@@ -776,7 +787,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
private labels: ResourceLabels, private labels: ResourceLabels,
private actionViewItemProvider: IActionViewItemProvider, private actionViewItemProvider: IActionViewItemProvider,
private aligner: Aligner, private aligner: Aligner,
@IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService, @IThemeService private readonly themeService: IThemeService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@ILabelService private readonly labelService: ILabelService @ILabelService private readonly labelService: ILabelService
) { ) {
@@ -812,6 +823,23 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
const treeItemLabel: ITreeItemLabel | undefined = node.label ? node.label : resource ? { label: basename(resource) } : undefined; const treeItemLabel: ITreeItemLabel | undefined = node.label ? node.label : resource ? { label: basename(resource) } : undefined;
const description = isString(node.description) ? node.description : resource && node.description === true ? this.labelService.getUriLabel(dirname(resource), { relative: true }) : undefined; const description = isString(node.description) ? node.description : resource && node.description === true ? this.labelService.getUriLabel(dirname(resource), { relative: true }) : undefined;
const label = treeItemLabel ? treeItemLabel.label : undefined; const label = treeItemLabel ? treeItemLabel.label : undefined;
const matches = (treeItemLabel && treeItemLabel.highlights && label) ? treeItemLabel.highlights.map(([start, end]) => {
if ((Math.abs(start) > label.length) || (Math.abs(end) >= label.length)) {
return ({ start: 0, end: 0 });
}
if (start < 0) {
start = label.length + start;
}
if (end < 0) {
end = label.length + end;
}
if (start > end) {
const swap = start;
start = end;
end = swap;
}
return ({ start, end });
}) : undefined;
const icon = this.themeService.getColorTheme().type === LIGHT ? node.icon : node.iconDark; const icon = this.themeService.getColorTheme().type === LIGHT ? node.icon : node.iconDark;
const iconUrl = icon ? URI.revive(icon) : null; const iconUrl = icon ? URI.revive(icon) : null;
const title = node.tooltip ? node.tooltip : resource ? undefined : label; const title = node.tooltip ? node.tooltip : resource ? undefined : label;
@@ -820,18 +848,30 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
// reset // reset
templateData.actionBar.clear(); templateData.actionBar.clear();
if (resource || node.themeIcon) { if (resource || this.isFileKindThemeIcon(node.themeIcon)) {
const fileDecorations = this.configurationService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations'); const fileDecorations = this.configurationService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations');
templateData.resourceLabel.setResource({ name: label, description, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: createMatches(element.filterData) }); templateData.resourceLabel.setResource({ name: label, description, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: matches ? matches : createMatches(element.filterData) });
} else { } else {
templateData.resourceLabel.setResource({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: createMatches(element.filterData) }); templateData.resourceLabel.setResource({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: matches ? matches : createMatches(element.filterData) });
} }
templateData.icon.className = ''; templateData.icon.title = title ? title : '';
templateData.icon.style.backgroundImage = iconUrl ? `url('${DOM.asDomUri(iconUrl).toString(true)}')` : '';
DOM.toggleClass(templateData.icon, sqlIcon, !!sqlIcon); if (iconUrl || sqlIcon) {
DOM.toggleClass(templateData.icon, sqlIcon, !!sqlIcon); // tracked change
DOM.toggleClass(templateData.icon, 'icon', !!sqlIcon); DOM.toggleClass(templateData.icon, 'icon', !!sqlIcon);
DOM.toggleClass(templateData.icon, 'custom-view-tree-node-item-icon', !!iconUrl || !!sqlIcon); templateData.icon.className = 'custom-view-tree-node-item-icon';
templateData.icon.style.backgroundImage = iconUrl ? DOM.asCSSUrl(iconUrl) : '';
} else {
let iconClass: string | undefined;
if (node.themeIcon && !this.isFileKindThemeIcon(node.themeIcon)) {
iconClass = ThemeIcon.asClassName(node.themeIcon);
}
templateData.icon.className = iconClass ? `custom-view-tree-node-item-icon ${iconClass}` : '';
templateData.icon.style.backgroundImage = '';
}
templateData.actionBar.context = <TreeViewItemHandleArg>{ $treeViewId: this.treeViewId, $treeItemHandle: node.handle }; templateData.actionBar.context = <TreeViewItemHandleArg>{ $treeViewId: this.treeViewId, $treeItemHandle: node.handle };
templateData.actionBar.push(this.menus.getResourceActions(node), { icon: true, label: false }); templateData.actionBar.push(this.menus.getResourceActions(node), { icon: true, label: false });
if (this._actionRunner) { if (this._actionRunner) {
@@ -845,6 +885,14 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
DOM.toggleClass(container.parentElement!, 'align-icon-with-twisty', this.aligner.alignIconWithTwisty(treeItem)); DOM.toggleClass(container.parentElement!, 'align-icon-with-twisty', this.aligner.alignIconWithTwisty(treeItem));
} }
private isFileKindThemeIcon(icon: ThemeIcon | undefined): boolean {
if (icon) {
return icon.id === FileThemeIcon.id || icon.id === FolderThemeIcon.id;
} else {
return false;
}
}
private getFileKind(node: ITreeItem): FileKind { private getFileKind(node: ITreeItem): FileKind {
if (node.themeIcon) { if (node.themeIcon) {
switch (node.themeIcon.id) { switch (node.themeIcon.id) {
@@ -869,9 +917,9 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
} }
class Aligner extends Disposable { class Aligner extends Disposable {
private _tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>; private _tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> | undefined;
constructor(private themeService: IWorkbenchThemeService) { constructor(private themeService: IThemeService) {
super(); super();
} }
@@ -887,11 +935,15 @@ class Aligner extends Disposable {
return false; return false;
} }
if (this._tree) {
const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput(); const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput();
if (this.hasIcon(parent)) { if (this.hasIcon(parent)) {
return false; return false;
} }
return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c)); return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c));
} else {
return false;
}
} }
private hasIcon(node: ITreeItem): boolean { private hasIcon(node: ITreeItem): boolean {
@@ -913,22 +965,32 @@ class Aligner extends Disposable {
class MultipleSelectionActionRunner extends ActionRunner { class MultipleSelectionActionRunner extends ActionRunner {
constructor(private getSelectedResources: (() => ITreeItem[])) { constructor(notificationService: INotificationService, private getSelectedResources: (() => ITreeItem[])) {
super(); super();
this._register(this.onDidRun(e => {
if (e.error) {
notificationService.error(localize('command-error', 'Error running command {1}: {0}. This is likely caused by the extension that contributes {1}.', e.error.message, e.action.id));
}
}));
} }
runAction(action: IAction, context: TreeViewItemHandleArg): Promise<any> { runAction(action: IAction, context: TreeViewItemHandleArg): Promise<void> {
const selection = this.getSelectedResources(); const selection = this.getSelectedResources();
let selectionHandleArgs: TreeViewItemHandleArg[] | undefined = undefined; let selectionHandleArgs: TreeViewItemHandleArg[] | undefined = undefined;
let actionInSelected: boolean = false;
if (selection.length > 1) { if (selection.length > 1) {
selectionHandleArgs = []; selectionHandleArgs = selection.map(selected => {
selection.forEach(selected => { if (selected.handle === context.$treeItemHandle) {
if (selected.handle !== context.$treeItemHandle) { actionInSelected = true;
selectionHandleArgs!.push({ $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle });
} }
return { $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle };
}); });
} }
if (!actionInSelected) {
selectionHandleArgs = undefined;
}
return action.run(...[context, selectionHandleArgs]); return action.run(...[context, selectionHandleArgs]);
} }
} }
@@ -945,14 +1007,14 @@ class TreeMenus extends Disposable implements IDisposable {
} }
getResourceActions(element: ITreeItem): IAction[] { getResourceActions(element: ITreeItem): IAction[] {
return this.mergeActions([ return this.mergeActions([ // tracked change
this.getActions(MenuId.ViewItemContext, { key: 'viewItem', value: element.contextValue }).primary, this.getActions(MenuId.ViewItemContext, { key: 'viewItem', value: element.contextValue }).primary,
this.getActions(MenuId.DataExplorerContext, { key: 'viewItem', value: element.contextValue }).primary this.getActions(MenuId.DataExplorerContext, { key: 'viewItem', value: element.contextValue }).primary
]); ]);
} }
getResourceContextActions(element: ITreeItem): IAction[] { getResourceContextActions(element: ITreeItem): IAction[] {
return this.mergeActions([ return this.mergeActions([ // tracked change
this.getActions(MenuId.ViewItemContext, { key: 'viewItem', value: element.contextValue }).secondary, this.getActions(MenuId.ViewItemContext, { key: 'viewItem', value: element.contextValue }).secondary,
this.getActions(MenuId.DataExplorerContext, { key: 'viewItem', value: element.contextValue }).secondary this.getActions(MenuId.DataExplorerContext, { key: 'viewItem', value: element.contextValue }).secondary
]); ]);
@@ -962,7 +1024,7 @@ class TreeMenus extends Disposable implements IDisposable {
return actions.reduce((p, c) => p.concat(...c.filter(a => firstIndex(p, x => x.id === a.id) === -1)), [] as IAction[]); return actions.reduce((p, c) => p.concat(...c.filter(a => firstIndex(p, x => x.id === a.id) === -1)), [] as IAction[]);
} }
private getActions(menuId: MenuId, context: { key: string, value: string }): { primary: IAction[]; secondary: IAction[]; } { private getActions(menuId: MenuId, context: { key: string, value?: string }): { primary: IAction[]; secondary: IAction[]; } {
const contextKeyService = this.contextKeyService.createScoped(); const contextKeyService = this.contextKeyService.createScoped();
contextKeyService.createKey('view', this.id); contextKeyService.createKey('view', this.id);
contextKeyService.createKey(context.key, context.value); contextKeyService.createKey(context.key, context.value);
@@ -980,38 +1042,43 @@ class TreeMenus extends Disposable implements IDisposable {
} }
} }
class MarkdownRenderer { export class CustomTreeView extends TreeView {
private activated: boolean = false;
constructor( constructor(
@IOpenerService private readonly _openerService: IOpenerService id: string,
title: string,
@IThemeService themeService: IThemeService,
@IInstantiationService instantiationService: IInstantiationService,
@ICommandService commandService: ICommandService,
@IConfigurationService configurationService: IConfigurationService,
@IProgressService progressService: IProgressService,
@IContextMenuService contextMenuService: IContextMenuService,
@IKeybindingService keybindingService: IKeybindingService,
@INotificationService notificationService: INotificationService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IExtensionService private readonly extensionService: IExtensionService,
) { ) {
super(id, title, themeService, instantiationService, commandService, configurationService, progressService, contextMenuService, keybindingService, notificationService, viewDescriptorService, contextKeyService);
} }
private getOptions(disposeables: DisposableStore): MarkdownRenderOptions { setVisibility(isVisible: boolean): void {
return { super.setVisibility(isVisible);
actionHandler: { if (this.visible) {
callback: (content) => { this.activate();
let uri: URI | undefined;
try {
uri = URI.parse(content);
} catch {
// ignore
} }
if (uri && this._openerService) {
this._openerService.open(uri).catch(onUnexpectedError);
}
},
disposeables
}
};
} }
render(markdown: IMarkdownString): IMarkdownRenderResult { private activate() {
const disposeables = new DisposableStore(); if (!this.activated) {
const element: HTMLElement = markdown ? renderMarkdown(markdown, this.getOptions(disposeables)) : document.createElement('span'); this.progressService.withProgress({ location: this.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`))
return { .then(() => timeout(2000))
element, .then(() => {
dispose: () => disposeables.dispose() this.updateMessage();
}; });
this.activated = true;
}
} }
} }
+1 -1
View File
@@ -32,7 +32,7 @@ export interface ITreeItem extends vsITreeItem {
export interface ITreeView extends vsITreeView { export interface ITreeView extends vsITreeView {
collapse(itemOrItems: ITreeItem): boolean; collapse(element: ITreeItem): boolean
} }
@@ -91,13 +91,13 @@ export class Insight {
private findctor(type: ChartType | InsightType): IInsightCtor { private findctor(type: ChartType | InsightType): IInsightCtor {
if (find(Graph.types, x => x === type as ChartType)) { if (find(Graph.types, x => x === type as ChartType)) {
return Graph; return Graph as IInsightCtor;
} else if (find(ImageInsight.types, x => x === type as InsightType)) { } else if (find(ImageInsight.types, x => x === type as InsightType)) {
return ImageInsight; return ImageInsight as IInsightCtor;
} else if (find(TableInsight.types, x => x === type as InsightType)) { } else if (find(TableInsight.types, x => x === type as InsightType)) {
return TableInsight; return TableInsight as IInsightCtor;
} else if (find(CountInsight.types, x => x === type as InsightType)) { } else if (find(CountInsight.types, x => x === type as InsightType)) {
return CountInsight; return CountInsight as IInsightCtor;
} }
return undefined; return undefined;
} }
@@ -8,6 +8,7 @@ import { mixin } from 'sql/base/common/objects';
import * as types from 'vs/base/common/types'; import * as types from 'vs/base/common/types';
import { IInsightOptions, InsightType, ChartType } from 'sql/workbench/contrib/charts/common/interfaces'; import { IInsightOptions, InsightType, ChartType } from 'sql/workbench/contrib/charts/common/interfaces';
import { IInsightData } from 'sql/platform/dashboard/browser/insightRegistry'; import { IInsightData } from 'sql/platform/dashboard/browser/insightRegistry';
import { BrandedService } from 'vs/platform/instantiation/common/instantiation';
export interface IPointDataSet { export interface IPointDataSet {
data: Array<{ x: number | string, y: number }>; data: Array<{ x: number | string, y: number }>;
@@ -42,6 +43,6 @@ export interface IInsight {
} }
export interface IInsightCtor { export interface IInsightCtor {
new(container: HTMLElement, options: IInsightOptions, ...services: { _serviceBrand: undefined; }[]): IInsight; new <Services extends BrandedService[]>(container: HTMLElement, options: IInsightOptions, ...services: Services): IInsight;
readonly types: Array<InsightType | ChartType>; readonly types: Array<InsightType | ChartType>;
} }
@@ -48,7 +48,7 @@ export class DashboardNavSection extends DashboardTab implements OnDestroy, OnCh
dashboardHelper.filterConfigs dashboardHelper.filterConfigs
]; ];
private readonly _gridModifiers: Array<(item: Array<WidgetConfig>, originalConfig: Array<WidgetConfig>) => Array<WidgetConfig>> = [ private readonly _gridModifiers: Array<(item: Array<WidgetConfig>, originalConfig?: Array<WidgetConfig>) => Array<WidgetConfig>> = [
dashboardHelper.validateGridConfig dashboardHelper.validateGridConfig
]; ];
@@ -12,7 +12,6 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo
import { WidgetConfig } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget'; import { WidgetConfig } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/browser/insightRegistry'; import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/browser/insightRegistry';
import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo'; import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo';
import { DashboardServiceInterface } from 'sql/workbench/contrib/dashboard/browser/services/dashboardServiceInterface.service';
import { WIDGETS_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardWidgetContainer.contribution'; import { WIDGETS_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardWidgetContainer.contribution';
import { GRID_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardGridContainer.contribution'; import { GRID_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardGridContainer.contribution';
import { WEBVIEW_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardWebviewContainer.contribution'; import { WEBVIEW_CONTAINER } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardWebviewContainer.contribution';
@@ -111,7 +110,7 @@ export function addProvider<T extends { connectionManagementService: SingleConne
* Adds the edition to the passed widgets and returns the new widgets * Adds the edition to the passed widgets and returns the new widgets
* @param widgets Array of widgets to add edition onto * @param widgets Array of widgets to add edition onto
*/ */
export function addEdition<T extends { connectionManagementService: SingleConnectionManagementService }>(config: WidgetConfig[], collection: DashboardServiceInterface): Array<WidgetConfig> { export function addEdition<T extends { connectionManagementService: SingleConnectionManagementService }>(config: WidgetConfig[], collection: T): Array<WidgetConfig> {
const connectionInfo: ConnectionManagementInfo = collection.connectionManagementService.connectionInfo; const connectionInfo: ConnectionManagementInfo = collection.connectionManagementService.connectionInfo;
if (connectionInfo.serverInfo) { if (connectionInfo.serverInfo) {
const edition = connectionInfo.serverInfo.engineEditionId; const edition = connectionInfo.serverInfo.engineEditionId;
@@ -107,7 +107,7 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig
return this.dashboardService.scopedContextKeyService; return this.dashboardService.scopedContextKeyService;
} }
private readonly _gridModifiers: Array<(item: Array<WidgetConfig>, originalConfig: Array<WidgetConfig>) => Array<WidgetConfig>> = [ private readonly _gridModifiers: Array<(item: Array<WidgetConfig>, originalConfig?: Array<WidgetConfig>) => Array<WidgetConfig>> = [
dashboardHelper.validateGridConfig dashboardHelper.validateGridConfig
]; ];
@@ -57,7 +57,7 @@ MenuRegistry.appendMenuItem(MenuId.ObjectExplorerItemContext, {
when: ContextKeyExpr.or(ContextKeyExpr.and(TreeNodeContextKey.Status.notEqualsTo('Unavailable'), TreeNodeContextKey.NodeType.isEqualTo('Server')), ContextKeyExpr.and(TreeNodeContextKey.Status.notEqualsTo('Unavailable'), TreeNodeContextKey.NodeType.isEqualTo('Database'))) when: ContextKeyExpr.or(ContextKeyExpr.and(TreeNodeContextKey.Status.notEqualsTo('Unavailable'), TreeNodeContextKey.NodeType.isEqualTo('Server')), ContextKeyExpr.and(TreeNodeContextKey.Status.notEqualsTo('Unavailable'), TreeNodeContextKey.NodeType.isEqualTo('Database')))
}); });
const dashboardEditorDescriptor = new EditorDescriptor( const dashboardEditorDescriptor = EditorDescriptor.create(
DashboardEditor, DashboardEditor,
DashboardEditor.ID, DashboardEditor.ID,
localize('dashboard.editor.label', "Dashboard") localize('dashboard.editor.label', "Dashboard")
@@ -7,16 +7,17 @@ import { localize } from 'vs/nls';
import { forEach } from 'vs/base/common/collections'; import { forEach } from 'vs/base/common/collections';
import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExtensions, ITreeViewDescriptor, IViewsRegistry } from 'vs/workbench/common/views'; import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExtensions, IViewsRegistry } from 'vs/workbench/common/views';
import { IExtensionPoint, ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { IExtensionPoint, ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { coalesce } from 'vs/base/common/arrays'; import { coalesce } from 'vs/base/common/arrays';
import { CustomTreeViewPane, CustomTreeView } from 'sql/workbench/browser/parts/views/customView'; import { CustomTreeView, TreeViewPane } from 'sql/workbench/browser/parts/views/treeView';
import { VIEWLET_ID } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet'; import { VIEWLET_ID } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ICustomViewDescriptor } from 'vs/workbench/api/browser/viewsExtensionPoint';
interface IUserFriendlyViewDescriptor { interface IUserFriendlyViewDescriptor {
id: string; id: string;
@@ -103,14 +104,15 @@ export class DataExplorerContainerExtensionHandler implements IWorkbenchContribu
return null; return null;
} }
const viewDescriptor = <ITreeViewDescriptor>{ const viewDescriptor = <ICustomViewDescriptor>{
id: item.id, id: item.id,
name: item.name, name: item.name,
ctorDescriptor: new SyncDescriptor(CustomTreeViewPane), ctorDescriptor: new SyncDescriptor(TreeViewPane),
when: ContextKeyExpr.deserialize(item.when), when: ContextKeyExpr.deserialize(item.when),
canToggleVisibility: true, canToggleVisibility: true,
canMoveView: true,
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name),
collapsed: this.showCollapsed(container), collapsed: this.showCollapsed(container),
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name, container),
extensionId: extension.description.identifier, extensionId: extension.description.identifier,
originalContainerId: entry.key originalContainerId: entry.key
}; };
@@ -12,7 +12,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
// Editor // Editor
const editDataEditorDescriptor = new EditorDescriptor( const editDataEditorDescriptor = EditorDescriptor.create(
EditDataEditor, EditDataEditor,
EditDataEditor.ID, EditDataEditor.ID,
'EditData' 'EditData'
@@ -22,7 +22,7 @@ Registry.as<IEditorRegistry>(Extensions.Editors)
.registerEditor(editDataEditorDescriptor, [new SyncDescriptor(EditDataInput)]); .registerEditor(editDataEditorDescriptor, [new SyncDescriptor(EditDataInput)]);
// Editor // Editor
const editDataResultsEditorDescriptor = new EditorDescriptor( const editDataResultsEditorDescriptor = EditorDescriptor.create(
EditDataResultsEditor, EditDataResultsEditor,
EditDataResultsEditor.ID, EditDataResultsEditor.ID,
'EditDataResults' 'EditDataResults'
@@ -21,7 +21,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext'; import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar'; import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions'; import { IAction } from 'vs/base/common/actions';
import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel'; import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel';
import { IEditorDescriptorService } from 'sql/workbench/services/queryEditor/browser/editorDescriptorService'; import { IEditorDescriptorService } from 'sql/workbench/services/queryEditor/browser/editorDescriptorService';
import { import {
@@ -321,7 +321,7 @@ export class EditDataEditor extends BaseEditor {
// Create QueryTaskbar // Create QueryTaskbar
this._taskbarContainer = DOM.append(parentElement, DOM.$('div')); this._taskbarContainer = DOM.append(parentElement, DOM.$('div'));
this._taskbar = new Taskbar(this._taskbarContainer, { this._taskbar = new Taskbar(this._taskbarContainer, {
actionViewItemProvider: (action: Action) => this._getChangeMaxRowsAction(action) actionViewItemProvider: (action: IAction) => this._getChangeMaxRowsAction(action)
}); });
// Create Actions for the toolbar // Create Actions for the toolbar
@@ -352,7 +352,7 @@ export class EditDataEditor extends BaseEditor {
/** /**
* Gets the IActionItem for the list of row number drop down * Gets the IActionItem for the list of row number drop down
*/ */
private _getChangeMaxRowsAction(action: Action): IActionViewItem { private _getChangeMaxRowsAction(action: IAction): IActionViewItem {
let actionID = ChangeMaxRowsAction.ID; let actionID = ChangeMaxRowsAction.ID;
if (action.id === actionID) { if (action.id === actionID) {
if (!this._changeMaxRowsActionItem) { if (!this._changeMaxRowsActionItem) {
@@ -25,8 +25,8 @@ export class ShowRecommendedExtensionsByScenarioAction extends Action {
run(): Promise<void> { run(): Promise<void> {
return this.viewletService.openViewlet(VIEWLET_ID, true) return this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet?.getViewPaneContainer()) .then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
.then((viewlet: IExtensionsViewPaneContainer) => { .then(viewlet => {
viewlet.search('@' + this.scenarioType); viewlet.search('@' + this.scenarioType);
viewlet.focus(); viewlet.focus();
}); });
@@ -51,8 +51,8 @@ export class InstallRecommendedExtensionsByScenarioAction extends Action {
run(): Promise<any> { run(): Promise<any> {
if (!this.recommendations.length) { return Promise.resolve(); } if (!this.recommendations.length) { return Promise.resolve(); }
return this.viewletService.openViewlet(VIEWLET_ID, true) return this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet?.getViewPaneContainer()) .then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
.then((viewlet: IExtensionsViewPaneContainer) => { .then(viewlet => {
viewlet.search('@' + this.scenarioType); viewlet.search('@' + this.scenarioType);
viewlet.focus(); viewlet.focus();
const names = this.recommendations.map(({ extensionId }) => extensionId); const names = this.recommendations.map(({ extensionId }) => extensionId);
@@ -57,7 +57,7 @@ Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.Language
.registerLanguageAssociation(NotebookEditorInputAssociation.languages, NotebookEditorInputAssociation); .registerLanguageAssociation(NotebookEditorInputAssociation.languages, NotebookEditorInputAssociation);
Registry.as<IEditorRegistry>(EditorExtensions.Editors) Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(new EditorDescriptor(NotebookEditor, NotebookEditor.ID, localize('notebookEditor.name', "Notebook Editor")), [new SyncDescriptor(UntitledNotebookInput), new SyncDescriptor(FileNotebookInput)]); .registerEditor(EditorDescriptor.create(NotebookEditor, NotebookEditor.ID, localize('notebookEditor.name', "Notebook Editor")), [new SyncDescriptor(UntitledNotebookInput), new SyncDescriptor(FileNotebookInput)]);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench) Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(NotebookThemingContribution, LifecyclePhase.Restored); .registerWorkbenchContribution(NotebookThemingContribution, LifecyclePhase.Restored);
@@ -14,7 +14,7 @@ import { ProfilerInput } from 'sql/workbench/browser/editor/profiler/profilerInp
import { ProfilerEditor } from 'sql/workbench/contrib/profiler/browser/profilerEditor'; import { ProfilerEditor } from 'sql/workbench/contrib/profiler/browser/profilerEditor';
import { PROFILER_VIEW_TEMPLATE_SETTINGS, PROFILER_SESSION_TEMPLATE_SETTINGS, IProfilerViewTemplate, IProfilerSessionTemplate, EngineType, PROFILER_FILTER_SETTINGS } from 'sql/workbench/services/profiler/browser/interfaces'; import { PROFILER_VIEW_TEMPLATE_SETTINGS, PROFILER_SESSION_TEMPLATE_SETTINGS, IProfilerViewTemplate, IProfilerSessionTemplate, EngineType, PROFILER_FILTER_SETTINGS } from 'sql/workbench/services/profiler/browser/interfaces';
const profilerDescriptor = new EditorDescriptor( const profilerDescriptor = EditorDescriptor.create(
ProfilerEditor, ProfilerEditor,
ProfilerEditor.ID, ProfilerEditor.ID,
'ProfilerEditor' 'ProfilerEditor'
@@ -395,7 +395,7 @@ export class ProfilerEditor extends BaseEditor {
this._detailTable.updateRowCount(); this._detailTable.updateRowCount();
}); });
const detailTableCopyKeybind = new CopyKeybind(); const detailTableCopyKeybind = new CopyKeybind<IDetailData>();
detailTableCopyKeybind.onCopy((ranges: Slick.Range[]) => { detailTableCopyKeybind.onCopy((ranges: Slick.Range[]) => {
// we always only get 1 item in the ranges // we always only get 1 item in the ranges
if (ranges && ranges.length === 1) { if (ranges && ranges.length === 1) {
@@ -323,7 +323,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
private table: Table<T>; private table: Table<T>;
private actionBar: ActionBar; private actionBar: ActionBar;
private container = document.createElement('div'); private container = document.createElement('div');
private selectionModel = new CellSelectionModel(); private selectionModel = new CellSelectionModel<T>();
private styles: ITableStyles; private styles: ITableStyles;
private currentHeight: number; private currentHeight: number;
private dataProvider: AsyncDataProvider<T>; private dataProvider: AsyncDataProvider<T>;
@@ -461,7 +461,7 @@ export abstract class GridTableBase<T> extends Disposable implements IView {
this.renderGridDataRowsRange(startIndex, count); this.renderGridDataRowsRange(startIndex, count);
}); });
this.rowNumberColumn = new RowNumberColumn({ numberOfRows: this.resultSet.rowCount }); this.rowNumberColumn = new RowNumberColumn({ numberOfRows: this.resultSet.rowCount });
let copyHandler = new CopyKeybind(); let copyHandler = new CopyKeybind<T>();
copyHandler.onCopy(e => { copyHandler.onCopy(e => {
new CopyResultAction(CopyResultAction.COPY_ID, CopyResultAction.COPY_LABEL, false).run(this.generateContext()); new CopyResultAction(CopyResultAction.COPY_ID, CopyResultAction.COPY_LABEL, false).run(this.generateContext());
}); });
@@ -57,10 +57,10 @@ Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.Language
.registerLanguageAssociation(QueryEditorLanguageAssociation.languages, QueryEditorLanguageAssociation, QueryEditorLanguageAssociation.isDefault); .registerLanguageAssociation(QueryEditorLanguageAssociation.languages, QueryEditorLanguageAssociation, QueryEditorLanguageAssociation.isDefault);
Registry.as<IEditorRegistry>(EditorExtensions.Editors) Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(new EditorDescriptor(QueryResultsEditor, QueryResultsEditor.ID, localize('queryResultsEditor.name', "Query Results")), [new SyncDescriptor(QueryResultsInput)]); .registerEditor(EditorDescriptor.create(QueryResultsEditor, QueryResultsEditor.ID, localize('queryResultsEditor.name', "Query Results")), [new SyncDescriptor(QueryResultsInput)]);
Registry.as<IEditorRegistry>(EditorExtensions.Editors) Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(new EditorDescriptor(QueryEditor, QueryEditor.ID, localize('queryEditor.name', "Query Editor")), [new SyncDescriptor(FileQueryEditorInput), new SyncDescriptor(UntitledQueryEditorInput)]); .registerEditor(EditorDescriptor.create(QueryEditor, QueryEditor.ID, localize('queryEditor.name', "Query Editor")), [new SyncDescriptor(FileQueryEditorInput), new SyncDescriptor(UntitledQueryEditorInput)]);
const actionRegistry = <IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions); const actionRegistry = <IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions);
@@ -24,7 +24,7 @@ import { SplitView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle'; import { DisposableStore } from 'vs/base/common/lifecycle';
import { ISelectionData } from 'azdata'; import { ISelectionData } from 'azdata';
import { Action, IActionViewItem } from 'vs/base/common/actions'; import { IActionViewItem, IAction } from 'vs/base/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor'; import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
@@ -171,7 +171,7 @@ export class QueryEditor extends BaseEditor {
// Create QueryTaskbar // Create QueryTaskbar
let taskbarContainer = DOM.append(parentElement, DOM.$('div')); let taskbarContainer = DOM.append(parentElement, DOM.$('div'));
this.taskbar = this._register(new Taskbar(taskbarContainer, { this.taskbar = this._register(new Taskbar(taskbarContainer, {
actionViewItemProvider: (action: Action) => this._getActionItemForAction(action), actionViewItemProvider: action => this._getActionItemForAction(action),
})); }));
// Create Actions for the toolbar // Create Actions for the toolbar
@@ -236,7 +236,7 @@ export class QueryEditor extends BaseEditor {
* Gets the IActionItem for the List Databases dropdown if provided the associated Action. * Gets the IActionItem for the List Databases dropdown if provided the associated Action.
* Otherwise returns null. * Otherwise returns null.
*/ */
private _getActionItemForAction(action: Action): IActionViewItem { private _getActionItemForAction(action: IAction): IActionViewItem {
if (action.id === actions.ListDatabasesAction.ID) { if (action.id === actions.ListDatabasesAction.ID) {
return this.listDatabasesActionItem; return this.listDatabasesActionItem;
} }
@@ -12,7 +12,7 @@ import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensio
// Query Plan editor registration // Query Plan editor registration
const queryPlanEditorDescriptor = new EditorDescriptor( const queryPlanEditorDescriptor = EditorDescriptor.create(
QueryPlanEditor, QueryPlanEditor,
QueryPlanEditor.ID, QueryPlanEditor.ID,
'QueryPlan' 'QueryPlan'
@@ -48,7 +48,7 @@ export class StatusUpdater extends lifecycle.Disposable implements ext.IWorkbenc
lifecycle.dispose(this.badgeHandle); lifecycle.dispose(this.badgeHandle);
let numOfInProgressTask: number = this.taskService.getNumberOfInProgressTasks(); let numOfInProgressTask: number = this.taskService.getNumberOfInProgressTasks();
let badge: NumberBadge = new NumberBadge(numOfInProgressTask, n => localize('inProgressTasksChangesBadge', "{0} in progress tasks", n)); let badge: NumberBadge = new NumberBadge(numOfInProgressTask, n => localize('inProgressTasksChangesBadge', "{0} in progress tasks", n));
this.badgeHandle = this.activityBarService.showActivity(TASKS_CONTAINER_ID, badge, 'taskhistory-viewlet-label'); this.badgeHandle = this.activityBarService.showViewContainerActivity(TASKS_CONTAINER_ID, { badge, clazz: 'taskhistory-viewlet-label' });
} }
public getId(): string { public getId(): string {
@@ -46,6 +46,7 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { KeyCode } from 'vs/base/common/keyCodes'; import { KeyCode } from 'vs/base/common/keyCodes';
import { joinPath } from 'vs/base/common/resources'; import { joinPath } from 'vs/base/common/resources';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { addStandardDisposableListener, EventHelper } from 'vs/base/browser/dom';
const configurationKey = 'workbench.startupEditor'; const configurationKey = 'workbench.startupEditor';
const oldConfigurationKey = 'workbench.welcome.enabled'; const oldConfigurationKey = 'workbench.welcome.enabled';
@@ -321,23 +322,21 @@ class WelcomePage extends Disposable {
} }
private createWidePreviewToolTip() { private createWidePreviewToolTip() {
const previewLink = document.querySelector('#tool_tip_container_wide'); const previewLink = document.querySelector('#tool_tip_container_wide') as HTMLElement;
const tooltip = document.querySelector('#tooltip_text_wide'); const tooltip = document.querySelector('#tooltip_text_wide') as HTMLElement;
const previewModalBody = document.querySelector('.preview_tooltip_body') as HTMLElement; const previewModalBody = document.querySelector('.preview_tooltip_body') as HTMLElement;
const previewModalHeader = document.querySelector('.preview_tooltip_header') as HTMLElement; const previewModalHeader = document.querySelector('.preview_tooltip_header') as HTMLElement;
previewLink.addEventListener('mouseover', () => { addStandardDisposableListener(previewLink, 'mouseover', () => {
tooltip.setAttribute('aria-hidden', 'true'); tooltip.setAttribute('aria-hidden', 'true');
tooltip.classList.toggle('show'); tooltip.classList.toggle('show');
}); });
previewLink.addEventListener('mouseout', () => { addStandardDisposableListener(previewLink, 'mouseout', () => {
tooltip.setAttribute('aria-hidden', 'false'); tooltip.setAttribute('aria-hidden', 'false');
tooltip.classList.remove('show'); tooltip.classList.remove('show');
}); });
previewLink.addEventListener('keydown', (e: KeyboardEvent) => { addStandardDisposableListener(previewLink, 'keydown', event => {
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Escape)) { if (event.equals(KeyCode.Escape)) {
if (tooltip.classList.contains('show')) { if (tooltip.classList.contains('show')) {
tooltip.setAttribute('aria-hidden', 'true'); tooltip.setAttribute('aria-hidden', 'true');
@@ -351,9 +350,7 @@ class WelcomePage extends Disposable {
} }
}); });
tooltip.addEventListener('keydown', (e: KeyboardEvent) => { addStandardDisposableListener(tooltip, 'keydown', event => {
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Escape)) { if (event.equals(KeyCode.Escape)) {
if (tooltip.classList.contains('show')) { if (tooltip.classList.contains('show')) {
tooltip.setAttribute('aria-hidden', 'true'); tooltip.setAttribute('aria-hidden', 'true');
@@ -361,8 +358,8 @@ class WelcomePage extends Disposable {
} }
} }
else if (event.equals(KeyCode.Tab)) { else if (event.equals(KeyCode.Tab)) {
e.preventDefault(); EventHelper.stop(event);
if (e.target === previewModalBody) { if (event.target === previewModalBody) {
previewModalHeader.focus(); previewModalHeader.focus();
} else { } else {
previewModalBody.focus(); previewModalBody.focus();
@@ -381,15 +378,14 @@ class WelcomePage extends Disposable {
} }
private createDropDown() { private createDropDown() {
const dropdownBtn = document.querySelector('#dropdown_btn'); const dropdownBtn = document.querySelector('#dropdown_btn') as HTMLElement;
const dropdown = document.querySelector('#dropdown') as HTMLInputElement; const dropdown = document.querySelector('#dropdown') as HTMLInputElement;
dropdownBtn.addEventListener('click', () => { addStandardDisposableListener(dropdownBtn, 'click', () => {
dropdown.classList.toggle('show'); dropdown.classList.toggle('show');
}); });
dropdownBtn.addEventListener('keydown', (e: KeyboardEvent) => { addStandardDisposableListener(dropdownBtn, 'keydown', event => {
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) { if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
const dropdownFirstElement = document.querySelector('#dropdown').firstElementChild.children[0] as HTMLInputElement; const dropdownFirstElement = document.querySelector('#dropdown').firstElementChild.children[0] as HTMLInputElement;
dropdown.classList.toggle('show'); dropdown.classList.toggle('show');
@@ -397,8 +393,7 @@ class WelcomePage extends Disposable {
} }
}); });
dropdown.addEventListener('keydown', (e: KeyboardEvent) => { addStandardDisposableListener(dropdown, 'keydown', event => {
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Escape)) { if (event.equals(KeyCode.Escape)) {
if (dropdown.classList.contains('show')) { if (dropdown.classList.contains('show')) {
dropdown.classList.remove('show'); dropdown.classList.remove('show');
@@ -427,16 +422,15 @@ class WelcomePage extends Disposable {
} }
}); });
dropdown.addEventListener('keydown', function (e: KeyboardEvent) { addStandardDisposableListener(dropdown, 'keydown', event => {
const dropdownLastElement = document.querySelector('#dropdown').lastElementChild.children[0] as HTMLInputElement; const dropdownLastElement = document.querySelector('#dropdown').lastElementChild.children[0] as HTMLInputElement;
const dropdownFirstElement = document.querySelector('#dropdown').firstElementChild.children[0] as HTMLInputElement; const dropdownFirstElement = document.querySelector('#dropdown').firstElementChild.children[0] as HTMLInputElement;
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Tab)) { if (event.equals(KeyCode.Tab)) {
e.preventDefault(); EventHelper.stop(event);
return; return;
} }
else if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.LeftArrow)) { else if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.LeftArrow)) {
if (e.target === dropdownFirstElement) { if (event.target === dropdownFirstElement) {
dropdownLastElement.focus(); dropdownLastElement.focus();
} else { } else {
const movePrev = <HTMLElement>document.querySelector('.move:focus').parentElement.previousElementSibling.children[0] as HTMLElement; const movePrev = <HTMLElement>document.querySelector('.move:focus').parentElement.previousElementSibling.children[0] as HTMLElement;
@@ -444,7 +438,7 @@ class WelcomePage extends Disposable {
} }
} }
else if (event.equals(KeyCode.DownArrow) || event.equals(KeyCode.RightArrow)) { else if (event.equals(KeyCode.DownArrow) || event.equals(KeyCode.RightArrow)) {
if (e.target === dropdownLastElement) { if (event.target === dropdownLastElement) {
dropdownFirstElement.focus(); dropdownFirstElement.focus();
} else { } else {
const moveNext = <HTMLElement>document.querySelector('.move:focus').parentElement.nextElementSibling.children[0] as HTMLElement; const moveNext = <HTMLElement>document.querySelector('.move:focus').parentElement.nextElementSibling.children[0] as HTMLElement;
@@ -52,16 +52,16 @@ const labelDisplay = nls.localize("insights.item", "Item");
const valueDisplay = nls.localize("insights.value", "Value"); const valueDisplay = nls.localize("insights.value", "Value");
const iconClass = 'codicon'; const iconClass = 'codicon';
class InsightTableView<T> extends ViewPane { class InsightTableView extends ViewPane {
private _table: Table<T>; private _table: Table<ListResource>;
public get table(): Table<T> { public get table(): Table<ListResource> {
return this._table; return this._table;
} }
constructor( constructor(
private columns: Slick.Column<T>[], private columns: Slick.Column<ListResource>[],
private data: IDisposableDataProvider<T> | Array<T>, private data: IDisposableDataProvider<ListResource> | Array<ListResource>,
private tableOptions: Slick.GridOptions<T>, private tableOptions: Slick.GridOptions<ListResource>,
options: IViewPaneOptions, options: IViewPaneOptions,
@IKeybindingService keybindingService: IKeybindingService, @IKeybindingService keybindingService: IKeybindingService,
@IContextMenuService contextMenuService: IContextMenuService, @IContextMenuService contextMenuService: IContextMenuService,
@@ -220,14 +220,14 @@ export class InsightsDialogView extends Modal {
const itemsHeaderTitle = nls.localize("insights.dialog.items", "Items"); const itemsHeaderTitle = nls.localize("insights.dialog.items", "Items");
const itemsDetailHeaderTitle = nls.localize("insights.dialog.itemDetails", "Item Details"); const itemsDetailHeaderTitle = nls.localize("insights.dialog.itemDetails", "Item Details");
this._topTableData = new TableDataView(); this._topTableData = new TableDataView<ListResource>();
this._bottomTableData = new TableDataView(); this._bottomTableData = new TableDataView<ListResource>();
let topTableView = this._instantiationService.createInstance(InsightTableView, this._topColumns, this._topTableData, { forceFitColumns: true }, { id: 'insights.top', title: itemsHeaderTitle }) as InsightTableView<ListResource>; let topTableView = this._instantiationService.createInstance(InsightTableView, this._topColumns, this._topTableData, { forceFitColumns: true }, { id: 'insights.top', title: itemsHeaderTitle });
topTableView.render(); topTableView.render();
attachPanelStyler(topTableView, this._themeService); attachPanelStyler(topTableView, this._themeService);
this._topTable = topTableView.table; this._topTable = topTableView.table;
this._topTable.setSelectionModel(new RowSelectionModel<ListResource>()); this._topTable.setSelectionModel(new RowSelectionModel<ListResource>());
let bottomTableView = this._instantiationService.createInstance(InsightTableView, this._bottomColumns, this._bottomTableData, { forceFitColumns: true }, { id: 'insights.bottom', title: itemsDetailHeaderTitle }) as InsightTableView<ListResource>; let bottomTableView = this._instantiationService.createInstance(InsightTableView, this._bottomColumns, this._bottomTableData, { forceFitColumns: true }, { id: 'insights.bottom', title: itemsDetailHeaderTitle });
bottomTableView.render(); bottomTableView.render();
attachPanelStyler(bottomTableView, this._themeService); attachPanelStyler(bottomTableView, this._themeService);
this._bottomTable = bottomTableView.table; this._bottomTable = bottomTableView.table;
@@ -275,8 +275,8 @@ export class InsightsDialogView extends Modal {
this._register(attachTableStyler(this._topTable, this._themeService)); this._register(attachTableStyler(this._topTable, this._themeService));
this._register(attachTableStyler(this._bottomTable, this._themeService)); this._register(attachTableStyler(this._bottomTable, this._themeService));
this._topTable.grid.onKeyDown.subscribe((e: KeyboardEvent) => { this._topTable.grid.onKeyDown.subscribe(e => {
let event = new StandardKeyboardEvent(e); let event = new StandardKeyboardEvent(<unknown>e as KeyboardEvent);
if (event.equals(KeyMod.Shift | KeyCode.Tab)) { if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
topTableView.focus(); topTableView.focus();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
@@ -286,8 +286,8 @@ export class InsightsDialogView extends Modal {
} }
}); });
this._bottomTable.grid.onKeyDown.subscribe((e: KeyboardEvent) => { this._bottomTable.grid.onKeyDown.subscribe(e => {
let event = new StandardKeyboardEvent(e); let event = new StandardKeyboardEvent(<unknown>e as KeyboardEvent);
if (event.equals(KeyMod.Shift | KeyCode.Tab)) { if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
bottomTableView.focus(); bottomTableView.focus();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
@@ -53,7 +53,7 @@ const languageAssociationRegistry = new class implements ILanguageAssociationReg
} }
} }
registerLanguageAssociation<Services extends BrandedService[]>(languages: string[], contribution: ILanguageAssociationSignature<Services>, isDefault?: boolean): IDisposable { registerLanguageAssociation(languages: string[], contribution: ILanguageAssociationSignature<BrandedService[]>, isDefault?: boolean): IDisposable {
for (const language of languages) { for (const language of languages) {
this.associationContructors.set(language, contribution); this.associationContructors.set(language, contribution);
} }
@@ -379,8 +379,8 @@ export class RestoreDialog extends Modal {
} }
}); });
this._restorePlanTable.grid.onKeyDown.subscribe((e: KeyboardEvent) => { this._restorePlanTable.grid.onKeyDown.subscribe(e => {
let event = new StandardKeyboardEvent(e); let event = new StandardKeyboardEvent(<unknown>e as KeyboardEvent);
if (event.equals(KeyMod.Shift | KeyCode.Tab)) { if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
this._destinationRestoreToInputBox.isEnabled() ? this._destinationRestoreToInputBox.focus() : this._databaseDropdown.focus(); this._destinationRestoreToInputBox.isEnabled() ? this._destinationRestoreToInputBox.focus() : this._databaseDropdown.focus();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
@@ -390,8 +390,8 @@ export class RestoreDialog extends Modal {
} }
}); });
this._fileListTable.grid.onKeyDown.subscribe((e: KeyboardEvent) => { this._fileListTable.grid.onKeyDown.subscribe(e => {
let event = new StandardKeyboardEvent(e); let event = new StandardKeyboardEvent(<unknown>e as KeyboardEvent);
if (event.equals(KeyMod.Shift | KeyCode.Tab)) { if (event.equals(KeyMod.Shift | KeyCode.Tab)) {
if ((<InputBox>this._optionsMap[this._relocatedLogFileFolderOption]).isEnabled()) { if ((<InputBox>this._optionsMap[this._relocatedLogFileFolderOption]).isEnabled()) {
(<InputBox>this._optionsMap[this._relocatedLogFileFolderOption]).focus(); (<InputBox>this._optionsMap[this._relocatedLogFileFolderOption]).focus();
+1 -1
View File
@@ -1554,7 +1554,7 @@ declare namespace Slick {
} }
export interface Formatter<T extends SlickData> { export interface Formatter<T extends SlickData> {
(row: number, cell: number, value: any, columnDef: Column<T>, dataContext: SlickData): string | undefined; (row: number, cell: number, value: any, columnDef: Column<T>, dataContext: T): string | undefined;
} }
export module Formatters { export module Formatters {
+4 -1
View File
@@ -209,7 +209,10 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
'iframe': ['allowfullscreen', 'frameborder', 'src'], 'iframe': ['allowfullscreen', 'frameborder', 'src'],
'img': ['src', 'title', 'alt', 'width', 'height'], 'img': ['src', 'title', 'alt', 'width', 'height'],
'div': ['class', 'data-code'], 'div': ['class', 'data-code'],
'span': ['class'] 'span': ['class'],
// https://github.com/microsoft/vscode/issues/95937
'th': ['align'],
'td': ['align']
} }
}); });

Some files were not shown because too many files have changed in this diff Show More