Merge remote-tracking branch 'origin' into electron-19.x.y

This commit is contained in:
deepak1556 2022-07-30 11:19:14 +09:00
commit 7bc2706edd
218 changed files with 3573 additions and 1698 deletions

View file

@ -24,14 +24,14 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: javascript
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -45,4 +45,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View file

@ -46,7 +46,7 @@ jobs:
uses: ./actions/classifier-deep/apply/apply-labels
with:
configPath: classifier
allowLabels: "needs more info|new release|error-telemetry|*english-please|translation-required"
allowLabels: "info-needed|new release|error-telemetry|*english-please|translation-required"
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
manifestDbConnectionString: ${{secrets.MANIFEST_DB_CONNECTION_STRING}}
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}

View file

@ -24,6 +24,6 @@ jobs:
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}}
nonEnglishLabel: "*english-please"
needsMoreInfoLabel: "needs more info"
needsMoreInfoLabel: "info-needed"
translatorRequestedLabelPrefix: "translation-required-"
translatorRequestedLabelColor: "c29cff"

View file

@ -1,4 +1,4 @@
name: Needs More Info Closer
name: info-needed Closer
on:
schedule:
- cron: 20 11 * * * # 4:20am Redmond
@ -17,12 +17,12 @@ jobs:
ref: stable
- name: Install Actions
run: npm install --production --prefix ./actions
- name: Run Needs More Info Closer
- name: Run info-needed Closer
uses: ./actions/needs-more-info-closer
with:
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
label: needs more info
label: info-needed
closeDays: 7
additionalTeam: "cleidigh|usernamehw|gjsjohnmurray|IllusionMH"
closeComment: "This issue has been closed automatically because it needs more information and has not had recent activity. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!"

View file

@ -85,6 +85,6 @@ jobs:
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}}
nonEnglishLabel: "*english-please"
needsMoreInfoLabel: "needs more info"
needsMoreInfoLabel: "info-needed"
translatorRequestedLabelPrefix: "translation-required-"
translatorRequestedLabelColor: "c29cff"

View file

@ -59,6 +59,6 @@ jobs:
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}}
nonEnglishLabel: "*english-please"
needsMoreInfoLabel: "needs more info"
needsMoreInfoLabel: "info-needed"
translatorRequestedLabelPrefix: "translation-required-"
translatorRequestedLabelColor: "c29cff"

View file

@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$inbox -label:\"needs more info\" sort:created-desc"
"value": "$inbox -label:\"info-needed\" sort:created-desc"
},
{
"kind": 2,

View file

@ -147,7 +147,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$REPOS $MILESTONE -$MINE is:issue is:closed author:@me sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:needs-triage -label:verification-found"
"value": "$REPOS $MILESTONE -$MINE is:issue is:closed author:@me sort:updated-asc label:bug -label:unreleased -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:triage-needed -label:verification-found"
},
{
"kind": 1,

File diff suppressed because one or more lines are too long

View file

@ -31,7 +31,7 @@ This project incorporates components from the projects listed below. The origina
24. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar)
25. James-Yu/LaTeX-Workshop version 8.19.1 (https://github.com/James-Yu/LaTeX-Workshop)
26. jeff-hykin/better-c-syntax version 1.13.2 (https://github.com/jeff-hykin/better-c-syntax)
27. jeff-hykin/better-cpp-syntax version 1.15.17 (https://github.com/jeff-hykin/better-cpp-syntax)
27. jeff-hykin/better-cpp-syntax version 1.15.18 (https://github.com/jeff-hykin/better-cpp-syntax)
28. jeff-hykin/better-objc-syntax version 0.2.0 (https://github.com/jeff-hykin/better-objc-syntax)
29. jeff-hykin/better-objcpp-syntax version 0.1.0 (https://github.com/jeff-hykin/better-objcpp-syntax)
30. jlelong/vscode-latex-basics version 1.3.0 (https://github.com/jlelong/vscode-latex-basics)
@ -47,7 +47,7 @@ This project incorporates components from the projects listed below. The origina
40. microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/microsoft/TypeScript-TmLanguage)
41. microsoft/vscode-JSON.tmLanguage (https://github.com/microsoft/vscode-JSON.tmLanguage)
42. microsoft/vscode-markdown-tm-grammar version 1.0.0 (https://github.com/microsoft/vscode-markdown-tm-grammar)
43. microsoft/vscode-mssql version 1.10.1 (https://github.com/microsoft/vscode-mssql)
43. microsoft/vscode-mssql version 1.16.0 (https://github.com/microsoft/vscode-mssql)
44. mmims/language-batchfile version 0.7.6 (https://github.com/mmims/language-batchfile)
45. NVIDIA/cuda-cpp-grammar (https://github.com/NVIDIA/cuda-cpp-grammar)
46. PowerShell/EditorSyntax version 1.0.0 (https://github.com/PowerShell/EditorSyntax)
@ -73,7 +73,7 @@ This project incorporates components from the projects listed below. The origina
66. TypeScript-TmLanguage version 1.0.0 (https://github.com/microsoft/TypeScript-TmLanguage)
67. Unicode version 12.0.0 (https://home.unicode.org/)
68. vscode-codicons version 0.0.14 (https://github.com/microsoft/vscode-codicons)
69. vscode-logfile-highlighter version 2.11.0 (https://github.com/emilast/vscode-logfile-highlighter)
69. vscode-logfile-highlighter version 2.15.0 (https://github.com/emilast/vscode-logfile-highlighter)
70. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift)
71. vscode-win32-app-container-tokens (https://github.com/microsoft/vscode-win32-app-container-tokens)
72. Web Background Synchronization (https://github.com/WICG/background-sync)

View file

@ -93,12 +93,21 @@ steps:
node build/azure-pipelines/common/computeNodeModulesCacheKey.js $VSCODE_ARCH $ENABLE_TERRAPIN > .build/yarnlockhash
displayName: Prepare yarn cache flags
- task: Cache@2
inputs:
key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}:
- task: Cache@2
inputs:
key: "genericNodeModules | $(Agent.OS) | .build/yarnlockhash"
path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
- task: Cache@2
inputs:
key: "nodeModules | $(Agent.OS) | .build/yarnlockhash"
path: .build/node_modules_cache
cacheHitVar: NODE_MODULES_RESTORED
displayName: Restore node_modules cache
- script: |
set -e

View file

@ -22,174 +22,168 @@ variables:
- name: VSCODE_STEP_ON_IT
value: false
stages:
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
- stage: MaintainNodeModulesCache
displayName: Maintain node_modules cache
jobs:
- job: MaintainNodeModulesCache
displayName: Maintain node_modules cache
pool: vscode-1es-vscode-linux-20.04
steps:
- template: product-build-pr-cache.yml
jobs:
- ${{ if ne(variables['VSCODE_CIBUILD'], true) }}:
- stage: Compile
- job: Compile
displayName: Compile & Hygiene
jobs:
- job: Compile
displayName: Compile & Hygiene
pool: vscode-1es-vscode-linux-20.04
variables:
VSCODE_ARCH: x64
steps:
- template: product-compile.yml
parameters:
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
steps:
- template: product-compile.yml
parameters:
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
- stage: Test
dependsOn: []
jobs:
- job: Linuxx64UnitTest
displayName: Linux (Unit Tests)
pool: vscode-1es-vscode-linux-20.04
# container: vscode-bionic-x64
timeoutInMinutes: 60
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: true
VSCODE_RUN_INTEGRATION_TESTS: false
VSCODE_RUN_SMOKE_TESTS: false
- job: Linuxx64IntegrationTest
displayName: Linux (Integration Tests)
pool: vscode-1es-vscode-linux-20.04
# container: vscode-bionic-x64
timeoutInMinutes: 60
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: false
VSCODE_RUN_INTEGRATION_TESTS: true
VSCODE_RUN_SMOKE_TESTS: false
- job: Linuxx64SmokeTest
displayName: Linux (Smoke Tests)
pool: vscode-1es-vscode-linux-20.04
# container: vscode-bionic-x64
timeoutInMinutes: 60
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: false
VSCODE_RUN_INTEGRATION_TESTS: false
VSCODE_RUN_SMOKE_TESTS: true
- job: Linuxx64UnitTest
displayName: Linux (Unit Tests)
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: true
VSCODE_RUN_INTEGRATION_TESTS: false
VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSUnitTest
# displayName: macOS (Unit Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: true
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSIntegrationTest
# displayName: macOS (Integration Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: true
# VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSSmokeTest
# displayName: macOS (Smoke Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: true
- job: Linuxx64IntegrationTest
displayName: Linux (Integration Tests)
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: false
VSCODE_RUN_INTEGRATION_TESTS: true
VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsUnitTests
# displayName: Windows (Unit Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: true
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsIntegrationTests
# displayName: Windows (Integration Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: true
# VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsSmokeTests
# displayName: Windows (Smoke Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: true
- job: Linuxx64SmokeTest
displayName: Linux (Smoke Tests)
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
NPM_ARCH: x64
DISPLAY: ":10"
steps:
- template: linux/product-build-linux-client.yml
parameters:
VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
VSCODE_RUN_UNIT_TESTS: false
VSCODE_RUN_INTEGRATION_TESTS: false
VSCODE_RUN_SMOKE_TESTS: true
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
- job: Linuxx64MaintainNodeModulesCache
displayName: Linux (Maintain node_modules cache)
pool: vscode-1es-vscode-linux-20.04
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
steps:
- template: product-build-pr-cache.yml
# - job: macOSUnitTest
# displayName: macOS (Unit Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: true
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSIntegrationTest
# displayName: macOS (Integration Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: true
# VSCODE_RUN_SMOKE_TESTS: false
# - job: macOSSmokeTest
# displayName: macOS (Smoke Tests)
# pool:
# vmImage: macOS-latest
# timeoutInMinutes: 60
# variables:
# BUILDSECMON_OPT_IN: true
# VSCODE_ARCH: x64
# steps:
# - template: darwin/product-build-darwin.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: true
# - job: WindowsUnitTests
# displayName: Windows (Unit Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: true
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsIntegrationTests
# displayName: Windows (Integration Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: true
# VSCODE_RUN_SMOKE_TESTS: false
# - job: WindowsSmokeTests
# displayName: Windows (Smoke Tests)
# pool: vscode-1es-vscode-windows-2019
# timeoutInMinutes: 60
# variables:
# VSCODE_ARCH: x64
# steps:
# - template: win32/product-build-win32.yml
# parameters:
# VSCODE_PUBLISH: ${{ variables.VSCODE_PUBLISH }}
# VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
# VSCODE_RUN_UNIT_TESTS: false
# VSCODE_RUN_INTEGRATION_TESTS: false
# VSCODE_RUN_SMOKE_TESTS: true

View file

@ -399,6 +399,7 @@ const esbuildMediaScripts = [
'markdown-language-features/esbuild-preview.js',
'markdown-math/esbuild.js',
'notebook-renderers/esbuild.js',
'ipynb/esbuild.js',
'simple-browser/esbuild-preview.js',
];
async function webpackExtensions(taskName, isWatch, webpackConfigLocations) {

View file

@ -486,6 +486,7 @@ const esbuildMediaScripts = [
'markdown-language-features/esbuild-preview.js',
'markdown-math/esbuild.js',
'notebook-renderers/esbuild.js',
'ipynb/esbuild.js',
'simple-browser/esbuild-preview.js',
];

View file

@ -298,6 +298,10 @@
"name": "vs/workbench/contrib/deprecatedExtensionMigrator",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/bracketPairColorizer2Telemetry",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/offline",
"project": "vscode-workbench"

View file

@ -228,6 +228,12 @@ function getColor(node) {
function setColor(node, color) {
node.$$$color = color;
}
function markNeededSourceFile(node) {
node.$$$neededSourceFile = true;
}
function isNeededSourceFile(node) {
return Boolean(node.$$$neededSourceFile);
}
function nodeOrParentIsBlack(node) {
while (node) {
const color = getColor(node);
@ -353,6 +359,19 @@ function markNodes(ts, languageService, options) {
}
});
}
/**
* Return the parent of `node` which is an ImportDeclaration
*/
function findParentImportDeclaration(node) {
let _node = node;
do {
if (ts.isImportDeclaration(_node)) {
return _node;
}
_node = _node.parent;
} while (_node);
return null;
}
function enqueue_gray(node) {
if (nodeOrParentIsBlack(node) || getColor(node) === 1 /* NodeColor.Gray */) {
return;
@ -420,6 +439,8 @@ function markNodes(ts, languageService, options) {
console.warn(`Cannot find source file ${filename}`);
return;
}
// This source file should survive even if it is empty
markNeededSourceFile(sourceFile);
enqueue_black(sourceFile);
}
function enqueueImport(node, importText) {
@ -472,6 +493,10 @@ function markNodes(ts, languageService, options) {
const [symbol, symbolImportNode] = getRealNodeSymbol(ts, checker, node);
if (symbolImportNode) {
setColor(symbolImportNode, 2 /* NodeColor.Black */);
const importDeclarationNode = findParentImportDeclaration(symbolImportNode);
if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) {
enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text);
}
}
if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) {
for (let i = 0, len = symbol.declarations.length; i < len; i++) {
@ -663,11 +688,23 @@ function generateResult(ts, languageService, shakeLevel) {
}
if (getColor(sourceFile) !== 2 /* NodeColor.Black */) {
if (!nodeOrChildIsBlack(sourceFile)) {
// none of the elements are reachable => don't write this file at all!
return;
// none of the elements are reachable
if (isNeededSourceFile(sourceFile)) {
// this source file must be written, even if nothing is used from it
// because there is an import somewhere for it.
// However, TS complains with empty files with the error "x" is not a module,
// so we will export a dummy variable
result = 'export const __dummy = 0;';
}
else {
// don't write this file at all!
return;
}
}
else {
sourceFile.forEachChild(writeMarkedNodes);
result += sourceFile.endOfFileToken.getFullText(sourceFile);
}
sourceFile.forEachChild(writeMarkedNodes);
result += sourceFile.endOfFileToken.getFullText(sourceFile);
}
else {
result = text;

View file

@ -307,6 +307,12 @@ function getColor(node: ts.Node): NodeColor {
function setColor(node: ts.Node, color: NodeColor): void {
(<any>node).$$$color = color;
}
function markNeededSourceFile(node: ts.SourceFile): void {
(<any>node).$$$neededSourceFile = true;
}
function isNeededSourceFile(node: ts.SourceFile): boolean {
return Boolean((<any>node).$$$neededSourceFile);
}
function nodeOrParentIsBlack(node: ts.Node): boolean {
while (node) {
const color = getColor(node);
@ -449,6 +455,20 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language
});
}
/**
* Return the parent of `node` which is an ImportDeclaration
*/
function findParentImportDeclaration(node: ts.Declaration): ts.ImportDeclaration | null {
let _node: ts.Node = node;
do {
if (ts.isImportDeclaration(_node)) {
return _node;
}
_node = _node.parent;
} while (_node);
return null;
}
function enqueue_gray(node: ts.Node): void {
if (nodeOrParentIsBlack(node) || getColor(node) === NodeColor.Gray) {
return;
@ -531,6 +551,8 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language
console.warn(`Cannot find source file ${filename}`);
return;
}
// This source file should survive even if it is empty
markNeededSourceFile(sourceFile);
enqueue_black(sourceFile);
}
@ -590,6 +612,10 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language
const [symbol, symbolImportNode] = getRealNodeSymbol(ts, checker, node);
if (symbolImportNode) {
setColor(symbolImportNode, NodeColor.Black);
const importDeclarationNode = findParentImportDeclaration(symbolImportNode);
if (importDeclarationNode && ts.isStringLiteral(importDeclarationNode.moduleSpecifier)) {
enqueueImport(importDeclarationNode, importDeclarationNode.moduleSpecifier.text);
}
}
if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) {
@ -802,11 +828,21 @@ function generateResult(ts: typeof import('typescript'), languageService: ts.Lan
if (getColor(sourceFile) !== NodeColor.Black) {
if (!nodeOrChildIsBlack(sourceFile)) {
// none of the elements are reachable => don't write this file at all!
return;
// none of the elements are reachable
if (isNeededSourceFile(sourceFile)) {
// this source file must be written, even if nothing is used from it
// because there is an import somewhere for it.
// However, TS complains with empty files with the error "x" is not a module,
// so we will export a dummy variable
result = 'export const __dummy = 0;';
} else {
// don't write this file at all!
return;
}
} else {
sourceFile.forEachChild(writeMarkedNodes);
result += sourceFile.endOfFileToken.getFullText(sourceFile);
}
sourceFile.forEachChild(writeMarkedNodes);
result += sourceFile.endOfFileToken.getFullText(sourceFile);
} else {
result = text;
}

View file

@ -173,5 +173,32 @@
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
"SOFTWARE"
]
},
{
// Reason: Waiting for https://github.com/microsoft/vscode-markdown-languageservice/pull/9
"name": "vscode-markdown-languageservice",
"fullLicenseText": [
"MIT License",
"",
"Copyright (c) Microsoft Corporation.",
"",
"Permission is hereby granted, free of charge, to any person obtaining a copy",
"of this software and associated documentation files (the \"Software\"), to deal",
"in the Software without restriction, including without limitation the rights",
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell",
"copies of the Software, and to permit persons to whom the Software is",
"furnished to do so, subject to the following conditions:",
"",
"The above copyright notice and this permission notice shall be included in all",
"copies or substantial portions of the Software.",
"",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR",
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
"SOFTWARE"
]
}
]

View file

@ -0,0 +1,189 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"customizations": {
"type": "object",
"properties": {
"codespaces": {
"type": "object",
"description": "Customizations specific to GitHub Codespaces",
"properties": {
"repositories": {
"type": "object",
"description": "Configuration relative to the given repositories, following the format 'owner/repo'.\n A wildcard (*) is permitted for the repo name (eg: 'microsoft/*')",
"patternProperties": {
"^[a-zA-Z0-9-_.]+[.]*\/[a-zA-Z0-9-_*]+[.]*$": {
"type": "object",
"additionalProperties": true,
"oneOf": [
{
"properties": {
"permissions": {
"type": "object",
"description": "Additional repository permissions.\n See https://aka.ms/ghcs/multi-repo-auth for more info.",
"additionalProperties": true,
"anyOf": [
{
"properties": {
"actions": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"checks": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"contents": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"deployments": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"discussions": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"issues": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"packages": {
"type": "string",
"enum": [
"read"
]
}
}
},
{
"properties": {
"pages": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"pull_requests": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"repository_projects": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"statuses": {
"type": "string",
"enum": [
"read",
"write"
]
}
}
},
{
"properties": {
"workflows": {
"type": "string",
"enum": [
"write"
]
}
}
}
]
}
}
},
{
"properties": {
"permissions": {
"type": "string",
"description": "Additional repository permissions.\n See https://aka.ms/ghcs/multi-repo-auth for more info.",
"enum": [
"read-all",
"write-all"
]
}
}
}
]
}
}
}
}
}
}
},
"codespaces": {
"type": "object",
"additionalProperties": true,
"description": "Codespaces-specific configuration.",
"deprecated": true,
"deprecationMessage": "Use 'customizations/codespaces' instead"
}
}
}

View file

@ -0,0 +1,56 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"customizations": {
"type": "object",
"properties": {
"vscode": {
"type": "object",
"properties": {
"extensions": {
"type": "array",
"description": "An array of extensions that should be installed into the container.",
"items": {
"type": "string",
"pattern": "^([a-z0-9A-Z][a-z0-9A-Z-]*)\\.([a-z0-9A-Z][a-z0-9A-Z-]*)(@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)?$",
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'."
}
},
"settings": {
"$ref": "vscode://schemas/settings/machine",
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again."
},
"devPort": {
"type": "integer",
"description": "The port VS Code can use to connect to its backend."
}
}
}
}
},
"extensions": {
"type": "array",
"description": "An array of extensions that should be installed into the container.",
"items": {
"type": "string",
"pattern": "^([a-z0-9A-Z][a-z0-9A-Z-]*)\\.([a-z0-9A-Z][a-z0-9A-Z-]*)((@(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)|@prerelease)?$",
"errorMessage": "Expected format: '${publisher}.${name}' or '${publisher}.${name}@${version}'. Example: 'ms-dotnettools.csharp'."
},
"deprecated": true,
"deprecationMessage": "Use 'customizations/vscode/extensions' instead"
},
"settings": {
"$ref": "vscode://schemas/settings/machine",
"description": "Machine specific settings that should be copied into the container. These are only copied when connecting to the container for the first time, rebuilding the container then triggers it again.",
"deprecated": true,
"deprecationMessage": "Use 'customizations/vscode/settings' instead"
},
"devPort": {
"type": "integer",
"description": "The port VS Code can use to connect to its backend.",
"deprecated": true,
"deprecationMessage": "Use 'customizations/vscode/devPort' instead"
}
}
}

View file

@ -65,6 +65,7 @@
"emmet.showAbbreviationSuggestions": {
"type": "boolean",
"default": true,
"scope": "language-overridable",
"markdownDescription": "%emmetShowAbbreviationSuggestions%"
},
"emmet.includeLanguages": {
@ -125,6 +126,7 @@
"emmet.triggerExpansionOnTab": {
"type": "boolean",
"default": false,
"scope": "language-overridable",
"markdownDescription": "%emmetTriggerExpansionOnTab%"
},
"emmet.useInlineCompletions": {

View file

@ -95,18 +95,19 @@ export class ActionButtonCommand {
return {
command: this.getCommitActionButtonPrimaryCommand(),
secondaryCommands: this.getCommitActionButtonSecondaryCommands(),
enabled: this.state.repositoryHasChangesToCommit && !this.state.isCommitInProgress && !this.state.isMergeInProgress
enabled: (this.state.repositoryHasChangesToCommit || this.state.isRebaseInProgress) && !this.state.isCommitInProgress && !this.state.isMergeInProgress
};
}
private getCommitActionButtonPrimaryCommand(): Command {
let commandArg = '';
let title = localize('scm button commit title', "{0} Commit", '$(check)');
let tooltip = this.state.isCommitInProgress ? localize('scm button committing tooltip', "Committing Changes...") : localize('scm button commit tooltip', "Commit Changes");
// Rebase Continue
if (this.state.isRebaseInProgress) {
return { command: 'git.commit', title, tooltip, arguments: [this.repository.sourceControl, commandArg] };
return {
command: 'git.commit',
title: localize('scm button continue title', "{0} Continue", '$(check)'),
tooltip: this.state.isCommitInProgress ? localize('scm button continuing tooltip', "Continuing Rebase...") : localize('scm button continue tooltip', "Continue Rebase"),
arguments: [this.repository.sourceControl, '']
};
}
// Commit
@ -122,6 +123,10 @@ export class ActionButtonCommand {
// Icon
const icon = alwaysPrompt ? '$(lock)' : alwaysCommitToNewBranch ? '$(git-branch)' : undefined;
let commandArg = '';
let title = localize('scm button commit title', "{0} Commit", icon ?? '$(check)');
let tooltip = this.state.isCommitInProgress ? localize('scm button committing tooltip', "Committing Changes...") : localize('scm button commit tooltip', "Commit Changes");
// Title, tooltip
switch (postCommitCommand) {
case 'push': {

View file

@ -1558,6 +1558,8 @@ export class CommandCenter {
// amend allows changing only the commit message
&& !opts.amend
&& !opts.empty
// rebase not in progress
&& repository.rebaseCommit === undefined
) {
const commitAnyway = localize('commit anyway', "Create Empty Commit");
const answer = await window.showInformationMessage(localize('no changes', "There are no changes to commit."), commitAnyway);
@ -1770,7 +1772,7 @@ export class CommandCenter {
const shouldPrompt = config.get<boolean>('confirmEmptyCommits') === true;
if (shouldPrompt) {
const message = localize('confirm emtpy commit', "Are you sure you want to create an empty commit?");
const message = localize('confirm empty commit', "Are you sure you want to create an empty commit?");
const yes = localize('yes', "Yes");
const neverAgain = localize('yes never again', "Yes, Don't Show Again");
const pick = await window.showWarningMessage(message, { modal: true }, yes, neverAgain);

View file

@ -9,9 +9,13 @@ import { publishRepository } from './publish';
import { DisposableStore } from './util';
import { getPermalink } from './links';
function getVscodeDevHost(): string {
return `https://${vscode.env.appName.toLowerCase().includes('insiders') ? 'insiders.' : ''}vscode.dev/github`;
}
async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) {
try {
const permalink = getPermalink(gitAPI, useSelection, 'https://vscode.dev/github');
const permalink = getPermalink(gitAPI, useSelection, getVscodeDevHost());
if (permalink) {
return vscode.env.clipboard.writeText(permalink);
}
@ -22,7 +26,7 @@ async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) {
async function openVscodeDevLink(gitAPI: GitAPI): Promise<vscode.Uri | undefined> {
try {
const permalink = getPermalink(gitAPI, true, 'https://vscode.dev/github');
const permalink = getPermalink(gitAPI, true, getVscodeDevHost());
return permalink ? vscode.Uri.parse(permalink) : undefined;
} catch (err) {
vscode.window.showErrorMessage(err.message);

View file

@ -125,11 +125,11 @@ export function getPermalink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?:
return;
}
const commitHash = gitRepo.state.HEAD?.commit;
const commitHash = (gitRepo.state.HEAD?.ahead === 0) ? `/blob/${gitRepo.state.HEAD?.commit}` : '';
const fileSegments = fileAndPosition.type === LinkType.File
? (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${rangeString(fileAndPosition.range)}` : '')
: (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${notebookCellRangeString(fileAndPosition.cellIndex, fileAndPosition.range)}` : '');
return `${hostPrefix}/${repo.owner}/${repo.repo}/blob/${commitHash
return `${hostPrefix}/${repo.owner}/${repo.repo}${commitHash
}${fileSegments}`;
}

View file

@ -2,3 +2,4 @@ out
dist
node_modules
*.vsix
notebook-out

View file

@ -6,4 +6,4 @@ extension.webpack.config.js
extension-browser.webpack.config.js
yarn.lock
.gitignore
esbuild.js

View file

@ -19,7 +19,7 @@ if (outputRootIndex >= 0) {
}
const srcDir = path.join(__dirname, 'src');
const outDir = path.join(outputRoot, 'out');
const outDir = path.join(outputRoot, 'notebook-out');
async function build() {
await esbuild.build({

View file

@ -57,7 +57,7 @@
"displayName": "Markdown it ipynb Cell Attachment renderer",
"entrypoint": {
"extends": "vscode.markdown-it-renderer",
"path": "./out/cellAttachmentRenderer.js"
"path": "./notebook-out/cellAttachmentRenderer.js"
}
}
],

View file

@ -22,11 +22,19 @@ export async function activate(ctx: RendererContext<void>) {
md.renderer.rules.image = (tokens: MarkdownItToken[], idx: number, options, env, self) => {
const token = tokens[idx];
const src = token.attrGet('src');
const attachments: Record<string, Record<string, string>> = env.outputItem.metadata?.custom?.attachments;
const attachments: Record<string, Record<string, string>> = env.outputItem.metadata?.custom?.attachments; // this stores attachment entries for every image in the cell
if (attachments && src) {
const [attachmentKey, attachmentVal] = Object.entries(attachments[src.replace('attachment:', '')])[0];
const b64Markdown = 'data:' + attachmentKey + ';base64,' + attachmentVal;
token.attrSet('src', b64Markdown);
const imageAttachment = attachments[src.replace('attachment:', '')];
if (imageAttachment) {
// objEntries will always be length 1, with objEntries[0] holding [0]=mime,[1]=b64
// if length = 0, something is wrong with the attachment, mime/b64 weren't copied over
const objEntries = Object.entries(imageAttachment);
if (objEntries.length) {
const [attachmentKey, attachmentVal] = objEntries[0];
const b64Markdown = 'data:' + attachmentKey + ';base64,' + attachmentVal;
token.attrSet('src', b64Markdown);
}
}
}
if (original) {

View file

@ -12,7 +12,8 @@ cgmanifest.json
yarn.lock
preview-src/**
webpack.config.js
esbuild.js
esbuild-notebook.js
esbuild-preview.js
.gitignore
server/src/**
server/extension.webpack.config.js

View file

@ -8,57 +8,108 @@ import MarkdownIt from 'markdown-it';
import type * as MarkdownItToken from 'markdown-it/lib/token';
import type { ActivationFunction } from 'vscode-notebook-renderer';
const allowedHtmlTags = Object.freeze([
'a',
'b',
'blockquote',
'br',
'button',
'caption',
'center',
'code',
'col',
'colgroup',
'details',
'div',
'em',
'font',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'hr',
'i',
'img',
'input',
'kbd',
'label',
'li',
'ol',
'p',
'pre',
'select',
'small',
'span',
'strong',
'sub',
'summary',
'sup',
'table',
'tbody',
'td',
'textarea',
'tfoot',
'th',
'thead',
'tr',
'tt',
'u',
'ul',
'video',
]);
const allowedSvgTags = Object.freeze([
'svg',
'a',
'altglyph',
'altglyphdef',
'altglyphitem',
'animatecolor',
'animatemotion',
'animatetransform',
'circle',
'clippath',
'defs',
'desc',
'ellipse',
'filter',
'font',
'g',
'glyph',
'glyphref',
'hkern',
'image',
'line',
'lineargradient',
'marker',
'mask',
'metadata',
'mpath',
'path',
'pattern',
'polygon',
'polyline',
'radialgradient',
'rect',
'stop',
'style',
'switch',
'symbol',
'text',
'textpath',
'title',
'tref',
'tspan',
'view',
'vkern',
]);
const sanitizerOptions: DOMPurify.Config = {
ALLOWED_TAGS: [
'a',
'b',
'blockquote',
'br',
'button',
'caption',
'center',
'code',
'col',
'colgroup',
'details',
'div',
'em',
'font',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'hr',
'i',
'img',
'input',
'kbd',
'label',
'li',
'ol',
'p',
'pre',
'select',
'small',
'span',
'strong',
'sub',
'summary',
'sup',
'table',
'tbody',
'td',
'textarea',
'tfoot',
'th',
'thead',
'tr',
'tt',
'u',
'ul',
'video',
...allowedHtmlTags,
...allowedSvgTags,
],
};

View file

@ -29,7 +29,7 @@
"configuration.markdown.links.openLocation.currentGroup": "Open links in the active editor group.",
"configuration.markdown.links.openLocation.beside": "Open links beside the active editor.",
"configuration.markdown.suggest.paths.enabled.description": "Enable/disable path suggestions for markdown links",
"configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#workbench.editor.dropIntoEditor.enabled#`.",
"configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#editor.dropIntoEditor.enabled#`.",
"configuration.markdown.editor.pasteLinks.enabled": "Enable/disable pasting files into a Markdown editor inserts Markdown links. Requires enabling `#editor.experimental.pasteActions.enabled#`.",
"configuration.markdown.experimental.validate.enabled.description": "Enable/disable all error reporting in Markdown files.",
"configuration.markdown.experimental.validate.referenceLinks.enabled.description": "Validate reference links in Markdown files, e.g. `[link][ref]`. Requires enabling `#markdown.experimental.validate.enabled#`.",

View file

@ -11,7 +11,7 @@ import * as nls from 'vscode-nls';
import { v4 as uuid } from 'uuid';
import fetch, { Response } from 'node-fetch';
import Logger from './logger';
import { toBase64UrlEncoding } from './utils';
import { isSupportedEnvironment, toBase64UrlEncoding } from './utils';
import { sha256 } from './env/node/sha256';
import { BetterTokenStorage, IDidChangeInOtherWindowEvent } from './betterSecretStorage';
import { LoopbackAuthServer } from './authServer';
@ -319,13 +319,7 @@ export class AzureActiveDirectoryService {
}, 5000);
}
const token = await this.exchangeCodeForToken(codeToExchange, codeVerifier, scopeData);
if (token.expiresIn) {
this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER);
}
await this.setToken(token, scopeData);
Logger.info(`Login successful for scopes: ${scopeData.scopeStr}`);
const session = await this.convertToSession(token);
const session = await this.exchangeCodeForSession(codeToExchange, codeVerifier, scopeData);
return session;
}
@ -355,9 +349,11 @@ export class AzureActiveDirectoryService {
const uri = vscode.Uri.parse(`${signInUrl}?${oauthStartQuery.toString()}`);
vscode.env.openExternal(uri);
let inputBox: vscode.InputBox | undefined;
const timeoutPromise = new Promise((_: (value: vscode.AuthenticationSession) => void, reject) => {
const wait = setTimeout(() => {
clearTimeout(wait);
inputBox?.dispose();
reject('Login timed out.');
}, 1000 * 60 * 5);
});
@ -369,7 +365,12 @@ export class AzureActiveDirectoryService {
// before completing it.
let existingPromise = this._codeExchangePromises.get(scopeData.scopeStr);
if (!existingPromise) {
existingPromise = this.handleCodeResponse(scopeData);
if (isSupportedEnvironment(callbackUri)) {
existingPromise = this.handleCodeResponse(scopeData);
} else {
inputBox = vscode.window.createInputBox();
existingPromise = Promise.race([this.handleCodeInputBox(inputBox, codeVerifier, scopeData), this.handleCodeResponse(scopeData)]);
}
this._codeExchangePromises.set(scopeData.scopeStr, existingPromise);
}
@ -659,13 +660,7 @@ export class AzureActiveDirectoryService {
throw new Error('No available code verifier');
}
const token = await this.exchangeCodeForToken(code, verifier, scopeData);
if (token.expiresIn) {
this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER);
}
await this.setToken(token, scopeData);
const session = await this.convertToSession(token);
const session = await this.exchangeCodeForSession(code, verifier, scopeData);
resolve(session);
} catch (err) {
reject(err);
@ -680,8 +675,33 @@ export class AzureActiveDirectoryService {
});
}
private async exchangeCodeForToken(code: string, codeVerifier: string, scopeData: IScopeData): Promise<IToken> {
private async handleCodeInputBox(inputBox: vscode.InputBox, verifier: string, scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
inputBox.ignoreFocusOut = true;
inputBox.title = localize('pasteCodeTitle', 'Microsoft Authentication');
inputBox.prompt = localize('pasteCodePrompt', 'Provide the authorization code to complete the sign in flow.');
inputBox.placeholder = localize('pasteCodePlaceholder', 'Paste authorization code here...');
return new Promise((resolve: (value: vscode.AuthenticationSession) => void, reject) => {
inputBox.show();
inputBox.onDidAccept(async () => {
const code = inputBox.value;
if (code) {
inputBox.dispose();
const session = await this.exchangeCodeForSession(code, verifier, scopeData);
resolve(session);
}
});
inputBox.onDidHide(() => {
if (!inputBox.value) {
inputBox.dispose();
reject('Cancelled');
}
});
});
}
private async exchangeCodeForSession(code: string, codeVerifier: string, scopeData: IScopeData): Promise<vscode.AuthenticationSession> {
Logger.info(`Exchanging login code for token for scopes: ${scopeData.scopeStr}`);
let token: IToken | undefined;
try {
const postData = querystring.stringify({
grant_type: 'authorization_code',
@ -698,11 +718,18 @@ export class AzureActiveDirectoryService {
const json = await this.fetchTokenResponse(endpoint, postData, scopeData);
Logger.info(`Exchanging login code for token (for scopes: ${scopeData.scopeStr}) succeeded!`);
return this.convertToTokenSync(json, scopeData);
token = this.convertToTokenSync(json, scopeData);
} catch (e) {
Logger.error(`Error exchanging code for token (for scopes ${scopeData.scopeStr}): ${e}`);
throw e;
}
if (token.expiresIn) {
this.setSessionTimeout(token.sessionId, token.refreshToken, scopeData, token.expiresIn * AzureActiveDirectoryService.REFRESH_TIMEOUT_MODIFIER);
}
await this.setToken(token, scopeData);
Logger.info(`Login successful for scopes: ${scopeData.scopeStr}`);
return await this.convertToSession(token);
}
private async fetchTokenResponse(endpoint: string, postData: string, scopeData: IScopeData): Promise<ITokenResponse> {

View file

@ -2,7 +2,40 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { env, UIKind, Uri } from 'vscode';
export function toBase64UrlEncoding(base64string: string) {
return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); // Need to use base64url encoding
}
const LOCALHOST_ADDRESSES = ['localhost', '127.0.0.1', '0:0:0:0:0:0:0:1', '::1'];
function isLocalhost(uri: Uri): boolean {
if (!/^https?$/i.test(uri.scheme)) {
return false;
}
const host = uri.authority.split(':')[0];
return LOCALHOST_ADDRESSES.indexOf(host) >= 0;
}
export function isSupportedEnvironment(uri: Uri): boolean {
if (env.uiKind === UIKind.Desktop) {
return true;
}
// local development (localhost:* or 127.0.0.1:*)
if (isLocalhost(uri)) {
return true;
}
// At this point we should only ever see https
if (uri.scheme !== 'https') {
return false;
}
return (
// vscode.dev & insiders.vscode.dev
/(?:^|\.)vscode\.dev$/.test(uri.authority) ||
// github.dev & codespaces
/(?:^|\.)github\.dev$/.test(uri.authority) ||
// github.dev/codespaces local setup (github.localhost)
/(?:^|\.)github\.localhost$/.test(uri.authority)
);
}

View file

@ -11,3 +11,4 @@ cgmanifest.json
yarn.lock
preview-src/**
webpack.config.js
esbuild-preview.js

View file

@ -45,7 +45,8 @@ const nonBuiltInLanguages = { // { fileNames, extensions }
const inheritIconFromLanguage = {
"jsonc": 'json',
"postcss": 'css',
"django-html": 'html'
"django-html": 'html',
"blade": 'php'
}
const FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo

View file

@ -6,7 +6,7 @@
"git": {
"name": "seti-ui",
"repositoryUrl": "https://github.com/jesseweed/seti-ui",
"commitHash": "4dd6c27e1f5aed8068c2451dbaf0db3364545937"
"commitHash": "2d10473b7575ec00c47eda751ea9caeec6b0b606"
}
},
"version": "0.1.0"

View file

@ -1694,6 +1694,7 @@
"tf": "_terraform",
"tf.json": "_terraform",
"tfvars": "_terraform",
"tfvars.json": "_terraform",
"dtx": "_tex_2",
"ins": "_tex_3",
"toml": "_config",
@ -1942,7 +1943,8 @@
"vala": "_vala",
"vue": "_vue",
"postcss": "_css",
"django-html": "_html_3"
"django-html": "_html_3",
"blade": "_php"
},
"light": {
"file": "_default_light",
@ -2093,6 +2095,7 @@
"tf": "_terraform_light",
"tf.json": "_terraform_light",
"tfvars": "_terraform_light",
"tfvars.json": "_terraform_light",
"dtx": "_tex_2_light",
"ins": "_tex_3_light",
"toml": "_config_light",
@ -2258,7 +2261,8 @@
"vala": "_vala_light",
"vue": "_vue_light",
"postcss": "_css_light",
"django-html": "_html_3_light"
"django-html": "_html_3_light",
"blade": "_php_light"
},
"fileNames": {
"mix": "_hex_light",
@ -2340,5 +2344,5 @@
"npm-debug.log": "_npm_ignored_light"
}
},
"version": "https://github.com/jesseweed/seti-ui/commit/4dd6c27e1f5aed8068c2451dbaf0db3364545937"
"version": "https://github.com/jesseweed/seti-ui/commit/2d10473b7575ec00c47eda751ea9caeec6b0b606"
}

View file

@ -430,32 +430,29 @@ export default class TypeScriptServiceClient extends Disposable implements IType
});
handle.onExit((data: TypeScriptServerExitEvent) => {
const { code, signal } = data;
this.error(`TSServer exited. Code: ${code}. Signal: ${signal}`);
// In practice, the exit code is an integer with no ties to any identity,
// so it can be classified as SystemMetaData, rather than CallstackOrException.
/* __GDPR__
"tsserver.exitWithCode" : {
"owner": "mjbvz",
"code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"${include}": [
"${TypeScriptCommonProperties}"
]
}
*/
this.logTelemetry('tsserver.exitWithCode', { code: code ?? undefined, signal: signal ?? undefined });
if (this.token !== mytoken) {
// this is coming from an old process
return;
}
const { code, signal } = data;
if (code === null || typeof code === 'undefined') {
this.info(`TSServer exited. Signal: ${signal}`);
} else {
// In practice, the exit code is an integer with no ties to any identity,
// so it can be classified as SystemMetaData, rather than CallstackOrException.
this.error(`TSServer exited with code: ${code}. Signal: ${signal}`);
/* __GDPR__
"tsserver.exitWithCode" : {
"owner": "mjbvz",
"code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" },
"${include}": [
"${TypeScriptCommonProperties}"
]
}
*/
this.logTelemetry('tsserver.exitWithCode', { code, signal: signal ?? undefined });
}
if (handle.tsServerLogFile) {
this.info(`TSServer log file: ${handle.tsServerLogFile}`);
}

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.70.0",
"distro": "990065ff739688c0d4ad94e172eeccd6bd5ef124",
"distro": "25c5a766dec5d762c3205176fec650c6964c7763",
"author": {
"name": "Microsoft Corporation"
},

View file

@ -46,7 +46,7 @@
},
{
"name": "ms-vscode.js-debug",
"version": "1.69.0",
"version": "1.70.0",
"repo": "https://github.com/microsoft/vscode-js-debug",
"metadata": {
"id": "25629058-ddac-4e17-abba-74678e126c5d",
@ -61,7 +61,7 @@
},
{
"name": "ms-vscode.vscode-js-profile-table",
"version": "1.0.2",
"version": "1.0.3",
"repo": "https://github.com/microsoft/vscode-js-profile-visualizer",
"metadata": {
"id": "7e52b41b-71ad-457b-ab7e-0620f1fc4feb",

View file

@ -58,11 +58,9 @@ apps:
command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ --no-sandbox
common-id: @@NAME@@.desktop
environment:
DISABLE_WAYLAND: 1
GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas
url-handler:
command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ --open-url --no-sandbox
environment:
DISABLE_WAYLAND: 1
GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas

View file

@ -15,6 +15,7 @@
"vs/base/browser/defaultWorkerFactory.ts",
"vs/base/worker/workerMain.ts",
"vs/editor/contrib/markdownRenderer/browser/markdownRenderer.ts",
"vs/editor/contrib/stickyScroll/browser/stickyScroll.ts",
"vs/editor/browser/view/domLineBreaksComputer.ts",
"vs/editor/browser/view/viewLayer.ts",
"vs/editor/browser/widget/diffEditorWidget.ts",

View file

@ -1869,9 +1869,11 @@ export function h(tag: string, ...args: [] | [attributes: { $: string } & Partia
typeof cssValue === 'number' ? cssValue + 'px' : '' + cssValue
);
}
continue;
} else if (key === 'tabIndex') {
el.tabIndex = value;
} else {
el.setAttribute(camelCaseToHyphenCase(key), value.toString());
}
el.setAttribute(camelCaseToHyphenCase(key), value.toString());
}
result['root'] = el;

View file

@ -126,9 +126,22 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
};
}
this.updateTooltip();
this.updateEnabled();
}
override getTooltip(): string | undefined {
let title: string | null = null;
if (this.getAction().tooltip) {
title = this.getAction().tooltip;
} else if (this.getAction().label) {
title = this.getAction().label;
}
return title ?? undefined;
}
override setActionContext(newContext: unknown): void {
super.setActionContext(newContext);

View file

@ -593,11 +593,11 @@ class FindFilter<T> implements ITreeFilter<T, FuzzyScore | LabelFuzzyScore>, IDi
}
filter(element: T, parentVisibility: TreeVisibility): TreeFilterResult<FuzzyScore | LabelFuzzyScore> {
let visibility = TreeVisibility.Visible;
if (this._filter) {
const result = this._filter.filter(element, parentVisibility);
let visibility: TreeVisibility;
if (typeof result === 'boolean') {
visibility = result ? TreeVisibility.Visible : TreeVisibility.Hidden;
} else if (isFilterResult(result)) {
@ -615,7 +615,7 @@ class FindFilter<T> implements ITreeFilter<T, FuzzyScore | LabelFuzzyScore>, IDi
if (!this._pattern) {
this._matchCount++;
return { data: FuzzyScore.Default, visibility: true };
return { data: FuzzyScore.Default, visibility };
}
const label = this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(element);
@ -624,22 +624,22 @@ class FindFilter<T> implements ITreeFilter<T, FuzzyScore | LabelFuzzyScore>, IDi
for (const l of labels) {
const labelStr = l && l.toString();
if (typeof labelStr === 'undefined') {
return { data: FuzzyScore.Default, visibility: true };
return { data: FuzzyScore.Default, visibility };
}
const score = fuzzyScore(this._pattern, this._lowercasePattern, 0, labelStr, labelStr.toLowerCase(), 0, { firstMatchCanBeWeak: true, boostFullMatch: true });
if (score) {
this._matchCount++;
return labels.length === 1 ?
{ data: score, visibility: true } :
{ data: { label: labelStr, score: score }, visibility: true };
{ data: score, visibility } :
{ data: { label: labelStr, score: score }, visibility };
}
}
if (this.tree.findMode === TreeFindMode.Filter) {
return TreeVisibility.Recurse;
} else {
return { data: FuzzyScore.Default, visibility: true };
return { data: FuzzyScore.Default, visibility };
}
}
@ -685,7 +685,7 @@ export enum TreeFindMode {
class FindWidget<T, TFilterData> extends Disposable {
private readonly elements = h('.monaco-tree-type-filter', [
h('.monaco-tree-type-filter-grab.codicon.codicon-debug-gripper@grab'),
h('.monaco-tree-type-filter-grab.codicon.codicon-debug-gripper@grab', { tabIndex: 0 }),
h('.monaco-tree-type-filter-input@findInput'),
h('.monaco-tree-type-filter-actionbar@actionbar'),
]);
@ -699,7 +699,7 @@ class FindWidget<T, TFilterData> extends Disposable {
private readonly findInput: FindInput;
private readonly actionbar: ActionBar;
private width = 0;
private right = 4;
private right = 0;
readonly _onDidDisable = new Emitter<void>();
readonly onDidDisable = this._onDidDisable.event;
@ -772,6 +772,28 @@ class FindWidget<T, TFilterData> extends Disposable {
}));
}));
const onGrabKeyDown = this._register(Event.chain(this._register(new DomEmitter(this.elements.grab, 'keydown')).event))
.map(e => new StandardKeyboardEvent(e))
.event;
this._register(onGrabKeyDown((e): any => {
let right: number | undefined;
if (e.keyCode === KeyCode.LeftArrow) {
right = Number.POSITIVE_INFINITY;
} else if (e.keyCode === KeyCode.RightArrow) {
right = 0;
} else if (e.keyCode === KeyCode.Space) {
right = this.right === 0 ? Number.POSITIVE_INFINITY : 0;
}
if (right !== undefined) {
e.preventDefault();
e.stopPropagation();
this.right = right;
this.layout();
}
}));
this.onDidChangeValue = this.findInput.onDidChange;
this.style(options ?? {});
@ -799,7 +821,7 @@ class FindWidget<T, TFilterData> extends Disposable {
layout(width: number = this.width): void {
this.width = width;
this.right = Math.min(Math.max(20, this.right), Math.max(20, width - 170));
this.right = clamp(this.right, 0, Math.max(0, width - 212));
this.elements.root.style.right = `${this.right}px`;
}
@ -876,7 +898,8 @@ class FindController<T, TFilterData> implements IDisposable {
return;
}
this.widget = new FindWidget(this.view.getHTMLElement(), this.tree, this.contextViewProvider, this._mode, this.styles);
this.mode = this.tree.options.defaultFindMode ?? TreeFindMode.Highlight;
this.widget = new FindWidget(this.view.getHTMLElement(), this.tree, this.contextViewProvider, this.mode, this.styles);
this.enabledDisposables.add(this.widget);
this.widget.onDidChangeValue(this.onDidChangeValue, this, this.enabledDisposables);
@ -1022,6 +1045,7 @@ export interface IAbstractTreeOptions<T, TFilterData = void> extends IAbstractTr
readonly filter?: ITreeFilter<T, TFilterData>;
readonly dnd?: ITreeDragAndDrop<T>;
readonly additionalScrollHeight?: number;
readonly findWidgetEnabled?: boolean;
}
function dfs<T, TFilterData>(node: ITreeNode<T, TFilterData>, fn: (node: ITreeNode<T, TFilterData>) => void): void {
@ -1436,7 +1460,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
onKeyDown.filter(e => e.keyCode === KeyCode.Space).on(this.onSpace, this, this.disposables);
}
if (_options.keyboardNavigationLabelProvider && _options.contextViewProvider) {
if ((_options.findWidgetEnabled ?? true) && _options.keyboardNavigationLabelProvider && _options.contextViewProvider) {
this.findController = new FindController(this, this.model, this.view, filter!, _options.contextViewProvider);
this.focusNavigationFilter = node => this.findController!.shouldAllowFocus(node);
this.onDidChangeFindOpenState = this.findController.onDidChangeOpenState;

View file

@ -74,8 +74,9 @@
display: flex;
padding: 3px;
transition: top 0.3s;
width: 160px;
max-width: 200px;
z-index: 100;
margin: 0 6px;
}
.monaco-tree-type-filter.disabled {
@ -87,6 +88,7 @@
align-items: center;
justify-content: center;
cursor: grab;
margin-right: 2px;
}
.monaco-tree-type-filter-grab.grabbing {
@ -98,12 +100,16 @@
}
.monaco-tree-type-filter-input .monaco-inputbox {
height: 26px;
height: 23px;
}
.monaco-tree-type-filter-input .monaco-inputbox > .ibwrapper > .input,
.monaco-tree-type-filter-input .monaco-inputbox > .ibwrapper > .mirror {
padding: 2px;
padding: 2px 4px;
}
.monaco-tree-type-filter-input .monaco-findInput > .controls {
top: 2px;
}
.monaco-tree-type-filter-actionbar {

View file

@ -8,7 +8,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { once as onceFn } from 'vs/base/common/functional';
import { combinedDisposable, Disposable, DisposableStore, IDisposable, SafeDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { LinkedList } from 'vs/base/common/linkedList';
import { IObservable, IObserver } from 'vs/base/common/observableImpl/base';
import { IObservable, IObserver } from 'vs/base/common/observable';
import { StopWatch } from 'vs/base/common/stopwatch';

View file

@ -101,6 +101,11 @@ export namespace Schemas {
* Scheme used vs live share
*/
export const vsls = 'vsls';
/**
* Scheme used for the Source Control commit input's text document
*/
export const vscodeSourceControl = 'vscode-scm';
}
export const connectionTokenCookieName = 'vscode-tkn';

View file

@ -275,9 +275,3 @@ export type UriDto<T> = { [K in keyof T]: T[K] extends URI
export function assertNever(value: never, message = 'Unreachable'): never {
throw new Error(message);
}
/**
* Given an object with all optional properties, requires at least one to be defined.
* i.e. AtLeastOne<MyObject>;
*/
export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];

View file

@ -7,7 +7,6 @@
position: absolute;
width: 600px;
z-index: 2550;
padding: 0 1px 1px 1px;
left: 50%;
margin-left: -300px;
-webkit-app-region: no-drag;
@ -151,6 +150,7 @@
.quick-input-list {
line-height: 22px;
margin-top: 6px;
padding: 0px 1px 1px 1px;
}
.quick-input-widget.hidden-input .quick-input-list {

View file

@ -62,7 +62,7 @@ import { ICustomEndpointTelemetryService, ITelemetryService } from 'vs/platform/
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender';
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { supportsTelemetry, ITelemetryAppender, NullAppender, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils';
import { supportsTelemetry, ITelemetryAppender, NullAppender, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import { CustomEndpointTelemetryService } from 'vs/platform/telemetry/node/customEndpointTelemetryService';
import { LocalReconnectConstants, TerminalIpcChannels, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal';
@ -277,19 +277,20 @@ class SharedProcessMain extends Disposable {
// Telemetry
let telemetryService: ITelemetryService;
const appenders: ITelemetryAppender[] = [];
const internalTelemetry = isInternalTelemetry(productService, configurationService);
if (supportsTelemetry(productService, environmentService)) {
const logAppender = new TelemetryLogAppender(loggerService, environmentService);
appenders.push(logAppender);
const { installSourcePath } = environmentService;
if (productService.aiConfig?.ariaKey) {
const collectorAppender = new OneDataSystemWebAppender(configurationService, 'monacoworkbench', null, productService.aiConfig.ariaKey);
const collectorAppender = new OneDataSystemWebAppender(internalTelemetry, 'monacoworkbench', null, productService.aiConfig.ariaKey);
this._register(toDisposable(() => collectorAppender.flush())); // Ensure the 1DS appender is disposed so that it flushes remaining data
appenders.push(collectorAppender);
}
telemetryService = new TelemetryService({
appenders,
commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, productService.msftInternalDomains, installSourcePath),
commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, this.configuration.machineId, internalTelemetry, installSourcePath),
sendErrorTelemetry: true,
piiPaths: getPiiPathsFromEnvironment(environmentService),
}, configurationService, productService);

View file

@ -75,7 +75,7 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProp
import { ITelemetryService, machineIdKey, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';
import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { getPiiPathsFromEnvironment, getTelemetryLevel, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import { getPiiPathsFromEnvironment, getTelemetryLevel, isInternalTelemetry, NullTelemetryService, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import { IUpdateService } from 'vs/platform/update/common/update';
import { UpdateChannel } from 'vs/platform/update/common/updateIpc';
import { DarwinUpdateService } from 'vs/platform/update/electron-main/updateService.darwin';
@ -680,9 +680,10 @@ export class CodeApplication extends Disposable {
// Telemetry
if (supportsTelemetry(this.productService, this.environmentMainService)) {
const isInternal = isInternalTelemetry(this.productService, this.configurationService);
const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender')));
const appender = new TelemetryAppenderClient(channel);
const commonProperties = resolveCommonProperties(this.fileService, release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, this.productService.msftInternalDomains, this.environmentMainService.installSourcePath);
const commonProperties = resolveCommonProperties(this.fileService, release(), hostname(), process.arch, this.productService.commit, this.productService.version, machineId, isInternal, this.environmentMainService.installSourcePath);
const piiPaths = getPiiPathsFromEnvironment(this.environmentMainService);
const config: ITelemetryServiceConfig = { appenders: [appender], commonProperties, piiPaths, sendErrorTelemetry: true };

View file

@ -4,7 +4,7 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: blob: vscode-remote-resource:; media-src 'self'; frame-src 'self' vscode-webview:; object-src 'self'; script-src 'self' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; connect-src 'self' https: ws:; font-src 'self' https: vscode-remote-resource:;">
<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'; trusted-types amdLoader cellRendererEditorText defaultWorkerFactory diffEditorWidget editorGhostText domLineBreaksComputer editorViewLayer diffReview dompurify notebookRenderer safeInnerHtml standaloneColorizer tokenizeToString;">
<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'; trusted-types amdLoader cellRendererEditorText defaultWorkerFactory diffEditorWidget stickyScrollViewLayer editorGhostText domLineBreaksComputer editorViewLayer diffReview dompurify notebookRenderer safeInnerHtml standaloneColorizer tokenizeToString;">
</head>
<body aria-label="">
</body>

View file

@ -63,10 +63,6 @@ export async function main(argv: string[]): Promise<any> {
// Shell integration
else if (args['locate-shell-integration-path']) {
// Silently fail when the terminal is not VS Code's integrated terminal
if (process.env['TERM_PROGRAM'] !== 'vscode') {
return;
}
let file: string;
switch (args['locate-shell-integration-path']) {
// Usage: `[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path bash)"`

View file

@ -52,7 +52,7 @@ import { StateService } from 'vs/platform/state/node/stateService';
import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties';
import { ITelemetryService, machineIdKey } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils';
import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment, isInternalTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender';
import { buildTelemetryMessage } from 'vs/platform/telemetry/node/telemetry';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
@ -187,9 +187,10 @@ class CliMain extends Disposable {
// Telemetry
const appenders: OneDataSystemAppender[] = [];
const isInternal = isInternalTelemetry(productService, configurationService);
if (supportsTelemetry(productService, environmentService)) {
if (productService.aiConfig && productService.aiConfig.ariaKey) {
appenders.push(new OneDataSystemAppender(configurationService, 'monacoworkbench', null, productService.aiConfig.ariaKey));
appenders.push(new OneDataSystemAppender(isInternal, 'monacoworkbench', null, productService.aiConfig.ariaKey));
}
const { installSourcePath } = environmentService;
@ -208,7 +209,7 @@ class CliMain extends Disposable {
}
}
return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, productService.msftInternalDomains, installSourcePath);
return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, isInternal, installSourcePath);
})(),
piiPaths: getPiiPathsFromEnvironment(environmentService)
};

View file

@ -84,7 +84,7 @@ export namespace EditorScroll_ {
\`\`\`
* 'by': Unit to move. Default is computed based on 'to' value.
\`\`\`
'line', 'wrappedLine', 'page', 'halfPage'
'line', 'wrappedLine', 'page', 'halfPage', 'editor'
\`\`\`
* 'value': Number of units to move. Default is '1'.
* 'revealCursor': If 'true' reveals the cursor if it is outside view port.
@ -100,7 +100,7 @@ export namespace EditorScroll_ {
},
'by': {
'type': 'string',
'enum': ['line', 'wrappedLine', 'page', 'halfPage']
'enum': ['line', 'wrappedLine', 'page', 'halfPage', 'editor']
},
'value': {
'type': 'number',
@ -130,7 +130,8 @@ export namespace EditorScroll_ {
Line: 'line',
WrappedLine: 'wrappedLine',
Page: 'page',
HalfPage: 'halfPage'
HalfPage: 'halfPage',
Editor: 'editor'
};
/**
@ -172,6 +173,9 @@ export namespace EditorScroll_ {
case RawUnit.HalfPage:
unit = Unit.HalfPage;
break;
case RawUnit.Editor:
unit = Unit.Editor;
break;
default:
unit = Unit.WrappedLine;
}
@ -205,7 +209,8 @@ export namespace EditorScroll_ {
Line = 1,
WrappedLine = 2,
Page = 3,
HalfPage = 4
HalfPage = 4,
Editor = 5
}
}
@ -1279,6 +1284,14 @@ export namespace CoreNavigationCommands {
return viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
}
if (args.unit === EditorScroll_.Unit.Editor) {
let desiredTopModelLineNumber = 0;
if (args.direction === EditorScroll_.Direction.Down) {
desiredTopModelLineNumber = viewModel.model.getLineCount() - viewModel.cursorConfig.pageSize;
}
return viewModel.viewLayout.getVerticalOffsetForLineNumber(desiredTopModelLineNumber);
}
let noOfLines: number;
if (args.unit === EditorScroll_.Unit.Page) {
noOfLines = viewModel.cursorConfig.pageSize * args.value;
@ -1345,6 +1358,29 @@ export namespace CoreNavigationCommands {
}
});
export const ScrollEditorTop: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
constructor() {
super({
id: 'scrollEditorTop',
precondition: undefined,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: EditorContextKeys.textInputFocus,
}
});
}
runCoreEditorCommand(viewModel: IViewModel, args: any): void {
EditorScroll._runEditorScroll(viewModel, args.source, {
direction: EditorScroll_.Direction.Up,
unit: EditorScroll_.Unit.Editor,
value: 1,
revealCursor: false,
select: false
});
}
});
export const ScrollLineDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
constructor() {
super({
@ -1396,6 +1432,29 @@ export namespace CoreNavigationCommands {
}
});
export const ScrollEditorBottom: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
constructor() {
super({
id: 'scrollEditorBottom',
precondition: undefined,
kbOpts: {
weight: CORE_WEIGHT,
kbExpr: EditorContextKeys.textInputFocus,
}
});
}
runCoreEditorCommand(viewModel: IViewModel, args: any): void {
EditorScroll._runEditorScroll(viewModel, args.source, {
direction: EditorScroll_.Direction.Down,
unit: EditorScroll_.Unit.Editor,
value: 1,
revealCursor: false,
select: false
});
}
});
class WordCommand extends CoreEditorCommand {
private readonly _inSelectionMode: boolean;

View file

@ -899,10 +899,15 @@ export interface ICodeEditor extends editorCommon.IEditor {
getWhitespaces(): IEditorWhitespace[];
/**
* Get the vertical position (top offset) for the line w.r.t. to the first line.
* Get the vertical position (top offset) for the line's top w.r.t. to the first line.
*/
getTopForLineNumber(lineNumber: number): number;
/**
* Get the vertical position (top offset) for the line's bottom w.r.t. to the first line.
*/
getBottomForLineNumber(lineNumber: number): number;
/**
* Get the vertical position (top offset) for the position w.r.t. to the first line.
*/

View file

@ -368,10 +368,15 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
this._actions[internalAction.id] = internalAction;
});
const isDropIntoEnabled = () => {
return !this._configuration.options.get(EditorOption.readOnly)
&& this._configuration.options.get(EditorOption.dropIntoEditor).enabled;
};
this._register(new dom.DragAndDropObserver(this._domElement, {
onDragEnter: () => undefined,
onDragOver: e => {
if (!this._configuration.options.get(EditorOption.enableDropIntoEditor)) {
if (!isDropIntoEnabled()) {
return;
}
@ -381,7 +386,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
}
},
onDrop: async e => {
if (!this._configuration.options.get(EditorOption.enableDropIntoEditor)) {
if (!isDropIntoEnabled()) {
return;
}

View file

@ -1189,7 +1189,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
result.ariaLabel = options.originalAriaLabel;
}
result.readOnly = !this._options.originalEditable;
result.enableDropIntoEditor = !result.readOnly;
result.dropIntoEditor = { enabled: !result.readOnly };
result.extraEditorClassName = 'original-in-monaco-diff-editor';
return {
...result,

View file

@ -169,6 +169,10 @@ export interface IEditorOptions {
* Control the behavior and rendering of the scrollbars.
*/
scrollbar?: IEditorScrollbarOptions;
/**
* Control the behavior of experimental options
*/
experimental?: IEditorExperimentalOptions;
/**
* Control the behavior and rendering of the minimap.
*/
@ -661,11 +665,11 @@ export interface IEditorOptions {
bracketPairColorization?: IBracketPairColorizationOptions;
/**
* Enables dropping into the editor from an external source.
* Controls dropping into the editor from an external source.
*
* This shows a preview of the drop location and triggers an `onDropIntoEditor` event.
* When enabled, this shows a preview of the drop location and triggers an `onDropIntoEditor` event.
*/
enableDropIntoEditor?: boolean;
dropIntoEditor?: IDropIntoEditorOptions;
}
/**
@ -876,7 +880,7 @@ function applyUpdate<T>(value: T | undefined, update: T): ApplyUpdateResult<T> {
}
if (Array.isArray(value) || Array.isArray(update)) {
const arrayEquals = Array.isArray(value) && Array.isArray(update) && arrays.equals(value, update);
return new ApplyUpdateResult(update, arrayEquals);
return new ApplyUpdateResult(update, !arrayEquals);
}
let didChange = false;
for (const key in update) {
@ -2504,6 +2508,57 @@ class EditorLightbulb extends BaseEditorOption<EditorOption.lightbulb, IEditorLi
//#endregion
//#region experimental
export interface IEditorExperimentalOptions {
/**
* Configuration options for editor sticky scroll
*/
stickyScroll?: {
/**
* Enable the sticky scroll
*/
enabled?: boolean;
};
}
export interface EditorExperimentalOptions {
stickyScroll: {
enabled: boolean;
};
}
class EditorExperimental extends BaseEditorOption<EditorOption.experimental, IEditorExperimentalOptions, EditorExperimentalOptions> {
constructor() {
const defaults: EditorExperimentalOptions = { stickyScroll: { enabled: false } };
super(
EditorOption.experimental, 'experimental', defaults,
{
'editor.experimental.stickyScroll.enabled': {
type: 'boolean',
default: defaults.stickyScroll.enabled,
description: nls.localize('editor.experimental.stickyScroll', "Shows the nested current scopes during the scroll at the top of the editor.")
},
}
);
}
public validate(_input: any): EditorExperimentalOptions {
if (!_input || typeof _input !== 'object') {
return this.defaultValue;
}
const input = _input as IEditorExperimentalOptions;
return {
stickyScroll: {
enabled: boolean(input.stickyScroll?.enabled, this.defaultValue.stickyScroll.enabled)
}
};
}
}
//#endregion
//#region inlayHints
/**
@ -4387,6 +4442,53 @@ class EditorWrappingInfoComputer extends ComputedEditorOption<EditorOption.wrapp
//#endregion
//#region dropIntoEditor
/**
* Configuration options for editor drop into behavior
*/
export interface IDropIntoEditorOptions {
/**
* Enable the dropping into editor.
* Defaults to true.
*/
enabled?: boolean;
}
/**
* @internal
*/
export type EditorDropIntoEditorOptions = Readonly<Required<IDropIntoEditorOptions>>;
class EditorDropIntoEditor extends BaseEditorOption<EditorOption.dropIntoEditor, IDropIntoEditorOptions, EditorDropIntoEditorOptions> {
constructor() {
const defaults: EditorDropIntoEditorOptions = { enabled: true };
super(
EditorOption.dropIntoEditor, 'dropIntoEditor', defaults,
{
'editor.dropIntoEditor.enabled': {
type: 'boolean',
default: defaults.enabled,
markdownDescription: nls.localize('dropIntoEditor.enabled', "Controls whether you can drag and drop a file into a text editor by holding down `shift` (instead of opening the file in an editor)."),
},
}
);
}
public validate(_input: any): EditorDropIntoEditorOptions {
if (!_input || typeof _input !== 'object') {
return this.defaultValue;
}
const input = _input as IDropIntoEditorOptions;
return {
enabled: boolean(input.enabled, this.defaultValue.enabled)
};
}
}
//#endregion
const DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \'Courier New\', monospace';
const DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \'Courier New\', monospace';
const DEFAULT_LINUX_FONT_FAMILY = '\'Droid Sans Mono\', \'monospace\', monospace';
@ -4449,8 +4551,9 @@ export const enum EditorOption {
disableMonospaceOptimizations,
domReadOnly,
dragAndDrop,
enableDropIntoEditor,
dropIntoEditor,
emptySelectionClipboard,
experimental,
extraEditorClassName,
fastScrollSensitivity,
find,
@ -4758,9 +4861,8 @@ export const EditorOptions = {
{ description: nls.localize('dragAndDrop', "Controls whether the editor should allow moving selections via drag and drop.") }
)),
emptySelectionClipboard: register(new EditorEmptySelectionClipboard()),
enableDropIntoEditor: register(new EditorBooleanOption(
EditorOption.enableDropIntoEditor, 'enableDropIntoEditor', true
)),
dropIntoEditor: register(new EditorDropIntoEditor()),
experimental: register(new EditorExperimental()),
extraEditorClassName: register(new EditorStringOption(
EditorOption.extraEditorClassName, 'extraEditorClassName', '',
)),

View file

@ -669,9 +669,6 @@ export interface CodeAction {
disabled?: string;
}
/**
* @internal
*/
export const enum CodeActionTriggerType {
Invoke = 1,
Auto = 2,
@ -1132,7 +1129,11 @@ export interface DocumentSymbolProvider {
provideDocumentSymbols(model: model.ITextModel, token: CancellationToken): ProviderResult<DocumentSymbol[]>;
}
export type TextEdit = { range: IRange; text: string; eol?: model.EndOfLineSequence };
export interface TextEdit {
range: IRange;
text: string;
eol?: model.EndOfLineSequence;
}
/**
* Interface used to format a model

View file

@ -528,13 +528,18 @@ export const enum TrackedRangeStickiness {
* Text snapshot that works like an iterator.
* Will try to return chunks of roughly ~64KB size.
* Will return null when finished.
*
* @internal
*/
export interface ITextSnapshot {
read(): string | null;
}
/**
* @internal
*/
export function isITextSnapshot(obj: any): obj is ITextSnapshot {
return (obj && typeof obj.read === 'function');
}
/**
* A model.
*/
@ -610,7 +615,7 @@ export interface ITextModel {
/**
* Replace the entire text buffer value contained in this model.
*/
setValue(newValue: string): void;
setValue(newValue: string | ITextSnapshot): void;
/**
* Get the text stored in this model.
@ -624,7 +629,6 @@ export interface ITextModel {
* Get the text stored in this model.
* @param preserverBOM Preserve a BOM character if it was detected when the model was constructed.
* @return The text snapshot (it is safe to consume it asynchronously).
* @internal
*/
createSnapshot(preserveBOM?: boolean): ITextSnapshot;

View file

@ -44,12 +44,8 @@ import { ITokenizationTextModelPart } from 'vs/editor/common/tokenizationTextMod
import { IColorTheme, ThemeColor } from 'vs/platform/theme/common/themeService';
import { IUndoRedoService, ResourceEditStackSnapshot } from 'vs/platform/undoRedo/common/undoRedo';
function createTextBufferBuilder() {
return new PieceTreeTextBufferBuilder();
}
export function createTextBufferFactory(text: string): model.ITextBufferFactory {
const builder = createTextBufferBuilder();
const builder = new PieceTreeTextBufferBuilder();
builder.acceptChunk(text);
return builder.finish();
}
@ -65,7 +61,7 @@ export function createTextBufferFactoryFromStream(stream: ITextStream): Promise<
export function createTextBufferFactoryFromStream(stream: VSBufferReadableStream): Promise<model.ITextBufferFactory>;
export function createTextBufferFactoryFromStream(stream: ITextStream | VSBufferReadableStream): Promise<model.ITextBufferFactory> {
return new Promise<model.ITextBufferFactory>((resolve, reject) => {
const builder = createTextBufferBuilder();
const builder = new PieceTreeTextBufferBuilder();
let done = false;
@ -90,7 +86,7 @@ export function createTextBufferFactoryFromStream(stream: ITextStream | VSBuffer
}
export function createTextBufferFactoryFromSnapshot(snapshot: model.ITextSnapshot): model.ITextBufferFactory {
const builder = createTextBufferBuilder();
const builder = new PieceTreeTextBufferBuilder();
let chunk: string | null;
while (typeof (chunk = snapshot.read()) === 'string') {
@ -100,8 +96,15 @@ export function createTextBufferFactoryFromSnapshot(snapshot: model.ITextSnapsho
return builder.finish();
}
export function createTextBuffer(value: string | model.ITextBufferFactory, defaultEOL: model.DefaultEndOfLine): { textBuffer: model.ITextBuffer; disposable: IDisposable } {
const factory = (typeof value === 'string' ? createTextBufferFactory(value) : value);
export function createTextBuffer(value: string | model.ITextBufferFactory | model.ITextSnapshot, defaultEOL: model.DefaultEndOfLine): { textBuffer: model.ITextBuffer; disposable: IDisposable } {
let factory: model.ITextBufferFactory;
if (typeof value === 'string') {
factory = createTextBufferFactory(value);
} else if (model.isITextSnapshot(value)) {
factory = createTextBufferFactoryFromSnapshot(value);
} else {
factory = value;
}
return factory.create(defaultEOL);
}
@ -424,7 +427,7 @@ export class TextModel extends Disposable implements model.ITextModel, IDecorati
this._eventEmitter.fire(new InternalModelContentChangeEvent(rawChange, change));
}
public setValue(value: string): void {
public setValue(value: string | model.ITextSnapshot): void {
this._assertNotDisposed();
if (value === null) {
// There's nothing to do

View file

@ -71,7 +71,6 @@ export function getIconClasses(modelService: IModelService, languageService: ILa
return classes;
}
export function getIconClassesForLanguageId(languageId: string): string[] {
return ['file-icon', `${cssEscape(languageId)}-lang-file-icon`];
}

View file

@ -15,6 +15,11 @@ export enum AccessibilitySupport {
Enabled = 2
}
export enum CodeActionTriggerType {
Invoke = 1,
Auto = 2
}
export enum CompletionItemInsertTextRule {
/**
* Adjust whitespace/indentation of multiline insert texts to
@ -199,108 +204,109 @@ export enum EditorOption {
disableMonospaceOptimizations = 29,
domReadOnly = 30,
dragAndDrop = 31,
enableDropIntoEditor = 32,
dropIntoEditor = 32,
emptySelectionClipboard = 33,
extraEditorClassName = 34,
fastScrollSensitivity = 35,
find = 36,
fixedOverflowWidgets = 37,
folding = 38,
foldingStrategy = 39,
foldingHighlight = 40,
foldingImportsByDefault = 41,
foldingMaximumRegions = 42,
unfoldOnClickAfterEndOfLine = 43,
fontFamily = 44,
fontInfo = 45,
fontLigatures = 46,
fontSize = 47,
fontWeight = 48,
formatOnPaste = 49,
formatOnType = 50,
glyphMargin = 51,
gotoLocation = 52,
hideCursorInOverviewRuler = 53,
hover = 54,
inDiffEditor = 55,
inlineSuggest = 56,
letterSpacing = 57,
lightbulb = 58,
lineDecorationsWidth = 59,
lineHeight = 60,
lineNumbers = 61,
lineNumbersMinChars = 62,
linkedEditing = 63,
links = 64,
matchBrackets = 65,
minimap = 66,
mouseStyle = 67,
mouseWheelScrollSensitivity = 68,
mouseWheelZoom = 69,
multiCursorMergeOverlapping = 70,
multiCursorModifier = 71,
multiCursorPaste = 72,
occurrencesHighlight = 73,
overviewRulerBorder = 74,
overviewRulerLanes = 75,
padding = 76,
parameterHints = 77,
peekWidgetDefaultFocus = 78,
definitionLinkOpensInPeek = 79,
quickSuggestions = 80,
quickSuggestionsDelay = 81,
readOnly = 82,
renameOnType = 83,
renderControlCharacters = 84,
renderFinalNewline = 85,
renderLineHighlight = 86,
renderLineHighlightOnlyWhenFocus = 87,
renderValidationDecorations = 88,
renderWhitespace = 89,
revealHorizontalRightPadding = 90,
roundedSelection = 91,
rulers = 92,
scrollbar = 93,
scrollBeyondLastColumn = 94,
scrollBeyondLastLine = 95,
scrollPredominantAxis = 96,
selectionClipboard = 97,
selectionHighlight = 98,
selectOnLineNumbers = 99,
showFoldingControls = 100,
showUnused = 101,
snippetSuggestions = 102,
smartSelect = 103,
smoothScrolling = 104,
stickyTabStops = 105,
stopRenderingLineAfter = 106,
suggest = 107,
suggestFontSize = 108,
suggestLineHeight = 109,
suggestOnTriggerCharacters = 110,
suggestSelection = 111,
tabCompletion = 112,
tabIndex = 113,
unicodeHighlighting = 114,
unusualLineTerminators = 115,
useShadowDOM = 116,
useTabStops = 117,
wordSeparators = 118,
wordWrap = 119,
wordWrapBreakAfterCharacters = 120,
wordWrapBreakBeforeCharacters = 121,
wordWrapColumn = 122,
wordWrapOverride1 = 123,
wordWrapOverride2 = 124,
wrappingIndent = 125,
wrappingStrategy = 126,
showDeprecated = 127,
inlayHints = 128,
editorClassName = 129,
pixelRatio = 130,
tabFocusMode = 131,
layoutInfo = 132,
wrappingInfo = 133
experimental = 34,
extraEditorClassName = 35,
fastScrollSensitivity = 36,
find = 37,
fixedOverflowWidgets = 38,
folding = 39,
foldingStrategy = 40,
foldingHighlight = 41,
foldingImportsByDefault = 42,
foldingMaximumRegions = 43,
unfoldOnClickAfterEndOfLine = 44,
fontFamily = 45,
fontInfo = 46,
fontLigatures = 47,
fontSize = 48,
fontWeight = 49,
formatOnPaste = 50,
formatOnType = 51,
glyphMargin = 52,
gotoLocation = 53,
hideCursorInOverviewRuler = 54,
hover = 55,
inDiffEditor = 56,
inlineSuggest = 57,
letterSpacing = 58,
lightbulb = 59,
lineDecorationsWidth = 60,
lineHeight = 61,
lineNumbers = 62,
lineNumbersMinChars = 63,
linkedEditing = 64,
links = 65,
matchBrackets = 66,
minimap = 67,
mouseStyle = 68,
mouseWheelScrollSensitivity = 69,
mouseWheelZoom = 70,
multiCursorMergeOverlapping = 71,
multiCursorModifier = 72,
multiCursorPaste = 73,
occurrencesHighlight = 74,
overviewRulerBorder = 75,
overviewRulerLanes = 76,
padding = 77,
parameterHints = 78,
peekWidgetDefaultFocus = 79,
definitionLinkOpensInPeek = 80,
quickSuggestions = 81,
quickSuggestionsDelay = 82,
readOnly = 83,
renameOnType = 84,
renderControlCharacters = 85,
renderFinalNewline = 86,
renderLineHighlight = 87,
renderLineHighlightOnlyWhenFocus = 88,
renderValidationDecorations = 89,
renderWhitespace = 90,
revealHorizontalRightPadding = 91,
roundedSelection = 92,
rulers = 93,
scrollbar = 94,
scrollBeyondLastColumn = 95,
scrollBeyondLastLine = 96,
scrollPredominantAxis = 97,
selectionClipboard = 98,
selectionHighlight = 99,
selectOnLineNumbers = 100,
showFoldingControls = 101,
showUnused = 102,
snippetSuggestions = 103,
smartSelect = 104,
smoothScrolling = 105,
stickyTabStops = 106,
stopRenderingLineAfter = 107,
suggest = 108,
suggestFontSize = 109,
suggestLineHeight = 110,
suggestOnTriggerCharacters = 111,
suggestSelection = 112,
tabCompletion = 113,
tabIndex = 114,
unicodeHighlighting = 115,
unusualLineTerminators = 116,
useShadowDOM = 117,
useTabStops = 118,
wordSeparators = 119,
wordWrap = 120,
wordWrapBreakAfterCharacters = 121,
wordWrapBreakBeforeCharacters = 122,
wordWrapColumn = 123,
wordWrapOverride1 = 124,
wordWrapOverride2 = 125,
wrappingIndent = 126,
wrappingStrategy = 127,
showDeprecated = 128,
inlayHints = 129,
editorClassName = 130,
pixelRatio = 131,
tabFocusMode = 132,
layoutInfo = 133,
wrappingInfo = 134
}
/**

View file

@ -70,7 +70,7 @@ export class ViewportData {
}
public getViewLineRenderingData(lineNumber: number): ViewLineRenderingData {
return this._model.getViewLineRenderingData(this.visibleRange, lineNumber);
return this._model.getViewportViewLineRenderingData(this.visibleRange, lineNumber);
}
public getDecorationsInViewport(): ViewModelDecoration[] {

View file

@ -41,12 +41,15 @@ export interface IViewModel extends ICursorSimpleModel {
onCompositionEnd(): void;
getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[];
getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData;
getViewportViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData;
getViewLineRenderingData(lineNumber: number): ViewLineRenderingData;
getViewLineData(lineNumber: number): ViewLineData;
getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): MinimapLinesRenderingData;
getCompletelyVisibleViewRange(): Range;
getCompletelyVisibleViewRangeAtScrollTop(scrollTop: number): Range;
getHiddenAreas(): Range[];
getLineCount(): number;
getLineContent(lineNumber: number): string;
getLineLength(lineNumber: number): number;

View file

@ -100,17 +100,21 @@ export class ViewModelDecorations implements IDisposable {
let cacheIsValid = (this._cachedModelDecorationsResolver !== null);
cacheIsValid = cacheIsValid && (viewRange.equalsRange(this._cachedModelDecorationsResolverViewRange));
if (!cacheIsValid) {
this._cachedModelDecorationsResolver = this._getDecorationsViewportData(viewRange);
this._cachedModelDecorationsResolver = this._getDecorationsInRange(viewRange);
this._cachedModelDecorationsResolverViewRange = viewRange;
}
return this._cachedModelDecorationsResolver!;
}
private _getDecorationsViewportData(viewportRange: Range): IDecorationsViewportData {
const modelDecorations = this._linesCollection.getDecorationsInRange(viewportRange, this.editorId, filterValidationDecorations(this.configuration.options));
public getInlineDecorationsOnLine(lineNumber: number): InlineDecoration[] {
const range = new Range(lineNumber, this._linesCollection.getViewLineMinColumn(lineNumber), lineNumber, this._linesCollection.getViewLineMaxColumn(lineNumber));
return this._getDecorationsInRange(range).inlineDecorations[0];
}
const startLineNumber = viewportRange.startLineNumber;
const endLineNumber = viewportRange.endLineNumber;
private _getDecorationsInRange(viewRange: Range): IDecorationsViewportData {
const modelDecorations = this._linesCollection.getDecorationsInRange(viewRange, this.editorId, filterValidationDecorations(this.configuration.options));
const startLineNumber = viewRange.startLineNumber;
const endLineNumber = viewRange.endLineNumber;
const decorationsInViewport: ViewModelDecoration[] = [];
let decorationsInViewportLen = 0;

View file

@ -34,9 +34,9 @@ import { ViewLayout } from 'vs/editor/common/viewLayout/viewLayout';
import { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker';
import { ILineBreaksComputer, ILineBreaksComputerFactory, InjectedText } from 'vs/editor/common/modelLineProjectionData';
import { ViewEventHandler } from 'vs/editor/common/viewEventHandler';
import { ICoordinatesConverter, IViewModel, IWhitespaceChangeAccessor, MinimapLinesRenderingData, OverviewRulerDecorationsGroup, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel';
import { ICoordinatesConverter, InlineDecoration, IViewModel, IWhitespaceChangeAccessor, MinimapLinesRenderingData, OverviewRulerDecorationsGroup, ViewLineData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel';
import { ViewModelDecorations } from 'vs/editor/common/viewModel/viewModelDecorations';
import { FocusChangedEvent, ModelContentChangedEvent, ModelDecorationsChangedEvent, ModelLanguageChangedEvent, ModelLanguageConfigurationChangedEvent, ModelOptionsChangedEvent, ModelTokensChangedEvent, OutgoingViewModelEvent, ReadOnlyEditAttemptEvent, ScrollChangedEvent, ViewModelEventDispatcher, ViewModelEventsCollector, ViewZonesChangedEvent } from 'vs/editor/common/viewModelEventDispatcher';
import { FocusChangedEvent, HiddenAreasChangedEvent, ModelContentChangedEvent, ModelDecorationsChangedEvent, ModelLanguageChangedEvent, ModelLanguageConfigurationChangedEvent, ModelOptionsChangedEvent, ModelTokensChangedEvent, OutgoingViewModelEvent, ReadOnlyEditAttemptEvent, ScrollChangedEvent, ViewModelEventDispatcher, ViewModelEventsCollector, ViewZonesChangedEvent } from 'vs/editor/common/viewModelEventDispatcher';
import { IViewModelLines, ViewModelLinesFromModelAsIs, ViewModelLinesFromProjectedModel } from 'vs/editor/common/viewModel/viewModelLines';
import { IThemeService } from 'vs/platform/theme/common/themeService';
@ -485,7 +485,7 @@ export class ViewModel extends Disposable implements IViewModel {
this._updateConfigurationViewLineCount.schedule();
if (lineMappingChanged) {
this._eventDispatcher.emitOutgoingEvent(new ViewZonesChangedEvent());
this._eventDispatcher.emitOutgoingEvent(new HiddenAreasChangedEvent());
}
}
@ -508,6 +508,10 @@ export class ViewModel extends Disposable implements IViewModel {
return this._toModelVisibleRanges(visibleViewRange);
}
public getHiddenAreas(): Range[] {
return this._lines.getHiddenAreas();
}
private _toModelVisibleRanges(visibleViewRange: Range): Range[] {
const visibleRange = this.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);
const hiddenAreas = this._lines.getHiddenAreas();
@ -679,13 +683,22 @@ export class ViewModel extends Disposable implements IViewModel {
return this._lines.getInjectedTextAt(viewPosition);
}
public getViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData {
public getViewportViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData {
const allInlineDecorations = this._decorations.getDecorationsViewportData(visibleRange).inlineDecorations;
const inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber];
return this._getViewLineRenderingData(lineNumber, inlineDecorations);
}
public getViewLineRenderingData(lineNumber: number): ViewLineRenderingData {
const inlineDecorations = this._decorations.getInlineDecorationsOnLine(lineNumber);
return this._getViewLineRenderingData(lineNumber, inlineDecorations);
}
private _getViewLineRenderingData(lineNumber: number, inlineDecorations: InlineDecoration[]): ViewLineRenderingData {
const mightContainRTL = this.model.mightContainRTL();
const mightContainNonBasicASCII = this.model.mightContainNonBasicASCII();
const tabSize = this.getTabSize();
const lineData = this._lines.getViewLineData(lineNumber);
const allInlineDecorations = this._decorations.getDecorationsViewportData(visibleRange).inlineDecorations;
let inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber];
if (lineData.inlineDecorations) {
inlineDecorations = [

View file

@ -151,6 +151,13 @@ export class QuickFixController extends Disposable implements IEditorContributio
}
}
public selectedOptionWithPreview() {
if (this._ui.hasValue()) {
this._ui.getValue().onPreviewEnter();
}
}
public showCodeActions(trigger: CodeActionTrigger, actions: CodeActionSet, at: IAnchor | IPosition) {
return this._ui.getValue().showCodeActionList(trigger, actions, at, { includeDisabledActions: false, fromLightbulb: false });
}
@ -566,4 +573,16 @@ registerEditorCommand(new CodeActionContribution({
}
}));
registerEditorCommand(new CodeActionContribution({
id: 'onEnterSelectCodeActionWithPreview',
precondition: Context.Visible,
handler(x) {
x.selectedOptionWithPreview();
},
kbOpts: {
weight: weight + 100000,
primary: KeyMod.CtrlCmd | KeyCode.Enter,
}
}));

View file

@ -5,7 +5,7 @@
import * as dom from 'vs/base/browser/dom';
import { IAnchor } from 'vs/base/browser/ui/contextview/contextview';
import { IListEvent, IListRenderer } from 'vs/base/browser/ui/list/list';
import { IListEvent, IListMouseEvent, IListRenderer } from 'vs/base/browser/ui/list/list';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { Action, IAction, Separator } from 'vs/base/common/actions';
import { canceled } from 'vs/base/common/errors';
@ -69,6 +69,7 @@ export interface ICodeActionMenuItem {
decoratorRight?: string;
isSeparator?: boolean;
isEnabled: boolean;
isDocumentation: boolean;
index: number;
disposables?: IDisposable[];
}
@ -93,6 +94,12 @@ const TEMPLATE_ID = 'codeActionWidget';
const codeActionLineHeight = 26;
class CodeMenuRenderer implements IListRenderer<ICodeActionMenuItem, ICodeActionMenuTemplateData> {
constructor(
private readonly acceptKeybindings: [string, string],
@IKeybindingService private readonly keybindingService: IKeybindingService,
) { }
get templateId(): string { return TEMPLATE_ID; }
renderTemplate(container: HTMLElement): ICodeActionMenuTemplateData {
@ -114,6 +121,7 @@ class CodeMenuRenderer implements IListRenderer<ICodeActionMenuItem, ICodeAction
const isEnabled = element.isEnabled;
const isSeparator = element.isSeparator;
const isDocumentation = element.isDocumentation;
data.text.textContent = text;
// data.detail.textContent = detail;
@ -130,6 +138,15 @@ class CodeMenuRenderer implements IListRenderer<ICodeActionMenuItem, ICodeAction
data.root.style.height = '10px';
}
if (!isDocumentation) {
const updateLabel = () => {
const [accept, preview] = this.acceptKeybindings;
data.root.title = localize({ key: 'label', comment: ['placeholders are keybindings, e.g "F2 to Refactor, Shift+F2 to Preview"'] }, "{0} to Refactor, {1} to Preview", this.keybindingService.lookupKeybinding(accept)?.getLabel(), this.keybindingService.lookupKeybinding(preview)?.getLabel());
// data.root.title = this.keybindingService.lookupKeybinding(accept)?.getLabel() + ' to Refactor, ' + this.keybindingService.lookupKeybinding(preview)?.getLabel() + ' to Preview';
};
updateLabel();
}
}
disposeTemplate(templateData: ICodeActionMenuTemplateData): void {
templateData.disposables = dispose(templateData.disposables);
@ -144,8 +161,11 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
private _ctxMenuWidgetVisible: IContextKey<boolean>;
private viewItems: ICodeActionMenuItem[] = [];
private focusedEnabledItem: number | undefined;
private currSelectedItem: number = 0;
private currSelectedItem: number | undefined;
private hasSeperator: boolean = false;
private block?: HTMLElement;
public static readonly documentationID: string = '_documentation';
public static readonly ID: string = 'editor.contrib.codeActionMenu';
@ -154,7 +174,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
}
private readonly _keybindingResolver: CodeActionKeybindingResolver;
private listRenderer: CodeMenuRenderer = new CodeMenuRenderer();
private listRenderer: CodeMenuRenderer;
constructor(
private readonly _editor: ICodeEditor,
@ -175,6 +195,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
});
this._ctxMenuWidgetVisible = Context.Visible.bindTo(this._contextKeyService);
this.listRenderer = new CodeMenuRenderer([`onEnterSelectCodeAction`, `onEnterSelectCodeActionWithPreview`], keybindingService);
}
get isVisible(): boolean {
@ -192,17 +213,46 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
e.elements.forEach(element => {
if (element.isEnabled) {
element.action.run();
this.hideCodeActionWidget();
}
});
this.hideCodeActionWidget();
}
}
private _onListHover(e: IListMouseEvent<ICodeActionMenuItem>): void {
if (!e.element) {
this.currSelectedItem = undefined;
this.codeActionList.value?.setFocus([]);
} else {
if (e.element?.isEnabled) {
this.codeActionList.value?.setFocus([e.element.index]);
this.focusedEnabledItem = this.viewItems.indexOf(e.element);
this.currSelectedItem = e.element.index;
} else {
this.currSelectedItem = undefined;
this.codeActionList.value?.setFocus([e.element.index]);
}
}
}
private renderCodeActionMenuList(element: HTMLElement, inputArray: IAction[]): IDisposable {
const renderDisposables = new DisposableStore();
const renderMenu = document.createElement('div');
// Render invisible div to block mouse interaction in the rest of the UI
const menuBlock = document.createElement('div');
this.block = element.appendChild(menuBlock);
this.block.classList.add('context-view-block');
this.block.style.position = 'fixed';
this.block.style.cursor = 'initial';
this.block.style.left = '0';
this.block.style.top = '0';
this.block.style.width = '100%';
this.block.style.height = '100%';
this.block.style.zIndex = '-1';
renderDisposables.add(dom.addDisposableListener(this.block, dom.EventType.MOUSE_DOWN, e => e.stopPropagation()));
renderMenu.id = 'codeActionMenuWidget';
renderMenu.classList.add('codeActionMenuWidget');
@ -221,6 +271,8 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
}, [this.listRenderer], { keyboardSupport: false }
);
renderDisposables.add(this.codeActionList.value.onMouseOver(e => this._onListHover(e)));
renderDisposables.add(this.codeActionList.value.onDidChangeFocus(e => this.codeActionList.value?.domFocus()));
renderDisposables.add(this.codeActionList.value.onDidChangeSelection(e => this._onListSelection(e)));
renderDisposables.add(this._editor.onDidLayoutChange(e => this.hideCodeActionWidget()));
@ -228,11 +280,16 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
// Populating the list widget and tracking enabled options.
inputArray.forEach((item, index) => {
const currIsSeparator = item.class === 'separator';
let isDocumentation = false;
if (item instanceof CodeActionAction) {
isDocumentation = item.action.kind === CodeActionMenu.documentationID;
}
if (currIsSeparator) {
// set to true forever
this.hasSeperator = true;
}
const menuItem = <ICodeActionMenuItem>{ title: item.label, detail: item.tooltip, action: inputArray[index], isEnabled: item.enabled, isSeparator: currIsSeparator, index };
const menuItem = <ICodeActionMenuItem>{ title: item.label, detail: item.tooltip, action: inputArray[index], isEnabled: item.enabled, isSeparator: currIsSeparator, index, isDocumentation };
if (item.enabled) {
this.viewItems.push(menuItem);
}
@ -263,9 +320,13 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
this.codeActionList.value?.layout(height, maxWidth);
// List selection
this.focusedEnabledItem = 0;
this.currSelectedItem = this.viewItems[0].index;
this.codeActionList.value.setFocus([this.currSelectedItem]);
if (this.viewItems.length < 1 || this.viewItems.every(item => item.isDocumentation)) {
this.currSelectedItem = undefined;
} else {
this.focusedEnabledItem = 0;
this.currSelectedItem = this.viewItems[0].index;
this.codeActionList.value.setFocus([this.currSelectedItem]);
}
// List Focus
this.codeActionList.value.domFocus();
@ -284,7 +345,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
protected focusPrevious() {
if (typeof this.focusedEnabledItem === 'undefined') {
this.focusedEnabledItem = this.viewItems[0].index;
} else if (this.viewItems.length <= 1) {
} else if (this.viewItems.length < 1) {
return false;
}
@ -307,7 +368,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
protected focusNext() {
if (typeof this.focusedEnabledItem === 'undefined') {
this.focusedEnabledItem = this.viewItems.length - 1;
} else if (this.viewItems.length <= 1) {
} else if (this.viewItems.length < 1) {
return false;
}
@ -333,7 +394,9 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
}
public onEnterSet() {
this.codeActionList.value?.setSelection([this.currSelectedItem]);
if (typeof this.currSelectedItem === 'number') {
this.codeActionList.value?.setSelection([this.currSelectedItem]);
}
}
override dispose() {
@ -345,7 +408,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
this.options = [];
this.viewItems = [];
this.focusedEnabledItem = 0;
this.currSelectedItem = 0;
this.currSelectedItem = undefined;
this.hasSeperator = false;
this._contextViewService.hideContextView({ source: this });
}
@ -455,6 +518,7 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
result.push(new Separator(), ...allDocumentation.map(command => toCodeActionAction(new CodeActionItem({
title: command.title,
command: command,
kind: CodeActionMenu.documentationID
}, undefined))));
}

View file

@ -23,6 +23,7 @@ export class CodeActionUi extends Disposable {
private readonly _codeActionWidget: Lazy<CodeActionMenu>;
private readonly _lightBulbWidget: Lazy<LightBulbWidget>;
private readonly _activeCodeActions = this._register(new MutableDisposable<CodeActionSet>());
private previewOn: boolean = false;
#disposed = false;
@ -40,7 +41,12 @@ export class CodeActionUi extends Disposable {
this._codeActionWidget = new Lazy(() => {
return this._register(instantiationService.createInstance(CodeActionMenu, this._editor, {
onSelectCodeAction: async (action, trigger) => {
this.delegate.applyCodeAction(action, /* retrigger */ true, Boolean(trigger.preview));
if (this.previewOn) {
this.delegate.applyCodeAction(action, /* retrigger */ true, Boolean(this.previewOn));
} else {
this.delegate.applyCodeAction(action, /* retrigger */ true, Boolean(trigger.preview));
}
this.previewOn = false;
}
}));
});
@ -70,6 +76,11 @@ export class CodeActionUi extends Disposable {
}
}
public onPreviewEnter() {
this.previewOn = true;
this.onEnter();
}
public navigateList(navUp: Boolean) {
if (this._codeActionWidget.hasValue()) {
if (navUp) {

View file

@ -18,6 +18,7 @@
border-color: none;
background-color: var(--vscode-menu-background);
color: var(--vscode-menu-foreground);
box-shadow: rgb(0,0,0, 16%) 0px 2px 8px;
}
.codeActionMenuWidget .monaco-list:not(.element-focused):focus:before {
@ -29,10 +30,10 @@
z-index: 5; /* make sure we are on top of the tree items */
content: "";
pointer-events: none; /* enable click through */
outline: 0px solid; /* we still need to handle the empty tree or no focus item case */
outline-width: 0px;
outline-style: none;
outline-offset: 0px;
outline: 0px solid !important; /* we still need to handle the empty tree or no focus item case */
outline-width: 0px !important;
outline-style: none !important;
outline-offset: 0px !important;
}
.codeActionMenuWidget .monaco-list {

View file

@ -311,7 +311,7 @@ export class ContextMenuController implements IEditorContribution {
const actions: IAction[] = [];
actions.push(createAction({
label: nls.localize('context.minimap.showMinimap', "Show Minimap"),
label: nls.localize('context.minimap.minimap', "Minimap"),
checked: minimapOptions.enabled,
run: () => {
this._configurationService.updateValue(`editor.minimap.enabled`, !minimapOptions.enabled);

View file

@ -25,7 +25,6 @@ import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/edit
import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2';
import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
import { localize } from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
@ -37,7 +36,6 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
constructor(
editor: ICodeEditor,
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
@IProgressService private readonly _progressService: IProgressService,
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService,
@ -46,22 +44,7 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
this._register(editor.onDropIntoEditor(e => this.onDropIntoEditor(editor, e.position, e.event)));
this._languageFeaturesService.documentOnDropEditProvider.register('*', new DefaultOnDropProvider(workspaceContextService));
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('workbench.editor.dropIntoEditor.enabled')) {
this.updateEditorOptions(editor);
}
}));
this.updateEditorOptions(editor);
}
private updateEditorOptions(editor: ICodeEditor) {
editor.updateOptions({
enableDropIntoEditor: this._configurationService.getValue('workbench.editor.dropIntoEditor.enabled')
});
}
private async onDropIntoEditor(editor: ICodeEditor, position: IPosition, dragEvent: DragEvent) {

View file

@ -2,7 +2,8 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .margin-view-overlays .codicon-folding-manual-collapsed,
.monaco-editor .margin-view-overlays .codicon-folding-manual-expanded,
.monaco-editor .margin-view-overlays .codicon-folding-expanded,
.monaco-editor .margin-view-overlays .codicon-folding-collapsed {
cursor: pointer;
@ -17,6 +18,7 @@
.monaco-editor .margin-view-overlays:hover .codicon,
.monaco-editor .margin-view-overlays .codicon.codicon-folding-collapsed,
.monaco-editor .margin-view-overlays .codicon.codicon-folding-manual-collapsed,
.monaco-editor .margin-view-overlays .codicon.alwaysShowFoldIcons {
opacity: 1;
}
@ -29,3 +31,4 @@
line-height: 1em;
cursor: pointer;
}

View file

@ -31,8 +31,8 @@ import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/cont
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { editorSelectionBackground, iconForeground, registerColor, transparent } from 'vs/platform/theme/common/colorRegistry';
import { registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { foldingCollapsedIcon, FoldingDecorationProvider, foldingExpandedIcon, foldingManualIcon } from './foldingDecorations';
import { FoldingRegion, FoldingRegions, FoldRange } from './foldingRanges';
import { foldingCollapsedIcon, FoldingDecorationProvider, foldingExpandedIcon, foldingManualCollapsedIcon, foldingManualExpandedIcon } from './foldingDecorations';
import { FoldingRegion, FoldingRegions, FoldRange, FoldSource, ILineRange } from './foldingRanges';
import { SyntaxRangeProvider } from './syntaxRangeProvider';
import { INotificationService } from 'vs/platform/notification/common/notification';
import Severity from 'vs/base/common/severity';
@ -222,7 +222,7 @@ export class FoldingController extends Disposable implements IEditorContribution
}
this._currentModelHasFoldedImports = false;
this.foldingModel = new FoldingModel(model, this.foldingDecorationProvider, this.triggerFoldingModelChanged.bind(this));
this.foldingModel = new FoldingModel(model, this.foldingDecorationProvider);
this.localToDispose.add(this.foldingModel);
this.hiddenRangeModel = new HiddenRangeModel(this.foldingModel);
@ -293,7 +293,7 @@ export class FoldingController extends Disposable implements IEditorContribution
this.triggerFoldingModelChanged();
}
private triggerFoldingModelChanged() {
public triggerFoldingModelChanged() {
if (this.updateScheduler) {
if (this.foldingRegionPromise) {
this.foldingRegionPromise.cancel();
@ -1066,17 +1066,17 @@ class GotoNextFoldAction extends FoldingAction<void> {
}
}
class FoldSelectedAction extends FoldingAction<void> {
class FoldRangeFromSelectionAction extends FoldingAction<void> {
constructor() {
super({
id: 'editor.foldSelected',
label: nls.localize('foldSelectedAction.label', "Fold Selected Lines"),
alias: 'Fold Selected Lines',
id: 'editor.createFoldingRangeFromSelection',
label: nls.localize('createManualFoldRange.label', "Create Manual Folding Range from Selection"),
alias: 'Create Folding Range from Selection',
precondition: CONTEXT_FOLDING_ENABLED,
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.Period),
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.Comma),
weight: KeybindingWeight.EditorContrib
}
});
@ -1097,7 +1097,7 @@ class FoldSelectedAction extends FoldingAction<void> {
endLineNumber: endLineNumber,
type: undefined,
isCollapsed: true,
isManualSelection: true
source: FoldSource.userDefined
});
editor.setSelection({
startLineNumber: selection.startLineNumber,
@ -1118,6 +1118,36 @@ class FoldSelectedAction extends FoldingAction<void> {
}
}
class RemoveFoldRangeFromSelectionAction extends FoldingAction<void> {
constructor() {
super({
id: 'editor.removeManualFoldingRanges',
label: nls.localize('removeManualFoldingRanges.label', "Remove Manual Folding Ranges"),
alias: 'Remove Manual Folding Ranges',
precondition: CONTEXT_FOLDING_ENABLED,
kbOpts: {
kbExpr: EditorContextKeys.editorTextFocus,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.Period),
weight: KeybindingWeight.EditorContrib
}
});
}
invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {
const selections = editor.getSelections();
if (selections) {
const ranges: ILineRange[] = [];
for (const selection of selections) {
const { startLineNumber, endLineNumber } = selection;
ranges.push(endLineNumber >= startLineNumber ? { startLineNumber, endLineNumber } : { endLineNumber, startLineNumber });
}
foldingModel.removeManualRanges(ranges);
foldingController.triggerFoldingModelChanged();
}
}
}
registerEditorContribution(FoldingController.ID, FoldingController);
registerEditorAction(UnfoldAction);
@ -1135,7 +1165,8 @@ registerEditorAction(ToggleFoldAction);
registerEditorAction(GotoParentFoldAction);
registerEditorAction(GotoPreviousFoldAction);
registerEditorAction(GotoNextFoldAction);
registerEditorAction(FoldSelectedAction);
registerEditorAction(FoldRangeFromSelectionAction);
registerEditorAction(RemoveFoldRangeFromSelectionAction);
for (let i = 1; i <= 7; i++) {
registerInstantiatedEditorAction(
@ -1167,7 +1198,8 @@ registerThemingParticipant((theme, collector) => {
collector.addRule(`
.monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingExpandedIcon)},
.monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingCollapsedIcon)},
.monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingManualIcon)} {
.monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingManualExpandedIcon)},
.monaco-editor .cldr${ThemeIcon.asCSSSelector(foldingManualCollapsedIcon)} {
color: ${editorFoldColor} !important;
}
`);

View file

@ -14,12 +14,14 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService';
export const foldingExpandedIcon = registerIcon('folding-expanded', Codicon.chevronDown, localize('foldingExpandedIcon', 'Icon for expanded ranges in the editor glyph margin.'));
export const foldingCollapsedIcon = registerIcon('folding-collapsed', Codicon.chevronRight, localize('foldingCollapsedIcon', 'Icon for collapsed ranges in the editor glyph margin.'));
export const foldingManualIcon = registerIcon('folding-manual', Codicon.ellipsis, localize('foldingManualIcon', 'Icon for manually collapsed ranges in the editor glyph margin.'));
export const foldingManualCollapsedIcon = registerIcon('folding-manual-collapsed', foldingCollapsedIcon, localize('foldingManualCollapedIcon', 'Icon for manually collapsed ranges in the editor glyph margin.'));
export const foldingManualExpandedIcon = registerIcon('folding-manual-expanded', foldingExpandedIcon, localize('foldingManualExpandedIcon', 'Icon for manually expanded ranges in the editor glyph margin.'));
export class FoldingDecorationProvider implements IDecorationProvider {
private static readonly COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({
description: 'folding-collapsed-visual-decoration',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges,
afterContentClassName: 'inline-folded',
isWholeLine: true,
firstLineDecorationClassName: ThemeIcon.asClassName(foldingCollapsedIcon)
@ -27,7 +29,7 @@ export class FoldingDecorationProvider implements IDecorationProvider {
private static readonly COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION = ModelDecorationOptions.register({
description: 'folding-collapsed-highlighted-visual-decoration',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges,
afterContentClassName: 'inline-folded',
className: 'folded-background',
isWholeLine: true,
@ -36,19 +38,19 @@ export class FoldingDecorationProvider implements IDecorationProvider {
private static readonly MANUALLY_COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({
description: 'folding-manually-collapsed-visual-decoration',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges,
afterContentClassName: 'inline-folded',
isWholeLine: true,
firstLineDecorationClassName: ThemeIcon.asClassName(foldingManualIcon)
firstLineDecorationClassName: 'alwaysShowFoldIcons ' + ThemeIcon.asClassName(foldingExpandedIcon)
});
private static readonly MANUALLY_COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION = ModelDecorationOptions.register({
description: 'folding-manually-collapsed-highlighted-visual-decoration',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges,
afterContentClassName: 'inline-folded',
className: 'folded-background',
isWholeLine: true,
firstLineDecorationClassName: ThemeIcon.asClassName(foldingManualIcon)
firstLineDecorationClassName: ThemeIcon.asClassName(foldingManualCollapsedIcon)
});
private static readonly EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({
@ -65,6 +67,21 @@ export class FoldingDecorationProvider implements IDecorationProvider {
firstLineDecorationClassName: 'alwaysShowFoldIcons ' + ThemeIcon.asClassName(foldingExpandedIcon)
});
private static readonly MANUALLY_EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({
description: 'folding-manually-expanded-visual-decoration',
stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges,
isWholeLine: true,
firstLineDecorationClassName: 'alwaysShowFoldIcons ' + ThemeIcon.asClassName(foldingManualExpandedIcon)
});
private static readonly MANUALLY_EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({
description: 'folding-manually-expanded-visual-decoration',
stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges,
isWholeLine: true,
firstLineDecorationClassName: ThemeIcon.asClassName(foldingManualExpandedIcon)
});
private static readonly HIDDEN_RANGE_DECORATION = ModelDecorationOptions.register({
description: 'folding-hidden-range-decoration',
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
@ -77,19 +94,19 @@ export class FoldingDecorationProvider implements IDecorationProvider {
constructor(private readonly editor: ICodeEditor) {
}
getDecorationOption(isCollapsed: boolean, isHidden: boolean, isManualSelection: boolean): IModelDecorationOptions {
getDecorationOption(isCollapsed: boolean, isHidden: boolean, isManual: boolean): IModelDecorationOptions {
if (isHidden // is inside another collapsed region
|| this.showFoldingControls === 'never' || (isManualSelection && !isCollapsed)) { //
|| this.showFoldingControls === 'never') {
return FoldingDecorationProvider.HIDDEN_RANGE_DECORATION;
}
if (isCollapsed) {
return isManualSelection ?
return isManual ?
(this.showFoldingHighlights ? FoldingDecorationProvider.MANUALLY_COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION : FoldingDecorationProvider.MANUALLY_COLLAPSED_VISUAL_DECORATION)
: (this.showFoldingHighlights ? FoldingDecorationProvider.COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION : FoldingDecorationProvider.COLLAPSED_VISUAL_DECORATION);
} else if (this.showFoldingControls === 'mouseover') {
return FoldingDecorationProvider.EXPANDED_AUTO_HIDE_VISUAL_DECORATION;
return isManual ? FoldingDecorationProvider.MANUALLY_EXPANDED_AUTO_HIDE_VISUAL_DECORATION : FoldingDecorationProvider.EXPANDED_AUTO_HIDE_VISUAL_DECORATION;
} else {
return FoldingDecorationProvider.EXPANDED_VISUAL_DECORATION;
return isManual ? FoldingDecorationProvider.MANUALLY_EXPANDED_VISUAL_DECORATION : FoldingDecorationProvider.EXPANDED_VISUAL_DECORATION;
}
}

View file

@ -5,11 +5,11 @@
import { Emitter, Event } from 'vs/base/common/event';
import { IModelDecorationOptions, IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';
import { FoldingRegion, FoldingRegions, ILineRange, FoldRange } from './foldingRanges';
import { FoldingRegion, FoldingRegions, ILineRange, FoldRange, FoldSource } from './foldingRanges';
import { hash } from 'vs/base/common/hash';
export interface IDecorationProvider {
getDecorationOption(isCollapsed: boolean, isHidden: boolean, isManualSelection: boolean): IModelDecorationOptions;
getDecorationOption(isCollapsed: boolean, isHidden: boolean, isManual: boolean): IModelDecorationOptions;
changeDecorations<T>(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T | null;
removeDecorations(decorationIds: string[]): void;
}
@ -21,6 +21,8 @@ export interface FoldingModelChangeEvent {
interface ILineMemento extends ILineRange {
checksum?: number;
isCollapsed?: boolean;
source?: FoldSource;
}
export type CollapseMemento = ILineMemento[];
@ -28,7 +30,6 @@ export type CollapseMemento = ILineMemento[];
export class FoldingModel {
private readonly _textModel: ITextModel;
private readonly _decorationProvider: IDecorationProvider;
private readonly _triggerRecomputeRanges: (() => void) | undefined;
private _regions: FoldingRegions;
private _editorDecorationIds: string[];
@ -40,10 +41,9 @@ export class FoldingModel {
public get textModel() { return this._textModel; }
public get decorationProvider() { return this._decorationProvider; }
constructor(textModel: ITextModel, decorationProvider: IDecorationProvider, triggerRecomputeRanges?: () => void) {
constructor(textModel: ITextModel, decorationProvider: IDecorationProvider) {
this._textModel = textModel;
this._decorationProvider = decorationProvider;
this._triggerRecomputeRanges = triggerRecomputeRanges;
this._regions = new FoldingRegions(new Uint32Array(0), new Uint32Array(0));
this._editorDecorationIds = [];
}
@ -55,7 +55,6 @@ export class FoldingModel {
toggledRegions = toggledRegions.sort((r1, r2) => r1.regionIndex - r2.regionIndex);
const processed: { [key: string]: boolean | undefined } = {};
const manualExpanded = false;
this._decorationProvider.changeDecorations(accessor => {
let k = 0; // index from [0 ... this.regions.length]
let dirtyRegionEndLine = -1; // end of the range where decorations need to be updated
@ -64,9 +63,9 @@ export class FoldingModel {
while (k < index) {
const endLineNumber = this._regions.getEndLineNumber(k);
const isCollapsed = this._regions.isCollapsed(k);
const isManualSelection = this.regions.isManualSelection(k);
if (endLineNumber <= dirtyRegionEndLine) {
accessor.changeDecorationOptions(this._editorDecorationIds[k], this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManualSelection));
const isManual = this.regions.getSource(k) !== FoldSource.provider;
accessor.changeDecorationOptions(this._editorDecorationIds[k], this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManual));
}
if (isCollapsed && endLineNumber > lastHiddenLine) {
lastHiddenLine = endLineNumber;
@ -91,16 +90,30 @@ export class FoldingModel {
updateDecorationsUntil(this._regions.length);
});
this._updateEventEmitter.fire({ model: this, collapseStateChanged: toggledRegions });
if (manualExpanded && this._triggerRecomputeRanges) {
// expanding a range which didn't originate from range provider might now enable ranges
// from the provider which were previously dropped due to the collapsed range
this._triggerRecomputeRanges();
}
public removeManualRanges(ranges: ILineRange[]) {
const newFoldingRanges: FoldRange[] = new Array();
const intersects = (foldRange: FoldRange) => {
for (const range of ranges) {
if (!(range.startLineNumber > foldRange.endLineNumber || foldRange.startLineNumber > range.endLineNumber)) {
return true;
}
}
return false;
};
for (let i = 0; i < this._regions.length; i++) {
const foldRange = this._regions.toFoldRange(i);
if (foldRange.source === FoldSource.provider || !intersects(foldRange)) {
newFoldingRanges.push(foldRange);
}
}
this.updatePost(FoldingRegions.fromFoldRanges(newFoldingRanges));
}
public update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void {
const hiddenRanges = this._currentHiddenRegions(blockedLineNumers);
const newRanges = FoldingRegions.sanitizeAndMerge(newRegions, hiddenRanges, this._textModel.getLineCount());
const foldedOrManualRanges = this._currentFoldedOrManualRanges(blockedLineNumers);
const newRanges = FoldingRegions.sanitizeAndMerge(newRegions, foldedOrManualRanges, this._textModel.getLineCount());
this.updatePost(FoldingRegions.fromFoldRanges(newRanges));
}
@ -111,14 +124,14 @@ export class FoldingModel {
const startLineNumber = newRegions.getStartLineNumber(index);
const endLineNumber = newRegions.getEndLineNumber(index);
const isCollapsed = newRegions.isCollapsed(index);
const isManualSelection = newRegions.isManualSelection(index);
const isManual = newRegions.getSource(index) !== FoldSource.provider;
const decorationRange = {
startLineNumber: startLineNumber,
startColumn: this._textModel.getLineMaxColumn(startLineNumber),
endLineNumber: endLineNumber,
endColumn: this._textModel.getLineMaxColumn(endLineNumber) + 1
};
newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManualSelection) });
newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManual) });
if (isCollapsed && endLineNumber > lastHiddenLine) {
lastHiddenLine = endLineNumber;
}
@ -128,7 +141,7 @@ export class FoldingModel {
this._updateEventEmitter.fire({ model: this });
}
private _currentHiddenRegions(blockedLineNumers: number[] = []): FoldRange[] {
private _currentFoldedOrManualRanges(blockedLineNumers: number[] = []): FoldRange[] {
const isBlocked = (startLineNumber: number, endLineNumber: number) => {
for (const blockedLineNumber of blockedLineNumers) {
@ -139,42 +152,45 @@ export class FoldingModel {
return false;
};
const hiddenRanges: FoldRange[] = [];
const foldedRanges: FoldRange[] = [];
for (let i = 0, limit = this._regions.length; i < limit; i++) {
if (this.regions.isCollapsed(i)) {
const hiddenRange = this._regions.toFoldRange(i);
let isCollapsed = this.regions.isCollapsed(i);
const source = this.regions.getSource(i);
if (isCollapsed || source !== FoldSource.provider) {
const foldRange = this._regions.toFoldRange(i);
const decRange = this._textModel.getDecorationRange(this._editorDecorationIds[i]);
if (decRange
&& !isBlocked(decRange.startLineNumber, decRange.endLineNumber)
// if not same length user has modified it, skip and auto-expand
&& decRange.endLineNumber - decRange.startLineNumber
=== hiddenRange.endLineNumber - hiddenRange.startLineNumber) {
hiddenRanges.push({
if (decRange) {
if (isCollapsed && (isBlocked(decRange.startLineNumber, decRange.endLineNumber) || decRange.endLineNumber - decRange.startLineNumber !== foldRange.endLineNumber - foldRange.startLineNumber)) {
isCollapsed = false; // uncollapse is the range is blocked or there has been lines removed or added
}
foldedRanges.push({
startLineNumber: decRange.startLineNumber,
endLineNumber: decRange.endLineNumber,
type: hiddenRange.type,
isCollapsed: true,
isManualSelection: hiddenRange.isManualSelection
type: foldRange.type,
isCollapsed,
source
});
}
}
}
return hiddenRanges;
return foldedRanges;
}
/**
* Collapse state memento, for persistence only
*/
public getMemento(): CollapseMemento | undefined {
const hiddenRegions = this._currentHiddenRegions();
const foldedOrManualRanges = this._currentFoldedOrManualRanges();
const result: ILineMemento[] = [];
for (let i = 0, limit = hiddenRegions.length; i < limit; i++) {
const range = hiddenRegions[i];
for (let i = 0, limit = foldedOrManualRanges.length; i < limit; i++) {
const range = foldedOrManualRanges[i];
const checksum = this._getLinesChecksum(range.startLineNumber + 1, range.endLineNumber);
result.push({
startLineNumber: range.startLineNumber,
endLineNumber: range.endLineNumber,
isCollapsed: range.isCollapsed,
source: range.source,
checksum: checksum
});
}
@ -188,7 +204,7 @@ export class FoldingModel {
if (!Array.isArray(state)) {
return;
}
const hiddenRanges: FoldRange[] = [];
const rangesToRestore: FoldRange[] = [];
const maxLineNumber = this._textModel.getLineCount();
for (const range of state) {
if (range.startLineNumber >= range.endLineNumber || range.startLineNumber < 1 || range.endLineNumber > maxLineNumber) {
@ -196,17 +212,17 @@ export class FoldingModel {
}
const checksum = this._getLinesChecksum(range.startLineNumber + 1, range.endLineNumber);
if (!range.checksum || checksum === range.checksum) {
hiddenRanges.push({
rangesToRestore.push({
startLineNumber: range.startLineNumber,
endLineNumber: range.endLineNumber,
type: undefined,
isCollapsed: true,
isManualSelection: true // converts to false when provider sends a match
isCollapsed: range.isCollapsed ?? true,
source: range.source ?? FoldSource.provider
});
}
}
const newRanges = FoldingRegions.sanitizeAndMerge(this._regions, hiddenRanges, maxLineNumber);
const newRanges = FoldingRegions.sanitizeAndMerge(this._regions, rangesToRestore, maxLineNumber);
this.updatePost(FoldingRegions.fromFoldRanges(newRanges));
}

View file

@ -8,12 +8,18 @@ export interface ILineRange {
endLineNumber: number;
}
export const enum FoldSource {
provider = 0,
userDefined = 1,
recovered = 2
}
export interface FoldRange {
startLineNumber: number;
endLineNumber: number;
type: string | undefined;
isCollapsed: boolean;
isManualSelection: boolean;
source: FoldSource;
}
export const MAX_FOLDING_REGIONS = 0xFFFF;
@ -21,11 +27,38 @@ export const MAX_LINE_NUMBER = 0xFFFFFF;
const MASK_INDENT = 0xFF000000;
class BitField {
private readonly _states: Uint32Array;
constructor(size: number) {
const numWords = Math.ceil(size / 32);
this._states = new Uint32Array(numWords);
}
public get(index: number): boolean {
const arrayIndex = (index / 32) | 0;
const bit = index % 32;
return (this._states[arrayIndex] & (1 << bit)) !== 0;
}
public set(index: number, newState: boolean) {
const arrayIndex = (index / 32) | 0;
const bit = index % 32;
const value = this._states[arrayIndex];
if (newState) {
this._states[arrayIndex] = value | (1 << bit);
} else {
this._states[arrayIndex] = value & ~(1 << bit);
}
}
}
export class FoldingRegions {
private readonly _startIndexes: Uint32Array;
private readonly _endIndexes: Uint32Array;
private readonly _collapseStates: Uint32Array;
private readonly _manualStates: Uint32Array;
private readonly _collapseStates: BitField;
private readonly _userDefinedStates: BitField;
private readonly _recoveredStates: BitField;
private _parentsComputed: boolean;
private readonly _types: Array<string | undefined> | undefined;
@ -35,9 +68,9 @@ export class FoldingRegions {
}
this._startIndexes = startIndexes;
this._endIndexes = endIndexes;
const numWords = Math.ceil(startIndexes.length / 32);
this._collapseStates = new Uint32Array(numWords);
this._manualStates = new Uint32Array(numWords);
this._collapseStates = new BitField(startIndexes.length);
this._userDefinedStates = new BitField(startIndexes.length);
this._recoveredStates = new BitField(startIndexes.length);
this._types = types;
this._parentsComputed = false;
}
@ -88,36 +121,48 @@ export class FoldingRegions {
}
public isCollapsed(index: number): boolean {
const arrayIndex = (index / 32) | 0;
const bit = index % 32;
return (this._collapseStates[arrayIndex] & (1 << bit)) !== 0;
return this._collapseStates.get(index);
}
public setCollapsed(index: number, newState: boolean) {
const arrayIndex = (index / 32) | 0;
const bit = index % 32;
const value = this._collapseStates[arrayIndex];
if (newState) {
this._collapseStates[arrayIndex] = value | (1 << bit);
} else {
this._collapseStates[arrayIndex] = value & ~(1 << bit);
this._collapseStates.set(index, newState);
}
private isUserDefined(index: number): boolean {
return this._userDefinedStates.get(index);
}
private setUserDefined(index: number, newState: boolean) {
return this._userDefinedStates.set(index, newState);
}
private isRecovered(index: number): boolean {
return this._recoveredStates.get(index);
}
private setRecovered(index: number, newState: boolean) {
return this._recoveredStates.set(index, newState);
}
public getSource(index: number): FoldSource {
if (this.isUserDefined(index)) {
return FoldSource.userDefined;
} else if (this.isRecovered(index)) {
return FoldSource.recovered;
}
return FoldSource.provider;
}
public isManualSelection(index: number): boolean {
const arrayIndex = (index / 32) | 0;
const bit = index % 32;
return (this._manualStates[arrayIndex] & (1 << bit)) !== 0;
}
public setManualSelection(index: number, newState: boolean) {
const arrayIndex = (index / 32) | 0;
const bit = index % 32;
const value = this._manualStates[arrayIndex];
if (newState) {
this._manualStates[arrayIndex] = value | (1 << bit);
public setSource(index: number, source: FoldSource): void {
if (source === FoldSource.userDefined) {
this.setUserDefined(index, true);
this.setRecovered(index, false);
} else if (source === FoldSource.recovered) {
this.setUserDefined(index, false);
this.setRecovered(index, true);
} else {
this._manualStates[arrayIndex] = value & ~(1 << bit);
this.setUserDefined(index, false);
this.setRecovered(index, false);
}
}
@ -185,10 +230,16 @@ export class FoldingRegions {
return -1;
}
private readonly sourceAbbr = {
[FoldSource.provider]: ' ',
[FoldSource.userDefined]: 'u',
[FoldSource.recovered]: 'r',
};
public toString() {
const res: string[] = [];
for (let i = 0; i < this.length; i++) {
res[i] = `[${this.isManualSelection(i) ? '*' : ' '}${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`;
res[i] = `[${this.sourceAbbr[this.getSource(i)]}${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`;
}
return res.join(', ');
}
@ -199,7 +250,7 @@ export class FoldingRegions {
endLineNumber: this._endIndexes[index] & MAX_LINE_NUMBER,
type: this._types ? this._types[index] : undefined,
isCollapsed: this.isCollapsed(index),
isManualSelection: this.isManualSelection(index)
source: this.getSource(index)
};
}
@ -226,9 +277,7 @@ export class FoldingRegions {
if (ranges[i].isCollapsed) {
regions.setCollapsed(i, true);
}
if (ranges[i].isManualSelection) {
regions.setManualSelection(i, true);
}
regions.setSource(i, ranges[i].source);
}
return regions;
}
@ -237,11 +286,10 @@ export class FoldingRegions {
* Two inputs, each a FoldingRegions or a FoldRange[], are merged.
* Each input must be pre-sorted on startLineNumber.
* The first list is assumed to always include all regions currently defined by range providers.
* The second list only contains hidden ranges.
* The second list only contains the previously collapsed and all manual ranges.
* If the line position matches, the range of the new range is taken, and the range is no longer manual
* When an entry in one list overlaps an entry in the other, the second list's entry "wins" and
* overlapping entries in the first list are discarded. With one exception: when there is just
* one such second list entry and it is not manual it is discarded, on the assumption that
* user editing has resulted in the range no longer existing.
* overlapping entries in the first list are discarded.
* Invalid entries are discarded. An entry is invalid if:
* the start and end line numbers aren't a valid range of line numbers,
* it is out of sequence or has the same start line as a preceding entry,
@ -252,18 +300,6 @@ export class FoldingRegions {
rangesB: FoldingRegions | FoldRange[],
maxLineNumber: number | undefined): FoldRange[] {
maxLineNumber = maxLineNumber ?? Number.MAX_VALUE;
let result = this._trySanitizeAndMerge(1, rangesA, rangesB, maxLineNumber);
if (!result) { // try again, converting hidden ranges to manually selected
result = this._trySanitizeAndMerge(2, rangesA, rangesB, maxLineNumber);
}
return result!;
}
private static _trySanitizeAndMerge(
passNumber: number, // it can take two passes to get this done
rangesA: FoldingRegions | FoldRange[],
rangesB: FoldingRegions | FoldRange[],
maxLineNumber: number): FoldRange[] | null {
const getIndexedFunction = (r: FoldingRegions | FoldRange[], limit: number) => {
return Array.isArray(r)
@ -281,41 +317,32 @@ export class FoldingRegions {
let topStackedRange: FoldRange | undefined;
let prevLineNumber = 0;
const resultRanges: FoldRange[] = [];
let numberAutoExpand = 0;
while (nextA || nextB) {
let useRange: FoldRange | undefined = undefined;
if (nextB && (!nextA || nextA.startLineNumber >= nextB.startLineNumber)) {
// nextB is next
if (nextA
&& nextA.startLineNumber === nextB.startLineNumber
&& nextA.endLineNumber === nextB.endLineNumber) {
// same range in both lists, merge the details
useRange = nextB;
useRange.isCollapsed = useRange.isCollapsed || nextA.isCollapsed;
// next line removes manual flag when range provider has matching range
useRange.isManualSelection = nextA.isManualSelection && nextB.isManualSelection;
if (!useRange.type) {
useRange.type = nextA.type;
if (nextA && nextA.startLineNumber === nextB.startLineNumber) {
if (nextB.source === FoldSource.userDefined) {
// a user defined range (possibly unfolded)
useRange = nextB;
} else {
// a previously folded range or a (possibly unfolded) recovered range
useRange = nextA;
useRange.isCollapsed = nextB.isCollapsed && nextA.endLineNumber === nextB.endLineNumber;
useRange.source = FoldSource.provider;
}
nextA = getA(++indexA); // not necessary, just for speed
} else if (nextB.isCollapsed && !nextB.isManualSelection && passNumber === 1) {
if (++numberAutoExpand > 1) {
// do second pass keeping these, assuming something like an unmatched /*
return null;
}
// skip nextB (auto expand) by not setting useRange, assuming it was edited
} else { // use nextB
} else {
useRange = nextB;
if (useRange.isCollapsed) {
// doesn't match nextA, convert to a manual selection if it wasn't already
useRange.isManualSelection = true;
if (nextB.isCollapsed && nextB.source === FoldSource.provider) {
// a previously collapsed range
useRange.source = FoldSource.recovered;
}
}
nextB = getB(++indexB);
} else {
// nextA is next. The B set takes precedence and we sometimes need to look
// nextA is next. The user folded B set takes precedence and we sometimes need to look
// ahead in it to check for an upcoming conflict.
let scanIndex = indexB;
let prescanB = nextB;
@ -324,8 +351,8 @@ export class FoldingRegions {
useRange = nextA;
break; // no conflict, use this nextA
}
if (prescanB.endLineNumber > nextA!.endLineNumber
&& (!prescanB.isCollapsed || prescanB.isManualSelection || passNumber === 2)) {
if (prescanB.source === FoldSource.userDefined && prescanB.endLineNumber > nextA!.endLineNumber) {
// we found a user folded range, it wins
break; // without setting nextResult, so this nextA gets skipped
}
prescanB = getB(++scanIndex);

View file

@ -5,7 +5,7 @@
import * as assert from 'assert';
import { FoldingMarkers } from 'vs/editor/common/languages/languageConfiguration';
import { MAX_FOLDING_REGIONS, FoldRange, FoldingRegions } from 'vs/editor/contrib/folding/browser/foldingRanges';
import { MAX_FOLDING_REGIONS, FoldRange, FoldingRegions, FoldSource } from 'vs/editor/contrib/folding/browser/foldingRanges';
import { computeRanges } from 'vs/editor/contrib/folding/browser/indentRangeProvider';
import { createTextModel } from 'vs/editor/test/common/testTextModel';
@ -16,20 +16,20 @@ const markers: FoldingMarkers = {
suite('FoldingRanges', () => {
const foldRange = (from: number, to: number, collapsed: boolean | undefined = undefined, manual: boolean | undefined = undefined, type: string | undefined = undefined) =>
const foldRange = (from: number, to: number, collapsed: boolean | undefined = undefined, source: FoldSource = FoldSource.provider, type: string | undefined = undefined) =>
<FoldRange>{
startLineNumber: from,
endLineNumber: to,
type: type,
isCollapsed: collapsed || false,
isManualSelection: manual || false
source
};
const assertEqualRanges = (range1: FoldRange, range2: FoldRange, msg: string) => {
assert.strictEqual(range1.startLineNumber, range2.startLineNumber, msg + ' start');
assert.strictEqual(range1.endLineNumber, range2.endLineNumber, msg + ' end');
assert.strictEqual(range1.type, range2.type, msg + ' type');
assert.strictEqual(range1.isCollapsed, range2.isCollapsed, msg + ' collapsed');
assert.strictEqual(range1.isManualSelection, range2.isManualSelection, msg + ' manual');
assert.strictEqual(range1.source, range2.source, msg + ' source');
};
test('test max folding regions', () => {
@ -122,110 +122,88 @@ suite('FoldingRanges', () => {
test('sanitizeAndMerge1', () => {
const regionSet1: FoldRange[] = [
foldRange(0, 100), // invalid, should be removed
foldRange(1, 100, false, false, 'A'), // valid
foldRange(1, 100, false, false, 'Z'), // invalid, duplicate start
foldRange(1, 100, false, FoldSource.provider, 'A'), // valid
foldRange(1, 100, false, FoldSource.provider, 'Z'), // invalid, duplicate start
foldRange(10, 10, false), // invalid, should be removed
foldRange(20, 80, false, false, 'C1'), // valid inside 'B'
foldRange(22, 80, true, false, 'D1'), // valid inside 'C1'
foldRange(20, 80, false, FoldSource.provider, 'C1'), // valid inside 'B'
foldRange(22, 80, true, FoldSource.provider, 'D1'), // valid inside 'C1'
foldRange(90, 101), // invalid, should be removed
];
const regionSet2: FoldRange[] = [
foldRange(2, 100, false, false, 'B'), // valid, inside 'A'
foldRange(20, 80, true), // should merge with C1
foldRange(18, 80, true), // invalid, out of order
foldRange(21, 81, true, false, 'Z'), // invalid, overlapping
foldRange(22, 80, false, false, 'D2'), // should merge with D1
foldRange(21, 81, true, FoldSource.provider, 'Z'), // invalid, overlapping
foldRange(22, 80, true, FoldSource.provider, 'D2'), // should merge with D1
];
let result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100);
assert.strictEqual(result.length, 4, 'result length1');
assertEqualRanges(result[0], foldRange(1, 100, false, false, 'A'), 'A1');
assertEqualRanges(result[1], foldRange(2, 100, false, false, 'B'), 'B1');
assertEqualRanges(result[2], foldRange(20, 80, true, false, 'C1'), 'C1');
assertEqualRanges(result[3], foldRange(22, 80, true, false, 'D2'), 'D1');
const regionClass1 = FoldingRegions.fromFoldRanges(regionSet1);
const regionClass2 = FoldingRegions.fromFoldRanges(regionSet2);
// same tests again with inputs as FoldingRegions instead of FoldRange[]
result = FoldingRegions.sanitizeAndMerge(regionClass1, regionClass2, 100);
assert.strictEqual(result.length, 4, 'result length2');
assertEqualRanges(result[0], foldRange(1, 100, false, false, 'A'), 'A2');
assertEqualRanges(result[1], foldRange(2, 100, false, false, 'B'), 'B2');
assertEqualRanges(result[2], foldRange(20, 80, true, false, 'C1'), 'C2');
assertEqualRanges(result[3], foldRange(22, 80, true, false, 'D2'), 'D2');
const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100);
assert.strictEqual(result.length, 3, 'result length1');
assertEqualRanges(result[0], foldRange(1, 100, false, FoldSource.provider, 'A'), 'A1');
assertEqualRanges(result[1], foldRange(20, 80, true, FoldSource.provider, 'C1'), 'C1');
assertEqualRanges(result[2], foldRange(22, 80, true, FoldSource.provider, 'D1'), 'D1');
});
test('sanitizeAndMerge2', () => {
const regionSet1: FoldRange[] = [
foldRange(1, 100, false, false, 'a1'), // valid
foldRange(2, 100, false, false, 'a2'), // valid
foldRange(3, 19, false, false, 'a3'), // valid
foldRange(20, 71, false, false, 'a4'), // overlaps b3
foldRange(21, 29, false, false, 'a5'), // valid
foldRange(81, 91, false, false, 'a6'), // overlaps b4
foldRange(1, 100, false, FoldSource.provider, 'a1'), // valid
foldRange(2, 100, false, FoldSource.provider, 'a2'), // valid
foldRange(3, 19, false, FoldSource.provider, 'a3'), // valid
foldRange(20, 71, false, FoldSource.provider, 'a4'), // overlaps b3
foldRange(21, 29, false, FoldSource.provider, 'a5'), // valid
foldRange(81, 91, false, FoldSource.provider, 'a6'), // overlaps b4
];
const regionSet2: FoldRange[] = [
foldRange(30, 39, false, false, 'b1'), // valid
foldRange(40, 49, false, false, 'b2'), // valid
foldRange(50, 100, false, false, 'b3'), // overlaps a4
foldRange(80, 90, false, false, 'b4'), // overlaps a6
foldRange(92, 100, false, false, 'b5'), // valid
foldRange(30, 39, true, FoldSource.provider, 'b1'), // valid, will be recovered
foldRange(40, 49, true, FoldSource.userDefined, 'b2'), // valid
foldRange(50, 100, true, FoldSource.userDefined, 'b3'), // overlaps a4
foldRange(80, 90, true, FoldSource.userDefined, 'b4'), // overlaps a6
foldRange(92, 100, true, FoldSource.userDefined, 'b5'), // valid
];
let result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100);
const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100);
assert.strictEqual(result.length, 9, 'result length1');
assertEqualRanges(result[0], foldRange(1, 100, false, false, 'a1'), 'P1');
assertEqualRanges(result[1], foldRange(2, 100, false, false, 'a2'), 'P2');
assertEqualRanges(result[2], foldRange(3, 19, false, false, 'a3'), 'P3');
assertEqualRanges(result[3], foldRange(21, 29, false, false, 'a5'), 'P4');
assertEqualRanges(result[4], foldRange(30, 39, false, false, 'b1'), 'P5');
assertEqualRanges(result[5], foldRange(40, 49, false, false, 'b2'), 'P6');
assertEqualRanges(result[6], foldRange(50, 100, false, false, 'b3'), 'P7');
assertEqualRanges(result[7], foldRange(80, 90, false, false, 'b4'), 'P8');
assertEqualRanges(result[8], foldRange(92, 100, false, false, 'b5'), 'P9');
// reverse the two inputs
result = FoldingRegions.sanitizeAndMerge(regionSet2, regionSet1, 100);
assert.strictEqual(result.length, 9, 'result length2');
assertEqualRanges(result[0], foldRange(1, 100, false, false, 'a1'), 'Q1');
assertEqualRanges(result[1], foldRange(2, 100, false, false, 'a2'), 'Q2');
assertEqualRanges(result[2], foldRange(3, 19, false, false, 'a3'), 'Q3');
assertEqualRanges(result[3], foldRange(20, 71, false, false, 'a4'), 'Q4');
assertEqualRanges(result[4], foldRange(21, 29, false, false, 'a5'), 'Q5');
assertEqualRanges(result[5], foldRange(30, 39, false, false, 'b1'), 'Q6');
assertEqualRanges(result[6], foldRange(40, 49, false, false, 'b2'), 'Q7');
assertEqualRanges(result[7], foldRange(81, 91, false, false, 'a6'), 'Q8');
assertEqualRanges(result[8], foldRange(92, 100, false, false, 'b5'), 'Q9');
assertEqualRanges(result[0], foldRange(1, 100, false, FoldSource.provider, 'a1'), 'P1');
assertEqualRanges(result[1], foldRange(2, 100, false, FoldSource.provider, 'a2'), 'P2');
assertEqualRanges(result[2], foldRange(3, 19, false, FoldSource.provider, 'a3'), 'P3');
assertEqualRanges(result[3], foldRange(21, 29, false, FoldSource.provider, 'a5'), 'P4');
assertEqualRanges(result[4], foldRange(30, 39, true, FoldSource.recovered, 'b1'), 'P5');
assertEqualRanges(result[5], foldRange(40, 49, true, FoldSource.userDefined, 'b2'), 'P6');
assertEqualRanges(result[6], foldRange(50, 100, true, FoldSource.userDefined, 'b3'), 'P7');
assertEqualRanges(result[7], foldRange(80, 90, true, FoldSource.userDefined, 'b4'), 'P8');
assertEqualRanges(result[8], foldRange(92, 100, true, FoldSource.userDefined, 'b5'), 'P9');
});
test('sanitizeAndMerge3', () => {
const regionSet1: FoldRange[] = [
foldRange(1, 100, false, false, 'a1'), // valid
foldRange(10, 29, false, false, 'a2'), // matches manual hidden
foldRange(35, 39, true, true, 'a3'), // valid
foldRange(1, 100, false, FoldSource.provider, 'a1'), // valid
foldRange(10, 29, false, FoldSource.provider, 'a2'), // matches manual hidden
foldRange(35, 39, true, FoldSource.recovered, 'a3'), // valid
];
const regionSet2: FoldRange[] = [
foldRange(10, 29, true, true, 'b1'), // matches a
foldRange(20, 28, true, false, 'b2'), // should get dropped
foldRange(30, 39, true, true, 'b3'), // should remain
foldRange(10, 29, true, FoldSource.recovered, 'b1'), // matches a
foldRange(20, 28, true, FoldSource.provider, 'b2'), // should remain
foldRange(30, 39, true, FoldSource.recovered, 'b3'), // should remain
];
const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100);
assert.strictEqual(result.length, 4, 'result length3');
assertEqualRanges(result[0], foldRange(1, 100, false, false, 'a1'), 'R1');
assertEqualRanges(result[1], foldRange(10, 29, true, false, 'b1'), 'R2');
assertEqualRanges(result[2], foldRange(30, 39, true, true, 'b3'), 'R3');
assertEqualRanges(result[3], foldRange(35, 39, true, true, 'a3'), 'R4');
assert.strictEqual(result.length, 5, 'result length3');
assertEqualRanges(result[0], foldRange(1, 100, false, FoldSource.provider, 'a1'), 'R1');
assertEqualRanges(result[1], foldRange(10, 29, true, FoldSource.provider, 'a2'), 'R2');
assertEqualRanges(result[2], foldRange(20, 28, true, FoldSource.recovered, 'b2'), 'R3');
assertEqualRanges(result[3], foldRange(30, 39, true, FoldSource.recovered, 'b3'), 'R3');
assertEqualRanges(result[4], foldRange(35, 39, true, FoldSource.recovered, 'a3'), 'R4');
});
test('sanitizeAndMerge4', () => {
const regionSet1: FoldRange[] = [
foldRange(1, 100, false, false, 'a1'), // valid
foldRange(1, 100, false, FoldSource.provider, 'a1'), // valid
];
const regionSet2: FoldRange[] = [
foldRange(20, 28, true, false, 'b1'), // hidden
foldRange(30, 38, true, false, 'b2'), // hidden
foldRange(20, 28, true, FoldSource.provider, 'b1'), // hidden
foldRange(30, 38, true, FoldSource.provider, 'b2'), // hidden
];
const result = FoldingRegions.sanitizeAndMerge(regionSet1, regionSet2, 100);
assert.strictEqual(result.length, 3, 'result length4');
assertEqualRanges(result[0], foldRange(1, 100, false, false, 'a1'), 'R1');
assertEqualRanges(result[1], foldRange(20, 28, true, true, 'b1'), 'R2');
assertEqualRanges(result[2], foldRange(30, 38, true, true, 'b2'), 'R3');
assertEqualRanges(result[0], foldRange(1, 100, false, FoldSource.provider, 'a1'), 'R1');
assertEqualRanges(result[1], foldRange(20, 28, true, FoldSource.recovered, 'b1'), 'R2');
assertEqualRanges(result[2], foldRange(30, 38, true, FoldSource.recovered, 'b2'), 'R3');
});
});

View file

@ -699,7 +699,7 @@ export async function provideInlineCompletions(
}
for (const item of completions.items) {
const range = item.range ? Range.lift(item.range) : defaultReplaceRange;
let range = item.range ? Range.lift(item.range) : defaultReplaceRange;
if (range.startLineNumber !== range.endLineNumber) {
// Ignore invalid ranges.
@ -724,6 +724,12 @@ export async function provideInlineCompletions(
model,
languageConfigurationService
);
// Modify range depending on if brackets are added or removed
const diff = insertText.length - item.insertText.length;
if (diff !== 0) {
range = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn + diff);
}
}
snippetInfo = undefined;

View file

@ -0,0 +1,408 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IActiveCodeEditor, ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/browser/outlineModel';
import { CancellationToken, CancellationTokenSource, } from 'vs/base/common/cancellation';
import * as dom from 'vs/base/browser/dom';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { createStringBuilder } from 'vs/editor/common/core/stringBuilder';
import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { SymbolKind } from 'vs/editor/common/languages';
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
class StickyScrollController extends Disposable implements IEditorContribution {
static readonly ID = 'store.contrib.stickyScrollController';
private readonly _editor: ICodeEditor;
private readonly stickyScrollWidget: StickyScrollWidget;
private readonly _languageFeaturesService: ILanguageFeaturesService;
private readonly _sessionStore: DisposableStore = new DisposableStore();
private _ranges: [number, number, number][] = [];
private _rangesVersionId: number = 0;
private _cts: CancellationTokenSource | undefined;
private readonly _updateSoon: RunOnceScheduler;
constructor(
editor: ICodeEditor,
@ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService,
) {
super();
this._editor = editor;
this._languageFeaturesService = _languageFeaturesService;
this.stickyScrollWidget = new StickyScrollWidget(this._editor);
this._register(this._editor.onDidChangeConfiguration(e => {
if (e.hasChanged(EditorOption.experimental)) {
this.onConfigurationChange();
}
}));
this._updateSoon = this._register(new RunOnceScheduler(() => this._update(true), 50));
this.onConfigurationChange();
}
private onConfigurationChange() {
const options = this._editor.getOption(EditorOption.experimental);
if (options.stickyScroll.enabled === false) {
this.stickyScrollWidget.emptyRootNode();
this._editor.removeOverlayWidget(this.stickyScrollWidget);
this._sessionStore.clear();
return;
} else {
this._editor.addOverlayWidget(this.stickyScrollWidget);
this._sessionStore.add(this._editor.onDidChangeModel(() => this._update(true)));
this._sessionStore.add(this._editor.onDidScrollChange(() => this._update(false)));
this._sessionStore.add(this._editor.onDidChangeHiddenAreas(() => this._update(true)));
this._sessionStore.add(this._editor.onDidChangeModelTokens((e) => this._onTokensChange(e)));
this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._updateSoon.schedule()));
this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true)));
this._update(true);
}
}
private _needsUpdate(event: IModelTokensChangedEvent) {
const stickyLineNumbers = this.stickyScrollWidget.getCurrentLines();
for (const stickyLineNumber of stickyLineNumbers) {
for (const range of event.ranges) {
if (stickyLineNumber >= range.fromLineNumber && stickyLineNumber <= range.toLineNumber) {
return true;
}
}
}
return false;
}
private _onTokensChange(event: IModelTokensChangedEvent) {
if (this._needsUpdate(event)) {
this._update(false);
}
}
private async _update(updateOutline: boolean = false): Promise<void> {
if (updateOutline) {
this._cts?.dispose(true);
this._cts = new CancellationTokenSource();
await this._updateOutlineModel(this._cts.token);
}
const hiddenRanges: Range[] | undefined = this._editor._getViewModel()?.getHiddenAreas();
if (hiddenRanges) {
for (const hiddenRange of hiddenRanges) {
this._ranges = this._ranges.filter(range => { return !(range[0] >= hiddenRange.startLineNumber && range[1] <= hiddenRange.endLineNumber + 1); });
}
}
this._renderStickyScroll();
}
private _findLineRanges(outlineElement: OutlineElement, depth: number) {
if (outlineElement?.children.size) {
let didRecursion: boolean = false;
for (const outline of outlineElement?.children.values()) {
const kind: SymbolKind = outline.symbol.kind;
if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method || kind === SymbolKind.Module) {
didRecursion = true;
this._findLineRanges(outline, depth + 1);
}
}
if (!didRecursion) {
this._addOutlineRanges(outlineElement, depth);
}
} else {
this._addOutlineRanges(outlineElement, depth);
}
}
private _addOutlineRanges(outlineElement: OutlineElement, depth: number) {
let currentStartLine: number | undefined = 0;
let currentEndLine: number | undefined = 0;
while (outlineElement) {
const kind: SymbolKind = outlineElement.symbol.kind;
if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method || kind === SymbolKind.Module) {
currentStartLine = outlineElement?.symbol.range.startLineNumber as number;
currentEndLine = outlineElement?.symbol.range.endLineNumber as number;
this._ranges.push([currentStartLine, currentEndLine, depth]);
depth--;
}
if (outlineElement.parent instanceof OutlineElement) {
outlineElement = outlineElement.parent;
} else {
break;
}
}
}
private async _updateOutlineModel(token: CancellationToken) {
if (this._editor.hasModel()) {
const model = this._editor.getModel();
const modelVersionId = model.getVersionId();
const outlineModel = await OutlineModel.create(this._languageFeaturesService.documentSymbolProvider, model, token);
if (token.isCancellationRequested) {
return;
}
this._ranges = [];
this._rangesVersionId = modelVersionId;
for (const outline of outlineModel.children.values()) {
if (outline instanceof OutlineElement) {
const kind: SymbolKind = outline.symbol.kind;
if (kind === SymbolKind.Class || kind === SymbolKind.Constructor || kind === SymbolKind.Function || kind === SymbolKind.Interface || kind === SymbolKind.Method || kind === SymbolKind.Module) {
this._findLineRanges(outline, 1);
} else {
this._findLineRanges(outline, 0);
}
}
this._ranges = this._ranges.sort(function (a, b) {
if (a[0] !== b[0]) {
return a[0] - b[0];
} else if (a[1] !== b[1]) {
return b[1] - a[1];
} else {
return a[2] - b[2];
}
});
let previous: number[] = [];
for (const [index, arr] of this._ranges.entries()) {
const [start, end, _depth] = arr;
if (previous[0] === start && previous[1] === end) {
this._ranges.splice(index, 1);
} else {
previous = arr;
}
}
}
}
}
private _renderStickyScroll() {
if (!(this._editor.hasModel())) {
return;
}
const lineHeight: number = this._editor.getOption(EditorOption.lineHeight);
const model = this._editor.getModel();
if (this._rangesVersionId !== model.getVersionId()) {
// Old _ranges not updated yet
return;
}
const scrollTop = this._editor.getScrollTop();
this.stickyScrollWidget.emptyRootNode();
const beginningLinesConsidered: Set<number> = new Set<number>();
for (const [index, arr] of this._ranges.entries()) {
const [start, end, depth] = arr;
if (end - start > 0 && model.getLineContent(start) !== '') {
const topOfElementAtDepth = (depth - 1) * lineHeight;
const bottomOfElementAtDepth = depth * lineHeight;
const bottomOfBeginningLine = this._editor.getBottomForLineNumber(start) - scrollTop;
const topOfEndLine = this._editor.getTopForLineNumber(end) - scrollTop;
const bottomOfEndLine = this._editor.getBottomForLineNumber(end) - scrollTop;
if (!beginningLinesConsidered.has(start)) {
if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) {
beginningLinesConsidered.add(start);
this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, depth, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth));
break;
}
else if (bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < bottomOfEndLine - 1) {
beginningLinesConsidered.add(start);
this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, depth, this._editor, 0, 0));
}
} else {
this._ranges.splice(index, 1);
}
}
}
this.stickyScrollWidget.updateRootNode();
}
override dispose(): void {
super.dispose();
this._sessionStore.dispose();
}
}
const _ttPolicy = window.trustedTypes?.createPolicy('stickyScrollViewLayer', { createHTML: value => value });
class StickyScrollCodeLine {
public readonly effectiveLineHeight: number = 0;
constructor(private readonly _lineNumber: number, private readonly _depth: number, private readonly _editor: IActiveCodeEditor,
private readonly _zIndex: number, private readonly _relativePosition: number) {
this.effectiveLineHeight = this._editor.getOption(EditorOption.lineHeight) + this._relativePosition;
}
get lineNumber() {
return this._lineNumber;
}
getDomNode() {
const root: HTMLElement = document.createElement('div');
const viewModel = this._editor._getViewModel();
const viewLineNumber = viewModel.coordinatesConverter.convertModelPositionToViewPosition(new Position(this._lineNumber, 1)).lineNumber;
const lineRenderingData = viewModel.getViewLineRenderingData(viewLineNumber);
let actualInlineDecorations: LineDecoration[];
try {
actualInlineDecorations = LineDecoration.filter(lineRenderingData.inlineDecorations, viewLineNumber, lineRenderingData.minColumn, lineRenderingData.maxColumn);
} catch (err) {
actualInlineDecorations = [];
}
const renderLineInput: RenderLineInput = new RenderLineInput(true, true, lineRenderingData.content, lineRenderingData.continuesWithWrappedLine,
lineRenderingData.isBasicASCII, lineRenderingData.containsRTL, 0, lineRenderingData.tokens, actualInlineDecorations, lineRenderingData.tabSize,
lineRenderingData.startVisibleColumn, 1, 1, 1, 100, 'none', true, true, null);
const sb = createStringBuilder(400);
renderViewLine(renderLineInput, sb);
let newLine;
if (_ttPolicy) {
newLine = _ttPolicy.createHTML(sb.build() as string);
} else {
newLine = sb.build();
}
const lineHTMLNode = document.createElement('span');
lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`;
lineHTMLNode.style.overflow = 'hidden';
lineHTMLNode.style.whiteSpace = 'nowrap';
lineHTMLNode.style.display = 'inline-block';
lineHTMLNode.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px';
lineHTMLNode.innerHTML = newLine as string;
const lineNumberHTMLNode = document.createElement('span');
lineNumberHTMLNode.style.width = this._editor.getLayoutInfo().contentLeft.toString() + 'px';
lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`;
lineNumberHTMLNode.style.color = 'var(--vscode-editorLineNumber-foreground)';
lineNumberHTMLNode.style.display = 'inline-block';
lineNumberHTMLNode.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px';
const innerLineNumberHTML = document.createElement('span');
innerLineNumberHTML.innerText = this._lineNumber.toString();
innerLineNumberHTML.style.paddingLeft = this._editor.getLayoutInfo().lineNumbersLeft.toString() + 'px';
innerLineNumberHTML.style.width = this._editor.getLayoutInfo().lineNumbersWidth.toString() + 'px';
innerLineNumberHTML.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`;
innerLineNumberHTML.style.textAlign = 'right';
innerLineNumberHTML.style.float = 'left';
innerLineNumberHTML.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px';
lineNumberHTMLNode.appendChild(innerLineNumberHTML);
root.onclick = e => {
e.stopPropagation();
e.preventDefault();
this._editor.revealPosition({ lineNumber: this._lineNumber - this._depth + 1, column: 1 });
};
root.onmouseover = e => {
innerLineNumberHTML.style.background = `var(--vscode-editorStickyScrollHover-background)`;
lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`;
lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`;
root.style.backgroundColor = `var(--vscode-editorStickyScrollHover-background)`;
innerLineNumberHTML.style.cursor = `pointer`;
lineHTMLNode.style.cursor = `pointer`;
root.style.cursor = `pointer`;
lineNumberHTMLNode.style.cursor = `pointer`;
};
root.onmouseleave = e => {
innerLineNumberHTML.style.background = `var(--vscode-editorStickyScroll-background)`;
lineHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`;
lineNumberHTMLNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`;
root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`;
};
this._editor.applyFontInfo(lineHTMLNode);
this._editor.applyFontInfo(innerLineNumberHTML);
root.appendChild(lineNumberHTMLNode);
root.appendChild(lineHTMLNode);
root.style.zIndex = this._zIndex.toString();
root.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`;
root.style.overflow = 'hidden';
root.style.whiteSpace = 'nowrap';
root.style.width = '100%';
root.style.lineHeight = this._editor.getOption(EditorOption.lineHeight).toString() + 'px';
root.style.height = this._editor.getOption(EditorOption.lineHeight).toString() + 'px';
// Special case for last line of sticky scroll
if (this._relativePosition) {
root.style.position = 'relative';
root.style.top = this._relativePosition + 'px';
root.style.width = '100%';
}
return root;
}
}
class StickyScrollWidget implements IOverlayWidget {
private readonly arrayOfCodeLines: StickyScrollCodeLine[] = [];
private readonly rootDomNode: HTMLElement = document.createElement('div');
constructor(public readonly _editor: ICodeEditor) {
this.rootDomNode = document.createElement('div');
this.rootDomNode.style.width = '100%';
this.rootDomNode.style.boxShadow = `var(--vscode-scrollbar-shadow) 0 6px 6px -6px`;
}
get codeLineCount() {
return this.arrayOfCodeLines.length;
}
getCurrentLines(): number[] {
const widgetLineRange: number[] = [];
for (const codeLine of this.arrayOfCodeLines) {
widgetLineRange.push(codeLine.lineNumber);
}
return widgetLineRange;
}
pushCodeLine(codeLine: StickyScrollCodeLine) {
this.arrayOfCodeLines.push(codeLine);
}
updateRootNode() {
let widgetHeight: number = 0;
for (const line of this.arrayOfCodeLines) {
widgetHeight += line.effectiveLineHeight;
this.rootDomNode.appendChild(line.getDomNode());
}
this.rootDomNode.style.height = widgetHeight.toString() + 'px';
}
emptyRootNode() {
this.arrayOfCodeLines.length = 0;
dom.clearNode(this.rootDomNode);
}
getId(): string {
return 'editor.contrib.stickyScrollWidget';
}
getDomNode(): HTMLElement {
this.rootDomNode.style.zIndex = '2';
this.rootDomNode.style.backgroundColor = `var(--vscode-editorStickyScroll-background)`;
return this.rootDomNode;
}
getPosition(): IOverlayWidgetPosition | null {
return {
preference: null
};
}
}
registerEditorContribution(StickyScrollController.ID, StickyScrollController);

View file

@ -41,6 +41,7 @@ import 'vs/editor/contrib/links/browser/links';
import 'vs/editor/contrib/multicursor/browser/multicursor';
import 'vs/editor/contrib/parameterHints/browser/parameterHints';
import 'vs/editor/contrib/rename/browser/rename';
import 'vs/editor/contrib/stickyScroll/browser/stickyScroll';
import 'vs/editor/contrib/smartSelect/browser/smartSelect';
import 'vs/editor/contrib/snippet/browser/snippetController2';
import 'vs/editor/contrib/suggest/browser/suggestController';

View file

@ -526,12 +526,13 @@ export function registerCodeActionProvider(languageSelector: LanguageSelector, p
const languageFeaturesService = StandaloneServices.get(ILanguageFeaturesService);
return languageFeaturesService.codeActionProvider.register(languageSelector, {
providedCodeActionKinds: metadata?.providedCodeActionKinds,
documentation: metadata?.documentation,
provideCodeActions: (model: model.ITextModel, range: Range, context: languages.CodeActionContext, token: CancellationToken): languages.ProviderResult<languages.CodeActionList> => {
const markerService = StandaloneServices.get(IMarkerService);
const markers = markerService.read({ resource: model.uri }).filter(m => {
return Range.areIntersectingOrTouching(m, range);
});
return provider.provideCodeActions(model, range, { markers, only: context.only }, token);
return provider.provideCodeActions(model, range, { markers, only: context.only, trigger: context.trigger }, token);
},
resolveCodeAction: provider.resolveCodeAction
});
@ -664,6 +665,11 @@ export interface CodeActionContext {
* Requested kind of actions to return.
*/
readonly only?: string;
/**
* The reason why code actions were requested.
*/
readonly trigger: languages.CodeActionTriggerType;
}
/**
@ -697,6 +703,8 @@ export interface CodeActionProviderMetadata {
* such as `["quickfix.removeLine", "source.fixAll" ...]`.
*/
readonly providedCodeActionKinds?: readonly string[];
readonly documentation?: ReadonlyArray<{ readonly kind: string; readonly command: languages.Command }>;
}
/**
@ -753,6 +761,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages {
SignatureHelpTriggerKind: standaloneEnums.SignatureHelpTriggerKind,
InlayHintKind: standaloneEnums.InlayHintKind,
InlineCompletionTriggerKind: standaloneEnums.InlineCompletionTriggerKind,
CodeActionTriggerType: standaloneEnums.CodeActionTriggerType,
// classes
FoldingRangeKind: languages.FoldingRangeKind,

View file

@ -97,7 +97,7 @@ suite('ViewModelDecorations', () => {
'dec14',
]);
const inlineDecorations1 = viewModel.getViewLineRenderingData(
const inlineDecorations1 = viewModel.getViewportViewLineRenderingData(
new Range(1, viewModel.getLineMinColumn(1), 2, viewModel.getLineMaxColumn(2)),
1
).inlineDecorations;
@ -118,7 +118,7 @@ suite('ViewModelDecorations', () => {
new InlineDecoration(new Range(1, 2, 1, 2), 'b-dec5', InlineDecorationType.Before),
]);
const inlineDecorations2 = viewModel.getViewLineRenderingData(
const inlineDecorations2 = viewModel.getViewportViewLineRenderingData(
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)),
2
).inlineDecorations;
@ -148,7 +148,7 @@ suite('ViewModelDecorations', () => {
new InlineDecoration(new Range(2, 3, 2, 3), 'b-dec12', InlineDecorationType.Before),
]);
const inlineDecorations3 = viewModel.getViewLineRenderingData(
const inlineDecorations3 = viewModel.getViewportViewLineRenderingData(
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)),
3
).inlineDecorations;
@ -198,13 +198,13 @@ suite('ViewModelDecorations', () => {
).filter(x => Boolean(x.options.beforeContentClassName));
assert.deepStrictEqual(decorations, []);
const inlineDecorations1 = viewModel.getViewLineRenderingData(
const inlineDecorations1 = viewModel.getViewportViewLineRenderingData(
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)),
2
).inlineDecorations;
assert.deepStrictEqual(inlineDecorations1, []);
const inlineDecorations2 = viewModel.getViewLineRenderingData(
const inlineDecorations2 = viewModel.getViewportViewLineRenderingData(
new Range(2, viewModel.getLineMinColumn(2), 3, viewModel.getLineMaxColumn(3)),
3
).inlineDecorations;
@ -229,7 +229,7 @@ suite('ViewModelDecorations', () => {
);
});
const inlineDecorations = viewModel.getViewLineRenderingData(
const inlineDecorations = viewModel.getViewportViewLineRenderingData(
new Range(1, 1, 1, 1),
1
).inlineDecorations;

285
src/vs/monaco.d.ts vendored
View file

@ -1738,6 +1738,15 @@ declare namespace monaco.editor {
GrowsOnlyWhenTypingAfter = 3
}
/**
* Text snapshot that works like an iterator.
* Will try to return chunks of roughly ~64KB size.
* Will return null when finished.
*/
export interface ITextSnapshot {
read(): string | null;
}
/**
* A model.
*/
@ -1769,7 +1778,7 @@ declare namespace monaco.editor {
/**
* Replace the entire text buffer value contained in this model.
*/
setValue(newValue: string): void;
setValue(newValue: string | ITextSnapshot): void;
/**
* Get the text stored in this model.
* @param eol The end of line character preference. Defaults to `EndOfLinePreference.TextDefined`.
@ -1777,6 +1786,12 @@ declare namespace monaco.editor {
* @return The text.
*/
getValue(eol?: EndOfLinePreference, preserveBOM?: boolean): string;
/**
* Get the text stored in this model.
* @param preserverBOM Preserve a BOM character if it was detected when the model was constructed.
* @return The text snapshot (it is safe to consume it asynchronously).
*/
createSnapshot(preserveBOM?: boolean): ITextSnapshot;
/**
* Get the length of the text stored in this model.
*/
@ -2931,6 +2946,10 @@ declare namespace monaco.editor {
* Control the behavior and rendering of the scrollbars.
*/
scrollbar?: IEditorScrollbarOptions;
/**
* Control the behavior of experimental options
*/
experimental?: IEditorExperimentalOptions;
/**
* Control the behavior and rendering of the minimap.
*/
@ -3420,11 +3439,11 @@ declare namespace monaco.editor {
*/
bracketPairColorization?: IBracketPairColorizationOptions;
/**
* Enables dropping into the editor from an external source.
* Controls dropping into the editor from an external source.
*
* This shows a preview of the drop location and triggers an `onDropIntoEditor` event.
* When enabled, this shows a preview of the drop location and triggers an `onDropIntoEditor` event.
*/
enableDropIntoEditor?: boolean;
dropIntoEditor?: IDropIntoEditorOptions;
}
export interface IDiffEditorBaseOptions {
@ -3789,6 +3808,24 @@ declare namespace monaco.editor {
enabled?: boolean;
}
export interface IEditorExperimentalOptions {
/**
* Configuration options for editor sticky scroll
*/
stickyScroll?: {
/**
* Enable the sticky scroll
*/
enabled?: boolean;
};
}
export interface EditorExperimentalOptions {
stickyScroll: {
enabled: boolean;
};
}
/**
* Configuration options for editor inlayHints
*/
@ -4301,6 +4338,17 @@ declare namespace monaco.editor {
readonly wrappingColumn: number;
}
/**
* Configuration options for editor drop into behavior
*/
export interface IDropIntoEditorOptions {
/**
* Enable the dropping into editor.
* Defaults to true.
*/
enabled?: boolean;
}
export enum EditorOption {
acceptSuggestionOnCommitCharacter = 0,
acceptSuggestionOnEnter = 1,
@ -4334,108 +4382,109 @@ declare namespace monaco.editor {
disableMonospaceOptimizations = 29,
domReadOnly = 30,
dragAndDrop = 31,
enableDropIntoEditor = 32,
dropIntoEditor = 32,
emptySelectionClipboard = 33,
extraEditorClassName = 34,
fastScrollSensitivity = 35,
find = 36,
fixedOverflowWidgets = 37,
folding = 38,
foldingStrategy = 39,
foldingHighlight = 40,
foldingImportsByDefault = 41,
foldingMaximumRegions = 42,
unfoldOnClickAfterEndOfLine = 43,
fontFamily = 44,
fontInfo = 45,
fontLigatures = 46,
fontSize = 47,
fontWeight = 48,
formatOnPaste = 49,
formatOnType = 50,
glyphMargin = 51,
gotoLocation = 52,
hideCursorInOverviewRuler = 53,
hover = 54,
inDiffEditor = 55,
inlineSuggest = 56,
letterSpacing = 57,
lightbulb = 58,
lineDecorationsWidth = 59,
lineHeight = 60,
lineNumbers = 61,
lineNumbersMinChars = 62,
linkedEditing = 63,
links = 64,
matchBrackets = 65,
minimap = 66,
mouseStyle = 67,
mouseWheelScrollSensitivity = 68,
mouseWheelZoom = 69,
multiCursorMergeOverlapping = 70,
multiCursorModifier = 71,
multiCursorPaste = 72,
occurrencesHighlight = 73,
overviewRulerBorder = 74,
overviewRulerLanes = 75,
padding = 76,
parameterHints = 77,
peekWidgetDefaultFocus = 78,
definitionLinkOpensInPeek = 79,
quickSuggestions = 80,
quickSuggestionsDelay = 81,
readOnly = 82,
renameOnType = 83,
renderControlCharacters = 84,
renderFinalNewline = 85,
renderLineHighlight = 86,
renderLineHighlightOnlyWhenFocus = 87,
renderValidationDecorations = 88,
renderWhitespace = 89,
revealHorizontalRightPadding = 90,
roundedSelection = 91,
rulers = 92,
scrollbar = 93,
scrollBeyondLastColumn = 94,
scrollBeyondLastLine = 95,
scrollPredominantAxis = 96,
selectionClipboard = 97,
selectionHighlight = 98,
selectOnLineNumbers = 99,
showFoldingControls = 100,
showUnused = 101,
snippetSuggestions = 102,
smartSelect = 103,
smoothScrolling = 104,
stickyTabStops = 105,
stopRenderingLineAfter = 106,
suggest = 107,
suggestFontSize = 108,
suggestLineHeight = 109,
suggestOnTriggerCharacters = 110,
suggestSelection = 111,
tabCompletion = 112,
tabIndex = 113,
unicodeHighlighting = 114,
unusualLineTerminators = 115,
useShadowDOM = 116,
useTabStops = 117,
wordSeparators = 118,
wordWrap = 119,
wordWrapBreakAfterCharacters = 120,
wordWrapBreakBeforeCharacters = 121,
wordWrapColumn = 122,
wordWrapOverride1 = 123,
wordWrapOverride2 = 124,
wrappingIndent = 125,
wrappingStrategy = 126,
showDeprecated = 127,
inlayHints = 128,
editorClassName = 129,
pixelRatio = 130,
tabFocusMode = 131,
layoutInfo = 132,
wrappingInfo = 133
experimental = 34,
extraEditorClassName = 35,
fastScrollSensitivity = 36,
find = 37,
fixedOverflowWidgets = 38,
folding = 39,
foldingStrategy = 40,
foldingHighlight = 41,
foldingImportsByDefault = 42,
foldingMaximumRegions = 43,
unfoldOnClickAfterEndOfLine = 44,
fontFamily = 45,
fontInfo = 46,
fontLigatures = 47,
fontSize = 48,
fontWeight = 49,
formatOnPaste = 50,
formatOnType = 51,
glyphMargin = 52,
gotoLocation = 53,
hideCursorInOverviewRuler = 54,
hover = 55,
inDiffEditor = 56,
inlineSuggest = 57,
letterSpacing = 58,
lightbulb = 59,
lineDecorationsWidth = 60,
lineHeight = 61,
lineNumbers = 62,
lineNumbersMinChars = 63,
linkedEditing = 64,
links = 65,
matchBrackets = 66,
minimap = 67,
mouseStyle = 68,
mouseWheelScrollSensitivity = 69,
mouseWheelZoom = 70,
multiCursorMergeOverlapping = 71,
multiCursorModifier = 72,
multiCursorPaste = 73,
occurrencesHighlight = 74,
overviewRulerBorder = 75,
overviewRulerLanes = 76,
padding = 77,
parameterHints = 78,
peekWidgetDefaultFocus = 79,
definitionLinkOpensInPeek = 80,
quickSuggestions = 81,
quickSuggestionsDelay = 82,
readOnly = 83,
renameOnType = 84,
renderControlCharacters = 85,
renderFinalNewline = 86,
renderLineHighlight = 87,
renderLineHighlightOnlyWhenFocus = 88,
renderValidationDecorations = 89,
renderWhitespace = 90,
revealHorizontalRightPadding = 91,
roundedSelection = 92,
rulers = 93,
scrollbar = 94,
scrollBeyondLastColumn = 95,
scrollBeyondLastLine = 96,
scrollPredominantAxis = 97,
selectionClipboard = 98,
selectionHighlight = 99,
selectOnLineNumbers = 100,
showFoldingControls = 101,
showUnused = 102,
snippetSuggestions = 103,
smartSelect = 104,
smoothScrolling = 105,
stickyTabStops = 106,
stopRenderingLineAfter = 107,
suggest = 108,
suggestFontSize = 109,
suggestLineHeight = 110,
suggestOnTriggerCharacters = 111,
suggestSelection = 112,
tabCompletion = 113,
tabIndex = 114,
unicodeHighlighting = 115,
unusualLineTerminators = 116,
useShadowDOM = 117,
useTabStops = 118,
wordSeparators = 119,
wordWrap = 120,
wordWrapBreakAfterCharacters = 121,
wordWrapBreakBeforeCharacters = 122,
wordWrapColumn = 123,
wordWrapOverride1 = 124,
wordWrapOverride2 = 125,
wrappingIndent = 126,
wrappingStrategy = 127,
showDeprecated = 128,
inlayHints = 129,
editorClassName = 130,
pixelRatio = 131,
tabFocusMode = 132,
layoutInfo = 133,
wrappingInfo = 134
}
export const EditorOptions: {
@ -4473,7 +4522,8 @@ declare namespace monaco.editor {
domReadOnly: IEditorOption<EditorOption.domReadOnly, boolean>;
dragAndDrop: IEditorOption<EditorOption.dragAndDrop, boolean>;
emptySelectionClipboard: IEditorOption<EditorOption.emptySelectionClipboard, boolean>;
enableDropIntoEditor: IEditorOption<EditorOption.enableDropIntoEditor, boolean>;
dropIntoEditor: IEditorOption<EditorOption.dropIntoEditor, Readonly<Required<IDropIntoEditorOptions>>>;
experimental: IEditorOption<EditorOption.experimental, EditorExperimentalOptions>;
extraEditorClassName: IEditorOption<EditorOption.extraEditorClassName, string>;
fastScrollSensitivity: IEditorOption<EditorOption.fastScrollSensitivity, number>;
find: IEditorOption<EditorOption.find, Readonly<Required<IEditorFindOptions>>>;
@ -5330,9 +5380,13 @@ declare namespace monaco.editor {
*/
getVisibleRanges(): Range[];
/**
* Get the vertical position (top offset) for the line w.r.t. to the first line.
* Get the vertical position (top offset) for the line's top w.r.t. to the first line.
*/
getTopForLineNumber(lineNumber: number): number;
/**
* Get the vertical position (top offset) for the line's bottom w.r.t. to the first line.
*/
getBottomForLineNumber(lineNumber: number): number;
/**
* Get the vertical position (top offset) for the position w.r.t. to the first line.
*/
@ -5833,6 +5887,10 @@ declare namespace monaco.languages {
* Requested kind of actions to return.
*/
readonly only?: string;
/**
* The reason why code actions were requested.
*/
readonly trigger: CodeActionTriggerType;
}
/**
@ -5863,6 +5921,10 @@ declare namespace monaco.languages {
* such as `["quickfix.removeLine", "source.fixAll" ...]`.
*/
readonly providedCodeActionKinds?: readonly string[];
readonly documentation?: ReadonlyArray<{
readonly kind: string;
readonly command: Command;
}>;
}
/**
@ -6435,6 +6497,11 @@ declare namespace monaco.languages {
disabled?: string;
}
export enum CodeActionTriggerType {
Invoke = 1,
Auto = 2
}
export interface CodeActionList extends IDisposable {
readonly actions: ReadonlyArray<CodeAction>;
}
@ -6771,11 +6838,11 @@ declare namespace monaco.languages {
provideDocumentSymbols(model: editor.ITextModel, token: CancellationToken): ProviderResult<DocumentSymbol[]>;
}
export type TextEdit = {
export interface TextEdit {
range: IRange;
text: string;
eol?: editor.EndOfLineSequence;
};
}
/**
* Interface used to format a model

View file

@ -223,8 +223,8 @@ export class ExtensionManagementCLIService implements IExtensionManagementCLISer
output.log(version ? localize('installing with version', "Installing extension '{0}' v{1}...", id, version) : localize('installing', "Installing extension '{0}'...", id));
}
await this.extensionManagementService.installFromGallery(galleryExtension, { ...installOptions, installGivenVersion: !!version });
output.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, galleryExtension.version));
const local = await this.extensionManagementService.installFromGallery(galleryExtension, { ...installOptions, installGivenVersion: !!version });
output.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, local.manifest.version));
return manifest;
} catch (error) {
if (isCancellationError(error)) {

View file

@ -51,7 +51,7 @@ export interface ResourceLabelFormatter {
}
export interface ResourceLabelFormatting {
label: string | ((resource: URI) => string); // myLabel:/${path}
label: string; // myLabel:/${path}
separator: '/' | '\\' | '';
tildify?: boolean;
normalizeDriveLetter?: boolean;

View file

@ -125,6 +125,7 @@ export const WorkbenchTreeElementHasParent = new RawContextKey<boolean>('treeEle
export const WorkbenchTreeElementCanExpand = new RawContextKey<boolean>('treeElementCanExpand', false);
export const WorkbenchTreeElementHasChild = new RawContextKey<boolean>('treeElementHasChild', false);
export const WorkbenchTreeFindOpen = new RawContextKey<boolean>('treeFindOpen', false);
export const WorkbenchTreeSupportsFind = new RawContextKey<boolean>('treeSupportsFind', true);
const WorkbenchListTypeNavigationModeKey = 'listTypeNavigationMode';
/**
@ -189,7 +190,6 @@ class MultipleSelectionController<T> extends Disposable implements IMultipleSele
function toWorkbenchListOptions<T>(
accessor: ServicesAccessor,
container: HTMLElement,
options: IListOptions<T>,
): [IListOptions<T>, IDisposable] {
const configurationService = accessor.get(IConfigurationService);
@ -203,7 +203,7 @@ function toWorkbenchListOptions<T>(
mouseWheelScrollSensitivity: configurationService.getValue<number>(mouseWheelScrollSensitivityKey),
fastScrollSensitivity: configurationService.getValue<number>(fastScrollSensitivityKey),
multipleSelectionController: options.multipleSelectionController ?? disposables.add(new MultipleSelectionController(configurationService)),
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService),
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(keybindingService),
};
return [result, disposables];
@ -244,7 +244,7 @@ export class WorkbenchList<T> extends List<T> {
@IInstantiationService instantiationService: IInstantiationService
) {
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey));
const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, container, options);
const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options);
super(user, container, delegate, renderers,
{
@ -384,7 +384,7 @@ export class WorkbenchPagedList<T> extends PagedList<T> {
@IInstantiationService instantiationService: IInstantiationService
) {
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey));
const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, container, options);
const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options);
super(user, container, delegate, renderers,
{
keyboardSupport: false,
@ -517,7 +517,7 @@ export class WorkbenchTable<TRow> extends Table<TRow> {
@IInstantiationService instantiationService: IInstantiationService
) {
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey));
const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, container, options);
const [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options);
super(user, container, delegate, columns, renderers,
{
@ -812,7 +812,7 @@ class TreeResourceNavigator<T, TFilterData> extends ResourceNavigator<T> {
}
}
function createKeyboardNavigationEventFilter(container: HTMLElement, keybindingService: IKeybindingService): IKeyboardNavigationEventFilter {
function createKeyboardNavigationEventFilter(keybindingService: IKeybindingService): IKeyboardNavigationEventFilter {
let inChord = false;
return event => {
@ -825,7 +825,7 @@ function createKeyboardNavigationEventFilter(container: HTMLElement, keybindingS
return false;
}
const result = keybindingService.softDispatch(event, container);
const result = keybindingService.softDispatch(event, event.target);
if (result?.enterChord) {
inChord = true;
@ -862,7 +862,7 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
@IThemeService themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService
) {
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any);
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);
super(user, container, delegate, renderers, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService);
@ -903,7 +903,7 @@ export class WorkbenchCompressibleObjectTree<T extends NonNullable<any>, TFilter
@IThemeService themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService
) {
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any);
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);
super(user, container, delegate, renderers, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService);
@ -950,7 +950,7 @@ export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<T
@IThemeService themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService
) {
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any);
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);
super(user, container, delegate, renderers, dataSource, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService);
@ -997,7 +997,7 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
@IThemeService themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService
) {
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any);
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);
super(user, container, delegate, renderers, dataSource, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService);
@ -1042,7 +1042,7 @@ export class WorkbenchCompressibleAsyncDataTree<TInput, T, TFilterData = void> e
@IThemeService themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService
) {
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, container, options as any);
const { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);
super(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions);
this.disposables.add(disposable);
this.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, themeService, configurationService);
@ -1077,11 +1077,9 @@ function getDefaultTreeFindMode(configurationService: IConfigurationService) {
function workbenchTreeDataPreamble<T, TFilterData, TOptions extends IAbstractTreeOptions<T, TFilterData> | IAsyncDataTreeOptions<T, TFilterData>>(
accessor: ServicesAccessor,
container: HTMLElement,
options: TOptions,
): { options: TOptions; getTypeNavigationMode: () => TypeNavigationMode | undefined; disposable: IDisposable } {
const configurationService = accessor.get(IConfigurationService);
const keybindingService = accessor.get(IKeybindingService);
const contextViewService = accessor.get(IContextViewService);
const contextKeyService = accessor.get(IContextKeyService);
const instantiationService = accessor.get(IInstantiationService);
@ -1107,7 +1105,7 @@ function workbenchTreeDataPreamble<T, TFilterData, TOptions extends IAbstractTre
};
const horizontalScrolling = options.horizontalScrolling !== undefined ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey));
const [workbenchListOptions, disposable] = instantiationService.invokeFunction(toWorkbenchListOptions, container, options);
const [workbenchListOptions, disposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options);
const additionalScrollHeight = options.additionalScrollHeight;
return {
@ -1122,7 +1120,6 @@ function workbenchTreeDataPreamble<T, TFilterData, TOptions extends IAbstractTre
smoothScrolling: Boolean(configurationService.getValue(listSmoothScrolling)),
defaultFindMode: getDefaultTreeFindMode(configurationService),
horizontalScrolling,
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService),
additionalScrollHeight,
hideTwistiesOfChildlessElements: options.hideTwistiesOfChildlessElements,
expandOnlyOnTwistieClick: options.expandOnlyOnTwistieClick ?? (configurationService.getValue<'singleClick' | 'doubleClick'>(treeExpandMode) === 'doubleClick'),
@ -1147,6 +1144,7 @@ class WorkbenchTreeInternals<TInput, T, TFilterData> {
private treeElementCanExpand: IContextKey<boolean>;
private treeElementHasChild: IContextKey<boolean>;
private treeFindOpen: IContextKey<boolean>;
private treeSupportFindWidget: IContextKey<boolean>;
private _useAltAsMultipleSelectionModifier: boolean;
private disposables: IDisposable[] = [];
private styler: IDisposable | undefined;
@ -1180,7 +1178,10 @@ class WorkbenchTreeInternals<TInput, T, TFilterData> {
this.treeElementHasParent = WorkbenchTreeElementHasParent.bindTo(this.contextKeyService);
this.treeElementCanExpand = WorkbenchTreeElementCanExpand.bindTo(this.contextKeyService);
this.treeElementHasChild = WorkbenchTreeElementHasChild.bindTo(this.contextKeyService);
this.treeFindOpen = WorkbenchTreeFindOpen.bindTo(this.contextKeyService);
this.treeSupportFindWidget = WorkbenchTreeSupportsFind.bindTo(this.contextKeyService);
this.treeSupportFindWidget.set(options.findWidgetEnabled ?? true);
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);

View file

@ -103,7 +103,7 @@ class MarkerStats implements MarkerStatistics {
const result: MarkerStatistics = { errors: 0, warnings: 0, infos: 0, unknowns: 0 };
// TODO this is a hack
if (resource.scheme === Schemas.inMemory || resource.scheme === Schemas.walkThrough || resource.scheme === Schemas.walkThroughSnippet) {
if (resource.scheme === Schemas.inMemory || resource.scheme === Schemas.walkThrough || resource.scheme === Schemas.walkThroughSnippet || resource.scheme === Schemas.vscodeSourceControl) {
return result;
}

View file

@ -417,30 +417,48 @@ export interface IAddressProvider {
}
export async function connectRemoteAgentManagement(options: IConnectionOptions, remoteAuthority: string, clientId: string): Promise<ManagementPersistentConnection> {
try {
const reconnectionToken = generateUuid();
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
const { protocol } = await doConnectRemoteAgentManagement(simpleOptions, CancellationToken.None);
return new ManagementPersistentConnection(options, remoteAuthority, clientId, reconnectionToken, protocol);
} catch (err) {
options.logService.error(`[remote-connection] An error occurred in the very first connect attempt, it will be treated as a permanent error! Error:`);
options.logService.error(err);
PersistentConnection.triggerPermanentFailure(0, 0, RemoteAuthorityResolverError.isHandled(err));
throw err;
}
return createInitialConnection(
options,
async (simpleOptions) => {
const { protocol } = await doConnectRemoteAgentManagement(simpleOptions, CancellationToken.None);
return new ManagementPersistentConnection(options, remoteAuthority, clientId, simpleOptions.reconnectionToken, protocol);
}
);
}
export async function connectRemoteAgentExtensionHost(options: IConnectionOptions, startArguments: IRemoteExtensionHostStartParams): Promise<ExtensionHostPersistentConnection> {
try {
const reconnectionToken = generateUuid();
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
const { protocol, debugPort } = await doConnectRemoteAgentExtensionHost(simpleOptions, startArguments, CancellationToken.None);
return new ExtensionHostPersistentConnection(options, startArguments, reconnectionToken, protocol, debugPort);
} catch (err) {
options.logService.error(`[remote-connection] An error occurred in the very first connect attempt, it will be treated as a permanent error! Error:`);
options.logService.error(err);
PersistentConnection.triggerPermanentFailure(0, 0, RemoteAuthorityResolverError.isHandled(err));
throw err;
return createInitialConnection(
options,
async (simpleOptions) => {
const { protocol, debugPort } = await doConnectRemoteAgentExtensionHost(simpleOptions, startArguments, CancellationToken.None);
return new ExtensionHostPersistentConnection(options, startArguments, simpleOptions.reconnectionToken, protocol, debugPort);
}
);
}
/**
* Will attempt to connect 5 times. If it fails 5 consecutive times, it will give up.
*/
async function createInitialConnection<T extends PersistentConnection>(options: IConnectionOptions, connectionFactory: (simpleOptions: ISimpleConnectionOptions) => Promise<T>): Promise<T> {
const MAX_ATTEMPTS = 5;
for (let attempt = 1; ; attempt++) {
try {
const reconnectionToken = generateUuid();
const simpleOptions = await resolveConnectionOptions(options, reconnectionToken, null);
const result = await connectionFactory(simpleOptions);
return result;
} catch (err) {
if (attempt < MAX_ATTEMPTS) {
options.logService.error(`[remote-connection][attempt ${attempt}] An error occurred in initial connection! Will retry... Error:`);
options.logService.error(err);
} else {
options.logService.error(`[remote-connection][attempt ${attempt}] An error occurred in initial connection! It will be treated as a permanent error. Error:`);
options.logService.error(err);
PersistentConnection.triggerPermanentFailure(0, 0, RemoteAuthorityResolverError.isHandled(err));
throw err;
}
}
}
}

View file

@ -9,7 +9,7 @@ import { parse as parseUrl } from 'url';
import { Promises } from 'vs/base/common/async';
import { streamToBufferReadableStream } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { canceled } from 'vs/base/common/errors';
import { CancellationError } from 'vs/base/common/errors';
import { Disposable } from 'vs/base/common/lifecycle';
import * as streams from 'vs/base/common/stream';
import { isBoolean, isNumber } from 'vs/base/common/types';
@ -170,7 +170,7 @@ export class RequestService extends Disposable implements IRequestService {
token.onCancellationRequested(() => {
req.abort();
e(canceled());
e(new CancellationError());
});
});
}

View file

@ -4,18 +4,17 @@
*--------------------------------------------------------------------------------------------*/
import type { AppInsightsCore } from '@microsoft/1ds-core-js';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { AbstractOneDataSystemAppender } from 'vs/platform/telemetry/common/1dsAppender';
export class OneDataSystemWebAppender extends AbstractOneDataSystemAppender {
constructor(
configurationService: IConfigurationService | undefined,
isInternalTelemetry: boolean,
eventPrefix: string,
defaultData: { [key: string]: any } | null,
iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing
) {
super(configurationService, eventPrefix, defaultData, iKeyOrClientFactory);
super(isInternalTelemetry, eventPrefix, defaultData, iKeyOrClientFactory);
// If we cannot fetch the endpoint it means it is down and we should not send any telemetry.
// This is most likely due to ad blockers

View file

@ -7,7 +7,6 @@ import type { AppInsightsCore, IExtendedConfiguration } from '@microsoft/1ds-cor
import type { IChannelConfiguration, IXHROverride, PostChannel } from '@microsoft/1ds-post-js';
import { onUnexpectedError } from 'vs/base/common/errors';
import { mixin } from 'vs/base/common/objects';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils';
const endpointUrl = 'https://mobile.events.data.microsoft.com/OneCollector/1.0';
@ -63,7 +62,7 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende
protected readonly endPointUrl = endpointUrl;
constructor(
private readonly _configurationService: IConfigurationService | undefined,
private readonly _isInternalTelemetry: boolean,
private _eventPrefix: string,
private _defaultData: { [key: string]: any } | null,
iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing
@ -92,8 +91,7 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende
}
if (!this._asyncAiCore) {
const isInternal = this._configurationService?.getValue<boolean>('telemetry.internalTesting');
this._asyncAiCore = getClient(this._aiCoreOrKey, isInternal, this._xhrOverride);
this._asyncAiCore = getClient(this._aiCoreOrKey, this._isInternalTelemetry, this._xhrOverride);
}
this._asyncAiCore.then(

View file

@ -25,7 +25,7 @@ export async function resolveCommonProperties(
commit: string | undefined,
version: string | undefined,
machineId: string | undefined,
msftInternalDomains: string[] | undefined,
isInternalTelemetry: boolean,
installSourcePath: string,
product?: string
): Promise<{ [name: string]: string | boolean | undefined }> {
@ -50,10 +50,9 @@ export async function resolveCommonProperties(
// __GDPR__COMMON__ "common.product" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
result['common.product'] = product || 'desktop';
const msftInternal = verifyMicrosoftInternalDomain(msftInternalDomains || []);
if (msftInternal) {
if (isInternalTelemetry) {
// __GDPR__COMMON__ "common.msftInternal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
result['common.msftInternal'] = msftInternal;
result['common.msftInternal'] = isInternalTelemetry;
}
// dynamic properties which value differs on each call

View file

@ -11,6 +11,7 @@ import { URI } from 'vs/base/common/uri';
import { ConfigurationTarget, ConfigurationTargetToString, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IProductService } from 'vs/platform/product/common/productService';
import { verifyMicrosoftInternalDomain } from 'vs/platform/telemetry/common/commonProperties';
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
import { ICustomEndpointTelemetryService, ITelemetryData, ITelemetryEndpoint, ITelemetryInfo, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry';
@ -252,6 +253,18 @@ function flatKeys(result: string[], prefix: string, value: { [key: string]: any
}
}
/**
* Whether or not this is an internal user
* @param productService The product service
* @param configService The config servivce
* @returns true if internal, false otherwise
*/
export function isInternalTelemetry(productService: IProductService, configService: IConfigurationService) {
const msftInternalDomains = productService.msftInternalDomains || [];
const internalTesting = configService.getValue<boolean>('telemetry.internalTesting');
return verifyMicrosoftInternalDomain(msftInternalDomains) || internalTesting;
}
interface IPathEnvironment {
appRoot: string;
extensionsPath: string;

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