Merge from vscode 2e5312cd61ff99c570299ecc122c52584265eda2

This commit is contained in:
ADS Merger
2020-04-23 02:50:35 +00:00
committed by Anthony Dresser
parent 3603f55d97
commit 7f1d8fc32f
659 changed files with 22709 additions and 12497 deletions

30
.github/workflows/english-please.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: English Please
on:
issues:
types: [edited]
# also make changes in ./on-label.yml and ./on-open.yml
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
if: contains(github.event.issue.labels.*.name, '*english-please')
uses: actions/checkout@v2
with:
repository: 'microsoft/vscode-github-triage-actions'
ref: v7
path: ./actions
- name: Install Actions
if: contains(github.event.issue.labels.*.name, '*english-please')
run: npm install --production --prefix ./actions
- name: Run English Please
if: contains(github.event.issue.labels.*.name, '*english-please')
uses: ./actions/english-please
with:
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}}
nonEnglishLabel: "*english-please"
needsMoreInfoLabel: "needs more info"
translatorRequestedLabelPrefix: "translation-required-"
translatorRequestedLabelColor: "c29cff"

49
.vscode/launch.json vendored
View File

@@ -14,18 +14,26 @@
{
"type": "node",
"request": "attach",
"restart": true,
"name": "Attach to Extension Host",
"timeout": 30000,
"port": 5870,
"outFiles": [
"${workspaceFolder}/out/**/*.js"
]
],
"presentation": {
"hidden": true
}
},
{
"type": "chrome",
"type": "pwa-chrome",
"request": "attach",
"name": "Attach to Shared Process",
"port": 9222,
"urlFilter": "*"
"urlFilter": "*sharedProcess.html*",
"presentation": {
"hidden": true
}
},
{
"type": "node",
@@ -67,9 +75,10 @@
"port": 9222
},
{
"type": "chrome",
"type": "pwa-chrome",
"request": "launch",
"name": "Launch azuredatastudio",
"browserLaunchLocation": "workspace",
"windows": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.bat"
},
@@ -97,25 +106,7 @@
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
},
{
"type": "node",
"request": "launch",
"name": "Launch ADS (Main Process)",
"runtimeExecutable": "${workspaceFolder}/scripts/sql.sh",
"windows": {
"runtimeExecutable": "${workspaceFolder}/scripts/sql.bat",
},
"runtimeArgs": [
"--no-cached-data"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"presentation": {
"group": "2_launch",
"order": 1
}
"browserLaunchLocation": "workspace"
},
{
"type": "chrome",
@@ -150,7 +141,7 @@
"web"
],
"presentation": {
"group": "2_launch",
"group": "0_vscode",
"order": 2
}
},
@@ -161,7 +152,7 @@
"url": "http://localhost:8080",
"preLaunchTask": "Run web",
"presentation": {
"group": "2_launch",
"group": "0_vscode",
"order": 3
}
},
@@ -270,13 +261,15 @@
]
},
{
"name": "Debug azuredatastudio Main and Renderer",
"name": "Azure Data Studio",
"configurations": [
"Launch azuredatastudio",
"Attach to Main Process"
"Attach to Main Process",
"Attach to Extension Host",
"Attach to Shared Process",
],
"presentation": {
"group": "1_vscode",
"group": "0_vscode",
"order": 1
}
},

View File

@@ -2,7 +2,7 @@
# Flags: CaseSensitive WordMatch
# ContextLines: 2
9 results - 4 files
10 results - 4 files
src/vs/base/common/arrays.ts:
401
@@ -24,17 +24,17 @@ src/vs/base/common/arrays.ts:
564 export function find<T>(arr: ArrayLike<T>, predicate: (value: T, index: number, arr: ArrayLike<T>) => any): T | undefined {
src/vs/base/common/map.ts:
9
10 /**
11: * @deprecated ES6: use `[...SetOrMap.values()]`
12 */
13 export function values<V = any>(set: Set<V>): V[];
11
12 /**
13: * @deprecated ES6: use `[...SetOrMap.values()]`
14 */
15 export function values<V = any>(set: Set<V>): V[];
20
21 /**
22: * @deprecated ES6: use `[...map.keys()]`
23 */
24 export function keys<K, V>(map: Map<K, V>): K[] {
22
23 /**
24: * @deprecated ES6: use `[...map.keys()]`
25 */
26 export function keys<K, V>(map: Map<K, V>): K[] {
src/vs/base/common/objects.ts:
115
@@ -61,3 +61,9 @@ src/vs/base/common/strings.ts:
169: * @deprecated ES6: use `String.endsWith`
170 */
171 export function endsWith(haystack: string, needle: string): boolean {
853
854 /**
855: * @deprecated ES6
856 */
857 export function repeat(s: string, count: number): string {

View File

@@ -72,5 +72,6 @@
"files.insertFinalNewline": true,
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
}
},
"typescript.tsc.autoDetect": "off"
}

12
.vscode/tasks.json vendored
View File

@@ -3,7 +3,7 @@
"tasks": [
{
"type": "npm",
"script": "watch",
"script": "watchd",
"label": "Build VS Code",
"group": {
"kind": "build",
@@ -45,6 +45,16 @@
"applyTo": "allDocuments"
}
},
{
"type": "npm",
"script": "kill-watchd",
"label": "Kill Build VS Code",
"group": "build",
"presentation": {
"reveal": "never"
},
"problemMatcher": "$tsc"
},
{
"label": "Run tests",
"type": "shell",

View File

@@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron"
target "7.1.11"
target "7.2.2"
runtime "electron"

View File

@@ -107,13 +107,13 @@ kerberos/build/**
# END SQL Modules
nsfw/binding.gyp
nsfw/build/**
nsfw/src/**
nsfw/openpa/**
nsfw/includes/**
!nsfw/build/Release/*.node
!nsfw/**/*.a
vscode-nsfw/binding.gyp
vscode-nsfw/build/**
vscode-nsfw/src/**
vscode-nsfw/openpa/**
vscode-nsfw/includes/**
!vscode-nsfw/build/Release/*.node
!vscode-nsfw/**/*.a
vsda/build/**
vsda/ci/**

View File

@@ -44,10 +44,10 @@ steps:
- script: |
./scripts/test.sh --tfs "Unit Tests"
displayName: Run Unit Tests (Electron)
# - script: | {{SQL CARBON EDIT}} disable for now @TODO @anthonydresser
# yarn test-browser --browser chromium --browser webkit
# - script: | {{SQL CARBON EDIT}} disable
# yarn test-browser --browser chromium --browser webkit --browser firefox
# displayName: Run Unit Tests (Browser)
# - script: | {{SQL CARBON EDIT}} remove step
# - script: | {{SQL CARBON EDIT}} disable
# ./scripts/test-integration.sh --tfs "Integration Tests"
# displayName: Run Integration Tests (Electron)
- task: PublishTestResults@2

View File

@@ -77,23 +77,6 @@ steps:
yarn postinstall
displayName: Run postinstall scripts
condition: and(succeeded(), eq(variables['CacheRestored'], 'true'))
env:
OSS_GITHUB_ID: "a5d3c261b032765a78de"
OSS_GITHUB_SECRET: $(oss-github-client-secret)
INSIDERS_GITHUB_ID: "31f02627809389d9f111"
INSIDERS_GITHUB_SECRET: $(insiders-github-client-secret)
STABLE_GITHUB_ID: "baa8a44b5e861d918709"
STABLE_GITHUB_SECRET: $(stable-github-client-secret)
EXPLORATION_GITHUB_ID: "94e8376d3a90429aeaea"
EXPLORATION_GITHUB_SECRET: $(exploration-github-client-secret)
VSO_GITHUB_ID: "3d4be8f37a0325b5817d"
VSO_GITHUB_SECRET: $(vso-github-client-secret)
VSO_PPE_GITHUB_ID: "eabf35024dc2e891a492"
VSO_PPE_GITHUB_SECRET: $(vso-ppe-github-client-secret)
VSO_DEV_GITHUB_ID: "84383ebd8a7c5f5efc5c"
VSO_DEV_GITHUB_SECRET: $(vso-dev-github-client-secret)
GITHUB_APP_ID: "Iv1.ae51e546bef24ff1"
GITHUB_APP_SECRET: $(github-app-client-secret)
- script: |
set -e
@@ -118,7 +101,7 @@ steps:
- script: |
set -e
yarn test-browser --build --browser chromium --browser webkit
yarn test-browser --build --browser chromium --browser webkit --browser firefox
displayName: Run unit tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))

View File

@@ -1,8 +1,12 @@
pool:
vmImage: 'Ubuntu-16.04'
trigger: none
pr: none
trigger:
branches:
include: ['master']
pr:
branches:
include: ['master']
steps:
- task: NodeTool@0
@@ -27,10 +31,10 @@ steps:
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
git checkout origin/electron-6.0.x
git checkout origin/electron-8.0.x
git merge origin/master
# Push master branch into exploration branch
git push origin HEAD:electron-6.0.x
git push origin HEAD:electron-8.0.x
displayName: Sync & Merge Exploration

View File

@@ -52,10 +52,10 @@ steps:
- script: |
DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests"
displayName: Run Unit Tests (Electron)
# - script: | {{SQL CARBON EDIT}} disable for now @TODO @anthonydresser
# - script: | {{SQL CARBON EDIT}} disable
# DISPLAY=:10 yarn test-browser --browser chromium
# displayName: Run Unit Tests (Browser)
# - script: | {{SQL CARBON EDIT}} remove step
# - script: | {{SQL CARBON EDIT}} disable
# DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests"
# displayName: Run Integration Tests (Electron)
- task: PublishTestResults@2

View File

@@ -86,23 +86,6 @@ steps:
yarn postinstall
displayName: Run postinstall scripts
condition: and(succeeded(), eq(variables['CacheRestored'], 'true'))
env:
OSS_GITHUB_ID: "a5d3c261b032765a78de"
OSS_GITHUB_SECRET: $(oss-github-client-secret)
INSIDERS_GITHUB_ID: "31f02627809389d9f111"
INSIDERS_GITHUB_SECRET: $(insiders-github-client-secret)
STABLE_GITHUB_ID: "baa8a44b5e861d918709"
STABLE_GITHUB_SECRET: $(stable-github-client-secret)
EXPLORATION_GITHUB_ID: "94e8376d3a90429aeaea"
EXPLORATION_GITHUB_SECRET: $(exploration-github-client-secret)
VSO_GITHUB_ID: "3d4be8f37a0325b5817d"
VSO_GITHUB_SECRET: $(vso-github-client-secret)
VSO_PPE_GITHUB_ID: "eabf35024dc2e891a492"
VSO_PPE_GITHUB_SECRET: $(vso-ppe-github-client-secret)
VSO_DEV_GITHUB_ID: "84383ebd8a7c5f5efc5c"
VSO_DEV_GITHUB_SECRET: $(vso-dev-github-client-secret)
GITHUB_APP_ID: "Iv1.ae51e546bef24ff1"
GITHUB_APP_SECRET: $(github-app-client-secret)
- script: |
set -e

View File

@@ -76,23 +76,6 @@ steps:
yarn postinstall
displayName: Run postinstall scripts
condition: and(succeeded(), eq(variables['CacheRestored'], 'true'))
env:
OSS_GITHUB_ID: "a5d3c261b032765a78de"
OSS_GITHUB_SECRET: $(oss-github-client-secret)
INSIDERS_GITHUB_ID: "31f02627809389d9f111"
INSIDERS_GITHUB_SECRET: $(insiders-github-client-secret)
STABLE_GITHUB_ID: "baa8a44b5e861d918709"
STABLE_GITHUB_SECRET: $(stable-github-client-secret)
EXPLORATION_GITHUB_ID: "94e8376d3a90429aeaea"
EXPLORATION_GITHUB_SECRET: $(exploration-github-client-secret)
VSO_GITHUB_ID: "3d4be8f37a0325b5817d"
VSO_GITHUB_SECRET: $(vso-github-client-secret)
VSO_PPE_GITHUB_ID: "eabf35024dc2e891a492"
VSO_PPE_GITHUB_SECRET: $(vso-ppe-github-client-secret)
VSO_DEV_GITHUB_ID: "84383ebd8a7c5f5efc5c"
VSO_DEV_GITHUB_SECRET: $(vso-dev-github-client-secret)
GITHUB_APP_ID: "Iv1.ae51e546bef24ff1"
GITHUB_APP_SECRET: $(github-app-client-secret)
- script: |
set -e

View File

@@ -74,9 +74,9 @@ steps:
- script: |
set -e
yarn postinstall
displayName: Run postinstall scripts
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['CacheRestored'], 'true'))
yarn generate-github-config
displayName: Generate GitHub config
condition: succeeded()
env:
OSS_GITHUB_ID: "a5d3c261b032765a78de"
OSS_GITHUB_SECRET: $(oss-github-client-secret)
@@ -95,6 +95,12 @@ steps:
GITHUB_APP_ID: "Iv1.ae51e546bef24ff1"
GITHUB_APP_SECRET: $(github-app-client-secret)
- script: |
set -e
yarn postinstall
displayName: Run postinstall scripts
condition: and(succeeded(), ne(variables['CacheExists-Compilation'], 'true'), eq(variables['CacheRestored'], 'true'))
# Mixin must run before optimize, because the CSS loader will
# inline small SVGs
- script: |

View File

@@ -63,7 +63,7 @@ steps:
MESSAGE="DefinitelyTyped/DefinitelyTyped#vscode-types-$TAG_VERSION created. Endgame master, please open this link, examine changes and create a PR:"
LINK="https://github.com/DefinitelyTyped/DefinitelyTyped/compare/vscode-types-$TAG_VERSION?quick_pull=1&body=Updating%20VS%20Code%20Extension%20API.%20See%20https%3A%2F%2Fgithub.com%2Fmicrosoft%2Fvscode%2Fissues%2F70175%20for%20details."
MESSAGE2="[@octref, @jrieken, @kmaetzel, @egamma]. Please review and merge PR to publish @types/vscode."
MESSAGE2="[@eamodio, @jrieken, @kmaetzel, @egamma]. Please review and merge PR to publish @types/vscode."
curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \
-H 'Content-type: application/json; charset=utf-8' \

View File

@@ -49,10 +49,10 @@ steps:
- powershell: |
.\scripts\test.bat --tfs "Unit Tests"
displayName: Run Unit Tests (Electron)
# - powershell: | {{SQL CARBON EDIT}} disable for now @TODO @anthonydresser
# yarn test-browser --browser chromium
# - powershell: | {{SQL CARBON EDIT}} disable
# yarn test-browser --browser chromium --browser firefox
# displayName: Run Unit Tests (Browser)
# - powershell: | {{SQL CARBON EDIT}} remove step
# - powershell: | {{SQL CARBON EDIT}} disable
# .\scripts\test-integration.bat --tfs "Integration Tests"
# displayName: Run Integration Tests (Electron)
- task: PublishTestResults@2

View File

@@ -86,23 +86,6 @@ steps:
exec { yarn postinstall }
displayName: Run postinstall scripts
condition: and(succeeded(), eq(variables['CacheRestored'], 'true'))
env:
OSS_GITHUB_ID: "a5d3c261b032765a78de"
OSS_GITHUB_SECRET: $(oss-github-client-secret)
INSIDERS_GITHUB_ID: "31f02627809389d9f111"
INSIDERS_GITHUB_SECRET: $(insiders-github-client-secret)
STABLE_GITHUB_ID: "baa8a44b5e861d918709"
STABLE_GITHUB_SECRET: $(stable-github-client-secret)
EXPLORATION_GITHUB_ID: "94e8376d3a90429aeaea"
EXPLORATION_GITHUB_SECRET: $(exploration-github-client-secret)
VSO_GITHUB_ID: "3d4be8f37a0325b5817d"
VSO_GITHUB_SECRET: $(vso-github-client-secret)
VSO_PPE_GITHUB_ID: "eabf35024dc2e891a492"
VSO_PPE_GITHUB_SECRET: $(vso-ppe-github-client-secret)
VSO_DEV_GITHUB_ID: "84383ebd8a7c5f5efc5c"
VSO_DEV_GITHUB_SECRET: $(vso-dev-github-client-secret)
GITHUB_APP_ID: "Iv1.ae51e546bef24ff1"
GITHUB_APP_SECRET: $(github-app-client-secret)
- powershell: |
. build/azure-pipelines/win32/exec.ps1
@@ -132,7 +115,7 @@ steps:
- powershell: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
exec { yarn test-browser --build --browser chromium }
exec { yarn test-browser --build --browser chromium --browser firefox }
displayName: Run unit tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))

View File

@@ -43,7 +43,7 @@ let editorEntryPoints = [
];
let editorResources = [
'out-editor-build/vs/base/browser/ui/codiconLabel/**/*.ttf'
'out-editor-build/vs/base/browser/ui/codicons/**/*.ttf'
];
let BUNDLED_FILE_HEADER = [

View File

@@ -76,7 +76,7 @@ const vscodeResources = [
'out-build/vs/base/common/performance.js',
'out-build/vs/base/node/languagePacks.js',
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}',
'out-build/vs/base/browser/ui/codiconLabel/codicon/**',
'out-build/vs/base/browser/ui/codicons/codicon/**',
'out-build/vs/workbench/browser/media/*-theme.css',
'out-build/vs/workbench/contrib/debug/**/*.json',
'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt',
@@ -186,6 +186,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
const checksums = computeChecksums(out, [
'vs/workbench/workbench.desktop.main.js',
'vs/workbench/workbench.desktop.main.css',
'vs/workbench/services/extensions/node/extensionHostProcess.js',
'vs/code/electron-browser/workbench/workbench.html',
'vs/code/electron-browser/workbench/workbench.js'
]);
@@ -357,6 +358,7 @@ const buildRoot = path.dirname(root);
const BUILD_TARGETS = [
{ platform: 'win32', arch: 'ia32' },
{ platform: 'win32', arch: 'x64' },
{ platform: 'win32', arch: 'arm64' },
{ platform: 'darwin', arch: null, opts: { stats: true } },
{ platform: 'linux', arch: 'ia32' },
{ platform: 'linux', arch: 'x64' },
@@ -488,20 +490,30 @@ const generateVSCodeConfigurationTask = task.define('generate-vscode-configurati
const extensionsDir = path.join(os.tmpdir(), 'tmpextdir');
const appName = process.env.VSCODE_QUALITY === 'insider' ? 'Visual\\ Studio\\ Code\\ -\\ Insiders.app' : 'Visual\\ Studio\\ Code.app';
const appPath = path.join(buildDir, `VSCode-darwin/${appName}/Contents/Resources/app/bin/code`);
const codeProc = cp.exec(`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`);
const codeProc = cp.exec(
`${appPath} --export-default-configuration='${allConfigDetailsPath}' --wait --user-data-dir='${userDataDir}' --extensions-dir='${extensionsDir}'`,
(err, stdout, stderr) => {
clearTimeout(timer);
if (err) {
console.log(`err: ${err} ${err.message} ${err.toString()}`);
reject(err);
}
if (stdout) {
console.log(`stdout: ${stdout}`);
}
if (stderr) {
console.log(`stderr: ${stderr}`);
}
resolve();
}
);
const timer = setTimeout(() => {
codeProc.kill();
reject(new Error('export-default-configuration process timed out'));
}, 10 * 1000);
codeProc.stdout.on('data', d => console.log(d.toString()));
codeProc.stderr.on('data', d => console.log(d.toString()));
codeProc.on('exit', () => {
clearTimeout(timer);
resolve();
});
}, 12 * 1000);
codeProc.on('error', err => {
clearTimeout(timer);

View File

@@ -128,6 +128,7 @@ function archiveWin32Setup(arch) {
gulp.task(task.define('vscode-win32-ia32-archive', task.series(util.rimraf(zipDir('ia32')), archiveWin32Setup('ia32'))));
gulp.task(task.define('vscode-win32-x64-archive', task.series(util.rimraf(zipDir('x64')), archiveWin32Setup('x64'))));
gulp.task(task.define('vscode-win32-arm64-archive', task.series(util.rimraf(zipDir('arm64')), archiveWin32Setup('arm64'))));
function copyInnoUpdater(arch) {
return () => {
@@ -150,3 +151,4 @@ gulp.task(task.define('vscode-win32-x64-inno-updater', task.series(copyInnoUpdat
gulp.task(task.define('vscode-win32-ia32-code-helper', task.series(updateIcon(path.join(buildPath('ia32'), 'resources', 'app', 'out', 'vs', 'platform', 'files', 'node', 'watcher', 'win32', 'CodeHelper.exe')))));
gulp.task(task.define('vscode-win32-x64-code-helper', task.series(updateIcon(path.join(buildPath('x64'), 'resources', 'app', 'out', 'vs', 'platform', 'files', 'node', 'watcher', 'win32', 'CodeHelper.exe')))));
gulp.task(task.define('vscode-win32-arm64-code-helper', task.series(updateIcon(path.join(buildPath('arm64'), 'resources', 'app', 'out', 'vs', 'platform', 'files', 'node', 'watcher', 'win32', 'CodeHelper.exe')))));

View File

@@ -27,13 +27,7 @@ module.exports = new (_a = class ApiEventNaming {
['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node) => {
var _a, _b;
const def = (_b = (_a = node.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.parent;
let ident;
if ((def === null || def === void 0 ? void 0 : def.type) === experimental_utils_1.AST_NODE_TYPES.Identifier) {
ident = def;
}
else if (((def === null || def === void 0 ? void 0 : def.type) === experimental_utils_1.AST_NODE_TYPES.TSPropertySignature || (def === null || def === void 0 ? void 0 : def.type) === experimental_utils_1.AST_NODE_TYPES.ClassProperty) && def.key.type === experimental_utils_1.AST_NODE_TYPES.Identifier) {
ident = def.key;
}
const ident = this.getIdent(def);
if (!ident) {
// event on unknown structure...
return context.report({
@@ -76,6 +70,18 @@ module.exports = new (_a = class ApiEventNaming {
}
};
}
getIdent(def) {
if (!def) {
return;
}
if (def.type === experimental_utils_1.AST_NODE_TYPES.Identifier) {
return def;
}
else if ((def.type === experimental_utils_1.AST_NODE_TYPES.TSPropertySignature || def.type === experimental_utils_1.AST_NODE_TYPES.ClassProperty) && def.key.type === experimental_utils_1.AST_NODE_TYPES.Identifier) {
return def.key;
}
return this.getIdent(def.parent);
}
},
_a._nameRegExp = /on(Did|Will)([A-Z][a-z]+)([A-Z][a-z]+)?/,
_a);

View File

@@ -32,14 +32,7 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node: any) => {
const def = (<TSESTree.Identifier>node).parent?.parent?.parent;
let ident: TSESTree.Identifier | undefined;
if (def?.type === AST_NODE_TYPES.Identifier) {
ident = def;
} else if ((def?.type === AST_NODE_TYPES.TSPropertySignature || def?.type === AST_NODE_TYPES.ClassProperty) && def.key.type === AST_NODE_TYPES.Identifier) {
ident = def.key;
}
const ident = this.getIdent(def);
if (!ident) {
// event on unknown structure...
@@ -87,5 +80,19 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
}
};
}
private getIdent(def: TSESTree.Node | undefined): TSESTree.Identifier | undefined {
if (!def) {
return;
}
if (def.type === AST_NODE_TYPES.Identifier) {
return def;
} else if ((def.type === AST_NODE_TYPES.TSPropertySignature || def.type === AST_NODE_TYPES.ClassProperty) && def.key.type === AST_NODE_TYPES.Identifier) {
return def.key;
}
return this.getIdent(def.parent);
}
};

View File

@@ -48,7 +48,7 @@
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"terser": "4.3.8",
"typescript": "^3.9.0-dev.20200327",
"typescript": "^3.9.0-dev.20200420",
"vsce": "1.48.0",
"vscode-telemetry-extractor": "^1.5.4",
"xml2js": "^0.4.17"

View File

@@ -3462,10 +3462,10 @@ typescript@^3.0.1:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
typescript@^3.9.0-dev.20200327:
version "3.9.0-dev.20200327"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200327.tgz#52179aae816587f772a0526e91143760f2bee42f"
integrity sha512-/TWD/zPvhAcN2Toqx2NBQ+oDVGVj4iqupjWcUAwL45TfcODeHpzszneABR1b/EjHbtUObtLH40vy5Z6rdVvKzg==
typescript@^3.9.0-dev.20200420:
version "3.9.0-dev.20200420"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200420.tgz#99c2bc0936dbf4479b0b5260d80475ed494b1532"
integrity sha512-36MW6V+oXNnsSgliSjUWvtOkO21g9+iFGHPFv+O06HsCl3dcuqzBac17m8xuOuWo1LUlEgS6yAnD9fiVgvmCfg==
typical@^4.0.0:
version "4.0.0"

View File

@@ -60,12 +60,12 @@
"git": {
"name": "electron",
"repositoryUrl": "https://github.com/electron/electron",
"commitHash": "d17dfabfcba7bd0bc994b8dac5f5d2000bef572c"
"commitHash": "959e80cc53cbebf8eb1d62eb2d14fa8fd86b0394"
}
},
"isOnlyProductionDependency": true,
"license": "MIT",
"version": "7.1.11"
"version": "7.2.2"
},
{
"component": {

View File

@@ -23,7 +23,7 @@
}],
"snippets": [{
"language": "bat",
"path": "./snippets/batchfile.snippets.json"
"path": "./snippets/batchfile.code-snippets"
}]
}
}
}

View File

@@ -411,6 +411,26 @@
"category": "Git"
}
],
"keybindings": [
{
"command": "git.stageSelectedRanges",
"key": "ctrl+k ctrl+alt+s",
"mac": "cmd+k cmd+alt+s",
"when": "isInDiffEditor"
},
{
"command": "git.unstageSelectedRanges",
"key": "ctrl+k ctrl+u",
"mac": "cmd+k cmd+u",
"when": "isInDiffEditor"
},
{
"command": "git.revertSelectedRanges",
"key": "ctrl+k ctrl+r",
"mac": "cmd+k cmd+r",
"when": "isInDiffEditor"
}
],
"menus": {
"commandPalette": [
{
@@ -1643,6 +1663,12 @@
"default": "mixed",
"description": "%config.untrackedChanges%",
"scope": "resource"
},
"git.showCommitInput": {
"type": "boolean",
"scope": "resource",
"default": true,
"description": "%config.showCommitInput%"
}
}
},

View File

@@ -102,7 +102,7 @@
"config.enableSmartCommit": "Commit all changes when there are no staged changes.",
"config.smartCommitChanges": "Control which changes are automatically staged by Smart Commit.",
"config.smartCommitChanges.all": "Automatically stage all changes.",
"config.smartCommitChanges.tracked": "Automatically staged tracked changes only.",
"config.smartCommitChanges.tracked": "Automatically stage tracked changes only.",
"config.suggestSmartCommit": "Suggests to enable smart commit (commit all changes when there are no staged changes).",
"config.enableCommitSigning": "Enables commit signing with GPG.",
"config.discardAllScope": "Controls what changes are discarded by the `Discard all changes` command. `all` discards all changes. `tracked` discards only tracked files. `prompt` shows a prompt dialog every time the action is run.",
@@ -143,6 +143,7 @@
"config.untrackedChanges.mixed": "All changes, tracked and untracked, appear together and behave equally.",
"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.showCommitInput": "Controls whether to show the commit input in the Git source control panel.",
"colors.added": "Color for added resources.",
"colors.modified": "Color for modified resources.",
"colors.deleted": "Color for deleted resources.",

View File

@@ -5,8 +5,8 @@
import { Model } from '../model';
import { Repository as BaseRepository, Resource } from '../repository';
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions } from './git';
import { Event, SourceControlInputBox, Uri, SourceControl } from 'vscode';
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, GitExtension, RefType, RemoteSourceProvider } from './git';
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands } from 'vscode';
import { mapEvent } from '../util';
import { toGitUri } from '../uri';
@@ -248,5 +248,82 @@ export class ApiImpl implements API {
return result ? new ApiRepository(result) : null;
}
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable {
return this._model.registerRemoteSourceProvider(provider);
}
constructor(private _model: Model) { }
}
function getRefType(type: RefType): string {
switch (type) {
case RefType.Head: return 'Head';
case RefType.RemoteHead: return 'RemoteHead';
case RefType.Tag: return 'Tag';
}
return 'unknown';
}
function getStatus(status: Status): string {
switch (status) {
case Status.INDEX_MODIFIED: return 'INDEX_MODIFIED';
case Status.INDEX_ADDED: return 'INDEX_ADDED';
case Status.INDEX_DELETED: return 'INDEX_DELETED';
case Status.INDEX_RENAMED: return 'INDEX_RENAMED';
case Status.INDEX_COPIED: return 'INDEX_COPIED';
case Status.MODIFIED: return 'MODIFIED';
case Status.DELETED: return 'DELETED';
case Status.UNTRACKED: return 'UNTRACKED';
case Status.IGNORED: return 'IGNORED';
case Status.INTENT_TO_ADD: return 'INTENT_TO_ADD';
case Status.ADDED_BY_US: return 'ADDED_BY_US';
case Status.ADDED_BY_THEM: return 'ADDED_BY_THEM';
case Status.DELETED_BY_US: return 'DELETED_BY_US';
case Status.DELETED_BY_THEM: return 'DELETED_BY_THEM';
case Status.BOTH_ADDED: return 'BOTH_ADDED';
case Status.BOTH_DELETED: return 'BOTH_DELETED';
case Status.BOTH_MODIFIED: return 'BOTH_MODIFIED';
}
return 'UNKNOWN';
}
export function registerAPICommands(extension: GitExtension): Disposable {
return Disposable.from(
commands.registerCommand('git.api.getRepositories', () => {
const api = extension.getAPI(1);
return api.repositories.map(r => r.rootUri.toString());
}),
commands.registerCommand('git.api.getRepositoryState', (uri: string) => {
const api = extension.getAPI(1);
const repository = api.getRepository(Uri.parse(uri));
if (!repository) {
return null;
}
const state = repository.state;
const ref = (ref: Ref | undefined) => (ref && { ...ref, type: getRefType(ref.type) });
const change = (change: Change) => ({
uri: change.uri.toString(),
originalUri: change.originalUri.toString(),
renameUri: change.renameUri?.toString(),
status: getStatus(change.status)
});
return {
HEAD: ref(state.HEAD),
refs: state.refs.map(ref),
remotes: state.remotes,
submodules: state.submodules,
rebaseCommit: state.rebaseCommit,
mergeChanges: state.mergeChanges.map(change),
indexChanges: state.indexChanges.map(change),
workingTreeChanges: state.workingTreeChanges.map(change)
};
})
);
}

View File

@@ -3,7 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri, SourceControlInputBox, Event, CancellationToken } from 'vscode';
import { Uri, Event, Disposable, ProviderResult } from 'vscode';
export { ProviderResult } from 'vscode';
export interface Git {
readonly path: string;
@@ -189,6 +190,19 @@ export interface Repository {
commit(message: string, opts?: CommitOptions): Promise<void>;
}
export interface RemoteSource {
readonly name: string;
readonly description?: string;
readonly url: string | string[];
}
export interface RemoteSourceProvider {
readonly name: string;
readonly icon?: string; // codicon name
readonly supportsQuery?: boolean;
getRemoteSources(query?: string): ProviderResult<RemoteSource[]>;
}
export type APIState = 'uninitialized' | 'initialized';
export interface API {
@@ -201,6 +215,7 @@ export interface API {
toGitUri(uri: Uri, ref: string): Uri;
getRepository(uri: Uri): Repository | null;
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable;
}
export interface GitExtension {

View File

@@ -6,10 +6,10 @@
import { lstat, Stats } from 'fs';
import * as os from 'os';
import * as path from 'path';
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env } from 'vscode';
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, QuickPick } from 'vscode';
import TelemetryReporter from 'vscode-extension-telemetry';
import * as nls from 'vscode-nls';
import { Branch, GitErrorCodes, Ref, RefType, Status, CommitOptions } from './api/git';
import { Branch, GitErrorCodes, Ref, RefType, Status, CommitOptions, RemoteSourceProvider, RemoteSource } from './api/git';
import { ForcePushMode, Git, Stash } from './git';
import { Model } from './model';
import { Repository, Resource, ResourceGroupType } from './repository';
@@ -18,6 +18,7 @@ import { fromGitUri, toGitUri, isGitUri } from './uri';
import { grep, isDescendant, pathEquals } from './util';
import { Log, LogLevel } from './log';
import { GitTimelineItem } from './timelineProvider';
import { throttle, debounce } from './decorators';
const localize = nls.loadMessageBundle();
@@ -233,6 +234,71 @@ interface PushOptions {
silent?: boolean;
}
async function getQuickPickResult<T extends QuickPickItem>(quickpick: QuickPick<T>): Promise<T | undefined> {
const result = await new Promise<T | undefined>(c => {
quickpick.onDidAccept(() => c(quickpick.selectedItems[0]));
quickpick.onDidHide(() => c(undefined));
quickpick.show();
});
quickpick.hide();
return result;
}
class RemoteSourceProviderQuickPick {
private quickpick: QuickPick<QuickPickItem & { remoteSource?: RemoteSource }>;
constructor(private provider: RemoteSourceProvider) {
this.quickpick = window.createQuickPick();
this.quickpick.ignoreFocusOut = true;
if (provider.supportsQuery) {
this.quickpick.placeholder = localize('type to search', "Repository name (type to search)");
this.quickpick.onDidChangeValue(this.onDidChangeValue, this);
} else {
this.quickpick.placeholder = localize('type to filter', "Repository name");
}
}
@debounce(300)
onDidChangeValue(): void {
this.query();
}
@throttle
async query(): Promise<void> {
this.quickpick.busy = true;
try {
const remoteSources = await this.provider.getRemoteSources(this.quickpick.value) || [];
if (remoteSources.length === 0) {
this.quickpick.items = [{
label: localize('none found', "No remote repositories found."),
alwaysShow: true
}];
} else {
this.quickpick.items = remoteSources.map(remoteSource => ({
label: remoteSource.name,
description: remoteSource.description || (typeof remoteSource.url === 'string' ? remoteSource.url : remoteSource.url[0]),
remoteSource
}));
}
} catch (err) {
this.quickpick.items = [{ label: localize('error', "$(error) Error: {0}", err.message), alwaysShow: true }];
} finally {
this.quickpick.busy = false;
}
}
async pick(): Promise<RemoteSource | undefined> {
this.query();
const result = await getQuickPickResult(this.quickpick);
return result?.remoteSource;
}
}
export class CommandCenter {
private disposables: Disposable[];
@@ -290,7 +356,7 @@ export class CommandCenter {
}
@command('git.openResource')
async openResource(resource: Resource): Promise<void> {
async openResource(resource: Resource, preserveFocus: boolean): Promise<void> {
const repository = this.model.getRepository(resource.resourceUri);
if (!repository) {
@@ -301,7 +367,7 @@ export class CommandCenter {
const openDiffOnClick = config.get<boolean>('openDiffOnClick');
if (openDiffOnClick) {
await this._openResource(resource, undefined, true, false);
await this._openResource(resource, undefined, preserveFocus, false);
} else {
await this.openFile(resource);
}
@@ -454,10 +520,51 @@ export class CommandCenter {
@command('git.clone')
async clone(url?: string, parentPath?: string): Promise<void> {
if (!url) {
url = await window.showInputBox({
prompt: localize('repourl', "Repository URL"),
ignoreFocusOut: true
});
const quickpick = window.createQuickPick<(QuickPickItem & { provider?: RemoteSourceProvider, url?: string })>();
quickpick.ignoreFocusOut = true;
const providers = this.model.getRemoteProviders()
.map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + localize('clonefrom', "Clone from {1}", provider.name), alwaysShow: true, provider }));
quickpick.placeholder = providers.length === 0
? localize('provide url', "Provide repository URL.")
: localize('provide url or pick', "Provide repository URL or pick a repository source.");
const updatePicks = (value?: string) => {
if (value) {
quickpick.items = [{
label: localize('repourl', "Clone from URL"),
description: value,
alwaysShow: true,
url: value
},
...providers];
} else {
quickpick.items = providers;
}
};
quickpick.onDidChangeValue(updatePicks);
updatePicks();
const result = await getQuickPickResult(quickpick);
if (result) {
if (result.url) {
url = result.url;
} else if (result.provider) {
const quickpick = new RemoteSourceProviderQuickPick(result.provider);
const remote = await quickpick.pick();
if (remote) {
if (typeof remote.url === 'string') {
url = remote.url;
} else if (remote.url.length > 0) {
url = await window.showQuickPick(remote.url, { ignoreFocusOut: true, placeHolder: localize('pick url', "Choose a URL to clone from.") });
}
}
}
}
}
if (!url) {

View File

@@ -1,150 +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 { workspace, Uri, Disposable, Event, EventEmitter, window } from 'vscode';
import { debounce, throttle } from './decorators';
import { fromGitUri, toGitUri } from './uri';
import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model';
import { filterEvent, eventToPromise, isDescendant, pathEquals } from './util';
interface CacheRow {
uri: Uri;
timestamp: number;
}
interface Cache {
[uri: string]: CacheRow;
}
const THREE_MINUTES = 1000 * 60 * 3;
const FIVE_MINUTES = 1000 * 60 * 5;
export class GitContentProvider {
private _onDidChange = new EventEmitter<Uri>();
get onDidChange(): Event<Uri> { return this._onDidChange.event; }
private changedRepositoryRoots = new Set<string>();
private cache: Cache = Object.create(null);
private disposables: Disposable[] = [];
constructor(private model: Model) {
this.disposables.push(
model.onDidChangeRepository(this.onDidChangeRepository, this),
model.onDidChangeOriginalResource(this.onDidChangeOriginalResource, this),
workspace.registerTextDocumentContentProvider('git', this)
);
setInterval(() => this.cleanup(), FIVE_MINUTES);
}
private onDidChangeRepository({ repository }: ModelChangeEvent): void {
this.changedRepositoryRoots.add(repository.root);
this.eventuallyFireChangeEvents();
}
private onDidChangeOriginalResource({ uri }: OriginalResourceChangeEvent): void {
if (uri.scheme !== 'file') {
return;
}
this._onDidChange.fire(toGitUri(uri, '', { replaceFileExtension: true }));
}
@debounce(1100)
private eventuallyFireChangeEvents(): void {
this.fireChangeEvents();
}
@throttle
private async fireChangeEvents(): Promise<void> {
if (!window.state.focused) {
const onDidFocusWindow = filterEvent(window.onDidChangeWindowState, e => e.focused);
await eventToPromise(onDidFocusWindow);
}
Object.keys(this.cache).forEach(key => {
const uri = this.cache[key].uri;
const fsPath = uri.fsPath;
for (const root of this.changedRepositoryRoots) {
if (isDescendant(root, fsPath)) {
this._onDidChange.fire(uri);
return;
}
}
});
this.changedRepositoryRoots.clear();
}
async provideTextDocumentContent(uri: Uri): Promise<string> {
let { path, ref, submoduleOf } = fromGitUri(uri);
if (submoduleOf) {
const repository = this.model.getRepository(submoduleOf);
if (!repository) {
return '';
}
if (ref === 'index') {
return await repository.diffIndexWithHEAD(path);
} else {
return await repository.diffWithHEAD(path);
}
}
const repository = this.model.getRepository(uri);
if (!repository) {
return '';
}
const cacheKey = uri.toString();
const timestamp = new Date().getTime();
const cacheValue: CacheRow = { uri, timestamp };
this.cache[cacheKey] = cacheValue;
if (ref === '~') {
const fileUri = Uri.file(path);
const uriString = fileUri.toString();
const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
ref = indexStatus ? '' : 'HEAD';
} else if (/^~\d$/.test(ref)) {
ref = `:${ref[1]}`;
}
try {
return await repository.show(ref, path);
} catch (err) {
return '';
}
}
private cleanup(): void {
const now = new Date().getTime();
const cache = Object.create(null);
Object.keys(this.cache).forEach(key => {
const row = this.cache[key];
const { path } = fromGitUri(row.uri);
const isOpen = workspace.textDocuments
.filter(d => d.uri.scheme === 'file')
.some(d => pathEquals(d.uri.fsPath, path));
if (isOpen || now - row.timestamp < THREE_MINUTES) {
cache[row.uri.toString()] = row;
}
});
this.cache = cache;
}
dispose(): void {
this.disposables.forEach(d => d.dispose());
}
}

View File

@@ -443,7 +443,10 @@ export class Git {
);
if (networkPath !== undefined) {
return path.normalize(
repoUri.fsPath.replace(networkPath, `${letter.toLowerCase()}:`),
repoUri.fsPath.replace(
networkPath,
`${letter.toLowerCase()}:${networkPath.endsWith('\\') ? '\\' : ''}`
),
);
}
} catch { }
@@ -537,7 +540,8 @@ export class Git {
options.env = assign({}, process.env, this.env, options.env || {}, {
VSCODE_GIT_COMMAND: args[0],
LC_ALL: 'en_US.UTF-8',
LANG: 'en_US.UTF-8'
LANG: 'en_US.UTF-8',
GIT_PAGER: 'cat'
});
if (options.cwd) {

View File

@@ -10,7 +10,6 @@ import { ExtensionContext, workspace, window, Disposable, commands, OutputChanne
import { findGit, Git, IGit } from './git';
import { Model } from './model';
import { CommandCenter } from './commands';
import { GitContentProvider } from './contentProvider';
import { GitFileSystemProvider } from './fileSystemProvider';
import { GitDecorations } from './decorationProvider';
import { Askpass } from './askpass';
@@ -23,6 +22,7 @@ import { GitExtensionImpl } from './api/extension';
// import * as fs from 'fs';
import { createIPCServer, IIPCServer } from './ipc/ipcServer';
import { GitTimelineProvider } from './timelineProvider';
import { registerAPICommands } from './api/api1';
const deactivateTasks: { (): Promise<any>; }[] = [];
@@ -80,7 +80,6 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
disposables.push(
new CommandCenter(git, model, outputChannel, telemetryReporter),
new GitContentProvider(model),
new GitFileSystemProvider(model),
new GitDecorations(model),
new GitProtocolHandler(),
@@ -141,7 +140,7 @@ async function warnAboutMissingGit(): Promise<void> {
}
}*/
export async function activate(context: ExtensionContext): Promise<GitExtension> {
export async function _activate(context: ExtensionContext): Promise<GitExtension> {
const disposables: Disposable[] = [];
context.subscriptions.push(new Disposable(() => Disposable.from(...disposables).dispose()));
@@ -183,10 +182,19 @@ export async function activate(context: ExtensionContext): Promise<GitExtension>
}
}
// {{SQL CARBON EDIT}} - Rename info to _info to prevent error due to unused variable
async function checkGitVersion(_info: IGit): Promise<void> {
export async function activate(context: ExtensionContext): Promise<GitExtension> {
const result = await _activate(context);
context.subscriptions.push(registerAPICommands(result));
return result;
}
async function checkGitVersion(_info: IGit): Promise<void> { // {{SQL CARBON EDIT}} - Rename info to _info to prevent error due to unused variable
return; /* {{SQL CARBON EDIT}} return immediately
/*const config = workspace.getConfiguration('git');
const shouldIgnore = config.get<boolean>('ignoreLegacyWarning') === true;
const config = workspace.getConfiguration('git');
const shouldIgnore = config.get<boolean>('ignoreLegacyWarning') === true;

View File

@@ -6,13 +6,13 @@
import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, OutputChannel } from 'vscode';
import { Repository, RepositoryState } from './repository';
import { memoize, sequentialize, debounce } from './decorators';
import { dispose, anyEvent, filterEvent, isDescendant, firstIndex, pathEquals } from './util';
import { dispose, anyEvent, filterEvent, isDescendant, firstIndex, pathEquals, toDisposable } from './util';
import { Git } from './git';
import * as path from 'path';
import * as fs from 'fs';
import * as nls from 'vscode-nls';
import { fromGitUri } from './uri';
import { GitErrorCodes, APIState as State } from './api/git';
import { GitErrorCodes, APIState as State, RemoteSourceProvider } from './api/git';
const localize = nls.loadMessageBundle();
@@ -74,6 +74,8 @@ export class Model {
this._onDidChangeState.fire(state);
}
private remoteProviders = new Set<RemoteSourceProvider>();
private disposables: Disposable[] = [];
constructor(readonly git: Git, private globalState: Memento, private outputChannel: OutputChannel) {
@@ -447,6 +449,15 @@ export class Model {
return undefined;
}
registerRemoteSourceProvider(provider: RemoteSourceProvider): Disposable {
this.remoteProviders.add(provider);
return toDisposable(() => this.remoteProviders.delete(provider));
}
getRemoteProviders(): RemoteSourceProvider[] {
return [...this.remoteProviders.values()];
}
dispose(): void {
const openRepositories = [...this.openRepositories];
openRepositories.forEach(r => r.dispose());

View File

@@ -743,6 +743,15 @@ export class Repository implements Disposable {
const onConfigListenerForUntracked = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.untrackedChanges', root));
onConfigListenerForUntracked(this.updateModelState, this, this.disposables);
const updateInputBoxVisibility = () => {
const config = workspace.getConfiguration('git', root);
this._sourceControl.inputBox.visible = config.get<boolean>('showCommitInput', true);
};
const onConfigListenerForInputBoxVisibility = filterEvent(workspace.onDidChangeConfiguration, e => e.affectsConfiguration('git.showCommitInput', root));
onConfigListenerForInputBoxVisibility(updateInputBoxVisibility, this, this.disposables);
updateInputBoxVisibility();
this.mergeGroup.hideWhenEmpty = true;
this.untrackedGroup.hideWhenEmpty = true;

View File

@@ -0,0 +1,8 @@
src/**
!src/common/config.json
out/**
build/**
extension.webpack.config.js
tsconfig.json
yarn.lock
README.md

View File

@@ -14,15 +14,16 @@
"activationEvents": [
"*"
],
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"main": "./out/extension.js",
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "gulp compile-extension:github-authentication",
"watch": "gulp watch-extension:github-authentication",
"postinstall": "node build/postinstall.js"
"watch": "gulp watch-extension:github-authentication"
},
"dependencies": {
"uuid": "^3.3.3",
"vscode-extension-telemetry": "0.1.1",
"vscode-nls": "^4.1.2"
},
"devDependencies": {

View File

@@ -7,8 +7,11 @@ import * as vscode from 'vscode';
import { GitHubAuthenticationProvider, onDidChangeSessions } from './github';
import { uriHandler } from './githubServer';
import Logger from './common/logger';
import TelemetryReporter from 'vscode-extension-telemetry';
export async function activate(context: vscode.ExtensionContext) {
const { name, version, aiKey } = require('../package.json') as { name: string, version: string, aiKey: string };
const telemetryReporter = new TelemetryReporter(name, version, aiKey);
context.subscriptions.push(vscode.window.registerUriHandler(uriHandler));
const loginService = new GitHubAuthenticationProvider();
@@ -22,19 +25,29 @@ export async function activate(context: vscode.ExtensionContext) {
getSessions: () => Promise.resolve(loginService.sessions),
login: async (scopeList: string[]) => {
try {
const session = await loginService.login(scopeList.join(' '));
telemetryReporter.sendTelemetryEvent('login');
const session = await loginService.login(scopeList.sort().join(' '));
Logger.info('Login success!');
onDidChangeSessions.fire({ added: [session.id], removed: [], changed: [] });
return session;
} catch (e) {
telemetryReporter.sendTelemetryEvent('loginFailed');
vscode.window.showErrorMessage(`Sign in failed: ${e}`);
Logger.error(e);
throw e;
}
},
logout: async (id: string) => {
await loginService.logout(id);
onDidChangeSessions.fire({ added: [], removed: [id], changed: [] });
try {
telemetryReporter.sendTelemetryEvent('logout');
await loginService.logout(id);
onDidChangeSessions.fire({ added: [], removed: [id], changed: [] });
} catch (e) {
telemetryReporter.sendTelemetryEvent('logoutFailed');
vscode.window.showErrorMessage(`Sign out failed: ${e}`);
Logger.error(e);
throw e;
}
}
});

View File

@@ -12,12 +12,27 @@ import Logger from './common/logger';
export const onDidChangeSessions = new vscode.EventEmitter<vscode.AuthenticationSessionsChangeEvent>();
interface SessionData {
id: string;
account?: {
displayName: string;
id: string;
}
scopes: string[];
accessToken: string;
}
// TODO remove
interface OldSessionData {
id: string;
accountName: string;
scopes: string[];
accessToken: string;
}
function isOldSessionData(x: any): x is OldSessionData {
return !!x.accountName;
}
export class GitHubAuthenticationProvider {
private _sessions: vscode.AuthenticationSession[] = [];
private _githubServer = new GitHubServer();
@@ -68,15 +83,34 @@ export class GitHubAuthenticationProvider {
const storedSessions = await keychain.getToken();
if (storedSessions) {
try {
const sessionData: SessionData[] = JSON.parse(storedSessions);
return sessionData.map(session => {
return {
id: session.id,
accountName: session.accountName,
scopes: session.scopes,
getAccessToken: () => Promise.resolve(session.accessToken)
};
const sessionData: (SessionData | OldSessionData)[] = JSON.parse(storedSessions);
const sessionPromises = sessionData.map(async (session: SessionData | OldSessionData): Promise<vscode.AuthenticationSession | undefined> => {
try {
const needsUserInfo = isOldSessionData(session) || !session.account;
let userInfo: { id: string, accountName: string };
if (needsUserInfo) {
userInfo = await this._githubServer.getUserInfo(session.accessToken);
}
return {
id: session.id,
account: {
displayName: isOldSessionData(session)
? session.accountName
: session.account?.displayName ?? userInfo!.accountName,
id: isOldSessionData(session)
? userInfo!.id
: session.account?.id ?? userInfo!.id
},
scopes: session.scopes,
getAccessToken: () => Promise.resolve(session.accessToken)
};
} catch (e) {
return undefined;
}
});
return (await Promise.all(sessionPromises)).filter((x: vscode.AuthenticationSession | undefined): x is vscode.AuthenticationSession => !!x);
} catch (e) {
Logger.error(`Error reading sessions: ${e}`);
}
@@ -90,7 +124,7 @@ export class GitHubAuthenticationProvider {
const resolvedAccessToken = await session.getAccessToken();
return {
id: session.id,
accountName: session.accountName,
account: session.account,
scopes: session.scopes,
accessToken: resolvedAccessToken
};
@@ -125,7 +159,10 @@ export class GitHubAuthenticationProvider {
return {
id: uuid(),
getAccessToken: () => Promise.resolve(token),
accountName: userInfo.accountName,
account: {
displayName: userInfo.accountName,
id: userInfo.id
},
scopes: scopes
};
}
@@ -137,7 +174,7 @@ export class GitHubAuthenticationProvider {
this._sessions.push(session);
}
this.storeSessions();
await this.storeSessions();
}
public async logout(id: string) {
@@ -145,9 +182,13 @@ export class GitHubAuthenticationProvider {
if (sessionIndex > -1) {
const session = this._sessions.splice(sessionIndex, 1)[0];
const token = await session.getAccessToken();
await this._githubServer.revokeToken(token);
try {
await this._githubServer.revokeToken(token);
} catch (_) {
// ignore, should still remove from keychain
}
}
this.storeSessions();
await this.storeSessions();
}
}

View File

@@ -145,6 +145,7 @@ export class GitHubServer {
Logger.info('Got account info!');
resolve({ id: json.id, accountName: json.login });
} else {
Logger.error('Getting account info failed');
reject(new Error(result.statusMessage));
}
});
@@ -186,6 +187,7 @@ export class GitHubServer {
Logger.info('Revoked token!');
resolve();
} else {
Logger.info(`Revoking token failed: ${result.statusMessage}`);
reject(new Error(result.statusMessage));
}
});

View File

@@ -29,6 +29,15 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
applicationinsights@1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5"
integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg==
dependencies:
diagnostic-channel "0.2.0"
diagnostic-channel-publishers "0.2.1"
zone.js "0.7.6"
aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@@ -91,6 +100,18 @@ detect-libc@^1.0.3:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
diagnostic-channel-publishers@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM=
diagnostic-channel@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=
dependencies:
semver "^5.3.0"
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
@@ -314,7 +335,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
semver@^5.4.1:
semver@^5.3.0, semver@^5.4.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -436,6 +457,13 @@ uuid@^3.3.3:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
vscode-extension-telemetry@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b"
integrity sha512-TkKKG/B/J94DP5qf6xWB4YaqlhWDg6zbbqVx7Bz//stLQNnfE9XS1xm3f6fl24c5+bnEK0/wHgMgZYKIKxPeUA==
dependencies:
applicationinsights "1.0.8"
vscode-nls@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
@@ -457,3 +485,8 @@ wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
zone.js@0.7.6:
version "0.7.6"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=

View File

@@ -23,7 +23,9 @@ export function activate(context: vscode.ExtensionContext) {
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,
}));
context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => {
previewManager.activePreview?.zoomIn();
@@ -33,4 +35,3 @@ export function activate(context: vscode.ExtensionContext) {
previewManager.activePreview?.zoomOut();
}));
}

View File

@@ -28,7 +28,7 @@ export class PreviewManager implements vscode.CustomEditorProvider {
) { }
public async openCustomDocument(uri: vscode.Uri) {
return new vscode.CustomDocument(uri);
return { uri, dispose: () => { } };
}
public async resolveCustomEditor(

View File

@@ -13,12 +13,12 @@ const localize = nls.loadMessageBundle();
import {
workspace, window, languages, commands, ExtensionContext, extensions, Uri, LanguageConfiguration,
Diagnostic, StatusBarAlignment, TextEditor, TextDocument, FormattingOptions, CancellationToken,
ProviderResult, TextEdit, Range, Position, Disposable, CompletionItem, CompletionList, CompletionContext
ProviderResult, TextEdit, Range, Position, Disposable, CompletionItem, CompletionList, CompletionContext, Hover, MarkdownString,
} from 'vscode';
import {
LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType,
DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError, DocumentRangeFormattingParams,
DocumentRangeFormattingRequest, ProvideCompletionItemsSignature
DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, ProvideHoverSignature
} from 'vscode-languageclient';
import TelemetryReporter from 'vscode-extension-telemetry';
@@ -153,25 +153,41 @@ export function activate(context: ExtensionContext) {
},
// testing the replace / insert mode
provideCompletionItem(document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken, next: ProvideCompletionItemsSignature): ProviderResult<CompletionItem[] | CompletionList> {
function updateRanges(item: CompletionItem) {
function update(item: CompletionItem) {
const range = item.range;
if (range instanceof Range && range.end.isAfter(position) && range.start.isBeforeOrEqual(position)) {
item.range = { inserting: new Range(range.start, position), replacing: range };
}
if (item.documentation instanceof MarkdownString) {
item.documentation = updateMarkdownString(item.documentation);
}
}
function updateProposals(r: CompletionItem[] | CompletionList | null | undefined): CompletionItem[] | CompletionList | null | undefined {
if (r) {
(Array.isArray(r) ? r : r.items).forEach(updateRanges);
(Array.isArray(r) ? r : r.items).forEach(update);
}
return r;
}
const isThenable = <T>(obj: ProviderResult<T>): obj is Thenable<T> => obj && (<any>obj)['then'];
const r = next(document, position, context, token);
if (isThenable<CompletionItem[] | CompletionList | null | undefined>(r)) {
return r.then(updateProposals);
}
return updateProposals(r);
},
provideHover(document: TextDocument, position: Position, token: CancellationToken, next: ProvideHoverSignature) {
function updateHover(r: Hover | null | undefined): Hover | null | undefined {
if (r && Array.isArray(r.contents)) {
r.contents = r.contents.map(h => h instanceof MarkdownString ? updateMarkdownString(h) : h);
}
return r;
}
const r = next(document, position, token);
if (isThenable<Hover | null | undefined>(r)) {
return r.then(updateHover);
}
return updateHover(r);
}
}
};
@@ -492,3 +508,13 @@ function readJSONFile(location: string) {
return {};
}
}
function isThenable<T>(obj: ProviderResult<T>): obj is Thenable<T> {
return obj && (<any>obj)['then'];
}
function updateMarkdownString(h: MarkdownString): MarkdownString {
const n = new MarkdownString(h.value, true);
n.isTrusted = h.isTrusted;
return n;
}

View File

@@ -22,13 +22,13 @@
"extensions": [
".json",
".bowerrc",
".jshintrc",
".jscsrc",
".swcrc",
".webmanifest",
".js.map",
".css.map",
".har"
".har",
".jslintrc",
".jsonld"
],
"filenames": [
"composer.lock",
@@ -51,7 +51,10 @@
".babelrc",
".jsonc",
".eslintrc",
".eslintrc.json"
".eslintrc.json",
".jsfmtrc",
".jshintrc",
".swcrc"
],
"configuration": "./language-configuration.json"
}

View File

@@ -68,7 +68,8 @@ function createContext(): TestContext {
packageJSON: '',
extensionKind: vscode.ExtensionKind.UI,
exports: extensionApi,
activate: () => {return Promise.resolve();}
activate: () => {return Promise.resolve();},
extensionUri: vscode.Uri.parse('')
},
apiWrapper: TypeMoq.Mock.ofType(ApiWrapper),
queryRunner: TypeMoq.Mock.ofType(QueryRunner),
@@ -88,7 +89,8 @@ function createContext(): TestContext {
asAbsolutePath: () => {return '';},
storagePath: '',
globalStoragePath: '',
logPath: ''
logPath: '',
extensionUri: vscode.Uri.parse('')
},
outputChannel: {
name: '',
@@ -106,7 +108,8 @@ function createContext(): TestContext {
packageJSON: {},
extensionKind: vscode.ExtensionKind.UI,
exports: {},
activate: () => { return Promise.resolve(); }
activate: () => { return Promise.resolve(); },
extensionUri: vscode.Uri.parse('')
},
workspaceConfig: {
get: () => {return 'value';},

View File

@@ -33,7 +33,7 @@ describe('Dashboard widget', () => {
let testContext = createContext();
const dashboard = new DashboardWidget(testContext.apiWrapper.object, '');
dashboard.register();
testContext.onClick.fire();
testContext.onClick.fire(undefined);
testContext.apiWrapper.verify(x => x.executeCommand(TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
});
});

View File

@@ -111,7 +111,7 @@ describe('Add Edit External Languages Tab', () => {
});
});
testContext.onClick.fire();
testContext.onClick.fire(undefined);
parent.onUpdatedLanguage(languageUpdateModel);
await promise;
should.equal(updateCalled, true);

View File

@@ -183,7 +183,7 @@ describe('Predict Wizard', () => {
view.modelBrowsePage.modelSourceType = ModelSourceType.RegisteredModels;
}
await view.refresh();
testContext.onClick.fire();
testContext.onClick.fire(undefined);
should.equal(view.modelSourcePage?.data, ModelSourceType.RegisteredModels);
should.notEqual(view.localModelsComponent?.data, undefined);

View File

@@ -85,11 +85,11 @@
"snippets": [
{
"language": "markdown",
"path": "./snippets/markdown.json"
"path": "./snippets/markdown.code-snippets"
}
]
},
"scripts": {
"update-grammar": "node ../../build/npm/update-grammar.js microsoft/vscode-markdown-tm-grammar syntaxes/markdown.tmLanguage ./syntaxes/markdown.tmLanguage.json"
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -18,8 +18,8 @@ const settings = getSettings();
const vscode = acquireVsCodeApi();
// Set VS Code state
let state = getData<{ line: number; fragment: string; }>('data-state');
const state = { ...vscode.getState(), ...getData<any>('data-state') };
// Make sure to sync VS Code state here
vscode.setState(state);
const messaging = createPosterForVsCode(vscode);
@@ -32,23 +32,35 @@ window.onload = () => {
};
onceDocumentLoaded(() => {
const scrollProgress = state.scrollProgress;
if (typeof scrollProgress === 'number' && !settings.fragment) {
setImmediate(() => {
scrollDisabled = true;
window.scrollTo(0, scrollProgress * document.body.clientHeight);
});
return;
}
if (settings.scrollPreviewWithEditor) {
setTimeout(() => {
setImmediate(() => {
// Try to scroll to fragment if available
if (state.fragment) {
const element = getLineElementForFragment(state.fragment);
if (settings.fragment) {
state.fragment = undefined;
vscode.setState(state);
const element = getLineElementForFragment(settings.fragment);
if (element) {
scrollDisabled = true;
scrollToRevealSourceLine(element.line);
}
} else {
const initialLine = +settings.line;
if (!isNaN(initialLine)) {
if (!isNaN(settings.line!)) {
scrollDisabled = true;
scrollToRevealSourceLine(initialLine);
scrollToRevealSourceLine(settings.line!);
}
}
}, 0);
});
}
});
@@ -58,9 +70,10 @@ const onUpdateView = (() => {
scrollToRevealSourceLine(line);
}, 50);
return (line: number, settings: any) => {
return (line: number) => {
if (!isNaN(line)) {
settings.line = line;
state.line = line;
doScroll(line);
}
};
@@ -91,6 +104,7 @@ let updateImageSizes = throttle(() => {
window.addEventListener('resize', () => {
scrollDisabled = true;
updateScrollProgress();
updateImageSizes();
}, true);
@@ -105,7 +119,7 @@ window.addEventListener('message', event => {
break;
case 'updateView':
onUpdateView(event.data.line, settings);
onUpdateView(event.data.line);
break;
}
}, false);
@@ -165,15 +179,20 @@ document.addEventListener('click', event => {
}, true);
window.addEventListener('scroll', throttle(() => {
updateScrollProgress();
if (scrollDisabled) {
scrollDisabled = false;
} else {
const line = getEditorLineNumberForPageOffset(window.scrollY);
if (typeof line === 'number' && !isNaN(line)) {
messaging.postMessage('revealLine', { line });
state.line = line;
vscode.setState(state);
}
}
}, 50));
function updateScrollProgress() {
state.scrollProgress = window.scrollY / document.body.clientHeight;
vscode.setState(state);
}

View File

@@ -5,7 +5,8 @@
export interface PreviewSettings {
readonly source: string;
readonly line: number;
readonly line?: number;
readonly fragment?: string
readonly lineCount: number;
readonly scrollPreviewWithEditor?: boolean;
readonly scrollEditorWithPreview: boolean;

View File

@@ -66,6 +66,11 @@ export class OpenDocumentLinkCommand implements Command {
}
}
const stat = await vscode.workspace.fs.stat(resource);
if (stat.type === vscode.FileType.Directory) {
return vscode.commands.executeCommand('revealInExplorer', resource);
}
return vscode.workspace.openTextDocument(resource)
.then(document => vscode.window.showTextDocument(document, column))
.then(editor => this.tryRevealLine(editor, args.fragment));

View File

@@ -13,7 +13,7 @@ import { Disposable } from '../util/dispose';
import * as nls from 'vscode-nls';
import { getVisibleLine, TopmostLineMonitor } from '../util/topmostLineMonitor';
import { MarkdownPreviewConfigurationManager } from './previewConfig';
import { MarkdownContributionProvider, MarkdownContributions } from '../markdownExtensions';
import { MarkdownContributionProvider } from '../markdownExtensions';
import { isMarkdownFile } from '../util/file';
import { resolveLinkToMarkdownFile } from '../commands/openDocumentLink';
import { WebviewResourceProvider, normalizeResource } from '../util/resources';
@@ -61,10 +61,14 @@ interface PreviewStyleLoadErrorMessage extends WebviewMessage {
}
export class PreviewDocumentVersion {
public constructor(
public readonly resource: vscode.Uri,
public readonly version: number,
) { }
private readonly resource: vscode.Uri;
private readonly version: number;
public constructor(document: vscode.TextDocument) {
this.resource = document.uri;
this.version = document.version;
}
public equals(other: PreviewDocumentVersion): boolean {
return this.resource.fsPath === other.resource.fsPath
@@ -72,102 +76,86 @@ export class PreviewDocumentVersion {
}
}
interface DynamicPreviewInput {
readonly resource: vscode.Uri;
readonly resourceColumn: vscode.ViewColumn;
readonly locked: boolean;
readonly line?: number;
interface MarkdownPreviewDelegate {
getTitle?(resource: vscode.Uri): string;
getAdditionalState(): {},
openPreviewLinkToMarkdownFile(markdownLink: vscode.Uri, fragment: string): void;
}
export class DynamicMarkdownPreview extends Disposable {
class StartingScrollLine {
public readonly type = 'line';
public static readonly viewType = 'markdown.preview';
constructor(
public readonly line: number,
) { }
}
class StartingScrollFragment {
public readonly type = 'fragment';
constructor(
public readonly fragment: string,
) { }
}
type StartingScrollLocation = StartingScrollLine | StartingScrollFragment;
class MarkdownPreview extends Disposable implements WebviewResourceProvider {
private readonly delay = 300;
private _resource: vscode.Uri;
private readonly _resourceColumn: vscode.ViewColumn;
private readonly _resource: vscode.Uri;
private readonly _webviewPanel: vscode.WebviewPanel;
private _locked: boolean;
private readonly editor: vscode.WebviewPanel;
private throttleTimer: any;
private line: number | undefined = undefined;
private line: number | undefined;
private scrollToFragment: string | undefined;
private firstUpdate = true;
private currentVersion?: PreviewDocumentVersion;
private isScrolling = false;
private _disposed: boolean = false;
private imageInfo: { id: string, width: number, height: number; }[] = [];
private scrollToFragment: string | undefined;
private imageInfo: { readonly id: string, readonly width: number, readonly height: number; }[] = [];
public static revive(
input: DynamicPreviewInput,
constructor(
webview: vscode.WebviewPanel,
contentProvider: MarkdownContentProvider,
previewConfigurations: MarkdownPreviewConfigurationManager,
logger: Logger,
topmostLineMonitor: TopmostLineMonitor,
contributionProvider: MarkdownContributionProvider,
): DynamicMarkdownPreview {
webview.webview.options = DynamicMarkdownPreview.getWebviewOptions(input.resource, contributionProvider.contributions);
webview.title = DynamicMarkdownPreview.getPreviewTitle(input.resource, input.locked);
return new DynamicMarkdownPreview(webview, input,
contentProvider, previewConfigurations, logger, topmostLineMonitor, contributionProvider);
}
public static create(
input: DynamicPreviewInput,
previewColumn: vscode.ViewColumn,
contentProvider: MarkdownContentProvider,
previewConfigurations: MarkdownPreviewConfigurationManager,
logger: Logger,
topmostLineMonitor: TopmostLineMonitor,
contributionProvider: MarkdownContributionProvider
): DynamicMarkdownPreview {
const webview = vscode.window.createWebviewPanel(
DynamicMarkdownPreview.viewType,
DynamicMarkdownPreview.getPreviewTitle(input.resource, input.locked),
previewColumn, {
enableFindWidget: true,
...DynamicMarkdownPreview.getWebviewOptions(input.resource, contributionProvider.contributions)
});
return new DynamicMarkdownPreview(webview, input,
contentProvider, previewConfigurations, logger, topmostLineMonitor, contributionProvider);
}
private constructor(
webview: vscode.WebviewPanel,
input: DynamicPreviewInput,
resource: vscode.Uri,
startingScroll: StartingScrollLocation | undefined,
private readonly delegate: MarkdownPreviewDelegate,
private readonly _contentProvider: MarkdownContentProvider,
private readonly _previewConfigurations: MarkdownPreviewConfigurationManager,
private readonly _logger: Logger,
topmostLineMonitor: TopmostLineMonitor,
private readonly _contributionProvider: MarkdownContributionProvider,
) {
super();
this._resource = input.resource;
this._resourceColumn = input.resourceColumn;
this._locked = input.locked;
this.editor = webview;
if (!isNaN(input.line!)) {
this.line = input.line;
this._webviewPanel = webview;
this._resource = resource;
switch (startingScroll?.type) {
case 'line':
if (!isNaN(startingScroll.line!)) {
this.line = startingScroll.line;
}
break;
case 'fragment':
this.scrollToFragment = startingScroll.fragment;
break;
}
this._register(this.editor.onDidDispose(() => {
this.dispose();
}));
this._register(this.editor.onDidChangeViewState(e => {
this._onDidChangeViewStateEmitter.fire(e);
}));
this._register(_contributionProvider.onContributionsChanged(() => {
setImmediate(() => this.refresh());
}));
this._register(this.editor.webview.onDidReceiveMessage((e: CacheImageSizesMessage | RevealLineMessage | DidClickMessage | ClickLinkMessage | ShowPreviewSecuritySelectorMessage | PreviewStyleLoadErrorMessage) => {
this._register(vscode.workspace.onDidChangeTextDocument(event => {
if (this.isPreviewOf(event.document.uri)) {
this.refresh();
}
}));
this._register(this._webviewPanel.webview.onDidReceiveMessage((e: CacheImageSizesMessage | RevealLineMessage | DidClickMessage | ClickLinkMessage | ShowPreviewSecuritySelectorMessage | PreviewStyleLoadErrorMessage) => {
if (e.source !== this._resource.toString()) {
return;
}
@@ -194,158 +182,50 @@ export class DynamicMarkdownPreview extends Disposable {
break;
case 'previewStyleLoadError':
vscode.window.showWarningMessage(localize('onPreviewStyleLoadError', "Could not load 'markdown.styles': {0}", e.body.unloadedStyles.join(', ')));
vscode.window.showWarningMessage(
localize('onPreviewStyleLoadError',
"Could not load 'markdown.styles': {0}",
e.body.unloadedStyles.join(', ')));
break;
}
}));
this._register(vscode.workspace.onDidChangeTextDocument(event => {
if (this.isPreviewOf(event.document.uri)) {
this.refresh();
}
}));
this._register(topmostLineMonitor.onDidChanged(event => {
if (this.isPreviewOf(event.resource)) {
this.updateForView(event.resource, event.line);
}
}));
this._register(vscode.window.onDidChangeTextEditorSelection(event => {
if (this.isPreviewOf(event.textEditor.document.uri)) {
this.postMessage({
type: 'onDidChangeTextEditorSelection',
line: event.selections[0].active.line,
source: this.resource.toString()
});
}
}));
this._register(vscode.window.onDidChangeActiveTextEditor(editor => {
if (editor && isMarkdownFile(editor.document) && !this._locked) {
this.update(editor.document.uri, false);
}
}));
this.doUpdate();
this.updatePreview();
}
private readonly _onDisposeEmitter = this._register(new vscode.EventEmitter<void>());
public readonly onDispose = this._onDisposeEmitter.event;
private readonly _onDidChangeViewStateEmitter = this._register(new vscode.EventEmitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
public readonly onDidChangeViewState = this._onDidChangeViewStateEmitter.event;
dispose() {
super.dispose();
this._disposed = true;
clearTimeout(this.throttleTimer);
}
public get resource(): vscode.Uri {
return this._resource;
}
public get resourceColumn(): vscode.ViewColumn {
return this._resourceColumn;
}
public get state() {
return {
resource: this.resource.toString(),
locked: this._locked,
resource: this._resource.toString(),
line: this.line,
resourceColumn: this.resourceColumn,
imageInfo: this.imageInfo,
fragment: this.scrollToFragment
fragment: this.scrollToFragment,
...this.delegate.getAdditionalState(),
};
}
public dispose() {
if (this._disposed) {
return;
}
this._disposed = true;
this._onDisposeEmitter.fire();
this._onDisposeEmitter.dispose();
this.editor.dispose();
super.dispose();
}
public update(resource: vscode.Uri, isRefresh = true) {
// Reposition scroll preview, position scroll to the top if active text editor
// doesn't corresponds with preview
const editor = vscode.window.activeTextEditor;
if (editor) {
if (!isRefresh || this._previewConfigurations.loadAndCacheConfiguration(this._resource).scrollEditorWithPreview) {
if (editor.document.uri.fsPath === resource.fsPath) {
this.line = getVisibleLine(editor);
} else {
this.line = 0;
}
}
}
// If we have changed resources, cancel any pending updates
const isResourceChange = resource.fsPath !== this._resource.fsPath;
if (isResourceChange) {
clearTimeout(this.throttleTimer);
this.throttleTimer = undefined;
}
this._resource = resource;
public refresh() {
// Schedule update if none is pending
if (!this.throttleTimer) {
if (isResourceChange || this.firstUpdate) {
this.doUpdate(isRefresh);
if (this.firstUpdate) {
this.updatePreview(true);
} else {
this.throttleTimer = setTimeout(() => this.doUpdate(isRefresh), this.delay);
this.throttleTimer = setTimeout(() => this.updatePreview(true), this.delay);
}
}
this.firstUpdate = false;
}
public refresh() {
this.update(this._resource, true);
}
public updateConfiguration() {
if (this._previewConfigurations.hasConfigurationChanged(this._resource)) {
this.refresh();
}
}
public get position(): vscode.ViewColumn | undefined {
return this.editor.viewColumn;
}
public matchesResource(
otherResource: vscode.Uri,
otherPosition: vscode.ViewColumn | undefined,
otherLocked: boolean
): boolean {
if (this.position !== otherPosition) {
return false;
}
if (this._locked) {
return otherLocked && this.isPreviewOf(otherResource);
} else {
return !otherLocked;
}
}
public matches(otherPreview: DynamicMarkdownPreview): boolean {
return this.matchesResource(otherPreview._resource, otherPreview.position, otherPreview._locked);
}
public reveal(viewColumn: vscode.ViewColumn) {
this.editor.reveal(viewColumn);
}
public toggleLock() {
this._locked = !this._locked;
this.editor.title = DynamicMarkdownPreview.getPreviewTitle(this._resource, this._locked);
}
private get iconPath() {
const root = path.join(this._contributionProvider.extensionPath, 'media');
return {
@@ -354,18 +234,18 @@ export class DynamicMarkdownPreview extends Disposable {
};
}
private isPreviewOf(resource: vscode.Uri): boolean {
public isPreviewOf(resource: vscode.Uri): boolean {
return this._resource.fsPath === resource.fsPath;
}
private static getPreviewTitle(resource: vscode.Uri, locked: boolean): string {
return locked
? localize('lockedPreviewTitle', '[Preview] {0}', path.basename(resource.fsPath))
: localize('previewTitle', 'Preview {0}', path.basename(resource.fsPath));
public postMessage(msg: any) {
if (!this._disposed) {
this._webviewPanel.webview.postMessage(msg);
}
}
private updateForView(resource: vscode.Uri, topLine: number | undefined) {
if (!this.isPreviewOf(resource)) {
public scrollTo(topLine: number) {
if (this._disposed) {
return;
}
@@ -374,36 +254,26 @@ export class DynamicMarkdownPreview extends Disposable {
return;
}
if (typeof topLine === 'number') {
this._logger.log('updateForView', { markdownFile: resource });
this.line = topLine;
this.postMessage({
type: 'updateView',
line: topLine,
source: resource.toString()
});
}
this._logger.log('updateForView', { markdownFile: this._resource });
this.line = topLine;
this.postMessage({
type: 'updateView',
line: topLine,
source: this._resource.toString()
});
}
private postMessage(msg: any) {
if (!this._disposed) {
this.editor.webview.postMessage(msg);
}
}
private async updatePreview(forceUpdate?: boolean): Promise<void> {
clearTimeout(this.throttleTimer);
this.throttleTimer = undefined;
private async doUpdate(forceUpdate?: boolean): Promise<void> {
if (this._disposed) {
return;
}
const markdownResource = this._resource;
clearTimeout(this.throttleTimer);
this.throttleTimer = undefined;
let document: vscode.TextDocument;
try {
document = await vscode.workspace.openTextDocument(markdownResource);
document = await vscode.workspace.openTextDocument(this._resource);
} catch {
await this.showFileNotFoundError();
return;
@@ -413,61 +283,24 @@ export class DynamicMarkdownPreview extends Disposable {
return;
}
const pendingVersion = new PreviewDocumentVersion(markdownResource, document.version);
const pendingVersion = new PreviewDocumentVersion(document);
if (!forceUpdate && this.currentVersion?.equals(pendingVersion)) {
if (this.line) {
this.updateForView(markdownResource, this.line);
this.scrollTo(this.line);
}
return;
}
this.currentVersion = pendingVersion;
if (this._resource === markdownResource) {
const self = this;
const resourceProvider: WebviewResourceProvider = {
asWebviewUri: (resource) => {
return this.editor.webview.asWebviewUri(normalizeResource(markdownResource, resource));
},
get cspSource() { return self.editor.webview.cspSource; }
};
const content = await this._contentProvider.provideTextDocumentContent(document, resourceProvider, this._previewConfigurations, this.line, this.state);
// Another call to `doUpdate` may have happened.
// Make sure we are still updating for the correct document
if (this.currentVersion && this.currentVersion.equals(pendingVersion)) {
this.setContent(content);
}
const content = await this._contentProvider.provideTextDocumentContent(document, this, this._previewConfigurations, this.line, this.state);
// Another call to `doUpdate` may have happened.
// Make sure we are still updating for the correct document
if (this.currentVersion?.equals(pendingVersion)) {
this.setContent(content);
}
}
private static getWebviewOptions(
resource: vscode.Uri,
contributions: MarkdownContributions
): vscode.WebviewOptions {
return {
enableScripts: true,
localResourceRoots: DynamicMarkdownPreview.getLocalResourceRoots(resource, contributions)
};
}
private static getLocalResourceRoots(
base: vscode.Uri,
contributions: MarkdownContributions
): ReadonlyArray<vscode.Uri> {
const baseRoots = Array.from(contributions.previewResourceRoots);
const folder = vscode.workspace.getWorkspaceFolder(base);
if (folder) {
const workspaceRoots = vscode.workspace.workspaceFolders?.map(folder => folder.uri);
if (workspaceRoots) {
baseRoots.push(...workspaceRoots);
}
} else if (!base.scheme || base.scheme === 'file') {
baseRoots.push(vscode.Uri.file(path.dirname(base.fsPath)));
}
return baseRoots.map(root => normalizeResource(base, root));
}
private onDidScrollPreview(line: number) {
this.line = line;
@@ -513,23 +346,55 @@ export class DynamicMarkdownPreview extends Disposable {
}
private async showFileNotFoundError() {
this.setContent(this._contentProvider.provideFileNotFoundContent(this._resource));
this._webviewPanel.webview.html = this._contentProvider.provideFileNotFoundContent(this._resource);
}
private setContent(html: string): void {
this.editor.title = DynamicMarkdownPreview.getPreviewTitle(this._resource, this._locked);
this.editor.iconPath = this.iconPath;
this.editor.webview.options = DynamicMarkdownPreview.getWebviewOptions(this._resource, this._contributionProvider.contributions);
this.editor.webview.html = html;
if (this._disposed) {
return;
}
if (this.delegate.getTitle) {
this._webviewPanel.title = this.delegate.getTitle(this._resource);
}
this._webviewPanel.iconPath = this.iconPath;
this._webviewPanel.webview.options = this.getWebviewOptions();
this._webviewPanel.webview.html = html;
}
private getWebviewOptions(): vscode.WebviewOptions {
return {
enableScripts: true,
localResourceRoots: this.getLocalResourceRoots()
};
}
private getLocalResourceRoots(): ReadonlyArray<vscode.Uri> {
const baseRoots = Array.from(this._contributionProvider.contributions.previewResourceRoots);
const folder = vscode.workspace.getWorkspaceFolder(this._resource);
if (folder) {
const workspaceRoots = vscode.workspace.workspaceFolders?.map(folder => folder.uri);
if (workspaceRoots) {
baseRoots.push(...workspaceRoots);
}
} else if (!this._resource.scheme || this._resource.scheme === 'file') {
baseRoots.push(vscode.Uri.file(path.dirname(this._resource.fsPath)));
}
return baseRoots.map(root => normalizeResource(this._resource, root));
}
private async onDidClickPreviewLink(href: string) {
let [hrefPath, fragment] = decodeURIComponent(href).split('#');
// We perviously already resolve absolute paths.
// Now make sure we handle relative file paths
if (hrefPath[0] !== '/') {
hrefPath = path.join(path.dirname(this.resource.path), hrefPath);
// Fix #93691, use this.resource.fsPath instead of this.resource.path
hrefPath = path.join(path.dirname(this.resource.fsPath), hrefPath);
}
const config = vscode.workspace.getConfiguration('markdown', this.resource);
@@ -537,14 +402,332 @@ export class DynamicMarkdownPreview extends Disposable {
if (openLinks === 'inPreview') {
const markdownLink = await resolveLinkToMarkdownFile(hrefPath);
if (markdownLink) {
if (fragment) {
this.scrollToFragment = fragment;
}
this.update(markdownLink);
this.delegate.openPreviewLinkToMarkdownFile(markdownLink, fragment);
return;
}
}
vscode.commands.executeCommand('_markdown.openDocumentLink', { path: hrefPath, fragment, fromResource: this.resource });
}
//#region WebviewResourceProvider
asWebviewUri(resource: vscode.Uri) {
return this._webviewPanel.webview.asWebviewUri(normalizeResource(this._resource, resource));
}
get cspSource() {
return this._webviewPanel.webview.cspSource;
}
//#endregion
}
export interface ManagedMarkdownPreview {
readonly resource: vscode.Uri;
readonly resourceColumn: vscode.ViewColumn;
readonly onDispose: vscode.Event<void>;
readonly onDidChangeViewState: vscode.Event<vscode.WebviewPanelOnDidChangeViewStateEvent>;
dispose(): void;
refresh(): void;
updateConfiguration(): void;
matchesResource(
otherResource: vscode.Uri,
otherPosition: vscode.ViewColumn | undefined,
otherLocked: boolean
): boolean;
}
export class StaticMarkdownPreview extends Disposable implements ManagedMarkdownPreview {
public static revive(
resource: vscode.Uri,
webview: vscode.WebviewPanel,
contentProvider: MarkdownContentProvider,
previewConfigurations: MarkdownPreviewConfigurationManager,
logger: Logger,
contributionProvider: MarkdownContributionProvider,
): StaticMarkdownPreview {
return new StaticMarkdownPreview(webview, resource, contentProvider, previewConfigurations, logger, contributionProvider);
}
private readonly preview: MarkdownPreview;
private constructor(
private readonly _webviewPanel: vscode.WebviewPanel,
resource: vscode.Uri,
contentProvider: MarkdownContentProvider,
private readonly _previewConfigurations: MarkdownPreviewConfigurationManager,
logger: Logger,
contributionProvider: MarkdownContributionProvider,
) {
super();
this.preview = this._register(new MarkdownPreview(this._webviewPanel, resource, undefined, {
getAdditionalState: () => { return {}; },
openPreviewLinkToMarkdownFile: () => { /* todo */ }
}, contentProvider, _previewConfigurations, logger, contributionProvider));
this._register(this._webviewPanel.onDidDispose(() => {
this.dispose();
}));
this._register(this._webviewPanel.onDidChangeViewState(e => {
this._onDidChangeViewState.fire(e);
}));
}
private readonly _onDispose = this._register(new vscode.EventEmitter<void>());
public readonly onDispose = this._onDispose.event;
private readonly _onDidChangeViewState = this._register(new vscode.EventEmitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
public readonly onDidChangeViewState = this._onDidChangeViewState.event;
dispose() {
this._onDispose.fire();
super.dispose();
}
public matchesResource(
_otherResource: vscode.Uri,
_otherPosition: vscode.ViewColumn | undefined,
_otherLocked: boolean
): boolean {
return false;
}
public refresh() {
this.preview.refresh();
}
public updateConfiguration() {
if (this._previewConfigurations.hasConfigurationChanged(this.preview.resource)) {
this.refresh();
}
}
public get resource() {
return this.preview.resource;
}
public get resourceColumn() {
return this._webviewPanel.viewColumn || vscode.ViewColumn.One;
}
}
interface DynamicPreviewInput {
readonly resource: vscode.Uri;
readonly resourceColumn: vscode.ViewColumn;
readonly locked: boolean;
readonly line?: number;
}
/**
* A
*/
export class DynamicMarkdownPreview extends Disposable implements ManagedMarkdownPreview {
public static readonly viewType = 'markdown.preview';
private readonly _resourceColumn: vscode.ViewColumn;
private _locked: boolean;
private readonly _webviewPanel: vscode.WebviewPanel;
private _preview: MarkdownPreview;
public static revive(
input: DynamicPreviewInput,
webview: vscode.WebviewPanel,
contentProvider: MarkdownContentProvider,
previewConfigurations: MarkdownPreviewConfigurationManager,
logger: Logger,
topmostLineMonitor: TopmostLineMonitor,
contributionProvider: MarkdownContributionProvider,
): DynamicMarkdownPreview {
return new DynamicMarkdownPreview(webview, input,
contentProvider, previewConfigurations, logger, topmostLineMonitor, contributionProvider);
}
public static create(
input: DynamicPreviewInput,
previewColumn: vscode.ViewColumn,
contentProvider: MarkdownContentProvider,
previewConfigurations: MarkdownPreviewConfigurationManager,
logger: Logger,
topmostLineMonitor: TopmostLineMonitor,
contributionProvider: MarkdownContributionProvider
): DynamicMarkdownPreview {
const webview = vscode.window.createWebviewPanel(
DynamicMarkdownPreview.viewType,
DynamicMarkdownPreview.getPreviewTitle(input.resource, input.locked),
previewColumn, { enableFindWidget: true, });
return new DynamicMarkdownPreview(webview, input,
contentProvider, previewConfigurations, logger, topmostLineMonitor, contributionProvider);
}
private constructor(
webview: vscode.WebviewPanel,
input: DynamicPreviewInput,
private readonly _contentProvider: MarkdownContentProvider,
private readonly _previewConfigurations: MarkdownPreviewConfigurationManager,
private readonly _logger: Logger,
private readonly _topmostLineMonitor: TopmostLineMonitor,
private readonly _contributionProvider: MarkdownContributionProvider,
) {
super();
this._webviewPanel = webview;
this._resourceColumn = input.resourceColumn;
this._locked = input.locked;
this._preview = this.createPreview(input.resource, typeof input.line === 'number' ? new StartingScrollLine(input.line) : undefined);
this._register(webview.onDidDispose(() => { this.dispose(); }));
this._register(this._webviewPanel.onDidChangeViewState(e => {
this._onDidChangeViewStateEmitter.fire(e);
}));
this._register(this._topmostLineMonitor.onDidChanged(event => {
if (this._preview.isPreviewOf(event.resource)) {
this._preview.scrollTo(event.line);
}
}));
this._register(vscode.window.onDidChangeTextEditorSelection(event => {
if (this._preview.isPreviewOf(event.textEditor.document.uri)) {
this._preview.postMessage({
type: 'onDidChangeTextEditorSelection',
line: event.selections[0].active.line,
source: this._preview.resource.toString()
});
}
}));
this._register(vscode.window.onDidChangeActiveTextEditor(editor => {
if (editor && isMarkdownFile(editor.document) && !this._locked && !this._preview.isPreviewOf(editor.document.uri)) {
const line = getVisibleLine(editor);
this.update(editor.document.uri, line ? new StartingScrollLine(line) : undefined);
}
}));
}
private readonly _onDisposeEmitter = this._register(new vscode.EventEmitter<void>());
public readonly onDispose = this._onDisposeEmitter.event;
private readonly _onDidChangeViewStateEmitter = this._register(new vscode.EventEmitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
public readonly onDidChangeViewState = this._onDidChangeViewStateEmitter.event;
dispose() {
this._preview.dispose();
this._webviewPanel.dispose();
this._onDisposeEmitter.fire();
this._onDisposeEmitter.dispose();
super.dispose();
}
public get resource() {
return this._preview.resource;
}
public get resourceColumn() {
return this._resourceColumn;
}
public reveal(viewColumn: vscode.ViewColumn) {
this._webviewPanel.reveal(viewColumn);
}
public refresh() {
this._preview.refresh();
}
public updateConfiguration() {
if (this._previewConfigurations.hasConfigurationChanged(this._preview.resource)) {
this.refresh();
}
}
public update(newResource: vscode.Uri, scrollLocation?: StartingScrollLocation) {
if (this._preview.isPreviewOf(newResource)) {
switch (scrollLocation?.type) {
case 'line':
this._preview.scrollTo(scrollLocation.line);
return;
case 'fragment':
// Workaround. For fragments, just reload the entire preview
break;
default:
return;
}
}
this._preview.dispose();
this._preview = this.createPreview(newResource, scrollLocation);
}
public toggleLock() {
this._locked = !this._locked;
this._webviewPanel.title = DynamicMarkdownPreview.getPreviewTitle(this._preview.resource, this._locked);
}
private static getPreviewTitle(resource: vscode.Uri, locked: boolean): string {
return locked
? localize('lockedPreviewTitle', '[Preview] {0}', path.basename(resource.fsPath))
: localize('previewTitle', 'Preview {0}', path.basename(resource.fsPath));
}
public get position(): vscode.ViewColumn | undefined {
return this._webviewPanel.viewColumn;
}
public matchesResource(
otherResource: vscode.Uri,
otherPosition: vscode.ViewColumn | undefined,
otherLocked: boolean
): boolean {
if (this.position !== otherPosition) {
return false;
}
if (this._locked) {
return otherLocked && this._preview.isPreviewOf(otherResource);
} else {
return !otherLocked;
}
}
public matches(otherPreview: DynamicMarkdownPreview): boolean {
return this.matchesResource(otherPreview._preview.resource, otherPreview.position, otherPreview._locked);
}
private createPreview(resource: vscode.Uri, startingScroll?: StartingScrollLocation): MarkdownPreview {
return new MarkdownPreview(this._webviewPanel, resource, startingScroll, {
getTitle: (resource) => DynamicMarkdownPreview.getPreviewTitle(resource, this._locked),
getAdditionalState: () => {
return {
resourceColumn: this.resourceColumn,
locked: this._locked,
};
},
openPreviewLinkToMarkdownFile: (link: vscode.Uri, fragment?: string) => {
this.update(link, fragment ? new StartingScrollFragment(fragment) : undefined);
}
},
this._contentProvider,
this._previewConfigurations,
this._logger,
this._contributionProvider);
}
}

View File

@@ -8,7 +8,7 @@ import { Logger } from '../logger';
import { MarkdownContributionProvider } from '../markdownExtensions';
import { disposeAll, Disposable } from '../util/dispose';
import { TopmostLineMonitor } from '../util/topmostLineMonitor';
import { DynamicMarkdownPreview } from './preview';
import { DynamicMarkdownPreview, StaticMarkdownPreview, ManagedMarkdownPreview } from './preview';
import { MarkdownPreviewConfigurationManager } from './previewConfig';
import { MarkdownContentProvider } from './previewContentProvider';
@@ -18,9 +18,9 @@ export interface DynamicPreviewSettings {
readonly locked: boolean;
}
class PreviewStore extends Disposable {
class PreviewStore<T extends ManagedMarkdownPreview> extends Disposable {
private readonly _previews = new Set<DynamicMarkdownPreview>();
private readonly _previews = new Set<T>();
public dispose(): void {
super.dispose();
@@ -30,11 +30,11 @@ class PreviewStore extends Disposable {
this._previews.clear();
}
[Symbol.iterator](): Iterator<DynamicMarkdownPreview> {
[Symbol.iterator](): Iterator<T> {
return this._previews[Symbol.iterator]();
}
public get(resource: vscode.Uri, previewSettings: DynamicPreviewSettings): DynamicMarkdownPreview | undefined {
public get(resource: vscode.Uri, previewSettings: DynamicPreviewSettings): T | undefined {
for (const preview of this._previews) {
if (preview.matchesResource(resource, previewSettings.previewColumn, previewSettings.locked)) {
return preview;
@@ -43,11 +43,11 @@ class PreviewStore extends Disposable {
return undefined;
}
public add(preview: DynamicMarkdownPreview) {
public add(preview: T) {
this._previews.add(preview);
}
public delete(preview: DynamicMarkdownPreview) {
public delete(preview: T) {
this._previews.delete(preview);
}
}
@@ -58,10 +58,10 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
private readonly _topmostLineMonitor = new TopmostLineMonitor();
private readonly _previewConfigurations = new MarkdownPreviewConfigurationManager();
private readonly _dynamicPreviews = this._register(new PreviewStore());
private readonly _staticPreviews = this._register(new PreviewStore());
private readonly _dynamicPreviews = this._register(new PreviewStore<DynamicMarkdownPreview>());
private readonly _staticPreviews = this._register(new PreviewStore<StaticMarkdownPreview>());
private _activePreview: DynamicMarkdownPreview | undefined = undefined;
private _activePreview: ManagedMarkdownPreview | undefined = undefined;
private readonly customEditorViewType = 'vscode.markdown.preview.editor';
@@ -117,7 +117,7 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
public toggleLock() {
const preview = this._activePreview;
if (preview) {
if (preview instanceof DynamicMarkdownPreview) {
preview.toggleLock();
// Close any previews that are now redundant, such as having two dynamic previews in the same editor group
@@ -133,6 +133,7 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
webview: vscode.WebviewPanel,
state: any
): Promise<void> {
console.log(state);
const resource = vscode.Uri.parse(state.resource);
const locked = state.locked;
const line = state.line;
@@ -150,21 +151,16 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
this.registerDynamicPreview(preview);
}
public async openCustomDocument(uri: vscode.Uri) {
return new vscode.CustomDocument(uri);
}
public async resolveCustomTextEditor(
document: vscode.TextDocument,
webview: vscode.WebviewPanel
): Promise<void> {
const preview = DynamicMarkdownPreview.revive(
{ resource: document.uri, locked: false, resourceColumn: vscode.ViewColumn.One },
const preview = StaticMarkdownPreview.revive(
document.uri,
webview,
this._contentProvider,
this._previewConfigurations,
this._logger,
this._topmostLineMonitor,
this._contributions);
this.registerStaticPreview(preview);
}
@@ -207,7 +203,7 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
return preview;
}
private registerStaticPreview(preview: DynamicMarkdownPreview): DynamicMarkdownPreview {
private registerStaticPreview(preview: StaticMarkdownPreview): StaticMarkdownPreview {
this._staticPreviews.add(preview);
preview.onDispose(() => {
@@ -218,7 +214,7 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
return preview;
}
private trackActive(preview: DynamicMarkdownPreview): void {
private trackActive(preview: ManagedMarkdownPreview): void {
preview.onDidChangeViewState(({ webviewPanel }) => {
this.setPreviewActiveContext(webviewPanel.active);
this._activePreview = webviewPanel.active ? preview : undefined;

View File

@@ -10,7 +10,7 @@ import * as vscode from 'vscode';
import { MarkdownContributionProvider as MarkdownContributionProvider } from './markdownExtensions';
import { Slugifier } from './slugify';
import { SkinnyTextDocument } from './tableOfContentsProvider';
import { Schemes, isOfScheme } from './util/links';
import { MarkdownFileExtensions, Schemes, isOfScheme } from './util/links';
const UNICODE_NEWLINE_REGEX = /\u2028|\u2029/g;
@@ -258,7 +258,9 @@ export class MarkdownEngine {
}
}
if (uri.fragment) {
const extname = path.extname(uri.fsPath);
if (uri.fragment && (extname === '' || MarkdownFileExtensions.includes(extname))) {
uri = uri.with({
fragment: this.slugifier.fromHeading(uri.fragment).value
});

View File

@@ -32,3 +32,15 @@ export function getUriForLinkWithKnownExternalScheme(link: string): vscode.Uri |
export function isOfScheme(scheme: string, link: string): boolean {
return link.toLowerCase().startsWith(scheme);
}
export const MarkdownFileExtensions: readonly string[] = [
'.md',
'.mkd',
'.mdwn',
'.mdown',
'.markdown',
'.markdn',
'.mdtxt',
'.mdtext',
'.workbook',
];

View File

@@ -138,7 +138,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
@debounce(1500)
async fireBookRefresh(book: BookModel): Promise<void> {
await book.initializeContents().then(() => {
this._onDidChangeTreeData.fire();
this._onDidChangeTreeData.fire(undefined);
});
}
@@ -154,7 +154,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
if (this.currentBook === deletedBook) {
this.currentBook = this.books.length > 0 ? this.books[this.books.length - 1] : undefined;
}
this._onDidChangeTreeData.fire();
this._onDidChangeTreeData.fire(undefined);
}
} catch (e) {
vscode.window.showErrorMessage(loc.closeBookError(book.root, e instanceof Error ? e.message : e));
@@ -313,7 +313,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
if (untitledBookIndex > -1) {
this.books.splice(untitledBookIndex, 1);
this.currentBook = undefined;
this._onDidChangeTreeData.fire();
this._onDidChangeTreeData.fire(undefined);
vscode.commands.executeCommand('bookTreeView.openBook', destinationUri.fsPath, false, undefined);
}
}

View File

@@ -12,6 +12,7 @@ export class MockExtensionContext implements vscode.ExtensionContext {
workspaceState: vscode.Memento;
globalState: vscode.Memento;
extensionPath: string;
extensionUri: vscode.Uri;
asAbsolutePath(relativePath: string): string {
return relativePath;
}

View File

@@ -70,7 +70,7 @@ describe('Manage Package Dialog', () => {
displayName: 'dl2',
name: 'nl2'
};
testContext.onClick.fire();
testContext.onClick.fire(undefined);
testContext.dialog.verify(x => x.changeLocation('nl2'), TypeMoq.Times.once());
testContext.dialog.verify(x => x.resetPages(), TypeMoq.Times.once());
@@ -100,7 +100,7 @@ describe('Manage Package Dialog', () => {
displayName: 'dl2',
name: 'nl2'
};
testContext.onClick.fire();
testContext.onClick.fire(undefined);
testContext.dialog.verify(x => x.changeLocation('nl2'), TypeMoq.Times.once());
testContext.dialog.verify(x => x.showErrorMessage(TypeMoq.It.isAny()), TypeMoq.Times.once());

View File

@@ -12,6 +12,8 @@
["{", "}"],
["[", "]"],
["(", ")"],
{ "open": "@'", "close": "\n'@", "notIn": ["string", "comment"]},
{ "open": "@\"", "close": "\n\"@", "notIn": ["string", "comment"]},
{ "open": "\"", "close": "\"", "notIn": ["string"]},
{ "open": "'", "close": "'", "notIn": ["string", "comment"]},
["<#", "#>"]
@@ -29,4 +31,4 @@
"end": "^\\s*#[eE]nd[rR]egion\\b"
}
}
}
}

View File

@@ -21,7 +21,7 @@
}],
"snippets": [{
"language": "powershell",
"path": "./snippets/powershell.json"
"path": "./snippets/powershell.code-snippets"
}]
},
"scripts": {

View File

@@ -56,6 +56,6 @@ export class SqlDatabaseProjectTreeViewProvider implements vscode.TreeDataProvid
}
this.roots = newRoots;
this._onDidChangeTreeData.fire();
this._onDidChangeTreeData.fire(undefined);
}
}

View File

@@ -17,7 +17,9 @@
"menu.background": "#252526",
"menu.foreground": "#CCCCCC",
"statusBarItem.remoteForeground": "#FFF",
"statusBarItem.remoteBackground": "#16825D"
"statusBarItem.remoteBackground": "#16825D",
"sideBarSectionHeader.background": "#0000",
"sideBarSectionHeader.border": "#ccc3"
},
"semanticHighlighting": true
}

View File

@@ -97,6 +97,16 @@
"foreground": "#9CDCFE"
}
},
{
"name": "Constants and enums",
"scope": [
"variable.other.constant",
"variable.other.enummember"
],
"settings": {
"foreground": "#D4D4D4",
}
},
{
"name": "Object keys, TS grammar specific",
"scope": [

View File

@@ -17,7 +17,9 @@
"settings.textInputBorder": "#CECECE",
"settings.numberInputBorder": "#CECECE",
"statusBarItem.remoteForeground": "#FFF",
"statusBarItem.remoteBackground": "#16825D"
"statusBarItem.remoteBackground": "#16825D",
"sideBarSectionHeader.background": "#0000",
"sideBarSectionHeader.border": "#61616130"
},
"semanticHighlighting": true
}

View File

@@ -97,6 +97,16 @@
"foreground": "#001080"
}
},
{
"name": "Constants and enums",
"scope": [
"variable.other.constant",
"variable.other.enummember"
],
"settings": {
"foreground": "#000000",
}
},
{
"name": "Object keys, TS grammar specific",
"scope": [

View File

@@ -14,6 +14,7 @@
"activationEvents": [
"*"
],
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"main": "./out/extension.js",
"contributes": {
"commands": [
@@ -56,6 +57,7 @@
},
"dependencies": {
"uuid": "^3.3.3",
"vscode-extension-telemetry": "0.1.1",
"vscode-nls": "^4.1.1"
}
}

View File

@@ -25,7 +25,10 @@ interface IToken {
expiresAt?: number; // UNIX epoch time at which token will expire
refreshToken: string;
accountName: string;
account: {
displayName: string;
id: string;
};
scope: string;
sessionId: string; // The account id + the scope
}
@@ -44,7 +47,10 @@ interface IStoredSession {
id: string;
refreshToken: string;
scope: string; // Scopes are alphabetized and joined with a space
accountName: string;
account: {
displayName: string,
id: string
}
}
function parseQuery(uri: vscode.Uri) {
@@ -76,6 +82,9 @@ export class AzureActiveDirectoryService {
}
public async initialize(): Promise<void> {
// TODO remove, temporary migration
await keychain.migrateToken();
const storedData = await keychain.getToken();
if (storedData) {
try {
@@ -90,7 +99,10 @@ export class AzureActiveDirectoryService {
this._tokens.push({
accessToken: undefined,
refreshToken: session.refreshToken,
accountName: session.accountName,
account: {
displayName: session.account.displayName,
id: session.account.id
},
scope: session.scope,
sessionId: session.id
});
@@ -122,7 +134,7 @@ export class AzureActiveDirectoryService {
id: token.sessionId,
refreshToken: token.refreshToken,
scope: token.scope,
accountName: token.accountName
account: token.account
};
});
@@ -196,7 +208,7 @@ export class AzureActiveDirectoryService {
return {
id: token.sessionId,
getAccessToken: () => this.resolveAccessToken(token),
accountName: token.accountName,
account: token.account,
scopes: token.scope.split(' ')
};
}
@@ -220,8 +232,6 @@ export class AzureActiveDirectoryService {
} catch (e) {
throw new Error('Unavailable due to network problems');
}
throw new Error('Unavailable due to network problems');
}
private getTokenClaims(accessToken: string): ITokenClaims {
@@ -416,7 +426,10 @@ export class AzureActiveDirectoryService {
refreshToken: json.refresh_token,
scope,
sessionId: existingId || `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}/${uuid()}`,
accountName: claims.email || claims.unique_name || 'user@example.com'
account: {
displayName: claims.email || claims.unique_name || 'user@example.com',
id: `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}`
}
};
}

View File

@@ -6,12 +6,15 @@
import * as vscode from 'vscode';
import { AzureActiveDirectoryService, onDidChangeSessions } from './AADHelper';
import * as nls from 'vscode-nls';
import TelemetryReporter from 'vscode-extension-telemetry';
const localize = nls.loadMessageBundle();
export const DEFAULT_SCOPES = 'https://management.core.windows.net/.default offline_access';
export async function activate(context: vscode.ExtensionContext) {
const { name, version, aiKey } = require('../package.json') as { name: string, version: string, aiKey: string };
const telemetryReporter = new TelemetryReporter(name, version, aiKey);
const loginService = new AzureActiveDirectoryService();
@@ -24,18 +27,24 @@ export async function activate(context: vscode.ExtensionContext) {
getSessions: () => Promise.resolve(loginService.sessions),
login: async (scopes: string[]) => {
try {
telemetryReporter.sendTelemetryEvent('login');
await loginService.login(scopes.sort().join(' '));
const session = loginService.sessions[loginService.sessions.length - 1];
onDidChangeSessions.fire({ added: [session.id], removed: [], changed: [] });
return loginService.sessions[0]!;
} catch (e) {
telemetryReporter.sendTelemetryEvent('loginFailed');
throw e;
}
},
logout: async (id: string) => {
await loginService.logout(id);
onDidChangeSessions.fire({ added: [], removed: [id], changed: [] });
vscode.window.showInformationMessage(localize('signedOut', "Successfully signed out."));
try {
telemetryReporter.sendTelemetryEvent('logout');
await loginService.logout(id);
onDidChangeSessions.fire({ added: [], removed: [id], changed: [] });
} catch (e) {
telemetryReporter.sendTelemetryEvent('logoutFailed');
}
}
}));
@@ -60,7 +69,7 @@ export async function activate(context: vscode.ExtensionContext) {
const selectedSession = await vscode.window.showQuickPick(sessions.map(session => {
return {
id: session.id,
label: session.accountName
label: session.account.displayName
};
}));

View File

@@ -28,7 +28,7 @@ export type Keytar = {
deletePassword: typeof keytarType['deletePassword'];
};
const SERVICE_ID = `${vscode.env.uriScheme}-vscode.login`;
const SERVICE_ID = `${vscode.env.uriScheme}-microsoft.login`;
const ACCOUNT_ID = 'account';
export class Keychain {
@@ -43,13 +43,38 @@ export class Keychain {
this.keytar = keytar;
}
// TODO remove, temporary migration
async migrateToken(): Promise<void> {
const oldServiceId = `${vscode.env.uriScheme}-vscode.login`;
try {
const data = await this.keytar.getPassword(oldServiceId, ACCOUNT_ID);
if (data) {
Logger.info('Migrating token...');
this.setToken(data);
await this.keytar.deletePassword(oldServiceId, ACCOUNT_ID);
Logger.info('Migration successful');
}
} catch (e) {
Logger.error(`Migrating token failed: ${e}`);
}
}
async setToken(token: string): Promise<void> {
try {
Logger.trace('Writing to keychain', token);
return await this.keytar.setPassword(SERVICE_ID, ACCOUNT_ID, token);
} catch (e) {
// Ignore
Logger.error(`Setting token failed: ${e}`);
// Temporary fix for #94005
// This happens when processes write simulatenously to the keychain, most
// likely when trying to refresh the token. Ignore the error since additional
// writes after the first one do not matter. Should actually be fixed upstream.
if (e.message === 'The specified item already exists in the keychain.') {
return;
}
const troubleshooting = localize('troubleshooting', "Troubleshooting Guide");
const result = await vscode.window.showErrorMessage(localize('keychainWriteError', "Writing login information to the keychain failed with error '{0}'.", e.message), troubleshooting);
if (result === troubleshooting) {

View File

@@ -17,7 +17,7 @@ class Log {
private level: Level;
constructor() {
this.output = vscode.window.createOutputChannel('Account');
this.output = vscode.window.createOutputChannel('Microsoft Authentication');
this.level = vscode.workspace.getConfiguration('microsoftAccount').get('logLevel') || Level.Info;
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('microsoftAccount.logLevel')) {

View File

@@ -52,6 +52,15 @@ ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
applicationinsights@1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5"
integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg==
dependencies:
diagnostic-channel "0.2.0"
diagnostic-channel-publishers "0.2.1"
zone.js "0.7.6"
aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@@ -170,6 +179,18 @@ detect-libc@^1.0.3:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
diagnostic-channel-publishers@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM=
diagnostic-channel@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17"
integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=
dependencies:
semver "^5.3.0"
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
@@ -645,6 +666,13 @@ uuid@^3.3.3:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
vscode-extension-telemetry@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b"
integrity sha512-TkKKG/B/J94DP5qf6xWB4YaqlhWDg6zbbqVx7Bz//stLQNnfE9XS1xm3f6fl24c5+bnEK0/wHgMgZYKIKxPeUA==
dependencies:
applicationinsights "1.0.8"
vscode-nls@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"
@@ -666,3 +694,8 @@ wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
zone.js@0.7.6:
version "0.7.6"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=

View File

@@ -15,6 +15,9 @@
"postinstall": "node build/npm/postinstall.js",
"compile": "gulp compile --max_old_space_size=4095",
"watch": "gulp watch --max_old_space_size=4095",
"watchd": "deemon yarn watch",
"kill-watchd": "deemon --kill yarn watch",
"restart-watchd": "deemon --restart yarn watch",
"watch-client": "gulp watch-client --max_old_space_size=4095",
"mocha": "mocha test/unit/node/all.js --delay",
"precommit": "node build/gulpfile.hygiene.js",
@@ -56,19 +59,19 @@
"iconv-lite": "0.5.0",
"jquery": "3.4.0",
"jschardet": "2.1.1",
"keytar": "github:rmacfarlane/node-keytar#334424bd26414923782f144110f4beda19168d24",
"keytar": "^5.5.0",
"minimist": "^1.2.5",
"native-is-elevated": "0.4.1",
"native-keymap": "2.1.1",
"native-watchdog": "1.3.0",
"ng2-charts": "^1.6.0",
"node-pty": "0.10.0-beta7",
"node-pty": "0.10.0-beta8",
"onigasm-umd": "2.2.5",
"plotly.js-dist-min": "^1.53.0",
"reflect-metadata": "^0.1.8",
"rxjs": "5.4.0",
"sanitize-html": "^1.19.1",
"semver-umd": "^5.5.5",
"semver-umd": "^5.5.6",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"spdlog": "^0.11.1",
"sudo-prompt": "9.1.1",
@@ -76,13 +79,13 @@
"vscode-nsfw": "1.2.8",
"vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.8",
"vscode-sqlite3": "4.0.9",
"vscode-sqlite3": "4.0.10",
"vscode-textmate": "4.4.0",
"xterm": "4.5.0-beta.4",
"xterm-addon-search": "0.5.0",
"xterm-addon-unicode11": "0.1.1",
"xterm-addon-web-links": "0.2.1",
"xterm-addon-webgl": "0.5.0",
"xterm": "4.6.0-beta.15",
"xterm-addon-search": "0.6.0",
"xterm-addon-unicode11": "0.2.0-beta.2",
"xterm-addon-web-links": "0.3.0",
"xterm-addon-webgl": "0.7.0-beta.6",
"yauzl": "^2.9.2",
"yazl": "^2.4.3",
"zone.js": "^0.8.4"
@@ -122,7 +125,8 @@
"cson-parser": "^1.3.3",
"css-loader": "^3.2.0",
"debounce": "^1.0.0",
"electron": "7.1.11",
"deemon": "^1.4.0",
"electron": "7.2.2",
"eslint": "6.8.0",
"eslint-plugin-jsdoc": "^19.1.0",
"event-stream": "3.3.4",
@@ -179,7 +183,7 @@
"temp-write": "^3.4.0",
"ts-loader": "^4.4.2",
"typemoq": "^0.3.2",
"typescript": "^3.9.0-dev.20200327",
"typescript": "^3.9.0-dev.20200420",
"typescript-formatter": "7.1.0",
"underscore": "^1.8.2",
"vinyl": "^2.0.0",

View File

@@ -26,23 +26,23 @@
"minimist": "^1.2.5",
"native-watchdog": "1.3.0",
"ng2-charts": "^1.6.0",
"node-pty": "0.10.0-beta7",
"node-pty": "0.10.0-beta8",
"onigasm-umd": "2.2.5",
"reflect-metadata": "^0.1.8",
"rxjs": "5.4.0",
"sanitize-html": "^1.19.1",
"semver-umd": "^5.5.5",
"semver-umd": "^5.5.6",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"spdlog": "^0.11.1",
"vscode-nsfw": "1.2.8",
"vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.8",
"vscode-textmate": "4.4.0",
"xterm": "4.5.0-beta.4",
"xterm-addon-search": "0.5.0",
"xterm-addon-unicode11": "0.1.1",
"xterm-addon-web-links": "0.2.1",
"xterm-addon-webgl": "0.5.0",
"xterm": "4.6.0-beta.15",
"xterm-addon-search": "0.6.0",
"xterm-addon-unicode11": "0.2.0-beta.2",
"xterm-addon-web-links": "0.3.0",
"xterm-addon-webgl": "0.7.0-beta.6",
"yauzl": "^2.9.2",
"yazl": "^2.4.3",
"zone.js": "^0.8.4"

View File

@@ -20,14 +20,14 @@
"reflect-metadata": "^0.1.8",
"rxjs": "5.4.0",
"sanitize-html": "^1.19.1",
"semver-umd": "^5.5.5",
"semver-umd": "^5.5.6",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"vscode-textmate": "4.4.0",
"xterm": "4.5.0-beta.4",
"xterm-addon-search": "0.5.0",
"xterm-addon-unicode11": "0.1.1",
"xterm-addon-web-links": "0.2.1",
"xterm-addon-webgl": "0.5.0",
"xterm": "4.6.0-beta.15",
"xterm-addon-search": "0.6.0",
"xterm-addon-unicode11": "0.2.0-beta.2",
"xterm-addon-web-links": "0.3.0",
"xterm-addon-webgl": "0.7.0-beta.6",
"zone.js": "^0.8.4"
}
}

View File

@@ -302,10 +302,10 @@ sanitize-html@^1.19.1:
srcset "^1.0.0"
xtend "^4.0.1"
semver-umd@^5.5.5:
version "5.5.5"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.5.tgz#a2e4280d0e92a2b27695c18811f0e939e144d86f"
integrity sha512-8rUq0nnTzlexpAdYmm8UDYsLkBn0MnBkfrGWPmyDBDDzv71dPOH07szOOaLj/5hO3BYmumYwS+wp3C60zLzh5g==
semver-umd@^5.5.6:
version "5.5.6"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.6.tgz#1d185bbd2caec825c564b54907cd09e14083f228"
integrity sha512-6ARYXVi4Y4VO5HfyCjT/6xyykBtJwEXSGQ8ON4UPQSFOjZUDsbAE0J614QcBBsLTTyQMEqvsXN804vAqpydjzw==
"slickgrid@github:anthonydresser/SlickGrid#2.3.33":
version "2.3.33"
@@ -367,30 +367,30 @@ xtend@^4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
xterm-addon-search@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.5.0.tgz#cd3a2f8056084c28e236d4e732da37682010bcc2"
integrity sha512-zLVqVTrg5w2nk9fRj3UuVKCPo/dmFe/cLf3EM9Is5Dm6cgOoXmeo9eq2KgD8A0gquAflTFTf0ya2NaFmShHwyg==
xterm-addon-search@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.6.0.tgz#542cc2c35e83e7332ce1982b65ad218ee769836c"
integrity sha512-k3EsZzUptCXygHFP5rQuCBdWWkI/ZNuX3pDSOVdxPV9jB7U5Aha9guTIZoMP7FIjL8jce+ClQs6q7VINcRV1+w==
xterm-addon-unicode11@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.1.1.tgz#b209ef137db38096f68636af4ef4d0c0acba85ad"
integrity sha512-z6vJTL+dpNljwAYzYoyDjJP8A2XjZuEosl0sRa+FGRf3jEyEVWquDM53MfUd1ztVdAPQ839qR6eYK1BXV04Bhw==
xterm-addon-unicode11@0.2.0-beta.2:
version "0.2.0-beta.2"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0-beta.2.tgz#2a13ba5b08fdb1005be241816c4e3302674db4af"
integrity sha512-Y047mnIWrAj65TpStdyPYoPeDTX4en+XX4Y90KuQB3cW2xIyZj25NSVV9BZdqzSb7gk9M6KBvIcm8chj7S2N8Q==
xterm-addon-web-links@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2"
integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ==
xterm-addon-web-links@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.3.0.tgz#88affe9235c928b41bab660a65330f46d91c940e"
integrity sha512-vGXiIDqNMyxK5S1IzOjDqcgeQrrv7TDcSHiOeCNAoWCI2f+Rap9d18gjgnMKPyR+AbG0KoKnaKA6Dc1du1vs5A==
xterm-addon-webgl@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0.tgz#c1031dc7599cce3509824643ab5f15361c928e3e"
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
xterm-addon-webgl@0.7.0-beta.6:
version "0.7.0-beta.6"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.6.tgz#340d728bae7456a1d67a7cb8996dfd51d96721b0"
integrity sha512-IoR0hPtG5qBrcLG1B7GSzo4W2hYocP8UgG5LlyXkEkT/0BqVcGnICgR8Ck7EfMmU8ci4jNFiHYjK/Bgc4m2S4g==
xterm@4.5.0-beta.4:
version "4.5.0-beta.4"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.5.0-beta.4.tgz#701f05553b643236d3fcd8bb7f14045bd4537c92"
integrity sha512-Yv1Bf60LTLBMaig1rv033hPz8hQGXZN6VYW2oe/409t2NbJXPg5xZgf47qyaWFV7a5k1BFiwjayJCWaL2nYBew==
xterm@4.6.0-beta.15:
version "4.6.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.15.tgz#93a0cb1ff047a452b03070499e2ccd0ba53e0678"
integrity sha512-5G+3QSM/GKN/Tdq/IIU7FDivzh0eXsv3sNmZFDdtvNggnu2K56l4N5P0KZo0HdFztDfTyW/FLfqsPAwhrK4Khg==
zone.js@^0.8.4:
version "0.8.29"

View File

@@ -498,10 +498,10 @@ node-addon-api@1.6.2:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217"
integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA==
node-pty@0.10.0-beta7:
version "0.10.0-beta7"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta7.tgz#7e383b2d1fe2f34509b57187f5a9a6ff90c46111"
integrity sha512-oC2VyIz9YaIvv6lWjAPZbUzmhLW1ouFmxOogNRNQrKeUzUi2yM/QRmybs+dW/Mhd3V89Yh61Ml0J5yuWiMIBbw==
node-pty@0.10.0-beta8:
version "0.10.0-beta8"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0-beta8.tgz#f4aa56c71a794f4580373a3030dfebd25240c6db"
integrity sha512-Ul/hLsadC0SvvShxpne+kq2ebSMcitewlNhrwoXXBvFdCqxJt7Ai1AgMhH7AKBUp06uBeYXThJ2ihTszrkdnYw==
dependencies:
nan "^2.14.0"
@@ -600,10 +600,10 @@ sanitize-html@^1.19.1:
srcset "^1.0.0"
xtend "^4.0.1"
semver-umd@^5.5.5:
version "5.5.5"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.5.tgz#a2e4280d0e92a2b27695c18811f0e939e144d86f"
integrity sha512-8rUq0nnTzlexpAdYmm8UDYsLkBn0MnBkfrGWPmyDBDDzv71dPOH07szOOaLj/5hO3BYmumYwS+wp3C60zLzh5g==
semver-umd@^5.5.6:
version "5.5.6"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.6.tgz#1d185bbd2caec825c564b54907cd09e14083f228"
integrity sha512-6ARYXVi4Y4VO5HfyCjT/6xyykBtJwEXSGQ8ON4UPQSFOjZUDsbAE0J614QcBBsLTTyQMEqvsXN804vAqpydjzw==
semver@^5.3.0:
version "5.6.0"
@@ -749,30 +749,30 @@ xtend@^4.0.1:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
xterm-addon-search@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.5.0.tgz#cd3a2f8056084c28e236d4e732da37682010bcc2"
integrity sha512-zLVqVTrg5w2nk9fRj3UuVKCPo/dmFe/cLf3EM9Is5Dm6cgOoXmeo9eq2KgD8A0gquAflTFTf0ya2NaFmShHwyg==
xterm-addon-search@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.6.0.tgz#542cc2c35e83e7332ce1982b65ad218ee769836c"
integrity sha512-k3EsZzUptCXygHFP5rQuCBdWWkI/ZNuX3pDSOVdxPV9jB7U5Aha9guTIZoMP7FIjL8jce+ClQs6q7VINcRV1+w==
xterm-addon-unicode11@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.1.1.tgz#b209ef137db38096f68636af4ef4d0c0acba85ad"
integrity sha512-z6vJTL+dpNljwAYzYoyDjJP8A2XjZuEosl0sRa+FGRf3jEyEVWquDM53MfUd1ztVdAPQ839qR6eYK1BXV04Bhw==
xterm-addon-unicode11@0.2.0-beta.2:
version "0.2.0-beta.2"
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0-beta.2.tgz#2a13ba5b08fdb1005be241816c4e3302674db4af"
integrity sha512-Y047mnIWrAj65TpStdyPYoPeDTX4en+XX4Y90KuQB3cW2xIyZj25NSVV9BZdqzSb7gk9M6KBvIcm8chj7S2N8Q==
xterm-addon-web-links@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2"
integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ==
xterm-addon-web-links@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.3.0.tgz#88affe9235c928b41bab660a65330f46d91c940e"
integrity sha512-vGXiIDqNMyxK5S1IzOjDqcgeQrrv7TDcSHiOeCNAoWCI2f+Rap9d18gjgnMKPyR+AbG0KoKnaKA6Dc1du1vs5A==
xterm-addon-webgl@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0.tgz#c1031dc7599cce3509824643ab5f15361c928e3e"
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
xterm-addon-webgl@0.7.0-beta.6:
version "0.7.0-beta.6"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.6.tgz#340d728bae7456a1d67a7cb8996dfd51d96721b0"
integrity sha512-IoR0hPtG5qBrcLG1B7GSzo4W2hYocP8UgG5LlyXkEkT/0BqVcGnICgR8Ck7EfMmU8ci4jNFiHYjK/Bgc4m2S4g==
xterm@4.5.0-beta.4:
version "4.5.0-beta.4"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.5.0-beta.4.tgz#701f05553b643236d3fcd8bb7f14045bd4537c92"
integrity sha512-Yv1Bf60LTLBMaig1rv033hPz8hQGXZN6VYW2oe/409t2NbJXPg5xZgf47qyaWFV7a5k1BFiwjayJCWaL2nYBew==
xterm@4.6.0-beta.15:
version "4.6.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.15.tgz#93a0cb1ff047a452b03070499e2ccd0ba53e0678"
integrity sha512-5G+3QSM/GKN/Tdq/IIU7FDivzh0eXsv3sNmZFDdtvNggnu2K56l4N5P0KZo0HdFztDfTyW/FLfqsPAwhrK4Khg==
yauzl@^2.9.2:
version "2.10.0"

View File

@@ -30,7 +30,8 @@ if not exist out yarn compile
set ELECTRON_RUN_AS_NODE=1
set NODE_ENV=development
set VSCODE_DEV=1
set ELECTRON_DEFAULT_ERROR_MODE=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
set ELECTRON_ENABLE_LOGGING=1
set ELECTRON_ENABLE_STACK_DUMPING=1

View File

@@ -39,6 +39,7 @@ function code() {
ELECTRON_RUN_AS_NODE=1 \
NODE_ENV=development \
VSCODE_DEV=1 \
ELECTRON_ENABLE_SECURITY_WARNINGS=1 \
ELECTRON_ENABLE_LOGGING=1 \
ELECTRON_ENABLE_STACK_DUMPING=1 \
"$CODE" --inspect=5874 "$ROOT/out/cli.js" . "$@"

View File

@@ -28,8 +28,9 @@ if not exist out yarn compile
:: Configuration
set NODE_ENV=development
set VSCODE_DEV=1
set ELECTRON_ENABLE_SECURITY_WARNINGS=1
set VSCODE_CLI=1
set ELECTRON_DEFAULT_ERROR_MODE=1
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_STACK_DUMPING=1
set VSCODE_LOGS=

View File

@@ -44,6 +44,7 @@ function code() {
# Configuration
export NODE_ENV=development
export VSCODE_DEV=1
export ELECTRON_ENABLE_SECURITY_WARNINGS=1
export VSCODE_CLI=1
export ELECTRON_ENABLE_STACK_DUMPING=1
export ELECTRON_ENABLE_LOGGING=1

View File

@@ -27,7 +27,7 @@ import { URI } from 'vs/base/common/uri';
import { dirname, basename } from 'vs/base/common/resources';
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
import { FileKind } from 'vs/platform/files/common/files';
import { WorkbenchAsyncDataTree, ResourceNavigator } from 'vs/platform/list/browser/listService';
import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
import { localize } from 'vs/nls';
import { timeout } from 'vs/base/common/async';
import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
@@ -416,9 +416,9 @@ export class CustomTreeView extends Disposable implements ITreeView {
accessibilityProvider: {
getAriaLabel(element: ITreeItem): string {
return element.label ? element.label.label : '';
}
},
getWidgetAriaLabel: () => this.title
},
ariaLabel: this.title,
keyboardNavigationLabelProvider: {
getKeyboardNavigationLabel: (item: ITreeItem) => {
return item.label ? item.label.label : (item.resourceUri ? basename(URI.revive(item.resourceUri)) : undefined);
@@ -451,7 +451,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
}));
this.tree.setInput(this.root).then(() => this.updateContentAreas());
const customTreeNavigator = ResourceNavigator.createTreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
const customTreeNavigator = new TreeResourceNavigator(this.tree, { openOnFocus: false, openOnSelection: false });
this._register(customTreeNavigator);
this._register(customTreeNavigator.onDidOpenResource(e => {
if (!e.browserEvent) {

View File

@@ -28,7 +28,8 @@ class AccountsStatusBarContributions extends Disposable implements IWorkbenchCon
this._register(
this.statusbarService.addEntry({
command: 'workbench.actions.modal.linkedAccount',
text: '$(person-filled)'
text: '$(person-filled)',
ariaLabel: 'Accounts'
},
'status.accountList',
localize('status.problems', "Problems"),

View File

@@ -30,6 +30,7 @@ export class ConnectionStatusbarItem extends Disposable implements IWorkbenchCon
this.statusItem = this._register(
this.statusbarService.addEntry({
text: '',
ariaLabel: ''
},
ConnectionStatusbarItem.ID,
localize('status.connection.status', "Connection Status"),
@@ -84,7 +85,7 @@ export class ConnectionStatusbarItem extends Disposable implements IWorkbenchCon
}
this.statusItem.update({
text, tooltip
text, ariaLabel: text, tooltip
});
}
}

View File

@@ -105,7 +105,7 @@ export class DataExplorerViewPaneContainer extends ViewPaneContainer {
@IContextKeyService private contextKeyService: IContextKeyService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService
) {
super(VIEWLET_ID, `${VIEWLET_ID}.state`, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
super(VIEWLET_ID, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
}
create(parent: HTMLElement): void {

View File

@@ -88,11 +88,13 @@ export class EditDataEditor extends BaseEditor {
}
if (_editorService) {
_editorService.overrideOpenEditor((editor, options, group) => {
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
this.saveEditorViewState();
_editorService.overrideOpenEditor({
open: (editor, options, group) => {
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
this.saveEditorViewState();
}
return {};
}
return {};
});
}
}

View File

@@ -27,7 +27,9 @@ export class EditorReplacementContribution implements IWorkbenchContribution {
@IEditorService private readonly editorService: IEditorService,
@IModeService private readonly modeService: IModeService
) {
this.editorOpeningListener = this.editorService.overrideOpenEditor((editor, options, group) => this.onEditorOpening(editor, options, group));
this.editorOpeningListener = this.editorService.overrideOpenEditor({
open: (editor, options, group) => this.onEditorOpening(editor, options, group)
});
}
private onEditorOpening(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): IOpenEditorOverride | undefined {

View File

@@ -194,7 +194,7 @@ class MockEditorService extends TestEditorService {
fireOpenEditor(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup) {
for (const handler of this.overridenOpens) {
let response: IOpenEditorOverride | undefined;
if (response = handler(editor, options, group)) {
if (response = handler.open(editor, options, group)) {
return response;
}
}

View File

@@ -0,0 +1,140 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
import { IProductService } from 'vs/platform/product/common/productService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { localize } from 'vs/nls';
import { IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { visualizerExtensions } from 'sql/workbench/contrib/extensions/common/constants';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
import { InstallRecommendedExtensionsByScenarioAction, ShowRecommendedExtensionsByScenarioAction } from 'sql/workbench/contrib/extensions/browser/extensionsActions';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
const choiceNever = localize('neverShowAgain', "Don't Show Again");
export class ScenarioRecommendations extends ExtensionRecommendations {
readonly _recommendations: ExtensionRecommendation[] = [];
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
constructor(
isExtensionAllowedToBeRecommended: (extensionId: string) => boolean,
@IProductService private readonly productService: IProductService,
@IInstantiationService instantiationService: IInstantiationService,
@IConfigurationService configurationService: IConfigurationService,
@INotificationService notificationService: INotificationService,
@ITelemetryService telemetryService: ITelemetryService,
@IStorageService storageService: IStorageService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IAdsTelemetryService private readonly adsTelemetryService: IAdsTelemetryService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
) {
super(isExtensionAllowedToBeRecommended, instantiationService, configurationService, notificationService, telemetryService, storageService, storageKeysSyncRegistryService);
// this._recommendations = productService.recommendedExtensionsByScenario.map(r => ({ extensionId: r, reason: { reasonId: ExtensionRecommendationReason.Application, reasonText: localize('defaultRecommendations', "This extension is recommended by Azure Data Studio.") }, source: 'application' }));
}
protected async doActivate(): Promise<void> {
return;
}
// {{SQL CARBON EDIT}}
promptRecommendedExtensionsByScenario(scenarioType: string): void {
const storageKey = 'extensionAssistant/RecommendationsIgnore/' + scenarioType;
if (this.storageService.getBoolean(storageKey, StorageScope.GLOBAL, false)) {
return;
}
const visualizerExtensionNotificationService = 'VisualizerExtensionNotificationService';
let recommendationMessage = localize('ExtensionsRecommended', "Azure Data Studio has extension recommendations.");
if (scenarioType === visualizerExtensions) {
recommendationMessage = localize('VisualizerExtensionsRecommended', "Azure Data Studio has extension recommendations for data visualization.\nOnce installed, you can select the Visualizer icon to visualize your query results.");
}
Promise.all([this.getRecommendedExtensionsByScenario(scenarioType), this.extensionManagementService.getInstalled(ExtensionType.User)]).then(([recommendations, localExtensions]) => {
if (!recommendations.every(rec => { return localExtensions.findIndex(local => local.identifier.id.toLocaleLowerCase() === rec.extensionId.toLocaleLowerCase()) !== -1; })) {
return new Promise<void>(c => {
this.notificationService.prompt(
Severity.Info,
recommendationMessage,
[{
label: localize('installAll', "Install All"),
run: () => {
this.adsTelemetryService.sendActionEvent(
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
TelemetryKeys.TelemetryAction.Click,
'InstallButton',
visualizerExtensionNotificationService
);
const installAllAction = this.instantiationService.createInstance(InstallRecommendedExtensionsByScenarioAction, scenarioType, recommendations);
installAllAction.run();
installAllAction.dispose();
}
}, {
label: localize('showRecommendations', "Show Recommendations"),
run: () => {
this.adsTelemetryService.sendActionEvent(
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
TelemetryKeys.TelemetryAction.Click,
'ShowRecommendationsButton',
visualizerExtensionNotificationService
);
const showAction = this.instantiationService.createInstance(ShowRecommendedExtensionsByScenarioAction, scenarioType);
showAction.run();
showAction.dispose();
c(undefined);
}
}, {
label: choiceNever,
isSecondary: true,
run: () => {
this.adsTelemetryService.sendActionEvent(
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
TelemetryKeys.TelemetryAction.Click,
'NeverShowAgainButton',
visualizerExtensionNotificationService
);
this.storageService.store(storageKey, true, StorageScope.GLOBAL);
c(undefined);
}
}],
{
sticky: true,
onCancel: () => {
this.adsTelemetryService.sendActionEvent(
TelemetryKeys.TelemetryView.ExtensionRecommendationDialog,
TelemetryKeys.TelemetryAction.Click,
'CancelButton',
visualizerExtensionNotificationService
);
c(undefined);
}
}
);
});
} else {
return Promise.resolve();
}
});
}
getRecommendedExtensionsByScenario(scenarioType: string): Promise<IExtensionRecommendation[]> {
if (!scenarioType) {
return Promise.reject(new Error(localize('scenarioTypeUndefined', 'The scenario type for extension recommendations must be provided.')));
}
return Promise.resolve((this.productService.recommendedExtensionsByScenario[scenarioType] || [])
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId))
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] })));
}
}

View File

@@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
import { IProductService } from 'vs/platform/product/common/productService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { localize } from 'vs/nls';
import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
export class StaticRecommendations extends ExtensionRecommendations {
readonly _recommendations: ExtensionRecommendation[] = [];
get recommendations(): ReadonlyArray<ExtensionRecommendation> { return this._recommendations; }
constructor(
isExtensionAllowedToBeRecommended: (extensionId: string) => boolean,
@IProductService productService: IProductService,
@IInstantiationService instantiationService: IInstantiationService,
@IConfigurationService configurationService: IConfigurationService,
@INotificationService notificationService: INotificationService,
@ITelemetryService telemetryService: ITelemetryService,
@IStorageService storageService: IStorageService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
) {
super(isExtensionAllowedToBeRecommended, instantiationService, configurationService, notificationService, telemetryService, storageService, storageKeysSyncRegistryService);
this._recommendations = productService.recommendedExtensions.map(r => ({ extensionId: r, reason: { reasonId: ExtensionRecommendationReason.Application, reasonText: localize('defaultRecommendations', "This extension is recommended by Azure Data Studio.") }, source: 'application' }));
}
protected async doActivate(): Promise<void> {
return;
}
}

View File

@@ -365,7 +365,8 @@ export class NotebookEditor extends BaseEditor implements IFindNotebookControlle
searchScope: true,
matchesPosition: false,
matchesCount: false,
currentMatch: false
currentMatch: false,
loop: true
};
this._notebookModel.cells.forEach(cell => {
this._register(cell.onCellModeChanged((state) => {
@@ -450,7 +451,8 @@ export class NotebookEditor extends BaseEditor implements IFindNotebookControlle
searchScope: false,
matchesPosition: false,
matchesCount: false,
currentMatch: false
currentMatch: false,
loop: true
};
this._onFindStateChange(changeEvent).catch(e => { onUnexpectedError(e); });
}

View File

@@ -172,11 +172,13 @@ export class ProfilerEditor extends BaseEditor {
this._profilerEditorContextKey = CONTEXT_PROFILER_EDITOR.bindTo(this._contextKeyService);
if (editorService) {
editorService.overrideOpenEditor((editor, options, group) => {
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
this.saveEditorViewState();
editorService.overrideOpenEditor({
open: (editor, options, group) => {
if (this.isVisible() && (editor !== this.input || group !== this.group)) {
this.saveEditorViewState();
}
return {};
}
return {};
});
}
}
@@ -502,7 +504,8 @@ export class ProfilerEditor extends BaseEditor {
seedSearchStringFromSelection: (controller.getState().searchString.length === 0),
shouldFocus: FindStartFocusAction.FocusFindInput,
shouldAnimate: true,
updateSearchScope: false
updateSearchScope: false,
loop: true
});
}
} else {

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