mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
Merge from vscode 2e5312cd61ff99c570299ecc122c52584265eda2
This commit is contained in:
committed by
Anthony Dresser
parent
3603f55d97
commit
7f1d8fc32f
30
.github/workflows/english-please.yml
vendored
Normal file
30
.github/workflows/english-please.yml
vendored
Normal 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
49
.vscode/launch.json
vendored
@@ -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
|
||||
}
|
||||
},
|
||||
|
||||
28
.vscode/searches/es6.code-search
vendored
28
.vscode/searches/es6.code-search
vendored
@@ -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 {
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -72,5 +72,6 @@
|
||||
"files.insertFinalNewline": true,
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
}
|
||||
},
|
||||
"typescript.tsc.autoDetect": "off"
|
||||
}
|
||||
|
||||
12
.vscode/tasks.json
vendored
12
.vscode/tasks.json
vendored
@@ -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",
|
||||
|
||||
2
.yarnrc
2
.yarnrc
@@ -1,3 +1,3 @@
|
||||
disturl "https://atom.io/download/electron"
|
||||
target "7.1.11"
|
||||
target "7.2.2"
|
||||
runtime "electron"
|
||||
|
||||
@@ -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/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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' \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'))
|
||||
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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')))));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
}],
|
||||
"snippets": [{
|
||||
"language": "bat",
|
||||
"path": "./snippets/batchfile.snippets.json"
|
||||
"path": "./snippets/batchfile.code-snippets"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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%"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
17
extensions/git/src/api/git.d.ts
vendored
17
extensions/git/src/api/git.d.ts
vendored
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
8
extensions/github-authentication/.vscodeignore
Normal file
8
extensions/github-authentication/.vscodeignore
Normal file
@@ -0,0 +1,8 @@
|
||||
src/**
|
||||
!src/common/config.json
|
||||
out/**
|
||||
build/**
|
||||
extension.webpack.config.js
|
||||
tsconfig.json
|
||||
yarn.lock
|
||||
README.md
|
||||
@@ -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": {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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();
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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';},
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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',
|
||||
];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
}],
|
||||
"snippets": [{
|
||||
"language": "powershell",
|
||||
"path": "./snippets/powershell.json"
|
||||
"path": "./snippets/powershell.code-snippets"
|
||||
}]
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -56,6 +56,6 @@ export class SqlDatabaseProjectTreeViewProvider implements vscode.TreeDataProvid
|
||||
}
|
||||
|
||||
this.roots = newRoots;
|
||||
this._onDidChangeTreeData.fire();
|
||||
this._onDidChangeTreeData.fire(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 || ''))}`
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}));
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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')) {
|
||||
|
||||
@@ -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=
|
||||
|
||||
26
package.json
26
package.json
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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" . "$@"
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'] })));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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); });
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user