Merge from vscode 7653d836944892f83ce9e1f95c1204bafa1aec31

This commit is contained in:
ADS Merger
2020-05-08 03:58:34 +00:00
parent dac1970c43
commit fa62ec1f34
209 changed files with 5131 additions and 2480 deletions
+16
View File
@@ -0,0 +1,16 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vscode-github-triage-actions/master/classifier/apply/apply-labels/classifier-config.schema.json",
"assignees": {
"JacksonKearl": {
"assign": true
}
},
"labels": {
"search-editor": {
"applyLabel": true,
"assign": [
"JacksonKearl"
]
}
}
}
-36
View File
@@ -1,36 +0,0 @@
{
perform: true,
alwaysRequireAssignee: false,
labelsRequiringAssignee: [],
defaultLabel: 'Triage: Needed',
defaultAssignee: '',
autoAssignees: {
Area - Acquisition: [],
Area - Azure: [],
Area - Backup\Restore: [],
Area - Charting\Insights: [],
Area - Connection: [ charles-gagnon ],
Area - DacFX: [],
Area - Dashboard: [],
Area - Data Explorer: [],
Area - Edit Data: [],
Area - Extensibility: [],
Area - External Table: [],
Area - Fundamentals: [],
Area - Language Service: [ charles-gagnon ],
Area - Localization: [],
Area - Notebooks: [ chlafreniere ],
Area - Performance: [],
Area - Query Editor: [ anthonydresser ],
Area - Query Plan: [],
Area - Reliability: [],
Area - Resource Deployment: [],
Area - Schema Compare: [],
Area - Shell: [],
Area - SQL Agent: [],
Area - SQL Import: [],
Area - SQL Profiler: [],
Area - SQL 2019: [],
Area - SSMS Integration: []
}
}
+43
View File
@@ -0,0 +1,43 @@
name: "Classifier: Apply"
on:
schedule:
- cron: 0,30 * * * *
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
uses: actions/checkout@v2
with:
repository: 'microsoft/vscode-github-triage-actions'
ref: v15
path: ./actions
- name: Install Actions
run: npm install --production --prefix ./actions
- name: Install Additional Dependencies
# Pulls in a bunch of other packages that arent needed for the rest of the actions
run: npm install @azure/storage-blob@12
- name: "Run Classifier: Scraper"
uses: ./actions/classifier/apply/fetch-issues
with:
# slightly overlapping to protect against issues slipping through the cracks if a run is delayed
from: 45
until: 5
blobContainerName: classifier-models
blobStorageKey: ${{secrets.AZURE_BLOB_STORAGE_CONNECTION_STRING}}
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install --upgrade numpy scipy scikit-learn joblib nltk
- name: "Run Classifier: Generator"
run: python ./actions/classifier/apply/generate-labels/main.py
- name: "Run Classifier: Labeler"
uses: ./actions/classifier/apply/apply-labels
with:
config-path: classifier
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
+19
View File
@@ -145,6 +145,25 @@
"order": 2
}
},
{
"type": "node",
"request": "launch",
"name": "Main Process",
"runtimeExecutable": "${workspaceFolder}/scripts/code.sh",
"windows": {
"runtimeExecutable": "${workspaceFolder}/scripts/code.bat",
},
"runtimeArgs": [
"--no-cached-data"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"presentation": {
"group": "1_vscode",
"order": 1
}
},
{
"type": "chrome",
"request": "launch",
@@ -2,54 +2,76 @@ steps:
- task: NodeTool@0
inputs:
versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 # {{SQL CARBON EDIT}} update version
inputs:
versionSpec: "1.x"
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
vstsFeed: 'npm-cache' # {{SQL CARBON EDIT}} update build cache
- script: |
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
displayName: Install Dependencies
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
vstsFeed: 'npm-cache' # {{SQL CARBON EDIT}} update build cache
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- script: |
yarn electron x64
displayName: Download Electron
- script: |
yarn gulp hygiene
displayName: Run Hygiene Checks
- script: | # {{SQL CARBON EDIT}} add step
yarn strict-vscode
displayName: Run Strict Null Check.
# - script: | {{SQL CARBON EDIT}} remove step
# yarn monaco-compile-check
# displayName: Run Monaco Editor Checks
- script: |
yarn valid-layers-check
displayName: Run Valid Layers Checks
- script: |
yarn compile
displayName: Compile Sources
# - script: | {{SQL CARBON EDIT}} remove step
# yarn download-builtin-extensions
# displayName: Download Built-in Extensions
- script: |
./scripts/test.sh --tfs "Unit Tests"
displayName: Run Unit Tests (Electron)
# - script: | {{SQL CARBON EDIT}} disable
# yarn test-browser --browser chromium --browser webkit --browser firefox
# displayName: Run Unit Tests (Browser)
# - script: | {{SQL CARBON EDIT}} disable
# ./scripts/test-integration.sh --tfs "Integration Tests"
# displayName: Run Integration Tests (Electron)
- task: PublishPipelineArtifact@0
inputs:
artifactName: crash-dump-macos
targetPath: .build/crashes
displayName: 'Publish Crash Reports'
condition: succeededOrFailed()
- task: PublishTestResults@2
displayName: Publish Tests Results
inputs:
@@ -2,13 +2,5 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
@@ -152,15 +152,29 @@ steps:
displayName: Run smoke tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- task: PublishPipelineArtifact@0
inputs:
artifactName: crash-dump-macos
targetPath: .build/crashes
displayName: 'Publish Crash Reports'
condition: succeededOrFailed()
- script: |
set -e
APP_ROOT=$(agent.builddirectory)/VSCode-darwin
APP_NAME="`ls $APP_ROOT | head -n 1`"
HELPER_APP_NAME="`echo $APP_NAME | sed -e 's/^Visual Studio //;s/\.app$//'`"
APP_FRAMEWORK_PATH="$APP_ROOT/$APP_NAME/Contents/Frameworks"
security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
security default-keychain -s $(agent.tempdirectory)/buildagent.keychain
security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12
security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain
codesign -s 99FM488X57 --deep --force --options runtime --entitlements build/azure-pipelines/darwin/entitlements.plist $(agent.builddirectory)/VSCode-darwin/*.app
codesign -s 99FM488X57 --deep --force --options runtime --entitlements build/azure-pipelines/darwin/entitlements.plist "$APP_ROOT"/*.app
codesign -s 99FM488X57 --force --options runtime --entitlements build/azure-pipelines/darwin/helper-gpu-entitlements.plist "$APP_FRAMEWORK_PATH/$HELPER_APP_NAME Helper (GPU).app"
codesign -s 99FM488X57 --force --options runtime --entitlements build/azure-pipelines/darwin/helper-plugin-entitlements.plist "$APP_FRAMEWORK_PATH/$HELPER_APP_NAME Helper (Plugin).app"
codesign -s 99FM488X57 --force --options runtime --entitlements build/azure-pipelines/darwin/helper-renderer-entitlements.plist "$APP_FRAMEWORK_PATH/$HELPER_APP_NAME Helper (Renderer).app"
displayName: Set Hardened Entitlements
- script: |
@@ -7,57 +7,80 @@ steps:
sudo chmod +x /etc/init.d/xvfb
sudo update-rc.d xvfb defaults
sudo service xvfb start
- task: NodeTool@0
inputs:
versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3
inputs:
versionSpec: "1.x"
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
vstsFeed: 'npm-cache' # {{SQL CARBON EDIT}} update build cache
- script: |
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
displayName: Install Dependencies
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
vstsFeed: 'npm-cache' # {{SQL CARBON EDIT}} update build cache
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- script: |
yarn electron x64
displayName: Download Electron
- script: |
yarn gulp hygiene
displayName: Run Hygiene Checks
- script: | # {{SQL CARBON EDIT}} add strict null check
yarn strict-vscode
displayName: Run Strict Null Check
# - script: | {{SQL CARBON EDIT}} remove monaco editor checks
# yarn monaco-compile-check
# displayName: Run Monaco Editor Checks
- script: |
yarn valid-layers-check
displayName: Run Valid Layers Checks
- script: |
yarn compile
displayName: Compile Sources
# - script: | {{SQL CARBON EDIT}} remove step
# yarn download-builtin-extensions
# displayName: Download Built-in Extensions
- script: |
DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests"
displayName: Run Unit Tests (Electron)
# - script: | {{SQL CARBON EDIT}} disable
# DISPLAY=:10 yarn test-browser --browser chromium
# displayName: Run Unit Tests (Browser)
# - script: | {{SQL CARBON EDIT}} disable
# DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests"
# displayName: Run Integration Tests (Electron)
- task: PublishPipelineArtifact@0
inputs:
artifactName: crash-dump-linux
targetPath: .build/crashes
displayName: 'Publish Crash Reports'
condition: succeededOrFailed()
- task: PublishTestResults@2
displayName: Publish Tests Results
inputs:
@@ -140,6 +140,13 @@ steps:
displayName: Run integration tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- task: PublishPipelineArtifact@0
inputs:
artifactName: crash-dump-linux
targetPath: .build/crashes
displayName: 'Publish Crash Reports'
condition: succeededOrFailed()
- script: |
set -e
yarn gulp "vscode-linux-x64-build-deb"
@@ -2,59 +2,83 @@ steps:
- task: NodeTool@0
inputs:
versionSpec: "12.13.0"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@3 # {{SQL CARBON EDIT}} update version
inputs:
versionSpec: "1.x"
- task: UsePythonVersion@0
inputs:
versionSpec: '2.x'
addToPath: true
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
vstsFeed: 'npm-cache' # {{SQL CARBON EDIT}} update build cache
- powershell: |
yarn --frozen-lockfile
env:
CHILD_CONCURRENCY: "1"
displayName: Install Dependencies
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock, !samples/**/yarn.lock'
targetfolder: '**/node_modules, !**/node_modules/**/node_modules, !samples/**/node_modules'
vstsFeed: 'npm-cache' # {{SQL CARBON EDIT}} update build cache
condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
- powershell: |
yarn electron
displayName: Download Electron
- script: |
yarn gulp hygiene
displayName: Run Hygiene Checks
- script: | # {{SQL CARBON EDIT}} add step
yarn strict-vscode
displayName: Run Strict Null Check
# - powershell: | {{SQL CARBON EDIT}} remove step
# yarn monaco-compile-check
# displayName: Run Monaco Editor Checks
- script: |
yarn valid-layers-check
displayName: Run Valid Layers Checks
- powershell: |
yarn compile
displayName: Compile Sources
# - powershell: | {{SQL CARBON EDIT}} remove step
# yarn download-builtin-extensions
# displayName: Download Built-in Extensions
- powershell: |
.\scripts\test.bat --tfs "Unit Tests"
displayName: Run Unit Tests (Electron)
# - powershell: | {{SQL CARBON EDIT}} disable
# yarn test-browser --browser chromium --browser firefox
# displayName: Run Unit Tests (Browser)
# - powershell: | {{SQL CARBON EDIT}} disable
# .\scripts\test-integration.bat --tfs "Integration Tests"
# displayName: Run Integration Tests (Electron)
- task: PublishPipelineArtifact@0
displayName: 'Publish Crash Reports'
inputs:
artifactName: crash-dump-windows
targetPath: .build\crashes
condition: succeededOrFailed()
- task: PublishTestResults@2
displayName: Publish Tests Results
inputs:
@@ -149,6 +149,13 @@ steps:
displayName: Run integration tests (Browser)
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- task: PublishPipelineArtifact@0
inputs:
artifactName: crash-dump-windows-$(VSCODE_ARCH)
targetPath: .build\crashes
displayName: 'Publish Crash Reports'
condition: succeededOrFailed()
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
inputs:
ConnectedServiceName: 'ESRP CodeSign'
+1
View File
@@ -430,6 +430,7 @@ function markNodes(languageService, options) {
|| ts.isIndexSignatureDeclaration(member)
|| ts.isCallSignatureDeclaration(member)
|| memberName === '[Symbol.iterator]'
|| memberName === '[Symbol.toStringTag]'
|| memberName === 'toJSON'
|| memberName === 'toString'
|| memberName === 'dispose' // TODO: keeping all `dispose` methods
+1
View File
@@ -548,6 +548,7 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt
|| ts.isIndexSignatureDeclaration(member)
|| ts.isCallSignatureDeclaration(member)
|| memberName === '[Symbol.iterator]'
|| memberName === '[Symbol.toStringTag]'
|| memberName === 'toJSON'
|| memberName === 'toString'
|| memberName === 'dispose'// TODO: keeping all `dispose` methods
+5
View File
@@ -409,6 +409,11 @@
"command": "git.timeline.copyCommitMessage",
"title": "%command.timelineCopyCommitMessage%",
"category": "Git"
},
{
"command": "git.rebaseAbort",
"title": "%command.rebaseAbort%",
"category": "Git"
}
],
"keybindings": [
+1
View File
@@ -63,6 +63,7 @@
"command.showOutput": "Show Git Output",
"command.ignore": "Add to .gitignore",
"command.revealInExplorer": "Reveal in Side Bar",
"command.rebaseAbort": "Abort Rebase",
"command.stashIncludeUntracked": "Stash (Include Untracked)",
"command.stash": "Stash",
"command.stashPop": "Pop Stash...",
+4
View File
@@ -2494,6 +2494,10 @@ export class CommandCenter {
env.clipboard.writeText(item.message);
}
@command('git.rebaseAbort', { repository: true })
async rebaseAbort(repository: Repository): Promise<void> {
await repository.rebaseAbort();
}
private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any {
const result = (...args: any[]) => {
+4
View File
@@ -1333,6 +1333,10 @@ export class Repository {
}
}
async rebaseAbort(): Promise<void> {
await this.run(['rebase', '--abort']);
}
async rebaseContinue(): Promise<void> {
const args = ['rebase', '--continue'];
+5
View File
@@ -303,6 +303,7 @@ export const enum Operation {
CheckIgnore = 'CheckIgnore',
GetObjectDetails = 'GetObjectDetails',
SubmoduleUpdate = 'SubmoduleUpdate',
RebaseAbort = 'RebaseAbort',
RebaseContinue = 'RebaseContinue',
FindTrackingBranches = 'GetTracking',
Apply = 'Apply',
@@ -1331,6 +1332,10 @@ export class Repository implements Disposable {
});
}
async rebaseAbort(): Promise<void> {
await this.run(Operation.RebaseAbort, async () => await this.repository.rebaseAbort());
}
checkIgnore(filePaths: string[]): Promise<Set<string>> {
return this.run(Operation.CheckIgnore, () => {
return new Promise<Set<string>>((resolve, reject) => {
@@ -77,6 +77,12 @@ interface JSONSchemaSettings {
schema?: any;
}
namespace SettingIds {
export const enableFormatter = 'json.format.enable';
export const enableSchemaDownload = 'json.schemaDownload.enable';
export const maxItemsComputed = 'json.maxItemsComputed';
}
let telemetryReporter: TelemetryReporter | undefined;
export function activate(context: ExtensionContext) {
@@ -107,10 +113,8 @@ export function activate(context: ExtensionContext) {
id: 'status.json.resolveError',
name: localize('json.resolveError', "JSON: Schema Resolution Error"),
alignment: StatusBarAlignment.Right,
priority: 0
priority: 0,
});
schemaResolutionErrorStatusBarItem.command = '_json.retryResolveSchema';
schemaResolutionErrorStatusBarItem.tooltip = localize('json.schemaResolutionErrorMessage', 'Unable to resolve schema.') + ' ' + localize('json.clickToRetry', 'Click to retry.');
schemaResolutionErrorStatusBarItem.text = '$(alert)';
toDispose.push(schemaResolutionErrorStatusBarItem);
@@ -200,6 +204,7 @@ export function activate(context: ExtensionContext) {
toDispose.push(disposable);
client.onReady().then(() => {
const schemaDocuments: { [uri: string]: boolean } = {};
let schemaDownloadEnabled = true;
// handle content request
client.onRequest(VSCodeContentRequest.type, (uriPath: string) => {
@@ -208,12 +213,16 @@ export function activate(context: ExtensionContext) {
return Promise.reject(new Error(localize('untitled.schema', 'Unable to load {0}', uri.toString())));
}
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
if (schemaDownloadEnabled) {
return workspace.openTextDocument(uri).then(doc => {
schemaDocuments[uri.toString()] = true;
return doc.getText();
}, error => {
return Promise.reject(error);
});
} else {
return Promise.reject(localize('schemaDownloadDisabled', 'Downloading schemas is disabled through setting \'{0}\'', SettingIds.enableSchemaDownload));
}
} else {
if (telemetryReporter && uri.authority === 'schema.management.azure.com') {
/* __GDPR__
@@ -294,30 +303,26 @@ export function activate(context: ExtensionContext) {
client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociations(context));
});
// manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652.
// manually register / deregister format provider based on the `json.format.enable` setting avoiding issues with late registration. See #71652.
updateFormatterRegistration();
toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() });
toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration('html.format.enable') && updateFormatterRegistration()));
updateSchemaDownloadSetting();
toDispose.push(workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(SettingIds.enableFormatter)) {
updateFormatterRegistration();
} else if (e.affectsConfiguration(SettingIds.enableSchemaDownload)) {
updateSchemaDownloadSetting();
}
}));
client.onNotification(ResultLimitReachedNotification.type, message => {
window.showInformationMessage(`${message}\nUse setting 'json.maxItemsComputed' to configure the limit.`);
window.showInformationMessage(`${message}\n${localize('configureLimit', 'Use setting \'{0}\' to configure the limit.', SettingIds.maxItemsComputed)}`);
});
});
const languageConfiguration: LanguageConfiguration = {
wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/,
indentationRules: {
increaseIndentPattern: /({+(?=([^"]*"[^"]*")*[^"}]*$))|(\[+(?=([^"]*"[^"]*")*[^"\]]*$))/,
decreaseIndentPattern: /^\s*[}\]],?\s*$/
}
};
languages.setLanguageConfiguration('json', languageConfiguration);
languages.setLanguageConfiguration('jsonc', languageConfiguration);
function updateFormatterRegistration() {
const formatEnabled = workspace.getConfiguration().get('json.format.enable');
const formatEnabled = workspace.getConfiguration().get(SettingIds.enableFormatter);
if (!formatEnabled && rangeFormatting) {
rangeFormatting.dispose();
rangeFormatting = undefined;
@@ -340,6 +345,31 @@ export function activate(context: ExtensionContext) {
});
}
}
function updateSchemaDownloadSetting() {
schemaDownloadEnabled = workspace.getConfiguration().get(SettingIds.enableSchemaDownload) !== false;
if (schemaDownloadEnabled) {
schemaResolutionErrorStatusBarItem.tooltip = localize('json.schemaResolutionErrorMessage', 'Unable to resolve schema. Click to retry.');
schemaResolutionErrorStatusBarItem.command = '_json.retryResolveSchema';
handleRetryResolveSchemaCommand();
} else {
schemaResolutionErrorStatusBarItem.tooltip = localize('json.schemaResolutionDisabledMessage', 'Downloading schemas is disabled. Click to configure.');
schemaResolutionErrorStatusBarItem.command = { command: 'workbench.action.openSettings', arguments: [SettingIds.enableSchemaDownload], title: '' };
}
}
});
const languageConfiguration: LanguageConfiguration = {
wordPattern: /("(?:[^\\\"]*(?:\\.)?)*"?)|[^\s{}\[\],:]+/,
indentationRules: {
increaseIndentPattern: /({+(?=([^"]*"[^"]*")*[^"}]*$))|(\[+(?=([^"]*"[^"]*")*[^"\]]*$))/,
decreaseIndentPattern: /^\s*[}\]],?\s*$/
}
};
languages.setLanguageConfiguration('json', languageConfiguration);
languages.setLanguageConfiguration('jsonc', languageConfiguration);
}
@@ -386,7 +416,7 @@ function getSchemaAssociations(_context: ExtensionContext): ISchemaAssociation[]
function getSettings(): Settings {
const httpSettings = workspace.getConfiguration('http');
const resultLimit: number = Math.trunc(Math.max(0, Number(workspace.getConfiguration().get('json.maxItemsComputed')))) || 5000;
const resultLimit: number = Math.trunc(Math.max(0, Number(workspace.getConfiguration().get(SettingIds.maxItemsComputed)))) || 5000;
const settings: Settings = {
http: {
@@ -95,6 +95,12 @@
"type": "number",
"default": 5000,
"description": "%json.maxItemsComputed.desc%"
},
"json.schemaDownload.enable": {
"type": "boolean",
"default": true,
"description": "%json.enableSchemaDownload.desc%",
"tags": ["usesOnlineServices"]
}
}
},
@@ -12,5 +12,6 @@
"json.colorDecorators.enable.deprecationMessage": "The setting `json.colorDecorators.enable` has been deprecated in favor of `editor.colorDecorators`.",
"json.schemaResolutionErrorMessage": "Unable to resolve schema.",
"json.clickToRetry": "Click to retry.",
"json.maxItemsComputed.desc": "The maximum number of outline symbols and folding regions computed (limited for performance reasons)."
"json.maxItemsComputed.desc": "The maximum number of outline symbols and folding regions computed (limited for performance reasons).",
"json.enableSchemaDownload.desc": "When enabled, JSON schemas can be fetched from http and https locations."
}
@@ -90,7 +90,8 @@ function createContext(): TestContext {
storagePath: '',
globalStoragePath: '',
logPath: '',
extensionUri: vscode.Uri.parse('')
extensionUri: vscode.Uri.parse(''),
environmentVariableCollection: { } as any
},
outputChannel: {
name: '',
@@ -22,6 +22,7 @@ export class MockExtensionContext implements vscode.ExtensionContext {
constructor() {
this.subscriptions = [];
}
environmentVariableCollection: vscode.EnvironmentVariableCollection;
}
export class MockOutputChannel implements vscode.OutputChannel {
@@ -33,7 +33,8 @@ export function createContext(): TestContext {
storagePath: '',
globalStoragePath: '',
logPath: '',
extensionUri: vscode.Uri.parse('')
extensionUri: vscode.Uri.parse(''),
environmentVariableCollection: undefined as any
},
};
}
@@ -10,7 +10,7 @@ let fs = require('fs');
let https = require('https');
let url = require('url');
// list of languagesIs not shipped with VSCode. The information is used to associate an icon with a language association
// list of languagesId not shipped with VSCode. The information is used to associate an icon with a language association
let nonBuiltInLanguages = { // { fileNames, extensions }
"r": { extensions: ['r', 'rhistory', 'rprofile', 'rt'] },
"argdown": { extensions: ['ad', 'adown', 'argdown', 'argdn'] },
@@ -32,10 +32,16 @@ let nonBuiltInLanguages = { // { fileNames, extensions }
"haml": { extensions: ['haml'] },
"stylus": { extensions: ['styl'] },
"vala": { extensions: ['vala'] },
"todo": { fileNames: ['todo'] },
"jsonc": { extensions: ['json'] }
"todo": { fileNames: ['todo'] }
};
// list of languagesId that inherit the icon from another language
let inheritIconFromLanguage = {
"jsonc": 'json',
"postcss": 'css',
"django-html": 'html'
}
let FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo
let font, fontMappingsFile, fileAssociationFile, colorsFile;
@@ -358,6 +364,16 @@ exports.update = function () {
}
}
}
for (let lang in inheritIconFromLanguage) {
let superLang = inheritIconFromLanguage[lang];
let def = lang2Def[superLang];
if (def) {
lang2Def[lang] = def;
} else {
console.log('skipping icon def for ' + lang + ': no icon for ' + superLang + ' defined');
}
}
return download(colorsFile).then(function (content) {
+1 -1
View File
@@ -6,7 +6,7 @@
"git": {
"name": "seti-ui",
"repositoryUrl": "https://github.com/jesseweed/seti-ui",
"commitHash": "4b3e0a3d0ca8999430bc3aa9f2c8324e6922b3de"
"commitHash": "8f22764c37feb7f706465f5186132111a2401b6b"
}
},
"version": "0.1.0"
Binary file not shown.
@@ -966,399 +966,413 @@
"fontCharacter": "\\E06C",
"fontColor": "#519aba"
},
"_pug_light": {
"_prolog_light": {
"fontCharacter": "\\E06E",
"fontColor": "#cc6d2e"
},
"_prolog": {
"fontCharacter": "\\E06E",
"fontColor": "#e37933"
},
"_pug_light": {
"fontCharacter": "\\E06F",
"fontColor": "#b8383d"
},
"_pug": {
"fontCharacter": "\\E06E",
"fontCharacter": "\\E06F",
"fontColor": "#cc3e44"
},
"_puppet_light": {
"fontCharacter": "\\E06F",
"fontCharacter": "\\E070",
"fontColor": "#b7b73b"
},
"_puppet": {
"fontCharacter": "\\E06F",
"fontCharacter": "\\E070",
"fontColor": "#cbcb41"
},
"_python_light": {
"fontCharacter": "\\E070",
"fontCharacter": "\\E071",
"fontColor": "#498ba7"
},
"_python": {
"fontCharacter": "\\E070",
"fontCharacter": "\\E071",
"fontColor": "#519aba"
},
"_react_light": {
"fontCharacter": "\\E072",
"fontCharacter": "\\E073",
"fontColor": "#498ba7"
},
"_react": {
"fontCharacter": "\\E072",
"fontCharacter": "\\E073",
"fontColor": "#519aba"
},
"_react_1_light": {
"fontCharacter": "\\E072",
"fontCharacter": "\\E073",
"fontColor": "#cc6d2e"
},
"_react_1": {
"fontCharacter": "\\E072",
"fontCharacter": "\\E073",
"fontColor": "#e37933"
},
"_react_2_light": {
"fontCharacter": "\\E072",
"fontCharacter": "\\E073",
"fontColor": "#b7b73b"
},
"_react_2": {
"fontCharacter": "\\E072",
"fontCharacter": "\\E073",
"fontColor": "#cbcb41"
},
"_reasonml_light": {
"fontCharacter": "\\E073",
"fontCharacter": "\\E074",
"fontColor": "#b8383d"
},
"_reasonml": {
"fontCharacter": "\\E073",
"fontCharacter": "\\E074",
"fontColor": "#cc3e44"
},
"_rmd_light": {
"fontColor": "#498ba7"
},
"_rmd": {
"fontColor": "#519aba"
},
"_rollup_light": {
"fontCharacter": "\\E074",
"fontCharacter": "\\E075",
"fontColor": "#b8383d"
},
"_rollup": {
"fontCharacter": "\\E074",
"fontCharacter": "\\E075",
"fontColor": "#cc3e44"
},
"_ruby_light": {
"fontCharacter": "\\E075",
"fontCharacter": "\\E076",
"fontColor": "#b8383d"
},
"_ruby": {
"fontCharacter": "\\E075",
"fontCharacter": "\\E076",
"fontColor": "#cc3e44"
},
"_rust_light": {
"fontCharacter": "\\E076",
"fontCharacter": "\\E077",
"fontColor": "#627379"
},
"_rust": {
"fontCharacter": "\\E076",
"fontCharacter": "\\E077",
"fontColor": "#6d8086"
},
"_salesforce_light": {
"fontCharacter": "\\E077",
"fontCharacter": "\\E078",
"fontColor": "#498ba7"
},
"_salesforce": {
"fontCharacter": "\\E077",
"fontCharacter": "\\E078",
"fontColor": "#519aba"
},
"_sass_light": {
"fontCharacter": "\\E078",
"fontCharacter": "\\E079",
"fontColor": "#dd4b78"
},
"_sass": {
"fontCharacter": "\\E078",
"fontCharacter": "\\E079",
"fontColor": "#f55385"
},
"_sbt_light": {
"fontCharacter": "\\E079",
"fontCharacter": "\\E07A",
"fontColor": "#498ba7"
},
"_sbt": {
"fontCharacter": "\\E079",
"fontCharacter": "\\E07A",
"fontColor": "#519aba"
},
"_scala_light": {
"fontCharacter": "\\E07A",
"fontCharacter": "\\E07B",
"fontColor": "#b8383d"
},
"_scala": {
"fontCharacter": "\\E07A",
"fontCharacter": "\\E07B",
"fontColor": "#cc3e44"
},
"_shell_light": {
"fontCharacter": "\\E07D",
"fontCharacter": "\\E07E",
"fontColor": "#455155"
},
"_shell": {
"fontCharacter": "\\E07D",
"fontCharacter": "\\E07E",
"fontColor": "#4d5a5e"
},
"_slim_light": {
"fontCharacter": "\\E07E",
"fontCharacter": "\\E07F",
"fontColor": "#cc6d2e"
},
"_slim": {
"fontCharacter": "\\E07E",
"fontCharacter": "\\E07F",
"fontColor": "#e37933"
},
"_smarty_light": {
"fontCharacter": "\\E07F",
"fontCharacter": "\\E080",
"fontColor": "#b7b73b"
},
"_smarty": {
"fontCharacter": "\\E07F",
"fontCharacter": "\\E080",
"fontColor": "#cbcb41"
},
"_spring_light": {
"fontCharacter": "\\E080",
"fontCharacter": "\\E081",
"fontColor": "#7fae42"
},
"_spring": {
"fontCharacter": "\\E080",
"fontCharacter": "\\E081",
"fontColor": "#8dc149"
},
"_stylelint_light": {
"fontCharacter": "\\E081",
"fontCharacter": "\\E082",
"fontColor": "#bfc2c1"
},
"_stylelint": {
"fontCharacter": "\\E081",
"fontCharacter": "\\E082",
"fontColor": "#d4d7d6"
},
"_stylelint_1_light": {
"fontCharacter": "\\E081",
"fontCharacter": "\\E082",
"fontColor": "#455155"
},
"_stylelint_1": {
"fontCharacter": "\\E081",
"fontCharacter": "\\E082",
"fontColor": "#4d5a5e"
},
"_stylus_light": {
"fontCharacter": "\\E082",
"fontCharacter": "\\E083",
"fontColor": "#7fae42"
},
"_stylus": {
"fontCharacter": "\\E082",
"fontCharacter": "\\E083",
"fontColor": "#8dc149"
},
"_sublime_light": {
"fontCharacter": "\\E083",
"fontCharacter": "\\E084",
"fontColor": "#cc6d2e"
},
"_sublime": {
"fontCharacter": "\\E083",
"fontCharacter": "\\E084",
"fontColor": "#e37933"
},
"_svg_light": {
"fontCharacter": "\\E084",
"fontCharacter": "\\E085",
"fontColor": "#9068b0"
},
"_svg": {
"fontCharacter": "\\E084",
"fontCharacter": "\\E085",
"fontColor": "#a074c4"
},
"_svg_1_light": {
"fontCharacter": "\\E084",
"fontCharacter": "\\E085",
"fontColor": "#498ba7"
},
"_svg_1": {
"fontCharacter": "\\E084",
"fontCharacter": "\\E085",
"fontColor": "#519aba"
},
"_swift_light": {
"fontCharacter": "\\E085",
"fontCharacter": "\\E086",
"fontColor": "#cc6d2e"
},
"_swift": {
"fontCharacter": "\\E085",
"fontCharacter": "\\E086",
"fontColor": "#e37933"
},
"_terraform_light": {
"fontCharacter": "\\E086",
"fontCharacter": "\\E087",
"fontColor": "#9068b0"
},
"_terraform": {
"fontCharacter": "\\E086",
"fontCharacter": "\\E087",
"fontColor": "#a074c4"
},
"_tex_light": {
"fontCharacter": "\\E087",
"fontCharacter": "\\E088",
"fontColor": "#498ba7"
},
"_tex": {
"fontCharacter": "\\E087",
"fontCharacter": "\\E088",
"fontColor": "#519aba"
},
"_tex_1_light": {
"fontCharacter": "\\E087",
"fontCharacter": "\\E088",
"fontColor": "#b7b73b"
},
"_tex_1": {
"fontCharacter": "\\E087",
"fontCharacter": "\\E088",
"fontColor": "#cbcb41"
},
"_tex_2_light": {
"fontCharacter": "\\E087",
"fontCharacter": "\\E088",
"fontColor": "#cc6d2e"
},
"_tex_2": {
"fontCharacter": "\\E087",
"fontCharacter": "\\E088",
"fontColor": "#e37933"
},
"_tex_3_light": {
"fontCharacter": "\\E087",
"fontCharacter": "\\E088",
"fontColor": "#bfc2c1"
},
"_tex_3": {
"fontCharacter": "\\E087",
"fontCharacter": "\\E088",
"fontColor": "#d4d7d6"
},
"_todo": {
"fontCharacter": "\\E089"
"fontCharacter": "\\E08A"
},
"_tsconfig_light": {
"fontCharacter": "\\E08A",
"fontCharacter": "\\E08B",
"fontColor": "#498ba7"
},
"_tsconfig": {
"fontCharacter": "\\E08A",
"fontCharacter": "\\E08B",
"fontColor": "#519aba"
},
"_twig_light": {
"fontCharacter": "\\E08B",
"fontCharacter": "\\E08C",
"fontColor": "#7fae42"
},
"_twig": {
"fontCharacter": "\\E08B",
"fontCharacter": "\\E08C",
"fontColor": "#8dc149"
},
"_typescript_light": {
"fontCharacter": "\\E08C",
"fontCharacter": "\\E08D",
"fontColor": "#498ba7"
},
"_typescript": {
"fontCharacter": "\\E08C",
"fontCharacter": "\\E08D",
"fontColor": "#519aba"
},
"_typescript_1_light": {
"fontCharacter": "\\E08C",
"fontCharacter": "\\E08D",
"fontColor": "#b7b73b"
},
"_typescript_1": {
"fontCharacter": "\\E08C",
"fontCharacter": "\\E08D",
"fontColor": "#cbcb41"
},
"_vala_light": {
"fontCharacter": "\\E08D",
"fontCharacter": "\\E08E",
"fontColor": "#627379"
},
"_vala": {
"fontCharacter": "\\E08D",
"fontCharacter": "\\E08E",
"fontColor": "#6d8086"
},
"_video_light": {
"fontCharacter": "\\E08E",
"fontCharacter": "\\E08F",
"fontColor": "#dd4b78"
},
"_video": {
"fontCharacter": "\\E08E",
"fontCharacter": "\\E08F",
"fontColor": "#f55385"
},
"_vue_light": {
"fontCharacter": "\\E08F",
"fontCharacter": "\\E090",
"fontColor": "#7fae42"
},
"_vue": {
"fontCharacter": "\\E08F",
"fontCharacter": "\\E090",
"fontColor": "#8dc149"
},
"_wasm_light": {
"fontCharacter": "\\E090",
"fontCharacter": "\\E091",
"fontColor": "#9068b0"
},
"_wasm": {
"fontCharacter": "\\E090",
"fontCharacter": "\\E091",
"fontColor": "#a074c4"
},
"_wat_light": {
"fontCharacter": "\\E091",
"fontCharacter": "\\E092",
"fontColor": "#9068b0"
},
"_wat": {
"fontCharacter": "\\E091",
"fontCharacter": "\\E092",
"fontColor": "#a074c4"
},
"_webpack_light": {
"fontCharacter": "\\E092",
"fontCharacter": "\\E093",
"fontColor": "#498ba7"
},
"_webpack": {
"fontCharacter": "\\E092",
"fontCharacter": "\\E093",
"fontColor": "#519aba"
},
"_wgt_light": {
"fontCharacter": "\\E093",
"fontCharacter": "\\E094",
"fontColor": "#498ba7"
},
"_wgt": {
"fontCharacter": "\\E093",
"fontCharacter": "\\E094",
"fontColor": "#519aba"
},
"_windows_light": {
"fontCharacter": "\\E094",
"fontCharacter": "\\E095",
"fontColor": "#498ba7"
},
"_windows": {
"fontCharacter": "\\E094",
"fontCharacter": "\\E095",
"fontColor": "#519aba"
},
"_word_light": {
"fontCharacter": "\\E095",
"fontCharacter": "\\E096",
"fontColor": "#498ba7"
},
"_word": {
"fontCharacter": "\\E095",
"fontCharacter": "\\E096",
"fontColor": "#519aba"
},
"_xls_light": {
"fontCharacter": "\\E096",
"fontCharacter": "\\E097",
"fontColor": "#7fae42"
},
"_xls": {
"fontCharacter": "\\E096",
"fontCharacter": "\\E097",
"fontColor": "#8dc149"
},
"_xml_light": {
"fontCharacter": "\\E097",
"fontCharacter": "\\E098",
"fontColor": "#cc6d2e"
},
"_xml": {
"fontCharacter": "\\E097",
"fontCharacter": "\\E098",
"fontColor": "#e37933"
},
"_yarn_light": {
"fontCharacter": "\\E098",
"fontCharacter": "\\E099",
"fontColor": "#498ba7"
},
"_yarn": {
"fontCharacter": "\\E098",
"fontCharacter": "\\E099",
"fontColor": "#519aba"
},
"_yml_light": {
"fontCharacter": "\\E099",
"fontCharacter": "\\E09A",
"fontColor": "#9068b0"
},
"_yml": {
"fontCharacter": "\\E099",
"fontCharacter": "\\E09A",
"fontColor": "#a074c4"
},
"_zip_light": {
"fontCharacter": "\\E09A",
"fontCharacter": "\\E09B",
"fontColor": "#b8383d"
},
"_zip": {
"fontCharacter": "\\E09A",
"fontCharacter": "\\E09B",
"fontColor": "#cc3e44"
},
"_zip_1_light": {
"fontCharacter": "\\E09A",
"fontCharacter": "\\E09B",
"fontColor": "#627379"
},
"_zip_1": {
"fontCharacter": "\\E09A",
"fontCharacter": "\\E09B",
"fontColor": "#6d8086"
},
// {{SQL CARBON EDIT}}
@@ -1392,6 +1406,7 @@
"edn": "_clojure_1",
"cfc": "_coldfusion",
"cfm": "_coldfusion",
"litcoffee": "_coffee",
"config": "_config",
"cfg": "_config",
"conf": "_config",
@@ -1434,6 +1449,7 @@
"hxml": "_haxe_3",
"class": "_java",
"classpath": "_java",
"properties": "_java",
"js.map": "_javascript",
"spec.js": "_javascript_1",
"test.js": "_javascript_1",
@@ -1480,6 +1496,7 @@
"test.tsx": "_react_2",
"re": "_reasonml",
"r": "_R",
"rmd": "_rmd",
"erb": "_html_erb",
"erb.html": "_html_erb",
"html.erb": "_html_erb",
@@ -1507,6 +1524,7 @@
"vue": "_vue",
"wasm": "_wasm",
"wat": "_wat",
"pro": "_prolog",
"jar": "_zip",
"zip": "_zip_1",
"wgt": "_wgt",
@@ -1545,6 +1563,8 @@
"obj": "_svg_1",
"dae": "_svg_1",
"babelrc": "_babel",
"babelrc.js": "_babel",
"babelrc.cjs": "_babel",
"bowerrc": "_bower",
"dockerignore": "_docker_1",
"codeclimate.yml": "_code-climate",
@@ -1588,12 +1608,14 @@
"version.md": "_clock",
"version": "_clock",
"mvnw": "_maven",
"tsconfig.json": "_tsconfig",
"swagger.json": "_json_1",
"swagger.yml": "_json_1",
"swagger.yaml": "_json_1",
"mime.types": "_config",
"jenkinsfile": "_jenkins",
"babel.config.js": "_babel",
"babel.config.json": "_babel",
"babel.config.cjs": "_babel",
"bower.json": "_bower",
"docker-healthcheck": "_docker_2",
"docker-compose.yml": "_docker_3",
@@ -1606,6 +1628,7 @@
"gruntfile.babel.js": "_grunt",
"gruntfile.coffee": "_grunt",
"gulpfile": "_gulp",
"gulpfile.js": "_gulp",
"ionic.config.json": "_ionic",
"ionic.project": "_ionic",
"platformio.ini": "_platformio",
@@ -1649,7 +1672,6 @@
"groovy": "_grails",
"handlebars": "_mustache",
"html": "_html_3",
"properties": "_java",
"java": "_java",
"javascriptreact": "_react",
"javascript": "_javascript",
@@ -1699,7 +1721,9 @@
"todo": "_todo",
// {{SQL CARBON EDIT}}
"notebook": "notebook_dark",
"scmp": "scmp_dark"
"scmp": "scmp_dark",
"postcss": "_css",
"django-html": "_html_3"
},
"light": {
"file": "_default_light",
@@ -1719,6 +1743,7 @@
"edn": "_clojure_1_light",
"cfc": "_coldfusion_light",
"cfm": "_coldfusion_light",
"litcoffee": "_coffee_light",
"config": "_config_light",
"cfg": "_config_light",
"conf": "_config_light",
@@ -1761,6 +1786,7 @@
"hxml": "_haxe_3_light",
"class": "_java_light",
"classpath": "_java_light",
"properties": "_java_light",
"js.map": "_javascript_light",
"spec.js": "_javascript_1_light",
"test.js": "_javascript_1_light",
@@ -1807,6 +1833,7 @@
"test.tsx": "_react_2_light",
"re": "_reasonml_light",
"r": "_R_light",
"rmd": "_rmd_light",
"erb": "_html_erb_light",
"erb.html": "_html_erb_light",
"html.erb": "_html_erb_light",
@@ -1834,6 +1861,7 @@
"vue": "_vue_light",
"wasm": "_wasm_light",
"wat": "_wat_light",
"pro": "_prolog_light",
"jar": "_zip_light",
"zip": "_zip_1_light",
"wgt": "_wgt_light",
@@ -1872,6 +1900,8 @@
"obj": "_svg_1_light",
"dae": "_svg_1_light",
"babelrc": "_babel_light",
"babelrc.js": "_babel_light",
"babelrc.cjs": "_babel_light",
"bowerrc": "_bower_light",
"dockerignore": "_docker_1_light",
"codeclimate.yml": "_code-climate_light",
@@ -1919,7 +1949,6 @@
"groovy": "_grails_light",
"handlebars": "_mustache_light",
"html": "_html_3_light",
"properties": "_java_light",
"java": "_java_light",
"javascriptreact": "_react_light",
"javascript": "_javascript_light",
@@ -1968,7 +1997,9 @@
"vala": "_vala_light",
// {{SQL CARBON EDIT}}
"notebook": "notebook",
"scmp": "scmp"
"scmp": "scmp",
"postcss": "_css_light",
"django-html": "_html_3_light"
},
"fileNames": {
"mix": "_hex_light",
@@ -1981,12 +2012,14 @@
"version.md": "_clock_light",
"version": "_clock_light",
"mvnw": "_maven_light",
"tsconfig.json": "_tsconfig_light",
"swagger.json": "_json_1_light",
"swagger.yml": "_json_1_light",
"swagger.yaml": "_json_1_light",
"mime.types": "_config_light",
"jenkinsfile": "_jenkins_light",
"babel.config.js": "_babel_light",
"babel.config.json": "_babel_light",
"babel.config.cjs": "_babel_light",
"bower.json": "_bower_light",
"docker-healthcheck": "_docker_2_light",
"docker-compose.yml": "_docker_3_light",
@@ -1999,6 +2032,7 @@
"gruntfile.babel.js": "_grunt_light",
"gruntfile.coffee": "_grunt_light",
"gulpfile": "_gulp_light",
"gulpfile.js": "_gulp_light",
"ionic.config.json": "_ionic_light",
"ionic.project": "_ionic_light",
"platformio.ini": "_platformio_light",
@@ -2027,5 +2061,5 @@
"Schema Compare": "scmp"
}
},
"version": "https://github.com/jesseweed/seti-ui/commit/4b3e0a3d0ca8999430bc3aa9f2c8324e6922b3de"
"version": "https://github.com/jesseweed/seti-ui/commit/8f22764c37feb7f706465f5186132111a2401b6b"
}
@@ -317,6 +317,10 @@ export class AzureActiveDirectoryService {
}
private getCallbackEnvironment(callbackUri: vscode.Uri): string {
if (callbackUri.authority.endsWith('.workspaces.github.com')) {
return `${callbackUri.authority},`;
}
switch (callbackUri.authority) {
case 'online.visualstudio.com':
return 'vso,';
+3 -3
View File
@@ -76,15 +76,15 @@
"sudo-prompt": "9.1.1",
"v8-inspect-profiler": "^0.0.20",
"vscode-nsfw": "1.2.8",
"vscode-oniguruma": "1.3.0",
"vscode-oniguruma": "1.3.1",
"vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.8",
"vscode-sqlite3": "4.0.10",
"vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.38",
"xterm": "4.6.0-beta.44",
"xterm-addon-search": "0.7.0-beta.2",
"xterm-addon-unicode11": "0.2.0-beta.5",
"xterm-addon-web-links": "0.4.0-beta.5",
"xterm-addon-web-links": "0.4.0-beta.6",
"xterm-addon-webgl": "0.7.0-beta.10",
"yauzl": "^2.9.2",
"yazl": "^2.4.3",
+3 -3
View File
@@ -34,14 +34,14 @@
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"spdlog": "^0.11.1",
"vscode-nsfw": "1.2.8",
"vscode-oniguruma": "1.3.0",
"vscode-oniguruma": "1.3.1",
"vscode-proxy-agent": "^0.5.2",
"vscode-ripgrep": "^1.5.8",
"vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.38",
"xterm": "4.6.0-beta.44",
"xterm-addon-search": "0.7.0-beta.2",
"xterm-addon-unicode11": "0.2.0-beta.5",
"xterm-addon-web-links": "0.4.0-beta.5",
"xterm-addon-web-links": "0.4.0-beta.6",
"xterm-addon-webgl": "0.7.0-beta.10",
"yauzl": "^2.9.2",
"yazl": "^2.4.3",
+3 -3
View File
@@ -21,12 +21,12 @@
"sanitize-html": "^1.19.1",
"semver-umd": "^5.5.6",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.33",
"vscode-oniguruma": "1.3.0",
"vscode-oniguruma": "1.3.1",
"vscode-textmate": "5.1.1",
"xterm": "4.6.0-beta.38",
"xterm": "4.6.0-beta.44",
"xterm-addon-search": "0.7.0-beta.2",
"xterm-addon-unicode11": "0.2.0-beta.5",
"xterm-addon-web-links": "0.4.0-beta.5",
"xterm-addon-web-links": "0.4.0-beta.6",
"xterm-addon-webgl": "0.7.0-beta.10",
"zone.js": "^0.8.4"
}
+12 -12
View File
@@ -338,10 +338,10 @@ util-deprecate@^1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
vscode-oniguruma@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.0.tgz#6788a9db2f8b0781243b4eb8c7a1dd25f6c0e2c8"
integrity sha512-m4Br19v6XD4MRbVrgsLNSZgQrBzk1BCMCleL8+GrcoGxKEJJd62zOFcTaoQR3hCrSlLqoxWmJ7Cc0VieVV3iTQ==
vscode-oniguruma@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f"
integrity sha512-gz6ZBofA7UXafVA+m2Yt2zHKgXC2qedArprIsHAPKByTkwq9l5y/izAGckqxYml7mSbYxTRTfdRwsFq3cwF4LQ==
vscode-textmate@5.1.1:
version "5.1.1"
@@ -363,20 +363,20 @@ xterm-addon-unicode11@0.2.0-beta.5:
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0-beta.5.tgz#5961850162df20b5e966166423cd6957ac2db298"
integrity sha512-IjnbBcyfS5JgJDXPO0W2nk/VBtGwx6GWE2snMC676z4DmAABUqPXfTzJKfUoWqoT6UcbxB0oIjDzykCfoRJp6Q==
xterm-addon-web-links@0.4.0-beta.5:
version "0.4.0-beta.5"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.4.0-beta.5.tgz#523fd0a1c5668370d73e05019ed16eaf596894c8"
integrity sha512-Qe0idPpSokCNvGrthSBjdrOZrsgXwnLYbzuv0JoEec/A9HVcxKmZ+ktw7fOA2gT/zbcwtrA5FWrir3GlRHglCQ==
xterm-addon-web-links@0.4.0-beta.6:
version "0.4.0-beta.6"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.4.0-beta.6.tgz#d159d4542eb9a02d57977fe7eb5f42f8ef2f27fa"
integrity sha512-dsQVD/EyVq8PtAYGh2PGQTCt009UipIfX6Q2SBDlz+W9x7IkXjhRxRaryMmLsBCca20qeVKwmbQ+ANhLi+nTaQ==
xterm-addon-webgl@0.7.0-beta.10:
version "0.7.0-beta.10"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.10.tgz#39fdb96351e97a1bf15f4c4c8944ba3d05cacee4"
integrity sha512-nQl/ASk+ck11aSrBZXb2a0tu+SNDnm89owBk/sAZeZzi5MHNo6bB8y2VTKNNC6D3i3aFouTz4VorYB25LUgNFg==
xterm@4.6.0-beta.38:
version "4.6.0-beta.38"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.38.tgz#8472b168941500c3071aba482c2b5c6040951ec7"
integrity sha512-Q+nOalMD1MDGOqXdtkGZmOQqbSBU+71vhlX2RBwQoSpJa1QBrKDAhSlN/J+/XvouvVEtCiEFDeacF4EufMEIMg==
xterm@4.6.0-beta.44:
version "4.6.0-beta.44"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.44.tgz#76b2a6b8e147595ab44aa752c0e721d935464615"
integrity sha512-vYtfz4spFcSKLEUpC6anH7TwDams71+k2wAtUzCJ47dNL2IrwYafcFsvGPm46QLTtq4M2Bp9rQo3R3V746yxNg==
zone.js@^0.8.4:
version "0.8.29"
+12 -12
View File
@@ -698,10 +698,10 @@ vscode-nsfw@1.2.8:
lodash.isundefined "^3.0.1"
nan "^2.10.0"
vscode-oniguruma@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.0.tgz#6788a9db2f8b0781243b4eb8c7a1dd25f6c0e2c8"
integrity sha512-m4Br19v6XD4MRbVrgsLNSZgQrBzk1BCMCleL8+GrcoGxKEJJd62zOFcTaoQR3hCrSlLqoxWmJ7Cc0VieVV3iTQ==
vscode-oniguruma@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f"
integrity sha512-gz6ZBofA7UXafVA+m2Yt2zHKgXC2qedArprIsHAPKByTkwq9l5y/izAGckqxYml7mSbYxTRTfdRwsFq3cwF4LQ==
vscode-proxy-agent@^0.5.2:
version "0.5.2"
@@ -750,20 +750,20 @@ xterm-addon-unicode11@0.2.0-beta.5:
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0-beta.5.tgz#5961850162df20b5e966166423cd6957ac2db298"
integrity sha512-IjnbBcyfS5JgJDXPO0W2nk/VBtGwx6GWE2snMC676z4DmAABUqPXfTzJKfUoWqoT6UcbxB0oIjDzykCfoRJp6Q==
xterm-addon-web-links@0.4.0-beta.5:
version "0.4.0-beta.5"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.4.0-beta.5.tgz#523fd0a1c5668370d73e05019ed16eaf596894c8"
integrity sha512-Qe0idPpSokCNvGrthSBjdrOZrsgXwnLYbzuv0JoEec/A9HVcxKmZ+ktw7fOA2gT/zbcwtrA5FWrir3GlRHglCQ==
xterm-addon-web-links@0.4.0-beta.6:
version "0.4.0-beta.6"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.4.0-beta.6.tgz#d159d4542eb9a02d57977fe7eb5f42f8ef2f27fa"
integrity sha512-dsQVD/EyVq8PtAYGh2PGQTCt009UipIfX6Q2SBDlz+W9x7IkXjhRxRaryMmLsBCca20qeVKwmbQ+ANhLi+nTaQ==
xterm-addon-webgl@0.7.0-beta.10:
version "0.7.0-beta.10"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.7.0-beta.10.tgz#39fdb96351e97a1bf15f4c4c8944ba3d05cacee4"
integrity sha512-nQl/ASk+ck11aSrBZXb2a0tu+SNDnm89owBk/sAZeZzi5MHNo6bB8y2VTKNNC6D3i3aFouTz4VorYB25LUgNFg==
xterm@4.6.0-beta.38:
version "4.6.0-beta.38"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.38.tgz#8472b168941500c3071aba482c2b5c6040951ec7"
integrity sha512-Q+nOalMD1MDGOqXdtkGZmOQqbSBU+71vhlX2RBwQoSpJa1QBrKDAhSlN/J+/XvouvVEtCiEFDeacF4EufMEIMg==
xterm@4.6.0-beta.44:
version "4.6.0-beta.44"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.6.0-beta.44.tgz#76b2a6b8e147595ab44aa752c0e721d935464615"
integrity sha512-vYtfz4spFcSKLEUpC6anH7TwDams71+k2wAtUzCJ47dNL2IrwYafcFsvGPm46QLTtq4M2Bp9rQo3R3V746yxNg==
yauzl@^2.9.2:
version "2.10.0"
+1
View File
@@ -9,6 +9,7 @@ if grep -qi Microsoft /proc/version && [ -z "$DONT_PROMPT_WSL_INSTALL" ]; then
read -e -p "Do you want to continue anyways ? [y/N] " YN
[[ $YN == "n" || $YN == "N" || $YN == "" ]] && exit 1
echo "To no longer see this prompt, start @@PRODNAME@@ with the environment variable DONT_PROMPT_WSL_INSTALL defined."
fi
+10 -8
View File
@@ -4,14 +4,16 @@ setlocal
pushd %~dp0\..
set VSCODEUSERDATADIR=%TEMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,2%
set VSCODECRASHDIR=%~dp0\..\.build\crashes
:: Figure out which Electron to use for running tests
if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
:: Run out of sources: no need to compile as code.sh takes care of it
:: Run out of sources: no need to compile as code.bat takes care of it
chcp 65001
set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat
set VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE=1
echo Storing crash reports into '%VSCODECRASHDIR%'.
echo Running integration tests out of sources.
) else (
:: Run from a built: need to compile all test extensions
@@ -29,8 +31,8 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
:: Configuration for more verbose output
set VSCODE_CLI=1
set ELECTRON_ENABLE_LOGGING=1
set ELECTRON_ENABLE_STACK_DUMPING=1
echo Storing crash reports into '%VSCODECRASHDIR%'.
echo Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build.
)
@@ -41,19 +43,19 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
:: Tests in the extension host
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
REM if %errorlevel% neq 0 exit /b %errorlevel%
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
REM if %errorlevel% neq 0 exit /b %errorlevel%
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
REM if %errorlevel% neq 0 exit /b %errorlevel%
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\markdown-language-features\out\test\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\markdown-language-features\out\test\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\markdown-language-features --extensionTestsPath=%~dp0\..\extensions\markdown-language-features\out\test --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
REM if %errorlevel% neq 0 exit /b %errorlevel%
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\out\test\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
REM call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\out\test\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
REM if %errorlevel% neq 0 exit /b %errorlevel%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\azurecore\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
@@ -62,7 +64,7 @@ if %errorlevel% neq 0 exit /b %errorlevel%
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
mkdir %GITWORKSPACE%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test --enable-proposed-api=vscode.git --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test --enable-proposed-api=vscode.git --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
if %errorlevel% neq 0 exit /b %errorlevel%
:: Tests in commonJS (HTML, CSS, JSON language server tests...)
+10 -7
View File
@@ -10,6 +10,7 @@ else
fi
VSCODEUSERDATADIR=`mktemp -d 2>/dev/null`
VSCODECRASHDIR=$ROOT/.build/crashes
cd $ROOT
# Figure out which Electron to use for running tests
@@ -18,6 +19,7 @@ then
# Run out of sources: no need to compile as code.sh takes care of it
INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh"
echo "Storing crash reports into '$VSCODECRASHDIR'."
echo "Running integration tests out of sources."
else
# Run from a built: need to compile all test extensions
@@ -38,6 +40,7 @@ else
export ELECTRON_ENABLE_STACK_DUMPING=1
export ELECTRON_ENABLE_LOGGING=1
echo "Storing crash reports into '$VSCODECRASHDIR'."
echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build."
fi
@@ -45,13 +48,13 @@ fi
./scripts/test.sh --runGlob **/*.integrationTest.js "$@"
# Tests in the extension host
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-notebook-tests/test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-notebook-tests --extensionTestsPath=$ROOT/extensions/vscode-notebook-tests/out/ --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/out/test/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
# "$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --enable-proposed-api=vscode.git --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --crash-reporter-directory=$VSCODECRASHDIR --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/azurecore/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=$VSCODEUSERDATADIR
+21 -1
View File
@@ -39,6 +39,25 @@ if (args['nogpu']) { // {{SQL CARBON EDIT}}
const userDataPath = getUserDataPath(args);
app.setPath('userData', userDataPath);
// Set temp directory based on crash-reporter-directory CLI argument
// The crash reporter will store crashes in temp folder so we need
// to change that location accordingly.
let crashReporterDirectory = args['crash-reporter-directory'];
if (crashReporterDirectory) {
crashReporterDirectory = path.normalize(crashReporterDirectory);
if (!fs.existsSync(crashReporterDirectory)) {
try {
fs.mkdirSync(crashReporterDirectory);
} catch (error) {
console.error(`The path '${crashReporterDirectory}' specified for --crash-reporter-directory does not seem to exist or cannot be created.`);
app.exit(1);
}
}
console.log(`Found --crash-reporter-directory argument. Setting temp directory to be '${crashReporterDirectory}'`);
app.setPath('temp', crashReporterDirectory);
}
// Set logs path before app 'ready' event if running portable
// to ensure that no 'logs' folder is created on disk at a
// location outside of the portable directory
@@ -336,7 +355,8 @@ function parseCLIArgs() {
'user-data-dir',
'locale',
'js-flags',
'max-memory'
'max-memory',
'crash-reporter-directory'
]
});
}
+12 -12
View File
@@ -477,27 +477,27 @@ export class ActionBar extends Disposable implements IActionRunner {
DOM.addClass(this.domNode, 'animated');
}
let previousKey: KeyCode;
let nextKey: KeyCode;
let previousKeys: KeyCode[];
let nextKeys: KeyCode[];
switch (this.options.orientation) {
case ActionsOrientation.HORIZONTAL:
previousKey = KeyCode.LeftArrow;
nextKey = KeyCode.RightArrow;
previousKeys = [KeyCode.LeftArrow, KeyCode.UpArrow];
nextKeys = [KeyCode.RightArrow, KeyCode.DownArrow];
break;
case ActionsOrientation.HORIZONTAL_REVERSE:
previousKey = KeyCode.RightArrow;
nextKey = KeyCode.LeftArrow;
previousKeys = [KeyCode.RightArrow, KeyCode.DownArrow];
nextKeys = [KeyCode.LeftArrow, KeyCode.UpArrow];
this.domNode.className += ' reverse';
break;
case ActionsOrientation.VERTICAL:
previousKey = KeyCode.UpArrow;
nextKey = KeyCode.DownArrow;
previousKeys = [KeyCode.LeftArrow, KeyCode.UpArrow];
nextKeys = [KeyCode.RightArrow, KeyCode.DownArrow];
this.domNode.className += ' vertical';
break;
case ActionsOrientation.VERTICAL_REVERSE:
previousKey = KeyCode.DownArrow;
nextKey = KeyCode.UpArrow;
previousKeys = [KeyCode.RightArrow, KeyCode.DownArrow];
nextKeys = [KeyCode.LeftArrow, KeyCode.UpArrow];
this.domNode.className += ' vertical reverse';
break;
}
@@ -506,9 +506,9 @@ export class ActionBar extends Disposable implements IActionRunner {
const event = new StandardKeyboardEvent(e);
let eventHandled = true;
if (event.equals(previousKey)) {
if (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) {
this.focusPrevious();
} else if (event.equals(nextKey)) {
} else if (nextKeys && (event.equals(nextKeys[0]) || event.equals(nextKeys[1]))) {
this.focusNext();
} else if (event.equals(KeyCode.Escape)) {
this._onDidCancel.fire();
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
.monaco-count-badge {
padding: 3px 5px;
padding: 3px 6px;
border-radius: 11px;
font-size: 11px;
min-width: 18px;
@@ -15,3 +15,8 @@
display: inline-block;
box-sizing: border-box;
}
.monaco-count-badge.long {
padding: 2px 3px;
border-radius: 2px;
}
+16 -1
View File
@@ -18,6 +18,7 @@ export interface IIndexTreeNode<T, TFilterData = void> extends ITreeNode<T, TFil
collapsible: boolean;
collapsed: boolean;
renderNodeCount: number;
visibility: TreeVisibility;
visible: boolean;
filterData: TFilterData | undefined;
}
@@ -95,6 +96,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
collapsible: false,
collapsed: false,
renderNodeCount: 0,
visibility: TreeVisibility.Visible,
visible: true,
filterData: undefined
};
@@ -185,6 +187,17 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
}
this._onDidSplice.fire({ insertedNodes: nodesToInsert, deletedNodes });
let node: IIndexTreeNode<T, TFilterData> | undefined = parentNode;
while (node) {
if (node.visibility === TreeVisibility.Recurse) {
this.refilter();
break;
}
node = node.parent;
}
}
rerender(location: number[]): void {
@@ -194,7 +207,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
const { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location);
if (revealed) {
if (node.visible && revealed) {
this.list.splice(listIndex, 1, [node]);
}
}
@@ -355,11 +368,13 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
collapsible: typeof treeElement.collapsible === 'boolean' ? treeElement.collapsible : (typeof treeElement.collapsed !== 'undefined'),
collapsed: typeof treeElement.collapsed === 'undefined' ? this.collapseByDefault : treeElement.collapsed,
renderNodeCount: 1,
visibility: TreeVisibility.Visible,
visible: true,
filterData: undefined
};
const visibility = this._filterNode(node, parentVisibility);
node.visibility = visibility;
if (revealed) {
treeListElements.push(node);
+2 -2
View File
@@ -43,12 +43,12 @@ const _registry = new Registry();
export const iconRegistry: IIconRegistry = _registry;
export function registerIcon(id: string, def: Codicon) {
export function registerIcon(id: string, def: Codicon, description?: string) {
return new Codicon(id, def);
}
export class Codicon {
constructor(public readonly id: string, public readonly definition: Codicon | IconDefinition) {
constructor(public readonly id: string, public readonly definition: Codicon | IconDefinition, public description?: string) {
_registry.add(this);
}
public get classNames() { return 'codicon codicon-' + this.id; }
+1
View File
@@ -63,6 +63,7 @@ export interface IJSONSchema {
markdownEnumDescriptions?: string[];
markdownDescription?: string;
doNotSuggest?: boolean;
suggestSortText?: string;
allowComments?: boolean;
allowTrailingCommas?: boolean;
}
+29 -34
View File
@@ -580,9 +580,7 @@ export const enum Touch {
AsNew = 2
}
export class LinkedMap<K, V> implements Map<K, V>{
readonly [Symbol.toStringTag] = 'LinkedMap';
export class LinkedMap<K, V> {
private _map: Map<K, Item<K, V>>;
private _head: Item<K, V> | undefined;
@@ -634,7 +632,7 @@ export class LinkedMap<K, V> implements Map<K, V>{
return item.value;
}
set(key: K, value: V, touch: Touch = Touch.None): this {
set(key: K, value: V, touch: Touch = Touch.None): void {
let item = this._map.get(key);
if (item) {
item.value = value;
@@ -660,7 +658,6 @@ export class LinkedMap<K, V> implements Map<K, V>{
this._map.set(key, item);
this._size++;
}
return this;
}
delete(key: K): boolean {
@@ -704,13 +701,34 @@ export class LinkedMap<K, V> implements Map<K, V>{
}
}
keys(): IterableIterator<K> {
values(): V[] {
const result: V[] = [];
let current = this._head;
while (current) {
result.push(current.value);
current = current.next;
}
return result;
}
keys(): K[] {
const result: K[] = [];
let current = this._head;
while (current) {
result.push(current.key);
current = current.next;
}
return result;
}
/* VS Code / Monaco editor runs on es5 which has no Symbol.iterator
keys(): IterableIterator<K> {
const current = this._head;
const iterator: IterableIterator<K> = {
[Symbol.iterator]() {
return iterator;
},
next(): IteratorResult<K> {
next():IteratorResult<K> {
if (current) {
const result = { value: current.key, done: false };
current = current.next;
@@ -724,12 +742,12 @@ export class LinkedMap<K, V> implements Map<K, V>{
}
values(): IterableIterator<V> {
let current = this._head;
const current = this._head;
const iterator: IterableIterator<V> = {
[Symbol.iterator]() {
return iterator;
},
next(): IteratorResult<V> {
next():IteratorResult<V> {
if (current) {
const result = { value: current.value, done: false };
current = current.next;
@@ -741,29 +759,7 @@ export class LinkedMap<K, V> implements Map<K, V>{
};
return iterator;
}
entries(): IterableIterator<[K, V]> {
let current = this._head;
const iterator: IterableIterator<[K, V]> = {
[Symbol.iterator]() {
return iterator;
},
next(): IteratorResult<[K, V]> {
if (current) {
const result: IteratorResult<[K, V]> = { value: [current.key, current.value], done: false };
current = current.next;
return result;
} else {
return { value: undefined, done: true };
}
}
};
return iterator;
}
[Symbol.iterator](): IterableIterator<[K, V]> {
return this.entries();
}
*/
protected trimOld(newSize: number) {
if (newSize >= this.size) {
@@ -965,10 +961,9 @@ export class LRUCache<K, V> extends LinkedMap<K, V> {
return super.get(key, Touch.None);
}
set(key: K, value: V): this {
set(key: K, value: V): void {
super.set(key, value, Touch.AsNew);
this.checkTrim();
return this;
}
private checkTrim() {
@@ -97,10 +97,14 @@
align-self: center;
position: absolute;
right: 4px;
display: flex;
align-items: center;
}
.quick-input-count .monaco-count-badge {
vertical-align: middle;
padding: 2px 4px;
border-radius: 2px;
}
.quick-input-action {
@@ -108,9 +112,8 @@
}
.quick-input-action .monaco-text-button {
font-size: 85%;
font-size: 11px;
padding: 0 6px;
line-height: initial;
display: flex;
height: 100%;
align-items: center;
@@ -4,13 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { ITreeNode, ITreeFilter, TreeVisibility } from 'vs/base/browser/ui/tree/tree';
import { ISpliceable } from 'vs/base/common/sequence';
import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
return {
splice(start: number, deleteCount: number, elements: T[]): void {
// console.log(`splice (${start}, ${deleteCount}, ${elements.length} [${elements.join(', ')}] )`); // debugging
arr.splice(start, deleteCount, ...elements);
}
};
@@ -240,4 +241,35 @@ suite('ObjectTreeModel', function () {
model.expandTo(1000);
assert.deepEqual(toArray(list), [0, 10, 100, 1000, 11, 12, 1, 2]);
});
test('issue #95641', () => {
const list: ITreeNode<string>[] = [];
let fn = (_: string) => true;
const filter = new class implements ITreeFilter<string> {
filter(element: string, parentVisibility: TreeVisibility): TreeVisibility {
if (element === 'file') {
return TreeVisibility.Recurse;
}
return fn(element) ? TreeVisibility.Visible : parentVisibility;
}
};
const model = new ObjectTreeModel<string>('test', toSpliceable(list), { filter });
model.setChildren(null, [{ element: 'file', children: [{ element: 'hello' }] }]);
assert.deepEqual(toArray(list), ['file', 'hello']);
fn = (el: string) => el === 'world';
model.refilter();
assert.deepEqual(toArray(list), []);
model.setChildren('file', [{ element: 'world' }]);
assert.deepEqual(toArray(list), ['file', 'world']);
model.setChildren('file', [{ element: 'hello' }]);
assert.deepEqual(toArray(list), []);
model.setChildren('file', [{ element: 'world' }]);
assert.deepEqual(toArray(list), ['file', 'world']);
});
});
+29 -31
View File
@@ -13,8 +13,8 @@ suite('Map', () => {
let map = new LinkedMap<string, string>();
map.set('ak', 'av');
map.set('bk', 'bv');
assert.deepStrictEqual([...map.keys()], ['ak', 'bk']);
assert.deepStrictEqual([...map.values()], ['av', 'bv']);
assert.deepStrictEqual(map.keys(), ['ak', 'bk']);
assert.deepStrictEqual(map.values(), ['av', 'bv']);
assert.equal(map.first, 'av');
assert.equal(map.last, 'bv');
});
@@ -23,16 +23,16 @@ suite('Map', () => {
let map = new LinkedMap<string, string>();
map.set('ak', 'av');
map.set('ak', 'av', Touch.AsOld);
assert.deepStrictEqual([...map.keys()], ['ak']);
assert.deepStrictEqual([...map.values()], ['av']);
assert.deepStrictEqual(map.keys(), ['ak']);
assert.deepStrictEqual(map.values(), ['av']);
});
test('LinkedMap - Touch New one', () => {
let map = new LinkedMap<string, string>();
map.set('ak', 'av');
map.set('ak', 'av', Touch.AsNew);
assert.deepStrictEqual([...map.keys()], ['ak']);
assert.deepStrictEqual([...map.values()], ['av']);
assert.deepStrictEqual(map.keys(), ['ak']);
assert.deepStrictEqual(map.values(), ['av']);
});
test('LinkedMap - Touch Old two', () => {
@@ -40,8 +40,8 @@ suite('Map', () => {
map.set('ak', 'av');
map.set('bk', 'bv');
map.set('bk', 'bv', Touch.AsOld);
assert.deepStrictEqual([...map.keys()], ['bk', 'ak']);
assert.deepStrictEqual([...map.values()], ['bv', 'av']);
assert.deepStrictEqual(map.keys(), ['bk', 'ak']);
assert.deepStrictEqual(map.values(), ['bv', 'av']);
});
test('LinkedMap - Touch New two', () => {
@@ -49,8 +49,8 @@ suite('Map', () => {
map.set('ak', 'av');
map.set('bk', 'bv');
map.set('ak', 'av', Touch.AsNew);
assert.deepStrictEqual([...map.keys()], ['bk', 'ak']);
assert.deepStrictEqual([...map.values()], ['bv', 'av']);
assert.deepStrictEqual(map.keys(), ['bk', 'ak']);
assert.deepStrictEqual(map.values(), ['bv', 'av']);
});
test('LinkedMap - Touch Old from middle', () => {
@@ -59,8 +59,8 @@ suite('Map', () => {
map.set('bk', 'bv');
map.set('ck', 'cv');
map.set('bk', 'bv', Touch.AsOld);
assert.deepStrictEqual([...map.keys()], ['bk', 'ak', 'ck']);
assert.deepStrictEqual([...map.values()], ['bv', 'av', 'cv']);
assert.deepStrictEqual(map.keys(), ['bk', 'ak', 'ck']);
assert.deepStrictEqual(map.values(), ['bv', 'av', 'cv']);
});
test('LinkedMap - Touch New from middle', () => {
@@ -69,8 +69,8 @@ suite('Map', () => {
map.set('bk', 'bv');
map.set('ck', 'cv');
map.set('bk', 'bv', Touch.AsNew);
assert.deepStrictEqual([...map.keys()], ['ak', 'ck', 'bk']);
assert.deepStrictEqual([...map.values()], ['av', 'cv', 'bv']);
assert.deepStrictEqual(map.keys(), ['ak', 'ck', 'bk']);
assert.deepStrictEqual(map.values(), ['av', 'cv', 'bv']);
});
test('LinkedMap - basics', function () {
@@ -136,15 +136,13 @@ suite('Map', () => {
assert.strictEqual(cache.size, 5);
cache.set(6, 6);
assert.strictEqual(cache.size, 5);
assert.deepStrictEqual([...cache.keys()], [2, 3, 4, 5, 6]);
assert.deepStrictEqual(cache.keys(), [2, 3, 4, 5, 6]);
cache.set(7, 7);
assert.strictEqual(cache.size, 5);
assert.deepStrictEqual([...cache.keys()], [3, 4, 5, 6, 7]);
assert.deepStrictEqual(cache.keys(), [3, 4, 5, 6, 7]);
let values: number[] = [];
[3, 4, 5, 6, 7].forEach(key => values.push(cache.get(key)!));
assert.deepStrictEqual(values, [3, 4, 5, 6, 7]);
assert.deepEqual([...cache.entries()], [[3, 3], [4, 4], [5, 5], [6, 6], [7, 7]]);
});
test('LinkedMap - LRU Cache get', () => {
@@ -152,11 +150,11 @@ suite('Map', () => {
[1, 2, 3, 4, 5].forEach(value => cache.set(value, value));
assert.strictEqual(cache.size, 5);
assert.deepStrictEqual([...cache.keys()], [1, 2, 3, 4, 5]);
assert.deepStrictEqual(cache.keys(), [1, 2, 3, 4, 5]);
cache.get(3);
assert.deepStrictEqual([...cache.keys()], [1, 2, 4, 5, 3]);
assert.deepStrictEqual(cache.keys(), [1, 2, 4, 5, 3]);
cache.peek(4);
assert.deepStrictEqual([...cache.keys()], [1, 2, 4, 5, 3]);
assert.deepStrictEqual(cache.keys(), [1, 2, 4, 5, 3]);
let values: number[] = [];
[1, 2, 3, 4, 5].forEach(key => values.push(cache.get(key)!));
assert.deepStrictEqual(values, [1, 2, 3, 4, 5]);
@@ -171,7 +169,7 @@ suite('Map', () => {
assert.strictEqual(cache.size, 10);
cache.limit = 5;
assert.strictEqual(cache.size, 5);
assert.deepStrictEqual([...cache.keys()], [6, 7, 8, 9, 10]);
assert.deepStrictEqual(cache.keys(), [6, 7, 8, 9, 10]);
cache.limit = 20;
assert.strictEqual(cache.size, 5);
for (let i = 11; i <= 20; i++) {
@@ -183,7 +181,7 @@ suite('Map', () => {
values.push(cache.get(i)!);
assert.strictEqual(cache.get(i), i);
}
assert.deepStrictEqual([...cache.values()], values);
assert.deepStrictEqual(cache.values(), values);
});
test('LinkedMap - LRU Cache limit with ratio', () => {
@@ -195,11 +193,11 @@ suite('Map', () => {
assert.strictEqual(cache.size, 10);
cache.set(11, 11);
assert.strictEqual(cache.size, 5);
assert.deepStrictEqual([...cache.keys()], [7, 8, 9, 10, 11]);
assert.deepStrictEqual(cache.keys(), [7, 8, 9, 10, 11]);
let values: number[] = [];
[...cache.keys()].forEach(key => values.push(cache.get(key)!));
cache.keys().forEach(key => values.push(cache.get(key)!));
assert.deepStrictEqual(values, [7, 8, 9, 10, 11]);
assert.deepStrictEqual([...cache.values()], values);
assert.deepStrictEqual(cache.values(), values);
});
test('LinkedMap - toJSON / fromJSON', () => {
@@ -239,7 +237,7 @@ suite('Map', () => {
map.delete('1');
assert.equal(map.get('1'), undefined);
assert.equal(map.size, 0);
assert.equal([...map.keys()].length, 0);
assert.equal(map.keys().length, 0);
});
test('LinkedMap - delete Head', function () {
@@ -253,8 +251,8 @@ suite('Map', () => {
map.delete('1');
assert.equal(map.get('2'), 2);
assert.equal(map.size, 1);
assert.equal([...map.keys()].length, 1);
assert.equal([...map.keys()][0], 2);
assert.equal(map.keys().length, 1);
assert.equal(map.keys()[0], 2);
});
test('LinkedMap - delete Tail', function () {
@@ -268,8 +266,8 @@ suite('Map', () => {
map.delete('2');
assert.equal(map.get('1'), 1);
assert.equal(map.size, 1);
assert.equal([...map.keys()].length, 1);
assert.equal([...map.keys()][0], 1);
assert.equal(map.keys().length, 1);
assert.equal(map.keys()[0], 1);
});
@@ -31,84 +31,6 @@ function gestureChangeEventMerger(lastEvent: IThrottledGestureEvent | null, curr
return r;
}
/**
* Basically IE10 and IE11
*/
class MsPointerHandler extends MouseHandler implements IDisposable {
private _lastPointerType: string;
private _installGestureHandlerTimeout: number;
constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {
super(context, viewController, viewHelper);
(this.viewHelper.linesContentDomNode.style as any).msTouchAction = 'none';
(this.viewHelper.linesContentDomNode.style as any).msContentZooming = 'none';
// TODO@Alex -> this expects that the view is added in 100 ms, might not be the case
// This handler should be added when the dom node is in the dom tree
this._installGestureHandlerTimeout = window.setTimeout(() => {
this._installGestureHandlerTimeout = -1;
if ((<any>window).MSGesture) {
const touchGesture = new MSGesture();
const penGesture = new MSGesture();
touchGesture.target = this.viewHelper.linesContentDomNode;
penGesture.target = this.viewHelper.linesContentDomNode;
this.viewHelper.linesContentDomNode.addEventListener(<any>'MSPointerDown', (e: MSPointerEvent) => {
// Circumvent IE11 breaking change in e.pointerType & TypeScript's stale definitions
const pointerType = <any>e.pointerType;
if (pointerType === ((<any>e).MSPOINTER_TYPE_MOUSE || 'mouse')) {
this._lastPointerType = 'mouse';
return;
} else if (pointerType === ((<any>e).MSPOINTER_TYPE_TOUCH || 'touch')) {
this._lastPointerType = 'touch';
touchGesture.addPointer(e.pointerId);
} else {
this._lastPointerType = 'pen';
penGesture.addPointer(e.pointerId);
}
});
this._register(dom.addDisposableThrottledListener<IThrottledGestureEvent, MSGestureEvent>(this.viewHelper.linesContentDomNode, 'MSGestureChange', (e) => this._onGestureChange(e), gestureChangeEventMerger));
this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, 'MSGestureTap', (e) => this._onCaptureGestureTap(e), true));
}
}, 100);
this._lastPointerType = 'mouse';
}
public _onMouseDown(e: EditorMouseEvent): void {
if (this._lastPointerType === 'mouse') {
super._onMouseDown(e);
}
}
private _onCaptureGestureTap(rawEvent: MSGestureEvent): void {
const e = new EditorMouseEvent(<MouseEvent><any>rawEvent, this.viewHelper.viewDomNode);
const t = this._createMouseTarget(e, false);
if (t.position) {
this.viewController.moveTo(t.position);
}
// IE does not want to focus when coming in from the browser's address bar
if ((<any>e.browserEvent).fromElement) {
e.preventDefault();
this.viewHelper.focusTextArea();
} else {
// TODO@Alex -> cancel this is focus is lost
setTimeout(() => {
this.viewHelper.focusTextArea();
});
}
}
private _onGestureChange(e: IThrottledGestureEvent): void {
this._context.viewLayout.deltaScrollNow(-e.translationX, -e.translationY);
}
public dispose(): void {
window.clearTimeout(this._installGestureHandlerTimeout);
super.dispose();
}
}
/**
* Basically Edge but should be modified to handle any pointerEnabled, even without support of MSGesture
*/
@@ -302,9 +224,7 @@ export class PointerHandler extends Disposable {
constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {
super();
if (window.navigator.msPointerEnabled) {
this.handler = this._register(new MsPointerHandler(context, viewController, viewHelper));
} else if ((platform.isIOS && BrowserFeatures.pointerEvents)) {
if ((platform.isIOS && BrowserFeatures.pointerEvents)) {
this.handler = this._register(new PointerEventHandler(context, viewController, viewHelper));
} else if ((<any>window).TouchEvent) {
this.handler = this._register(new TouchHandler(context, viewController, viewHelper));
@@ -111,7 +111,7 @@ export class EditorScrollbar extends ViewPart {
const minimap = options.get(EditorOption.minimap);
const side = minimap.side;
if (side === 'right') {
this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimapWidth);
this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimap.minimapWidth);
} else {
this.scrollbarDomNode.setWidth(layoutInfo.contentWidth);
}
@@ -104,30 +104,31 @@ class MinimapOptions {
const options = configuration.options;
const pixelRatio = options.get(EditorOption.pixelRatio);
const layoutInfo = options.get(EditorOption.layoutInfo);
const minimapLayout = layoutInfo.minimap;
const fontInfo = options.get(EditorOption.fontInfo);
const minimapOpts = options.get(EditorOption.minimap);
this.renderMinimap = layoutInfo.renderMinimap | 0;
this.renderMinimap = minimapLayout.renderMinimap;
this.size = minimapOpts.size;
this.minimapHeightIsEditorHeight = layoutInfo.minimapHeightIsEditorHeight;
this.minimapHeightIsEditorHeight = minimapLayout.minimapHeightIsEditorHeight;
this.scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine);
this.showSlider = minimapOpts.showSlider;
this.pixelRatio = pixelRatio;
this.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;
this.lineHeight = options.get(EditorOption.lineHeight);
this.minimapLeft = layoutInfo.minimapLeft;
this.minimapWidth = layoutInfo.minimapWidth;
this.minimapLeft = minimapLayout.minimapLeft;
this.minimapWidth = minimapLayout.minimapWidth;
this.minimapHeight = layoutInfo.height;
this.canvasInnerWidth = layoutInfo.minimapCanvasInnerWidth;
this.canvasInnerHeight = layoutInfo.minimapCanvasInnerHeight;
this.canvasOuterWidth = layoutInfo.minimapCanvasOuterWidth;
this.canvasOuterHeight = layoutInfo.minimapCanvasOuterHeight;
this.canvasInnerWidth = minimapLayout.minimapCanvasInnerWidth;
this.canvasInnerHeight = minimapLayout.minimapCanvasInnerHeight;
this.canvasOuterWidth = minimapLayout.minimapCanvasOuterWidth;
this.canvasOuterHeight = minimapLayout.minimapCanvasOuterHeight;
this.isSampling = layoutInfo.minimapIsSampling;
this.isSampling = minimapLayout.minimapIsSampling;
this.editorHeight = layoutInfo.height;
this.fontScale = layoutInfo.minimapScale;
this.minimapLineHeight = layoutInfo.minimapLineHeight;
this.fontScale = minimapLayout.minimapScale;
this.minimapLineHeight = minimapLayout.minimapLineHeight;
this.minimapCharWidth = Constants.BASE_CHAR_WIDTH * this.fontScale;
this.charRenderer = once(() => MinimapCharRendererFactory.create(this.fontScale, fontInfo.fontFamily));
@@ -262,7 +263,8 @@ class MinimapLayout {
const computedSliderRatio = (maxMinimapSliderTop) / (scrollHeight - viewportHeight);
const sliderTop = (scrollTop * computedSliderRatio);
const sliderNeeded = (maxMinimapSliderTop > 0);
return new MinimapLayout(scrollTop, scrollHeight, sliderNeeded, computedSliderRatio, sliderTop, sliderHeight, 1, lineCount);
const maxLinesFitting = Math.floor(options.canvasInnerHeight / options.minimapLineHeight);
return new MinimapLayout(scrollTop, scrollHeight, sliderNeeded, computedSliderRatio, sliderTop, sliderHeight, 1, Math.min(lineCount, maxLinesFitting));
}
// The visible line count in a viewport can change due to a number of reasons:
@@ -42,7 +42,7 @@ export class ViewOverlayWidgets extends ViewPart {
this._widgets = {};
this._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth;
this._minimapWidth = layoutInfo.minimapWidth;
this._minimapWidth = layoutInfo.minimap.minimapWidth;
this._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight;
this._editorHeight = layoutInfo.height;
this._editorWidth = layoutInfo.width;
@@ -68,7 +68,7 @@ export class ViewOverlayWidgets extends ViewPart {
const layoutInfo = options.get(EditorOption.layoutInfo);
this._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth;
this._minimapWidth = layoutInfo.minimapWidth;
this._minimapWidth = layoutInfo.minimap.minimapWidth;
this._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight;
this._editorHeight = layoutInfo.height;
this._editorWidth = layoutInfo.width;
@@ -58,10 +58,10 @@ export class ScrollDecorationViewPart extends ViewPart {
const options = this._context.configuration.options;
const layoutInfo = options.get(EditorOption.layoutInfo);
if (layoutInfo.renderMinimap === 0 || (layoutInfo.minimapWidth > 0 && layoutInfo.minimapLeft === 0)) {
if (layoutInfo.minimap.renderMinimap === 0 || (layoutInfo.minimap.minimapWidth > 0 && layoutInfo.minimap.minimapLeft === 0)) {
this._width = layoutInfo.width;
} else {
this._width = layoutInfo.width - layoutInfo.minimapWidth - layoutInfo.verticalScrollbarWidth;
this._width = layoutInfo.width - layoutInfo.minimap.minimapWidth - layoutInfo.verticalScrollbarWidth;
}
}
@@ -8,7 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import * as objects from 'vs/base/common/objects';
import * as arrays from 'vs/base/common/arrays';
import { IEditorOptions, editorOptionsRegistry, ValidatedEditorOptions, IEnvironmentalOptions, IComputedEditorOptions, ConfigurationChangedEvent, EDITOR_MODEL_DEFAULTS, EditorOption, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions';
import { IEditorOptions, editorOptionsRegistry, ValidatedEditorOptions, IEnvironmentalOptions, IComputedEditorOptions, ConfigurationChangedEvent, EDITOR_MODEL_DEFAULTS, EditorOption, FindComputedEditorOptionValueById, ComputeOptionsMemory } from 'vs/editor/common/config/editorOptions';
import { EditorZoom } from 'vs/editor/common/config/editorZoom';
import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
import { IConfiguration, IDimension } from 'vs/editor/common/editorCommon';
@@ -284,6 +284,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
public readonly onDidChange: Event<ConfigurationChangedEvent> = this._onDidChange.event;
public readonly isSimpleWidget: boolean;
private _computeOptionsMemory: ComputeOptionsMemory;
public options!: ComputedEditorOptions;
private _isDominatedByLongLines: boolean;
@@ -299,6 +300,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
this.isSimpleWidget = isSimpleWidget;
this._isDominatedByLongLines = false;
this._computeOptionsMemory = new ComputeOptionsMemory();
this._viewLineCount = 1;
this._lineNumbersDigitCount = 1;
@@ -344,6 +346,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements IC
const partialEnv = this._getEnvConfiguration();
const bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.zoomLevel, this.isSimpleWidget);
const env: IEnvironmentalOptions = {
memory: this._computeOptionsMemory,
outerWidth: partialEnv.outerWidth,
outerHeight: partialEnv.outerHeight,
fontInfo: this.readConfiguration(bareFontInfo),
+334 -194
View File
@@ -693,6 +693,7 @@ export interface IComputedEditorOptions {
* @internal
*/
export interface IEnvironmentalOptions {
readonly memory: ComputeOptionsMemory | null;
readonly outerWidth: number;
readonly outerHeight: number;
readonly fontInfo: FontInfo;
@@ -706,6 +707,22 @@ export interface IEnvironmentalOptions {
readonly accessibilitySupport: AccessibilitySupport;
}
/**
* @internal
*/
export class ComputeOptionsMemory {
public stableMinimapLayoutInput: IMinimapLayoutInput | null;
public stableFitMaxMinimapScale: number;
public stableFitRemainingWidth: number;
constructor() {
this.stableMinimapLayoutInput = null;
this.stableFitMaxMinimapScale = 0;
this.stableFitRemainingWidth = 0;
}
}
export interface IEditorOption<K1 extends EditorOption, V> {
readonly id: K1;
readonly name: string;
@@ -1717,32 +1734,19 @@ export interface EditorLayoutInfo {
readonly contentWidth: number;
/**
* The position for the minimap
* Layout information for the minimap
*/
readonly minimapLeft: number;
/**
* The width of the minimap
*/
readonly minimapWidth: number;
readonly minimapHeightIsEditorHeight: boolean;
readonly minimapIsSampling: boolean;
readonly minimapScale: number;
readonly minimapLineHeight: number;
readonly minimapCanvasInnerWidth: number;
readonly minimapCanvasInnerHeight: number;
readonly minimapCanvasOuterWidth: number;
readonly minimapCanvasOuterHeight: number;
/**
* Minimap render type
*/
readonly renderMinimap: RenderMinimap;
readonly minimap: EditorMinimapLayoutInfo;
/**
* The number of columns (of typical characters) fitting on a viewport line.
*/
readonly viewportColumn: number;
readonly isWordWrapMinified: boolean;
readonly isViewportWrapping: boolean;
readonly wrappingColumn: number;
/**
* The width of the vertical scrollbar.
*/
@@ -1758,18 +1762,80 @@ export interface EditorLayoutInfo {
readonly overviewRuler: OverviewRulerPosition;
}
/**
* The internal layout details of the editor.
*/
export interface EditorMinimapLayoutInfo {
readonly renderMinimap: RenderMinimap;
readonly minimapLeft: number;
readonly minimapWidth: number;
readonly minimapHeightIsEditorHeight: boolean;
readonly minimapIsSampling: boolean;
readonly minimapScale: number;
readonly minimapLineHeight: number;
readonly minimapCanvasInnerWidth: number;
readonly minimapCanvasInnerHeight: number;
readonly minimapCanvasOuterWidth: number;
readonly minimapCanvasOuterHeight: number;
}
/**
* @internal
*/
export interface EditorLayoutInfoComputerEnv {
outerWidth: number;
outerHeight: number;
lineHeight: number;
viewLineCount: number;
lineNumbersDigitCount: number;
typicalHalfwidthCharacterWidth: number;
maxDigitWidth: number;
pixelRatio: number;
readonly memory: ComputeOptionsMemory | null;
readonly outerWidth: number;
readonly outerHeight: number;
readonly isDominatedByLongLines: boolean
readonly lineHeight: number;
readonly viewLineCount: number;
readonly lineNumbersDigitCount: number;
readonly typicalHalfwidthCharacterWidth: number;
readonly maxDigitWidth: number;
readonly pixelRatio: number;
}
/**
* @internal
*/
export interface IEditorLayoutComputerInput {
readonly outerWidth: number;
readonly outerHeight: number;
readonly isDominatedByLongLines: boolean
readonly lineHeight: number;
readonly lineNumbersDigitCount: number;
readonly typicalHalfwidthCharacterWidth: number;
readonly maxDigitWidth: number;
readonly pixelRatio: number;
readonly glyphMargin: boolean;
readonly lineDecorationsWidth: string | number;
readonly folding: boolean;
readonly minimap: Readonly<Required<IEditorMinimapOptions>>;
readonly scrollbar: InternalEditorScrollbarOptions;
readonly lineNumbers: InternalEditorRenderLineNumbersOptions;
readonly lineNumbersMinChars: number;
readonly scrollBeyondLastLine: boolean;
readonly wordWrap: 'wordWrapColumn' | 'on' | 'off' | 'bounded';
readonly wordWrapColumn: number;
readonly wordWrapMinified: boolean;
readonly accessibilitySupport: AccessibilitySupport;
}
/**
* @internal
*/
export interface IMinimapLayoutInput {
readonly outerWidth: number;
readonly outerHeight: number;
readonly lineHeight: number;
readonly typicalHalfwidthCharacterWidth: number;
readonly pixelRatio: number;
readonly scrollBeyondLastLine: boolean;
readonly minimap: Readonly<Required<IEditorMinimapOptions>>;
readonly verticalScrollbarWidth: number;
readonly viewLineCount: number;
readonly remainingWidth: number;
readonly isViewportWrapping: boolean;
}
/**
@@ -1780,14 +1846,22 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
constructor() {
super(
EditorOption.layoutInfo,
[EditorOption.glyphMargin, EditorOption.lineDecorationsWidth, EditorOption.folding, EditorOption.minimap, EditorOption.scrollbar, EditorOption.lineNumbers]
[
EditorOption.glyphMargin, EditorOption.lineDecorationsWidth, EditorOption.folding,
EditorOption.minimap, EditorOption.scrollbar, EditorOption.lineNumbers,
EditorOption.lineNumbersMinChars, EditorOption.scrollBeyondLastLine,
EditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapMinified,
EditorOption.accessibilitySupport
]
);
}
public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorLayoutInfo): EditorLayoutInfo {
return EditorLayoutInfoComputer.computeLayout(options, {
memory: env.memory,
outerWidth: env.outerWidth,
outerHeight: env.outerHeight,
isDominatedByLongLines: env.isDominatedByLongLines,
lineHeight: env.fontInfo.lineHeight,
viewLineCount: env.viewLineCount,
lineNumbersDigitCount: env.lineNumbersDigitCount,
@@ -1811,6 +1885,172 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
return { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount };
}
private static _computeMinimapLayout(input: IMinimapLayoutInput, memory: ComputeOptionsMemory): EditorMinimapLayoutInfo {
const outerWidth = input.outerWidth;
const outerHeight = input.outerHeight;
const pixelRatio = input.pixelRatio;
if (!input.minimap.enabled) {
return {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
minimapHeightIsEditorHeight: false,
minimapIsSampling: false,
minimapScale: 1,
minimapLineHeight: 1,
minimapCanvasInnerWidth: 0,
minimapCanvasInnerHeight: Math.floor(pixelRatio * outerHeight),
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: outerHeight,
};
}
// Can use memory if only the `viewLineCount` and `remainingWidth` have changed
const stableMinimapLayoutInput = memory.stableMinimapLayoutInput;
const couldUseMemory = (
stableMinimapLayoutInput
// && input.outerWidth === lastMinimapLayoutInput.outerWidth !!! INTENTIONAL OMITTED
&& input.outerHeight === stableMinimapLayoutInput.outerHeight
&& input.lineHeight === stableMinimapLayoutInput.lineHeight
&& input.typicalHalfwidthCharacterWidth === stableMinimapLayoutInput.typicalHalfwidthCharacterWidth
&& input.pixelRatio === stableMinimapLayoutInput.pixelRatio
&& input.scrollBeyondLastLine === stableMinimapLayoutInput.scrollBeyondLastLine
&& input.minimap.enabled === stableMinimapLayoutInput.minimap.enabled
&& input.minimap.side === stableMinimapLayoutInput.minimap.side
&& input.minimap.size === stableMinimapLayoutInput.minimap.size
&& input.minimap.showSlider === stableMinimapLayoutInput.minimap.showSlider
&& input.minimap.renderCharacters === stableMinimapLayoutInput.minimap.renderCharacters
&& input.minimap.maxColumn === stableMinimapLayoutInput.minimap.maxColumn
&& input.minimap.scale === stableMinimapLayoutInput.minimap.scale
&& input.verticalScrollbarWidth === stableMinimapLayoutInput.verticalScrollbarWidth
// && input.viewLineCount === lastMinimapLayoutInput.viewLineCount !!! INTENTIONAL OMITTED
// && input.remainingWidth === lastMinimapLayoutInput.remainingWidth !!! INTENTIONAL OMITTED
&& input.isViewportWrapping === stableMinimapLayoutInput.isViewportWrapping
);
const lineHeight = input.lineHeight;
const typicalHalfwidthCharacterWidth = input.typicalHalfwidthCharacterWidth;
const scrollBeyondLastLine = input.scrollBeyondLastLine;
const minimapRenderCharacters = input.minimap.renderCharacters;
let minimapScale = (pixelRatio >= 2 ? Math.round(input.minimap.scale * 2) : input.minimap.scale);
const minimapMaxColumn = input.minimap.maxColumn;
const minimapSize = input.minimap.size;
const minimapSide = input.minimap.side;
const verticalScrollbarWidth = input.verticalScrollbarWidth;
const viewLineCount = input.viewLineCount;
const remainingWidth = input.remainingWidth;
const isViewportWrapping = input.isViewportWrapping;
const baseCharHeight = minimapRenderCharacters ? 2 : 3;
let minimapCanvasInnerHeight = Math.floor(pixelRatio * outerHeight);
const minimapCanvasOuterHeight = minimapCanvasInnerHeight / pixelRatio;
let minimapHeightIsEditorHeight = false;
let minimapIsSampling = false;
let minimapLineHeight = baseCharHeight * minimapScale;
let minimapCharWidth = minimapScale / pixelRatio;
let minimapWidthMultiplier: number = 1;
if (minimapSize === 'fill' || minimapSize === 'fit') {
const { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({
viewLineCount: viewLineCount,
scrollBeyondLastLine: scrollBeyondLastLine,
height: outerHeight,
lineHeight: lineHeight,
pixelRatio: pixelRatio
});
// ratio is intentionally not part of the layout to avoid the layout changing all the time
// when doing sampling
const ratio = viewLineCount / minimapLineCount;
if (ratio > 1) {
minimapHeightIsEditorHeight = true;
minimapIsSampling = true;
minimapScale = 1;
minimapLineHeight = 1;
minimapCharWidth = minimapScale / pixelRatio;
} else {
let fitBecomesFill = false;
let maxMinimapScale = minimapScale + 1;
if (minimapSize === 'fit') {
const effectiveMinimapHeight = Math.ceil((viewLineCount + extraLinesBeyondLastLine) * minimapLineHeight);
if (isViewportWrapping && couldUseMemory && remainingWidth <= memory.stableFitRemainingWidth) {
// There is a loop when using `fit` and viewport wrapping:
// - view line count impacts minimap layout
// - minimap layout impacts viewport width
// - viewport width impacts view line count
// To break the loop, once we go to a smaller minimap scale, we try to stick with it.
fitBecomesFill = true;
maxMinimapScale = memory.stableFitMaxMinimapScale;
} else {
fitBecomesFill = (effectiveMinimapHeight > minimapCanvasInnerHeight);
if (isViewportWrapping && fitBecomesFill) {
// remember for next time
memory.stableMinimapLayoutInput = input;
memory.stableFitRemainingWidth = remainingWidth;
} else {
memory.stableMinimapLayoutInput = null;
memory.stableFitRemainingWidth = 0;
}
}
}
if (minimapSize === 'fill' || fitBecomesFill) {
minimapHeightIsEditorHeight = true;
const configuredMinimapScale = minimapScale;
minimapLineHeight = Math.min(lineHeight * pixelRatio, Math.max(1, Math.floor(1 / desiredRatio)));
minimapScale = Math.min(maxMinimapScale, Math.max(1, Math.floor(minimapLineHeight / baseCharHeight)));
if (minimapScale > configuredMinimapScale) {
minimapWidthMultiplier = Math.min(2, minimapScale / configuredMinimapScale);
}
minimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier;
minimapCanvasInnerHeight = Math.ceil((Math.max(typicalViewportLineCount, viewLineCount + extraLinesBeyondLastLine)) * minimapLineHeight);
if (isViewportWrapping && fitBecomesFill) {
memory.stableFitMaxMinimapScale = minimapScale;
}
}
}
}
// Given:
// (leaving 2px for the cursor to have space after the last character)
// viewportColumn = (contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth
// minimapWidth = viewportColumn * minimapCharWidth
// contentWidth = remainingWidth - minimapWidth
// What are good values for contentWidth and minimapWidth ?
// minimapWidth = ((contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth) * minimapCharWidth
// typicalHalfwidthCharacterWidth * minimapWidth = (contentWidth - verticalScrollbarWidth - 2) * minimapCharWidth
// typicalHalfwidthCharacterWidth * minimapWidth = (remainingWidth - minimapWidth - verticalScrollbarWidth - 2) * minimapCharWidth
// (typicalHalfwidthCharacterWidth + minimapCharWidth) * minimapWidth = (remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth
// minimapWidth = ((remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth) / (typicalHalfwidthCharacterWidth + minimapCharWidth)
const minimapMaxWidth = Math.floor(minimapMaxColumn * minimapCharWidth);
const minimapWidth = Math.min(minimapMaxWidth, Math.max(0, Math.floor(((remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth) / (typicalHalfwidthCharacterWidth + minimapCharWidth))) + MINIMAP_GUTTER_WIDTH);
let minimapCanvasInnerWidth = Math.floor(pixelRatio * minimapWidth);
const minimapCanvasOuterWidth = minimapCanvasInnerWidth / pixelRatio;
minimapCanvasInnerWidth = Math.floor(minimapCanvasInnerWidth * minimapWidthMultiplier);
const renderMinimap = (minimapRenderCharacters ? RenderMinimap.Text : RenderMinimap.Blocks);
const minimapLeft = (minimapSide === 'left' ? 0 : (outerWidth - minimapWidth - verticalScrollbarWidth));
return {
renderMinimap,
minimapLeft,
minimapWidth,
minimapHeightIsEditorHeight,
minimapIsSampling,
minimapScale,
minimapLineHeight,
minimapCanvasInnerWidth,
minimapCanvasInnerHeight,
minimapCanvasOuterWidth,
minimapCanvasOuterHeight,
};
}
public static computeLayout(options: IComputedEditorOptions, env: EditorLayoutInfoComputerEnv): EditorLayoutInfo {
const outerWidth = env.outerWidth | 0;
const outerHeight = env.outerHeight | 0;
@@ -1819,24 +2059,25 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
const typicalHalfwidthCharacterWidth = env.typicalHalfwidthCharacterWidth;
const maxDigitWidth = env.maxDigitWidth;
const pixelRatio = env.pixelRatio;
const viewLineCount = env.viewLineCount;
const wordWrap = options.get(EditorOption.wordWrap);
const wordWrapColumn = options.get(EditorOption.wordWrapColumn);
const wordWrapMinified = options.get(EditorOption.wordWrapMinified);
const accessibilitySupport = options.get(EditorOption.accessibilitySupport);
const isDominatedByLongLines = env.isDominatedByLongLines;
const showGlyphMargin = options.get(EditorOption.glyphMargin);
const showLineNumbers = (options.get(EditorOption.lineNumbers).renderType !== RenderLineNumbersType.Off);
const lineNumbersMinChars = options.get(EditorOption.lineNumbersMinChars) | 0;
const lineNumbersMinChars = options.get(EditorOption.lineNumbersMinChars);
const scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine);
const minimap = options.get(EditorOption.minimap);
const minimapEnabled = minimap.enabled;
const minimapSide = minimap.side;
const minimapRenderCharacters = minimap.renderCharacters;
let minimapScale = (pixelRatio >= 2 ? Math.round(minimap.scale * 2) : minimap.scale);
const minimapMaxColumn = minimap.maxColumn | 0;
const minimapSize = minimap.size;
const scrollbar = options.get(EditorOption.scrollbar);
const verticalScrollbarWidth = scrollbar.verticalScrollbarSize | 0;
const verticalScrollbarWidth = scrollbar.verticalScrollbarSize;
const verticalScrollbarHasArrows = scrollbar.verticalHasArrows;
const scrollbarArrowSize = scrollbar.arrowSize | 0;
const horizontalScrollbarHeight = scrollbar.horizontalScrollbarSize | 0;
const scrollbarArrowSize = scrollbar.arrowSize;
const horizontalScrollbarHeight = scrollbar.horizontalScrollbarSize;
const rawLineDecorationsWidth = options.get(EditorOption.lineDecorationsWidth);
const folding = options.get(EditorOption.folding);
@@ -1870,107 +2111,62 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
const remainingWidth = outerWidth - glyphMarginWidth - lineNumbersWidth - lineDecorationsWidth;
const baseCharHeight = minimapRenderCharacters ? 2 : 3;
let renderMinimap: RenderMinimap;
let minimapLeft: number;
let minimapWidth: number;
let minimapCanvasInnerWidth: number;
let minimapCanvasInnerHeight = Math.floor(pixelRatio * outerHeight);
let minimapCanvasOuterWidth: number;
const minimapCanvasOuterHeight = minimapCanvasInnerHeight / pixelRatio;
let minimapHeightIsEditorHeight = false;
let minimapIsSampling = false;
let minimapLineHeight = baseCharHeight * minimapScale;
let contentWidth: number;
if (!minimapEnabled) {
minimapLeft = 0;
minimapWidth = 0;
minimapCanvasInnerWidth = 0;
minimapCanvasOuterWidth = 0;
minimapLineHeight = 1;
renderMinimap = RenderMinimap.None;
contentWidth = remainingWidth;
} else {
let minimapCharWidth = minimapScale / pixelRatio;
let minimapWidthMultiplier: number = 1;
let isWordWrapMinified = false;
let isViewportWrapping = false;
let wrappingColumn = -1;
if (minimapSize === 'fill' || minimapSize === 'fit') {
const viewLineCount = env.viewLineCount;
const { typicalViewportLineCount, extraLinesBeyondLastLine, desiredRatio, minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({
viewLineCount: viewLineCount,
scrollBeyondLastLine: scrollBeyondLastLine,
height: outerHeight,
if (accessibilitySupport !== AccessibilitySupport.Enabled) {
// See https://github.com/Microsoft/vscode/issues/27766
// Never enable wrapping when a screen reader is attached
// because arrow down etc. will not move the cursor in the way
// a screen reader expects.
if (wordWrapMinified && isDominatedByLongLines) {
// Force viewport width wrapping if model is dominated by long lines
isWordWrapMinified = true;
isViewportWrapping = true;
} else if (wordWrap === 'on' || wordWrap === 'bounded') {
isViewportWrapping = true;
} else if (wordWrap === 'wordWrapColumn') {
wrappingColumn = wordWrapColumn;
}
}
const minimapLayout = EditorLayoutInfoComputer._computeMinimapLayout({
outerWidth: outerWidth,
outerHeight: outerHeight,
lineHeight: lineHeight,
pixelRatio: pixelRatio
});
// ratio is intentionally not part of the layout to avoid the layout changing all the time
// when doing sampling
const ratio = viewLineCount / minimapLineCount;
typicalHalfwidthCharacterWidth: typicalHalfwidthCharacterWidth,
pixelRatio: pixelRatio,
scrollBeyondLastLine: scrollBeyondLastLine,
minimap: minimap,
verticalScrollbarWidth: verticalScrollbarWidth,
viewLineCount: viewLineCount,
remainingWidth: remainingWidth,
isViewportWrapping: isViewportWrapping,
}, env.memory || new ComputeOptionsMemory());
if (ratio > 1) {
minimapHeightIsEditorHeight = true;
minimapIsSampling = true;
minimapScale = 1;
minimapLineHeight = 1;
minimapCharWidth = minimapScale / pixelRatio;
} else {
const effectiveMinimapHeight = Math.ceil((viewLineCount + extraLinesBeyondLastLine) * minimapLineHeight);
if (minimapSize === 'fill' || effectiveMinimapHeight > minimapCanvasInnerHeight) {
minimapHeightIsEditorHeight = true;
const configuredFontScale = minimapScale;
minimapLineHeight = Math.min(lineHeight * pixelRatio, Math.max(1, Math.floor(1 / desiredRatio)));
minimapScale = Math.min(configuredFontScale + 1, Math.max(1, Math.floor(minimapLineHeight / baseCharHeight)));
if (minimapScale > configuredFontScale) {
minimapWidthMultiplier = Math.min(2, minimapScale / configuredFontScale);
}
minimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier;
minimapCanvasInnerHeight = Math.ceil((Math.max(typicalViewportLineCount, viewLineCount + extraLinesBeyondLastLine)) * minimapLineHeight);
}
}
}
renderMinimap = minimapRenderCharacters ? RenderMinimap.Text : RenderMinimap.Blocks;
// Given:
// (leaving 2px for the cursor to have space after the last character)
// viewportColumn = (contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth
// minimapWidth = viewportColumn * minimapCharWidth
// contentWidth = remainingWidth - minimapWidth
// What are good values for contentWidth and minimapWidth ?
// minimapWidth = ((contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth) * minimapCharWidth
// typicalHalfwidthCharacterWidth * minimapWidth = (contentWidth - verticalScrollbarWidth - 2) * minimapCharWidth
// typicalHalfwidthCharacterWidth * minimapWidth = (remainingWidth - minimapWidth - verticalScrollbarWidth - 2) * minimapCharWidth
// (typicalHalfwidthCharacterWidth + minimapCharWidth) * minimapWidth = (remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth
// minimapWidth = ((remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth) / (typicalHalfwidthCharacterWidth + minimapCharWidth)
minimapWidth = Math.max(0, Math.floor(((remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth) / (typicalHalfwidthCharacterWidth + minimapCharWidth))) + MINIMAP_GUTTER_WIDTH;
let minimapColumns = minimapWidth / minimapCharWidth;
if (minimapColumns > minimapMaxColumn) {
minimapWidth = Math.floor(minimapMaxColumn * minimapCharWidth);
}
contentWidth = remainingWidth - minimapWidth;
if (minimapSide === 'left') {
minimapLeft = 0;
glyphMarginLeft += minimapWidth;
lineNumbersLeft += minimapWidth;
decorationsLeft += minimapWidth;
contentLeft += minimapWidth;
} else {
minimapLeft = outerWidth - minimapWidth - verticalScrollbarWidth;
}
minimapCanvasInnerWidth = Math.floor(pixelRatio * minimapWidth);
minimapCanvasOuterWidth = minimapCanvasInnerWidth / pixelRatio;
minimapCanvasInnerWidth = Math.floor(minimapCanvasInnerWidth * minimapWidthMultiplier);
if (minimapLayout.renderMinimap !== RenderMinimap.None && minimapLayout.minimapLeft === 0) {
// the minimap is rendered to the left, so move everything to the right
glyphMarginLeft += minimapLayout.minimapWidth;
lineNumbersLeft += minimapLayout.minimapWidth;
decorationsLeft += minimapLayout.minimapWidth;
contentLeft += minimapLayout.minimapWidth;
}
const contentWidth = remainingWidth - minimapLayout.minimapWidth;
// (leaving 2px for the cursor to have space after the last character)
const viewportColumn = Math.max(1, Math.floor((contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth));
const verticalArrowSize = (verticalScrollbarHasArrows ? scrollbarArrowSize : 0);
if (isViewportWrapping) {
// compute the actual wrappingColumn
wrappingColumn = Math.max(1, viewportColumn);
if (wordWrap === 'bounded') {
wrappingColumn = Math.min(wrappingColumn, wordWrapColumn);
}
}
return {
width: outerWidth,
height: outerHeight,
@@ -1987,20 +2183,14 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption<EditorOption.
contentLeft: contentLeft,
contentWidth: contentWidth,
renderMinimap: renderMinimap,
minimapLeft: minimapLeft,
minimapWidth: minimapWidth,
minimapHeightIsEditorHeight: minimapHeightIsEditorHeight,
minimapIsSampling: minimapIsSampling,
minimapScale: minimapScale,
minimapLineHeight: minimapLineHeight,
minimapCanvasInnerWidth: minimapCanvasInnerWidth,
minimapCanvasInnerHeight: minimapCanvasInnerHeight,
minimapCanvasOuterWidth: minimapCanvasOuterWidth,
minimapCanvasOuterHeight: minimapCanvasOuterHeight,
minimap: minimapLayout,
viewportColumn: viewportColumn,
isWordWrapMinified: isWordWrapMinified,
isViewportWrapping: isViewportWrapping,
wrappingColumn: wrappingColumn,
verticalScrollbarWidth: verticalScrollbarWidth,
horizontalScrollbarHeight: horizontalScrollbarHeight,
@@ -3231,67 +3421,17 @@ export interface EditorWrappingInfo {
class EditorWrappingInfoComputer extends ComputedEditorOption<EditorOption.wrappingInfo, EditorWrappingInfo> {
constructor() {
super(EditorOption.wrappingInfo, [EditorOption.wordWrap, EditorOption.wordWrapColumn, EditorOption.wordWrapMinified, EditorOption.layoutInfo, EditorOption.accessibilitySupport]);
super(EditorOption.wrappingInfo, [EditorOption.layoutInfo]);
}
public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorWrappingInfo): EditorWrappingInfo {
const wordWrap = options.get(EditorOption.wordWrap);
const wordWrapColumn = options.get(EditorOption.wordWrapColumn);
const wordWrapMinified = options.get(EditorOption.wordWrapMinified);
const layoutInfo = options.get(EditorOption.layoutInfo);
const accessibilitySupport = options.get(EditorOption.accessibilitySupport);
let bareWrappingInfo: { isWordWrapMinified: boolean; isViewportWrapping: boolean; wrappingColumn: number; } | null = null;
{
if (accessibilitySupport === AccessibilitySupport.Enabled) {
// See https://github.com/Microsoft/vscode/issues/27766
// Never enable wrapping when a screen reader is attached
// because arrow down etc. will not move the cursor in the way
// a screen reader expects.
bareWrappingInfo = {
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1
};
} else if (wordWrapMinified && env.isDominatedByLongLines) {
// Force viewport width wrapping if model is dominated by long lines
bareWrappingInfo = {
isWordWrapMinified: true,
isViewportWrapping: true,
wrappingColumn: Math.max(1, layoutInfo.viewportColumn)
};
} else if (wordWrap === 'on') {
bareWrappingInfo = {
isWordWrapMinified: false,
isViewportWrapping: true,
wrappingColumn: Math.max(1, layoutInfo.viewportColumn)
};
} else if (wordWrap === 'bounded') {
bareWrappingInfo = {
isWordWrapMinified: false,
isViewportWrapping: true,
wrappingColumn: Math.min(Math.max(1, layoutInfo.viewportColumn), wordWrapColumn)
};
} else if (wordWrap === 'wordWrapColumn') {
bareWrappingInfo = {
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: wordWrapColumn
};
} else {
bareWrappingInfo = {
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1
};
}
}
return {
isDominatedByLongLines: env.isDominatedByLongLines,
isWordWrapMinified: bareWrappingInfo.isWordWrapMinified,
isViewportWrapping: bareWrappingInfo.isViewportWrapping,
wrappingColumn: bareWrappingInfo.wrappingColumn,
isWordWrapMinified: layoutInfo.isWordWrapMinified,
isViewportWrapping: layoutInfo.isViewportWrapping,
wrappingColumn: layoutInfo.wrappingColumn,
};
}
}
+2 -2
View File
@@ -701,7 +701,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
}
const editorWidth = layoutInfo.width;
const minimapWidth = layoutInfo.minimapWidth;
const minimapWidth = layoutInfo.minimap.minimapWidth;
let collapsedFindWidget = false;
let reducedFindWidget = false;
let narrowFindWidget = false;
@@ -1218,7 +1218,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
// 1. never resized before, double click should maximizes it
// 2. users resized it already but its width is the same as default
const layoutInfo = this._codeEditor.getLayoutInfo();
width = layoutInfo.width - 28 - layoutInfo.minimapWidth - 15;
width = layoutInfo.width - 28 - layoutInfo.minimap.minimapWidth - 15;
this._resized = true;
} else {
/**
@@ -254,13 +254,13 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider {
}
private _getWidth(info: EditorLayoutInfo): number {
return info.width - info.minimapWidth - info.verticalScrollbarWidth;
return info.width - info.minimap.minimapWidth - info.verticalScrollbarWidth;
}
private _getLeft(info: EditorLayoutInfo): number {
// If minimap is to the left, we move beyond it
if (info.minimapWidth > 0 && info.minimapLeft === 0) {
return info.minimapWidth;
if (info.minimap.minimapWidth > 0 && info.minimap.minimapLeft === 0) {
return info.minimap.minimapWidth;
}
return 0;
}
@@ -526,6 +526,6 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider {
getHorizontalSashWidth() {
const layoutInfo = this.editor.getLayoutInfo();
return layoutInfo.width - layoutInfo.minimapWidth;
return layoutInfo.width - layoutInfo.minimap.minimapWidth;
}
}
@@ -76,9 +76,16 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
};
options._write(EditorOption.lineNumbers, lineNumbersOptions);
options._write(EditorOption.wordWrap, 'off');
options._write(EditorOption.wordWrapColumn, 80);
options._write(EditorOption.wordWrapMinified, true);
options._write(EditorOption.accessibilitySupport, 'auto');
const actual = EditorLayoutInfoComputer.computeLayout(options, {
memory: null,
outerWidth: input.outerWidth,
outerHeight: input.outerHeight,
isDominatedByLongLines: false,
lineHeight: input.lineHeight,
viewLineCount: input.maxLineNumber || Math.pow(10, input.lineNumbersDigitCount) - 1,
lineNumbersDigitCount: input.lineNumbersDigitCount,
@@ -126,6 +133,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 990,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -137,7 +145,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 800,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 98,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -188,6 +201,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 990,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -199,7 +213,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 800,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 97,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 11,
horizontalScrollbarHeight: 12,
@@ -250,6 +269,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 890,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -261,7 +281,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 800,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 88,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -312,6 +337,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 890,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -323,7 +349,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 900,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 900,
},
viewportColumn: 88,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -374,6 +405,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 890,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -385,7 +417,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 900,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 900,
},
viewportColumn: 88,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -436,6 +473,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 60,
contentWidth: 840,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -447,7 +485,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 900,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 900,
},
viewportColumn: 83,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -498,6 +541,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 60,
contentWidth: 840,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -509,7 +553,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 900,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 900,
},
viewportColumn: 83,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -560,6 +609,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 70,
contentWidth: 830,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -571,7 +621,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 900,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 900,
},
viewportColumn: 82,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -622,6 +677,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 40,
contentWidth: 860,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -633,7 +689,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 900,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 900,
},
viewportColumn: 171,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -684,6 +745,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 40,
contentWidth: 860,
minimap: {
renderMinimap: RenderMinimap.None,
minimapLeft: 0,
minimapWidth: 0,
@@ -695,7 +757,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 900,
minimapCanvasOuterWidth: 0,
minimapCanvasOuterHeight: 900,
},
viewportColumn: 169,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -746,6 +813,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 893,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 903,
minimapWidth: 97,
@@ -757,7 +825,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 800,
minimapCanvasOuterWidth: 97,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 89,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -808,6 +881,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 893,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 903,
minimapWidth: 97,
@@ -819,7 +893,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 1600,
minimapCanvasOuterWidth: 97,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 89,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -870,6 +949,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 935,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 945,
minimapWidth: 55,
@@ -881,7 +961,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 3200,
minimapCanvasOuterWidth: 55,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 93,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -932,6 +1017,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 65,
contentWidth: 935,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 0,
minimapWidth: 55,
@@ -943,7 +1029,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 3200,
minimapCanvasOuterWidth: 55,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 93,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -996,6 +1087,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 893,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 903,
minimapWidth: 97,
@@ -1007,7 +1099,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 1560,
minimapCanvasOuterWidth: 97,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 89,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -1060,6 +1157,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 935,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 945,
minimapWidth: 55,
@@ -1071,7 +1169,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 1600,
minimapCanvasOuterWidth: 55,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 93,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -1124,6 +1227,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 893,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 903,
minimapWidth: 97,
@@ -1135,7 +1239,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 1600,
minimapCanvasOuterWidth: 97,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 89,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -1188,6 +1297,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 10,
contentWidth: 935,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 945,
minimapWidth: 55,
@@ -1199,7 +1309,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 1600,
minimapCanvasOuterWidth: 55,
minimapCanvasOuterHeight: 800,
},
viewportColumn: 93,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 0,
horizontalScrollbarHeight: 0,
@@ -1250,6 +1365,7 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
contentLeft: 92,
contentWidth: 1018,
minimap: {
renderMinimap: RenderMinimap.Text,
minimapLeft: 1096,
minimapWidth: 91,
@@ -1261,7 +1377,12 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
minimapCanvasInnerHeight: 844,
minimapCanvasOuterWidth: 91,
minimapCanvasOuterHeight: 422,
},
viewportColumn: 83,
isWordWrapMinified: false,
isViewportWrapping: false,
wrappingColumn: -1,
verticalScrollbarWidth: 14,
horizontalScrollbarHeight: 10,
+22 -18
View File
@@ -3404,29 +3404,16 @@ declare namespace monaco.editor {
*/
readonly contentWidth: number;
/**
* The position for the minimap
* Layout information for the minimap
*/
readonly minimapLeft: number;
/**
* The width of the minimap
*/
readonly minimapWidth: number;
readonly minimapHeightIsEditorHeight: boolean;
readonly minimapIsSampling: boolean;
readonly minimapScale: number;
readonly minimapLineHeight: number;
readonly minimapCanvasInnerWidth: number;
readonly minimapCanvasInnerHeight: number;
readonly minimapCanvasOuterWidth: number;
readonly minimapCanvasOuterHeight: number;
/**
* Minimap render type
*/
readonly renderMinimap: RenderMinimap;
readonly minimap: EditorMinimapLayoutInfo;
/**
* The number of columns (of typical characters) fitting on a viewport line.
*/
readonly viewportColumn: number;
readonly isWordWrapMinified: boolean;
readonly isViewportWrapping: boolean;
readonly wrappingColumn: number;
/**
* The width of the vertical scrollbar.
*/
@@ -3441,6 +3428,23 @@ declare namespace monaco.editor {
readonly overviewRuler: OverviewRulerPosition;
}
/**
* The internal layout details of the editor.
*/
export interface EditorMinimapLayoutInfo {
readonly renderMinimap: RenderMinimap;
readonly minimapLeft: number;
readonly minimapWidth: number;
readonly minimapHeightIsEditorHeight: boolean;
readonly minimapIsSampling: boolean;
readonly minimapScale: number;
readonly minimapLineHeight: number;
readonly minimapCanvasInnerWidth: number;
readonly minimapCanvasInnerHeight: number;
readonly minimapCanvasOuterWidth: number;
readonly minimapCanvasOuterHeight: number;
}
/**
* Configuration options for editor lightbulb
*/
@@ -324,7 +324,8 @@ export class ConfigurationModelParser {
result[key] = this.filterByScope(properties[key], configurationProperties, false, scopes);
} else {
const scope = this.getScope(key, configurationProperties);
if (scopes.indexOf(scope) !== -1) {
// Load unregistered configurations always.
if (scope === undefined || scopes.indexOf(scope) !== -1) {
result[key] = properties[key];
}
}
@@ -332,9 +333,9 @@ export class ConfigurationModelParser {
return result;
}
private getScope(key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): ConfigurationScope {
private getScope(key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): ConfigurationScope | undefined {
const propertySchema = configurationProperties[key];
return propertySchema && typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW;
return propertySchema ? typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW : undefined;
}
}
@@ -5,7 +5,7 @@
import * as osLib from 'os';
import { virtualMachineHint } from 'vs/base/node/id';
import { IMachineInfo, WorkspaceStats, WorkspaceStatItem, PerformanceInfo, SystemInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError, isRemoteDiagnosticError, IWorkspaceInformation } from 'vs/platform/diagnostics/common/diagnostics';
import { readdir, stat, exists, readFile } from 'fs';
import { readdir, exists, readFile } from 'fs';
import { join, basename } from 'vs/base/common/path';
import { parse, ParseError, getNodeType } from 'vs/base/common/json';
import { listProcesses } from 'vs/base/node/ps';
@@ -17,6 +17,7 @@ import { ProcessItem } from 'vs/base/common/processes';
import { IMainProcessInfo } from 'vs/platform/launch/common/launch';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Iterable } from 'vs/base/common/iterator';
export const ID = 'diagnosticsService';
export const IDiagnosticsService = createDecorator<IDiagnosticsService>(ID);
@@ -42,24 +43,31 @@ export interface ProcessInfo {
name: string;
}
export function collectWorkspaceStats(folder: string, filter: string[]): Promise<WorkspaceStats> {
const configFilePatterns = [
{ 'tag': 'grunt.js', 'pattern': /^gruntfile\.js$/i },
{ 'tag': 'gulp.js', 'pattern': /^gulpfile\.js$/i },
{ 'tag': 'tsconfig.json', 'pattern': /^tsconfig\.json$/i },
{ 'tag': 'package.json', 'pattern': /^package\.json$/i },
{ 'tag': 'jsconfig.json', 'pattern': /^jsconfig\.json$/i },
{ 'tag': 'tslint.json', 'pattern': /^tslint\.json$/i },
{ 'tag': 'eslint.json', 'pattern': /^eslint\.json$/i },
{ 'tag': 'tasks.json', 'pattern': /^tasks\.json$/i },
{ 'tag': 'launch.json', 'pattern': /^launch\.json$/i },
{ 'tag': 'settings.json', 'pattern': /^settings\.json$/i },
{ 'tag': 'webpack.config.js', 'pattern': /^webpack\.config\.js$/i },
{ 'tag': 'project.json', 'pattern': /^project\.json$/i },
{ 'tag': 'makefile', 'pattern': /^makefile$/i },
{ 'tag': 'sln', 'pattern': /^.+\.sln$/i },
{ 'tag': 'csproj', 'pattern': /^.+\.csproj$/i },
{ 'tag': 'cmake', 'pattern': /^.+\.cmake$/i }
interface ConfigFilePatterns {
tag: string;
filePattern: RegExp;
relativePathPattern?: RegExp;
}
export async function collectWorkspaceStats(folder: string, filter: string[]): Promise<WorkspaceStats> {
const configFilePatterns: ConfigFilePatterns[] = [
{ tag: 'grunt.js', filePattern: /^gruntfile\.js$/i },
{ tag: 'gulp.js', filePattern: /^gulpfile\.js$/i },
{ tag: 'tsconfig.json', filePattern: /^tsconfig\.json$/i },
{ tag: 'package.json', filePattern: /^package\.json$/i },
{ tag: 'jsconfig.json', filePattern: /^jsconfig\.json$/i },
{ tag: 'tslint.json', filePattern: /^tslint\.json$/i },
{ tag: 'eslint.json', filePattern: /^eslint\.json$/i },
{ tag: 'tasks.json', filePattern: /^tasks\.json$/i },
{ tag: 'launch.json', filePattern: /^launch\.json$/i },
{ tag: 'settings.json', filePattern: /^settings\.json$/i },
{ tag: 'webpack.config.js', filePattern: /^webpack\.config\.js$/i },
{ tag: 'project.json', filePattern: /^project\.json$/i },
{ tag: 'makefile', filePattern: /^makefile$/i },
{ tag: 'sln', filePattern: /^.+\.sln$/i },
{ tag: 'csproj', filePattern: /^.+\.csproj$/i },
{ tag: 'cmake', filePattern: /^.+\.cmake$/i },
{ tag: 'github-actions', filePattern: /^.+\.yml$/i, relativePathPattern: /^\.github(?:\/|\\)workflows$/i }
];
const fileTypes = new Map<string, number>();
@@ -67,23 +75,28 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Promise
const MAX_FILES = 20000;
function walk(dir: string, filter: string[], token: { count: number, maxReached: boolean }, done: (allFiles: string[]) => void): void {
let results: string[] = [];
readdir(dir, async (err, files) => {
function collect(root: string, dir: string, filter: string[], token: { count: number, maxReached: boolean }): Promise<void> {
const relativePath = dir.substring(root.length + 1);
return new Promise(resolve => {
readdir(dir, { withFileTypes: true }, async (err, files) => {
// Ignore folders that can't be read
if (err) {
return done(results);
resolve();
return;
}
if (token.count > MAX_FILES) {
token.count += files.length;
token.maxReached = true;
return done(results);
resolve();
return;
}
let pending = files.length;
if (pending === 0) {
return done(results);
resolve();
return;
}
let filesToRead = files;
@@ -96,94 +109,57 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Promise
token.count += files.length;
for (const file of filesToRead) {
stat(join(dir, file), (err, stats) => {
// Ignore files that can't be read
if (err) {
if (--pending === 0) {
return done(results);
if (file.isDirectory()) {
if (!filter.includes(file.name)) {
await collect(root, join(dir, file.name), filter, token);
}
} else {
if (stats.isDirectory()) {
if (filter.indexOf(file) === -1) {
walk(join(dir, file), filter, token, (res: string[]) => {
results = results.concat(res);
if (--pending === 0) {
return done(results);
}
});
} else {
if (--pending === 0) {
done(results);
}
resolve();
return;
}
} else {
results.push(file);
const index = file.name.lastIndexOf('.');
if (index >= 0) {
const fileType = file.name.substring(index + 1);
if (fileType) {
fileTypes.set(fileType, (fileTypes.get(fileType) ?? 0) + 1);
}
}
for (const configFile of configFilePatterns) {
if (configFile.relativePathPattern?.test(relativePath) !== false && configFile.filePattern.test(file.name)) {
configFiles.set(configFile.tag, (configFiles.get(configFile.tag) ?? 0) + 1);
}
}
if (--pending === 0) {
done(results);
resolve();
return;
}
}
}
});
}
});
}
const addFileType = (fileType: string) => {
if (fileTypes.has(fileType)) {
fileTypes.set(fileType, fileTypes.get(fileType)! + 1);
}
else {
fileTypes.set(fileType, 1);
}
};
const addConfigFiles = (fileName: string) => {
for (const each of configFilePatterns) {
if (each.pattern.test(fileName)) {
if (configFiles.has(each.tag)) {
configFiles.set(each.tag, configFiles.get(each.tag)! + 1);
} else {
configFiles.set(each.tag, 1);
}
}
}
};
const acceptFile = (name: string) => {
if (name.lastIndexOf('.') >= 0) {
const suffix: string | undefined = name.split('.').pop();
if (suffix) {
addFileType(suffix);
}
}
addConfigFiles(name);
};
const token: { count: number, maxReached: boolean } = { count: 0, maxReached: false };
return new Promise((resolve, reject) => {
walk(folder, filter, token, async (files) => {
files.forEach(acceptFile);
await collect(folder, folder, filter, token);
const launchConfigs = await collectLaunchConfigs(folder);
resolve({
return {
configFiles: asSortedItems(configFiles),
fileTypes: asSortedItems(fileTypes),
fileCount: token.count,
maxFilesReached: token.maxReached,
launchConfigFiles: launchConfigs
});
});
});
};
}
function asSortedItems(map: Map<string, number>): WorkspaceStatItem[] {
const a: WorkspaceStatItem[] = [];
map.forEach((value, index) => a.push({ name: index, count: value }));
return a.sort((a, b) => b.count - a.count);
function asSortedItems(items: Map<string, number>): WorkspaceStatItem[] {
return [
...Iterable.map(items.entries(), ([name, count]) => ({ name: name, count: count }))
].sort((a, b) => b.count - a.count);
}
export function getMachineInfo(): IMachineInfo {
@@ -540,11 +516,15 @@ export class DiagnosticsService implements IDiagnosticsService {
}
public async reportWorkspaceStats(workspace: IWorkspaceInformation): Promise<void> {
workspace.folders.forEach(folder => {
const folderUri = URI.revive(folder.uri);
if (folderUri.scheme === 'file') {
for (const { uri } of workspace.folders) {
const folderUri = URI.revive(uri);
if (folderUri.scheme !== 'file') {
continue;
}
const folder = folderUri.fsPath;
collectWorkspaceStats(folder, ['node_modules', '.git']).then(stats => {
try {
const stats = await collectWorkspaceStats(folder, ['node_modules', '.git']);
type WorkspaceStatsClassification = {
'workspace.id': { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
rendererSessionId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
@@ -588,10 +568,9 @@ export class DiagnosticsService implements IDiagnosticsService {
count: e.count
});
});
}).catch(_ => {
} catch {
// Report nothing if collecting metadata fails.
});
}
});
}
}
}
+6
View File
@@ -170,6 +170,12 @@ export interface IEditorOptions {
*/
readonly pinned?: boolean;
/**
* An editor that is sticky moves to the beginning of the editors list within the group and will remain
* there unless explicitly closed. Operations such as "Close All" will not close sticky editors.
*/
readonly sticky?: boolean;
/**
* The index in the document stack where to insert the editor into when opening.
*/
+2
View File
@@ -62,6 +62,7 @@ export interface ParsedArgs {
'install-source'?: string;
'disable-updates'?: boolean;
'disable-crash-reporter'?: boolean;
'crash-reporter-directory'?: string;
'skip-add-to-recently-opened'?: boolean;
'max-memory'?: string;
'file-write'?: boolean;
@@ -186,6 +187,7 @@ export const OPTIONS: OptionDescriptions<Required<ParsedArgs>> = {
'disable-telemetry': { type: 'boolean' },
'disable-updates': { type: 'boolean' },
'disable-crash-reporter': { type: 'boolean' },
'crash-reporter-directory': { type: 'string' },
'disable-user-env-probe': { type: 'boolean' },
'skip-add-to-recently-opened': { type: 'boolean' },
'unity-launch': { type: 'boolean' },
@@ -253,6 +253,7 @@ export class EnvironmentService implements INativeEnvironmentService {
get disableUpdates(): boolean { return !!this._args['disable-updates']; }
get disableCrashReporter(): boolean { return !!this._args['disable-crash-reporter']; }
get crashReporterDirectory(): string | undefined { return this._args['crash-reporter-directory']; }
get driverHandle(): string | undefined { return this._args['driver']; }
get driverVerbose(): boolean { return !!this._args['driver-verbose']; }
+113
View File
@@ -5452,6 +5452,12 @@ declare module 'vscode' {
*/
readonly extensionPath: string;
/**
* Gets the extension's environment variable collection for this workspace, enabling changes
* to be applied to terminal environment variables.
*/
readonly environmentVariableCollection: EnvironmentVariableCollection;
/**
* Get the absolute path of a resource contained in the extension.
*
@@ -8257,6 +8263,113 @@ declare module 'vscode' {
readonly code: number | undefined;
}
/**
* A type of mutation that can be applied to an environment variable.
*/
export enum EnvironmentVariableMutatorType {
/**
* Replace the variable's existing value.
*/
Replace = 1,
/**
* Append to the end of the variable's existing value.
*/
Append = 2,
/**
* Prepend to the start of the variable's existing value.
*/
Prepend = 3
}
/**
* A type of mutation and its value to be applied to an environment variable.
*/
export interface EnvironmentVariableMutator {
/**
* The type of mutation that will occur to the variable.
*/
readonly type: EnvironmentVariableMutatorType;
/**
* The value to use for the variable.
*/
readonly value: string;
}
/**
* A collection of mutations that an extension can apply to a process environment.
*/
export interface EnvironmentVariableCollection {
/**
* Whether the collection should be cached for the workspace and applied to the terminal
* across window reloads. When true the collection will be active immediately such when the
* window reloads. Additionally, this API will return the cached version if it exists. The
* collection will be invalidated when the extension is uninstalled or when the collection
* is cleared. Defaults to true.
*/
persistent: boolean;
/**
* Replace an environment variable with a value.
*
* Note that an extension can only make a single change to any one variable, so this will
* overwrite any previous calls to replace, append or prepend.
*
* @param variable The variable to replace.
* @param value The value to replace the variable with.
*/
replace(variable: string, value: string): void;
/**
* Append a value to an environment variable.
*
* Note that an extension can only make a single change to any one variable, so this will
* overwrite any previous calls to replace, append or prepend.
*
* @param variable The variable to append to.
* @param value The value to append to the variable.
*/
append(variable: string, value: string): void;
/**
* Prepend a value to an environment variable.
*
* Note that an extension can only make a single change to any one variable, so this will
* overwrite any previous calls to replace, append or prepend.
*
* @param variable The variable to prepend.
* @param value The value to prepend to the variable.
*/
prepend(variable: string, value: string): void;
/**
* Gets the mutator that this collection applies to a variable, if any.
*
* @param variable The variable to get the mutator for.
*/
get(variable: string): EnvironmentVariableMutator | undefined;
/**
* Iterate over each mutator in this collection.
*
* @param callback Function to execute for each entry.
* @param thisArg The `this` context used when invoking the handler function.
*/
forEach(callback: (variable: string, mutator: EnvironmentVariableMutator, collection: EnvironmentVariableCollection) => any, thisArg?: any): void;
/**
* Deletes this collection's mutator for a variable.
*
* @param variable The variable to delete the mutator for.
*/
delete(variable: string): void;
/**
* Clears all mutators from this collection.
*/
clear(): void;
}
/**
* A location in the editor at which progress information can be shown. It depends on the
* location how progress is visually represented.
+37 -108
View File
@@ -930,103 +930,6 @@ declare module 'vscode' {
//#endregion
//#region Contribute to terminal environment https://github.com/microsoft/vscode/issues/46696
export enum EnvironmentVariableMutatorType {
/**
* Replace the variable's existing value.
*/
Replace = 1,
/**
* Append to the end of the variable's existing value.
*/
Append = 2,
/**
* Prepend to the start of the variable's existing value.
*/
Prepend = 3
}
export interface EnvironmentVariableMutator {
/**
* The type of mutation that will occur to the variable.
*/
readonly type: EnvironmentVariableMutatorType;
/**
* The value to use for the variable.
*/
readonly value: string;
}
/**
* A collection of mutations that an extension can apply to a process environment.
*/
export interface EnvironmentVariableCollection {
/**
* Whether the collection should be cached for the workspace and applied to the terminal
* across window reloads. When true the collection will be active immediately such when the
* window reloads. Additionally, this API will return the cached version if it exists. The
* collection will be invalidated when the extension is uninstalled or when the collection
* is cleared. Defaults to true.
*/
persistent: boolean;
/**
* Replace an environment variable with a value.
*
* Note that an extension can only make a single change to any one variable, so this will
* overwrite any previous calls to replace, append or prepend.
*/
replace(variable: string, value: string): void;
/**
* Append a value to an environment variable.
*
* Note that an extension can only make a single change to any one variable, so this will
* overwrite any previous calls to replace, append or prepend.
*/
append(variable: string, value: string): void;
/**
* Prepend a value to an environment variable.
*
* Note that an extension can only make a single change to any one variable, so this will
* overwrite any previous calls to replace, append or prepend.
*/
prepend(variable: string, value: string): void;
/**
* Gets the mutator that this collection applies to a variable, if any.
*/
get(variable: string): EnvironmentVariableMutator | undefined;
/**
* Iterate over each mutator in this collection.
*/
forEach(callback: (variable: string, mutator: EnvironmentVariableMutator, collection: EnvironmentVariableCollection) => any, thisArg?: any): void;
/**
* Deletes this collection's mutator for a variable.
*/
delete(variable: string): void;
/**
* Clears all mutators from this collection.
*/
clear(): void;
}
export interface ExtensionContext {
/**
* Gets the extension's environment variable collection for this workspace, enabling changes
* to be applied to terminal environment variables.
*/
readonly environmentVariableCollection: EnvironmentVariableCollection;
}
//#endregion
//#region @jrieken -> exclusive document filters
export interface DocumentFilter {
@@ -1737,12 +1640,6 @@ declare module 'vscode' {
edit(callback: (editBuilder: NotebookEditorCellEdit) => void): Thenable<boolean>;
}
export interface NotebookProvider {
resolveNotebook(editor: NotebookEditor): Promise<void>;
executeCell(document: NotebookDocument, cell: NotebookCell | undefined, token: CancellationToken): Promise<void>;
save(document: NotebookDocument): Promise<boolean>;
}
export interface NotebookOutputSelector {
type: string;
subTypes?: string[];
@@ -1805,11 +1702,6 @@ declare module 'vscode' {
provider: NotebookContentProvider
): Disposable;
export function registerNotebookProvider(
notebookType: string,
provider: NotebookProvider
): Disposable;
export function registerNotebookOutputRenderer(
type: string,
outputSelector: NotebookOutputSelector,
@@ -1839,6 +1731,43 @@ declare module 'vscode' {
//#endregion
//#region @connor4312 extension mode: https://github.com/microsoft/vscode/issues/95926
/**
* The ExtensionMode is provided on the `ExtensionContext` and indicates the
* mode the specific extension is running in.
*/
export enum ExtensionMode {
/**
* The extension is installed normally (for example, from the marketplace
* or VSIX) in VS Code.
*/
Release = 1,
/**
* The extension is running from an `--extensionDevelopmentPath` provided
* when launching VS Code.
*/
Development = 2,
/**
* The extension is running from an `--extensionDevelopmentPath` and
* the extension host is running unit tests.
*/
Test = 3,
}
export interface ExtensionContext {
/**
* The mode the extension is running in. This is specific to the current
* extension. One extension may be in `ExtensionMode.Development` while
* other extensions in the host run in `ExtensionMode.Release`.
*/
readonly extensionMode: ExtensionMode;
}
//#endregion
//#region https://github.com/microsoft/vscode/issues/39441
export interface CompletionItem {
@@ -8,7 +8,7 @@ import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IEx
import { Disposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, CellKind, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -84,7 +84,9 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
registerListeners() {
this._register(this._notebookService.onDidChangeActiveEditor(e => {
this._proxy.$updateActiveEditor(e.viewType, e.uri);
this._proxy.$acceptDocumentAndEditorsDelta({
newActiveEditor: e.uri
});
}));
const updateOrder = () => {
@@ -129,16 +131,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return;
}
async $createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> {
let controller = this._notebookProviders.get(viewType);
if (controller) {
controller.createNotebookDocument(handle, viewType, resource);
}
return;
}
async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
let controller = this._notebookProviders.get(viewType);
@@ -163,11 +155,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
}
async resolveNotebook(viewType: string, uri: URI): Promise<number | undefined> {
let handle = await this._proxy.$resolveNotebook(viewType, uri);
return handle;
}
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
let controller = this._notebookProviders.get(viewType);
controller?.spliceNotebookCellOutputs(resource, cellHandle, splices, renderers);
@@ -195,6 +182,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
export class MainThreadNotebookController implements IMainNotebookController {
private _mapping: Map<string, MainThreadNotebookDocument> = new Map();
static documentHandle: number = 0;
constructor(
private readonly _proxy: ExtHostNotebookShape,
@@ -203,26 +191,44 @@ export class MainThreadNotebookController implements IMainNotebookController {
) {
}
async resolveNotebook(viewType: string, uri: URI): Promise<NotebookTextModel | undefined> {
// TODO: resolve notebook should wait for all notebook document destory operations to finish.
async createNotebook(viewType: string, uri: URI, forBackup: boolean, forceReload: boolean): Promise<NotebookTextModel | undefined> {
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
if (mainthreadNotebook) {
if (forceReload) {
const data = await this._proxy.$resolveNotebookData(viewType, uri);
if (!data) {
return undefined; // {{SQL CARBON EDIT}}
}
mainthreadNotebook.textModel.languages = data.languages;
mainthreadNotebook.textModel.metadata = data.metadata;
mainthreadNotebook.textModel.applyEdit(mainthreadNotebook.textModel.versionId, [
{ editType: CellEditType.Delete, count: mainthreadNotebook.textModel.cells.length, index: 0 },
{ editType: CellEditType.Insert, index: 0, cells: data.cells }
]);
}
return mainthreadNotebook.textModel;
}
let notebookHandle = await this._mainThreadNotebook.resolveNotebook(viewType, uri);
if (notebookHandle !== undefined) {
mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
if (mainthreadNotebook && mainthreadNotebook.textModel.cells.length === 0) {
// it's empty, we should create an empty template one
const mainCell = mainthreadNotebook.textModel.createCellTextModel([''], mainthreadNotebook.textModel.languages.length ? mainthreadNotebook.textModel.languages[0] : '', CellKind.Code, [], undefined);
mainthreadNotebook.textModel.insertTemplateCell(mainCell);
}
return mainthreadNotebook?.textModel;
let document = new MainThreadNotebookDocument(this._proxy, MainThreadNotebookController.documentHandle++, viewType, uri);
await this.createNotebookDocument(document);
if (forBackup) {
return document.textModel;
}
return undefined;
// open notebook document
const data = await this._proxy.$resolveNotebookData(viewType, uri);
if (!data) {
return undefined; // {{SQL CARBON EDIT}}
}
document.textModel.languages = data.languages;
document.textModel.metadata = data.metadata;
document.textModel.initialize(data!.cells);
return document.textModel;
}
async tryApplyEdits(resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
@@ -250,12 +256,32 @@ export class MainThreadNotebookController implements IMainNotebookController {
this._proxy.$onDidReceiveMessage(uri, message);
}
// Methods for ExtHost
async createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> {
let document = new MainThreadNotebookDocument(this._proxy, handle, viewType, URI.revive(resource));
this._mapping.set(URI.revive(resource).toString(), document);
async createNotebookDocument(document: MainThreadNotebookDocument): Promise<void> {
this._mapping.set(document.uri.toString(), document);
await this._proxy.$acceptDocumentAndEditorsDelta({
addedDocuments: [{
viewType: document.viewType,
handle: document.handle,
uri: document.uri
}]
});
}
async removeNotebookDocument(notebook: INotebookTextModel): Promise<void> {
let document = this._mapping.get(URI.from(notebook.uri).toString());
if (!document) {
return;
}
await this._proxy.$acceptDocumentAndEditorsDelta({ removedDocuments: [notebook.uri] });
document.dispose();
this._mapping.delete(URI.from(notebook.uri).toString());
}
// Methods for ExtHost
updateLanguages(resource: UriComponents, languages: string[]) {
let document = this._mapping.get(URI.from(resource).toString());
document?.textModel.updateLanguages(languages);
@@ -280,21 +306,12 @@ export class MainThreadNotebookController implements IMainNotebookController {
return this._proxy.$executeNotebook(this._viewType, uri, handle, token);
}
async destoryNotebookDocument(notebook: INotebookTextModel): Promise<void> {
let document = this._mapping.get(URI.from(notebook.uri).toString());
if (!document) {
return;
}
let removeFromExtHost = await this._proxy.$destoryNotebookDocument(this._viewType, notebook.uri);
if (removeFromExtHost) {
document.dispose();
this._mapping.delete(URI.from(notebook.uri).toString());
}
}
async save(uri: URI, token: CancellationToken): Promise<boolean> {
return this._proxy.$saveNotebook(this._viewType, uri, token);
}
async saveAs(uri: URI, target: URI, token: CancellationToken): Promise<boolean> {
return this._proxy.$saveNotebookAs(this._viewType, uri, target, token);
}
}
@@ -368,6 +368,9 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
}
private addViews(extensions: readonly IExtensionPointUser<ViewExtensionPointType>[]): void {
const viewIds: Set<string> = new Set<string>();
const allViewDescriptors: { views: IViewDescriptor[], viewContainer: ViewContainer }[] = [];
for (const extension of extensions) {
const { value, collector } = extension;
@@ -386,10 +389,9 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Explorer'.", entry.key));
}
const container = viewContainer || this.getDefaultViewContainer();
const viewIds: string[] = [];
const viewDescriptors = coalesce(entry.value.map((item, index) => {
// validate
if (viewIds.indexOf(item.id) !== -1) {
if (viewIds.has(item.id)) {
collector.error(localize('duplicateView1', "Cannot register multiple views with same id `{0}`", item.id));
return null;
}
@@ -421,12 +423,16 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
remoteAuthority: item.remoteName || (<any>item).remoteAuthority // TODO@roblou - delete after remote extensions are updated
};
viewIds.push(viewDescriptor.id);
viewIds.add(viewDescriptor.id);
return viewDescriptor;
}));
this.viewsRegistry.registerViews(viewDescriptors, container);
allViewDescriptors.push({ viewContainer: container, views: viewDescriptors });
});
}
this.viewsRegistry.registerViews2(allViewDescriptors);
}
private getDefaultViewContainer(): ViewContainer {
@@ -931,10 +931,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostNotebook.onDidCloseNotebookDocument;
},
registerNotebookProvider: (viewType: string, provider: vscode.NotebookProvider) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookProvider(extension, viewType, provider);
},
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider);
@@ -1015,6 +1011,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
EvaluatableExpression: extHostTypes.EvaluatableExpression,
EventEmitter: Emitter,
ExtensionKind: extHostTypes.ExtensionKind,
ExtensionMode: extHostTypes.ExtensionMode,
CustomExecution: extHostTypes.CustomExecution,
CustomExecution2: extHostTypes.CustomExecution,
FileChangeType: extHostTypes.FileChangeType,
@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { INotebookMimeTypeSelector, IOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookMimeTypeSelector, IOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
@@ -695,7 +695,6 @@ export interface MainThreadNotebookShape extends IDisposable {
$unregisterNotebookProvider(viewType: string): Promise<void>;
$registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, handle: number, preloads: UriComponents[]): Promise<void>;
$unregisterNotebookRenderer(handle: number): Promise<void>;
$createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void>;
$tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean>;
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
$updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void>;
@@ -1542,16 +1541,31 @@ export interface INotebookEditorPropertiesChangeData {
selections: INotebookSelectionChangeEvent | null;
}
export interface INotebookModelAddedData {
uri: UriComponents;
handle: number;
// versionId: number;
viewType: string;
}
export interface INotebookDocumentsAndEditorsDelta {
removedDocuments?: UriComponents[];
addedDocuments?: INotebookModelAddedData[];
// removedEditors?: string[];
// addedEditors?: ITextEditorAddData[];
newActiveEditor?: UriComponents | null;
}
export interface ExtHostNotebookShape {
$resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined>;
$resolveNotebookData(viewType: string, uri: UriComponents): Promise<NotebookDataDto | undefined>;
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void>;
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
$updateActiveEditor(viewType: string, uri: UriComponents): Promise<void>;
$destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean>;
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
$onDidReceiveMessage(uri: UriComponents, message: any): void;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void;
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void;
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): Promise<void>;
}
export interface ExtHostStorageShape {
@@ -25,7 +25,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
import { Schemas } from 'vs/base/common/network';
import { VSBuffer } from 'vs/base/common/buffer';
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
import { RemoteAuthorityResolverError } from 'vs/workbench/api/common/extHostTypes';
import { RemoteAuthorityResolverError, ExtensionMode } from 'vs/workbench/api/common/extHostTypes';
import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
@@ -358,8 +358,12 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
const globalState = new ExtensionMemento(extensionDescription.identifier.value, true, this._storage);
const workspaceState = new ExtensionMemento(extensionDescription.identifier.value, false, this._storage);
const extensionMode = extensionDescription.isUnderDevelopment
? (this._initData.environment.extensionTestsLocationURI ? ExtensionMode.Test : ExtensionMode.Development)
: ExtensionMode.Release;
this._logService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.identifier.value}`);
return Promise.all([
globalState.whenReady,
workspaceState.whenReady,
@@ -376,10 +380,11 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription); },
asAbsolutePath(relativePath: string) { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
get environmentVariableCollection() {
get extensionMode() {
checkProposedApiEnabled(extensionDescription);
return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription);
}
return extensionMode;
},
get environmentVariableCollection() { return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription); }
});
});
}
+157 -147
View File
@@ -10,10 +10,10 @@ import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecyc
import { ISplice } from 'vs/base/common/sequence';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { CellKind, CellOutputKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice, MainThreadDocumentsShape, INotebookEditorPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol';
import { CellKind, CellOutputKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice, MainThreadDocumentsShape, INotebookEditorPropertiesChangeData, INotebookDocumentsAndEditorsDelta } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, IErrorOutput, INotebookDisplayOrder, INotebookEditData, IOrderedMimeType, IStreamOutput, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, NotebookCellsChangedEvent, NotebookCellsSplice2, sortMimeTypes, ICellDeleteEdit, notebookDocumentMetadataDefaults, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, IErrorOutput, INotebookDisplayOrder, INotebookEditData, IOrderedMimeType, IStreamOutput, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, NotebookCellsChangedEvent, NotebookCellsSplice2, sortMimeTypes, ICellDeleteEdit, notebookDocumentMetadataDefaults, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Disposable as VSCodeDisposable } from './extHostTypes';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
@@ -345,8 +345,6 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
transformMimeTypes(output: vscode.CellDisplayOutput): ITransformedDisplayOutputDto {
let mimeTypes = Object.keys(output.data);
// TODO@rebornix, the document display order might be assigned a bit later. We need to postpone sending the outputs to the core side.
let coreDisplayOrder = this.renderingHandler.outputDisplayOrder;
const sorted = sortMimeTypes(mimeTypes, coreDisplayOrder?.userOrder || [], this._displayOrder, coreDisplayOrder?.defaultOrder || []);
@@ -415,7 +413,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
}
}
export class NotebookEditorCellEdit {
export class NotebookEditorCellEditBuilder implements vscode.NotebookEditorCellEdit {
private _finalized: boolean = false;
private readonly _documentVersionId: number;
private _collectedEdits: ICellEditOperation[] = [];
@@ -526,13 +524,13 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
}));
}
edit(callback: (editBuilder: NotebookEditorCellEdit) => void): Thenable<boolean> {
const edit = new NotebookEditorCellEdit(this);
edit(callback: (editBuilder: NotebookEditorCellEditBuilder) => void): Thenable<boolean> {
const edit = new NotebookEditorCellEditBuilder(this);
callback(edit);
return this._applyEdit(edit);
}
private _applyEdit(editBuilder: NotebookEditorCellEdit): Promise<boolean> {
private _applyEdit(editBuilder: NotebookEditorCellEditBuilder): Promise<boolean> {
const editData = editBuilder.finalize();
// return when there is nothing to do
@@ -625,7 +623,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private static _handlePool: number = 0;
private readonly _proxy: MainThreadNotebookShape;
private readonly _notebookProviders = new Map<string, { readonly provider: vscode.NotebookProvider, readonly extension: IExtensionDescription; }>();
private readonly _notebookContentProviders = new Map<string, { readonly provider: vscode.NotebookContentProvider, readonly extension: IExtensionDescription; }>();
private readonly _documents = new Map<string, ExtHostNotebookDocument>();
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; }>();
@@ -706,31 +703,13 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return matches;
}
registerNotebookProvider(
extension: IExtensionDescription,
viewType: string,
provider: vscode.NotebookProvider,
): vscode.Disposable {
if (this._notebookProviders.has(viewType)) {
throw new Error(`Notebook provider for '${viewType}' already registered`);
}
this._notebookProviders.set(viewType, { extension, provider });
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType);
return new VSCodeDisposable(() => {
this._notebookProviders.delete(viewType);
this._proxy.$unregisterNotebookProvider(viewType);
});
}
registerNotebookContentProvider(
extension: IExtensionDescription,
viewType: string,
provider: vscode.NotebookContentProvider,
): vscode.Disposable {
if (this._notebookProviders.has(viewType)) {
if (this._notebookContentProviders.has(viewType)) {
throw new Error(`Notebook provider for '${viewType}' already registered`);
}
@@ -742,97 +721,99 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
});
}
async _resolveNotebookFromContentProvider(viewType: string, uri: UriComponents): Promise<number | undefined> {
async $resolveNotebookData(viewType: string, uri: UriComponents): Promise<NotebookDataDto | undefined> {
let provider = this._notebookContentProviders.get(viewType);
let document = this._documents.get(URI.revive(uri).toString());
if (provider) {
const revivedUri = URI.revive(uri);
if (!this._documents.has(revivedUri.toString())) {
let document = new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, viewType, revivedUri, this);
await this._proxy.$createNotebookDocument(
document.handle,
viewType,
uri
);
this._documents.set(revivedUri.toString(), document);
}
const onDidReceiveMessage = new Emitter<any>();
let editor = new ExtHostNotebookEditor(
viewType,
`${ExtHostNotebookController._handlePool++}`,
revivedUri,
this._proxy,
onDidReceiveMessage,
this._documents.get(revivedUri.toString())!,
this._documentsAndEditors
);
this._editors.set(revivedUri.toString(), { editor, onDidReceiveMessage });
const data = await provider.provider.openNotebook(revivedUri);
editor.document.languages = data.languages;
editor.document.metadata = {
if (provider && document) {
const rawCells = await provider.provider.openNotebook(URI.revive(uri));
const renderers = new Set<number>();
const dto = {
metadata: {
...notebookDocumentMetadataDefaults,
...data.metadata
};
...rawCells.metadata
},
languages: rawCells.languages,
cells: rawCells.cells.map(cell => {
let transformedOutputs = cell.outputs.map(output => {
if (output.outputKind === CellOutputKind.Rich) {
// TODO display string[]
const ret = this._transformMimeTypes(document!, (rawCells.metadata.displayOrder as string[]) || [], output);
await editor.edit(editBuilder => {
for (let i = 0; i < data.cells.length; i++) {
const cell = data.cells[i];
editBuilder.insert(0, cell.source, cell.language, cell.cellKind, cell.outputs, cell.metadata);
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
}
return ret;
} else {
return output as IStreamOutput | IErrorOutput;
}
});
this._onDidOpenNotebookDocument.fire(editor.document);
return editor.document.handle;
return {
language: cell.language,
cellKind: cell.cellKind,
metadata: cell.metadata,
source: cell.source,
outputs: transformedOutputs
};
})
};
return dto;
}
return undefined; // {{SQL CARBON EDIT}}
}
private _transformMimeTypes(document: ExtHostNotebookDocument, displayOrder: string[], output: vscode.CellDisplayOutput): ITransformedDisplayOutputDto {
let mimeTypes = Object.keys(output.data);
let coreDisplayOrder = this.outputDisplayOrder;
const sorted = sortMimeTypes(mimeTypes, coreDisplayOrder?.userOrder || [], displayOrder, coreDisplayOrder?.defaultOrder || []);
let orderMimeTypes: IOrderedMimeType[] = [];
sorted.forEach(mimeType => {
let handlers = this.findBestMatchedRenderer(mimeType);
if (handlers.length) {
let renderedOutput = handlers[0].render(document, output, mimeType);
orderMimeTypes.push({
mimeType: mimeType,
isResolved: true,
rendererId: handlers[0].handle,
output: renderedOutput
});
for (let i = 1; i < handlers.length; i++) {
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false,
rendererId: handlers[i].handle
});
}
if (mimeTypeSupportedByCore(mimeType)) {
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false,
rendererId: -1
});
}
} else {
return Promise.resolve(undefined);
}
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false
});
}
});
async $resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined> {
let notebookFromNotebookContentProvider = await this._resolveNotebookFromContentProvider(viewType, uri);
if (notebookFromNotebookContentProvider !== undefined) {
return notebookFromNotebookContentProvider;
}
let provider = this._notebookProviders.get(viewType);
if (provider) {
if (!this._documents.has(URI.revive(uri).toString())) {
let document = new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, viewType, URI.revive(uri), this);
await this._proxy.$createNotebookDocument(
document.handle,
viewType,
uri
);
this._documents.set(URI.revive(uri).toString(), document);
}
const onDidReceiveMessage = new Emitter<any>();
let editor = new ExtHostNotebookEditor(
viewType,
`${ExtHostNotebookController._handlePool++}`,
URI.revive(uri),
this._proxy,
onDidReceiveMessage,
this._documents.get(URI.revive(uri).toString())!,
this._documentsAndEditors
);
this._editors.set(URI.revive(uri).toString(), { editor, onDidReceiveMessage });
await provider.provider.resolveNotebook(editor);
// await editor.document.$updateCells();
return editor.document.handle;
}
return Promise.resolve(undefined);
return {
outputKind: output.outputKind,
data: output.data,
orderedMimeTypes: orderMimeTypes,
pickedMimeTypeIndex: 0
};
}
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void> {
@@ -847,15 +828,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return this._notebookContentProviders.get(viewType)!.provider.executeCell(document, cell, token);
}
let provider = this._notebookProviders.get(viewType);
if (!provider) {
return;
}
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
return provider.provider.executeCell(document!, cell, token);
}
async $saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean> {
@@ -874,46 +846,28 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return true;
}
let provider = this._notebookProviders.get(viewType);
if (provider && document) {
return await provider.provider.save(document);
}
return false;
}
async $updateActiveEditor(viewType: string, uri: UriComponents): Promise<void> {
this._activeNotebookDocument = this._documents.get(URI.revive(uri).toString());
this._activeNotebookEditor = this._editors.get(URI.revive(uri).toString())?.editor;
}
async $destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean> {
let provider = this._notebookProviders.get(viewType);
if (!provider) {
return false;
}
async $saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean> {
let document = this._documents.get(URI.revive(uri).toString());
if (document) {
document.dispose();
this._documents.delete(URI.revive(uri).toString());
this._onDidCloseNotebookDocument.fire(document);
if (!document) {
return false;
}
let editor = this._editors.get(URI.revive(uri).toString());
if (editor) {
editor.editor.dispose();
editor.onDidReceiveMessage.dispose();
this._editors.delete(URI.revive(uri).toString());
if (this._notebookContentProviders.has(viewType)) {
try {
await this._notebookContentProviders.get(viewType)!.provider.saveNotebookAs(URI.revive(target), document, token);
} catch (e) {
return false;
}
return true;
}
return false;
}
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void {
this._outputDisplayOrder = displayOrder;
}
@@ -957,4 +911,60 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
}
}
async $acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta) {
if (delta.removedDocuments) {
delta.removedDocuments.forEach((uri) => {
let document = this._documents.get(URI.revive(uri).toString());
if (document) {
document.dispose();
this._documents.delete(URI.revive(uri).toString());
this._onDidCloseNotebookDocument.fire(document);
}
let editor = this._editors.get(URI.revive(uri).toString());
if (editor) {
editor.editor.dispose();
editor.onDidReceiveMessage.dispose();
this._editors.delete(URI.revive(uri).toString());
}
});
}
if (delta.addedDocuments) {
delta.addedDocuments.forEach(modelData => {
const revivedUri = URI.revive(modelData.uri);
const viewType = modelData.viewType;
if (!this._documents.has(revivedUri.toString())) {
let document = new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, viewType, revivedUri, this);
this._documents.set(revivedUri.toString(), document);
}
const onDidReceiveMessage = new Emitter<any>();
const document = this._documents.get(revivedUri.toString())!;
let editor = new ExtHostNotebookEditor(
viewType,
`${ExtHostNotebookController._handlePool++}`,
revivedUri,
this._proxy,
onDidReceiveMessage,
document,
this._documentsAndEditors
);
this._onDidOpenNotebookDocument.fire(document);
// TODO, does it already exist?
this._editors.set(revivedUri.toString(), { editor, onDidReceiveMessage });
});
}
if (delta.newActiveEditor) {
this._activeNotebookDocument = this._documents.get(URI.revive(delta.newActiveEditor).toString());
this._activeNotebookEditor = this._editors.get(URI.revive(delta.newActiveEditor).toString())?.editor;
}
}
}
@@ -2742,3 +2742,27 @@ export class TimelineItem implements vscode.TimelineItem {
}
//#endregion Timeline
//#region ExtensionContext
export enum ExtensionMode {
/**
* The extension is installed normally (for example, from the marketplace
* or VSIX) in VS Code.
*/
Release = 1,
/**
* The extension is running from an `--extensionDevelopmentPath` provided
* when launching VS Code.
*/
Development = 2,
/**
* The extension is running from an `--extensionDevelopmentPath` and
* the extension host is running unit tests.
*/
Test = 3,
}
//#endregion ExtensionContext
@@ -37,7 +37,6 @@ namespace schema {
case 'debug/callstack/context': return MenuId.DebugCallStackContext;
case 'debug/toolbar': return MenuId.DebugToolBar;
case 'debug/toolBar': return MenuId.DebugToolBar;
case 'menuBar/file': return MenuId.MenubarFileMenu;
case 'menuBar/webNavigation': return MenuId.MenubarWebNavigationMenu;
case 'scm/title': return MenuId.SCMTitle;
case 'scm/sourceControl': return MenuId.SCMSourceControl;
@@ -70,7 +69,6 @@ namespace schema {
export function isProposedAPI(menuId: MenuId): boolean {
switch (menuId) {
case MenuId.StatusBarWindowIndicatorMenu:
case MenuId.MenubarFileMenu:
case MenuId.MenubarWebNavigationMenu:
return true;
}
@@ -230,13 +230,10 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
public getEnvironmentVariableCollection(extension: IExtensionDescription): vscode.EnvironmentVariableCollection {
let collection = this._environmentVariableCollections.get(extension.identifier.value);
if (!collection) {
// TODO: Disable dispose
collection = new EnvironmentVariableCollection();
this._setEnvironmentVariableCollection(extension.identifier.value, collection);
}
return collection;
}
@@ -202,8 +202,9 @@ class NavigateDownAction extends BaseNavigationAction {
}
function findVisibleNeighbour(layoutService: IWorkbenchLayoutService, part: Parts, next: boolean): Parts {
const neighbour = part === Parts.EDITOR_PART ? (next ? Parts.STATUSBAR_PART : Parts.PANEL_PART) : part === Parts.STATUSBAR_PART ? (next ? Parts.SIDEBAR_PART : Parts.EDITOR_PART) :
part === Parts.SIDEBAR_PART ? (next ? Parts.PANEL_PART : Parts.STATUSBAR_PART) : part === Parts.PANEL_PART ? (next ? Parts.EDITOR_PART : Parts.SIDEBAR_PART) : Parts.EDITOR_PART;
const neighbour = part === Parts.EDITOR_PART ? (next ? Parts.STATUSBAR_PART : Parts.PANEL_PART) : part === Parts.STATUSBAR_PART ? (next ? Parts.ACTIVITYBAR_PART : Parts.EDITOR_PART) :
part === Parts.ACTIVITYBAR_PART ? (next ? Parts.SIDEBAR_PART : Parts.STATUSBAR_PART) : part === Parts.SIDEBAR_PART ? (next ? Parts.PANEL_PART : Parts.ACTIVITYBAR_PART) :
part === Parts.PANEL_PART ? (next ? Parts.EDITOR_PART : Parts.SIDEBAR_PART) : Parts.EDITOR_PART;
if (layoutService.isVisible(neighbour) || neighbour === Parts.EDITOR_PART) {
return neighbour;
}
@@ -212,8 +213,8 @@ function findVisibleNeighbour(layoutService: IWorkbenchLayoutService, part: Part
}
function focusNextOrPreviousPart(layoutService: IWorkbenchLayoutService, next: boolean): void {
const currentlyFocusedPart = layoutService.hasFocus(Parts.EDITOR_PART) ? Parts.EDITOR_PART : layoutService.hasFocus(Parts.STATUSBAR_PART) ? Parts.STATUSBAR_PART :
layoutService.hasFocus(Parts.SIDEBAR_PART) ? Parts.SIDEBAR_PART : layoutService.hasFocus(Parts.PANEL_PART) ? Parts.PANEL_PART : undefined;
const currentlyFocusedPart = layoutService.hasFocus(Parts.EDITOR_PART) ? Parts.EDITOR_PART : layoutService.hasFocus(Parts.ACTIVITYBAR_PART) ? Parts.ACTIVITYBAR_PART :
layoutService.hasFocus(Parts.STATUSBAR_PART) ? Parts.STATUSBAR_PART : layoutService.hasFocus(Parts.SIDEBAR_PART) ? Parts.SIDEBAR_PART : layoutService.hasFocus(Parts.PANEL_PART) ? Parts.PANEL_PART : undefined;
let partToFocus = Parts.EDITOR_PART;
if (currentlyFocusedPart) {
partToFocus = findVisibleNeighbour(layoutService, currentlyFocusedPart, next);
+24 -12
View File
@@ -11,7 +11,7 @@ import { IWindowOpenable } from 'vs/platform/windows/common/windows';
import { URI } from 'vs/base/common/uri';
import { ITextFileService, stringToSnapshot } from 'vs/workbench/services/textfile/common/textfiles';
import { Schemas } from 'vs/base/common/network';
import { IEditorViewState } from 'vs/editor/common/editorCommon';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd';
import { DragMouseEvent } from 'vs/base/browser/mouseEvent';
import { normalizeDriveLetter } from 'vs/base/common/labels';
@@ -58,7 +58,7 @@ export interface IDraggedEditor extends IDraggedResource {
content?: string;
encoding?: string;
mode?: string;
viewState?: IEditorViewState;
options?: ITextEditorOptions;
}
export interface ISerializedDraggedEditor {
@@ -66,7 +66,7 @@ export interface ISerializedDraggedEditor {
content?: string;
encoding?: string;
mode?: string;
viewState?: IEditorViewState;
options?: ITextEditorOptions;
}
export const CodeDataTransfers = {
@@ -90,7 +90,7 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array<ID
resources.push({
resource: URI.parse(draggedEditor.resource),
content: draggedEditor.content,
viewState: draggedEditor.viewState,
options: draggedEditor.options,
encoding: draggedEditor.encoding,
mode: draggedEditor.mode,
isExternal: false
@@ -202,9 +202,9 @@ export class ResourcesDropHandler {
encoding: (untitledOrFileResource as IDraggedEditor).encoding,
mode: (untitledOrFileResource as IDraggedEditor).mode,
options: {
...(untitledOrFileResource as IDraggedEditor).options,
pinned: true,
index: targetIndex,
viewState: (untitledOrFileResource as IDraggedEditor).viewState
index: targetIndex
}
}));
@@ -311,7 +311,7 @@ export class ResourcesDropHandler {
}
}
export function fillResourceDataTransfers(accessor: ServicesAccessor, resources: (URI | { resource: URI, isDirectory: boolean })[], event: DragMouseEvent | DragEvent): void {
export function fillResourceDataTransfers(accessor: ServicesAccessor, resources: (URI | { resource: URI, isDirectory: boolean })[], optionsCallback: ((resource: URI) => ITextEditorOptions) | undefined, event: DragMouseEvent | DragEvent): void {
if (resources.length === 0 || !event.dataTransfer) {
return;
}
@@ -346,20 +346,32 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
const draggedEditors: ISerializedDraggedEditor[] = [];
files.forEach(file => {
let options: ITextEditorOptions | undefined = undefined;
// Try to find editor view state from the visible editors that match given resource
let viewState: IEditorViewState | undefined = undefined;
// Use provided callback for editor options
if (typeof optionsCallback === 'function') {
options = optionsCallback(file.resource);
}
// Otherwise try to figure out the view state from opened editors that match
else {
options = {
viewState: (() => {
const textEditorControls = editorService.visibleTextEditorControls;
for (const textEditorControl of textEditorControls) {
if (isCodeEditor(textEditorControl)) {
const model = textEditorControl.getModel();
if (model?.uri?.toString() === file.resource.toString()) {
viewState = withNullAsUndefined(textEditorControl.saveViewState());
break;
return withNullAsUndefined(textEditorControl.saveViewState());
}
}
}
return undefined;
})()
};
}
// Try to find encoding and mode from text model
let encoding: string | undefined = undefined;
let mode: string | undefined = undefined;
@@ -378,7 +390,7 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
}
// Add as dragged editor
draggedEditors.push({ resource: file.resource.toString(), content, viewState, encoding, mode });
draggedEditors.push({ resource: file.resource.toString(), content, options, encoding, mode });
});
if (draggedEditors.length) {
+14 -2
View File
@@ -42,8 +42,21 @@ function toResource(props: IResourceLabelProps | undefined): URI | undefined {
}
export interface IResourceLabelOptions extends IIconLabelValueOptions {
/**
* A hint to the file kind of the resource.
*/
fileKind?: FileKind;
/**
* File decorations to use for the label.
*/
fileDecorations?: { colors: boolean, badges: boolean };
/**
* Will take the provided label as is and e.g. not override it for untitled files.
*/
forceLabel?: boolean;
}
export interface IFileLabelOptions extends IResourceLabelOptions {
@@ -368,7 +381,7 @@ class ResourceLabelWidget extends IconLabel {
/*const resource = toResource(label); {{SQL CARBON EDIT}} we don't want to special case untitled files
const isMasterDetail = label?.resource && !URI.isUri(label.resource);
if (!isMasterDetail && resource?.scheme === Schemas.untitled) {
if (!options.forceLabel && !isMasterDetail && resource?.scheme === Schemas.untitled) {
// Untitled labels are very dynamic because they may change
// whenever the content changes (unless a path is associated).
// As such we always ask the actual editor for it's name and
@@ -528,7 +541,6 @@ class ResourceLabelWidget extends IconLabel {
);
if (deco) {
this.renderDisposables.add(deco);
if (deco.tooltip) {
+5 -1
View File
@@ -177,6 +177,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
private backupFileService!: IBackupFileService;
private notificationService!: INotificationService;
private themeService!: IThemeService;
private activityBarService!: IActivityBarService;
protected readonly state = {
fullscreen: false,
@@ -260,8 +261,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.viewDescriptorService = accessor.get(IViewDescriptorService);
this.titleService = accessor.get(ITitleService);
this.notificationService = accessor.get(INotificationService);
this.activityBarService = accessor.get(IActivityBarService);
accessor.get(IStatusbarService); // not used, but called to ensure instantiated
accessor.get(IActivityBarService); // not used, but called to ensure instantiated
// Listeners
this.registerLayoutListeners();
@@ -846,6 +847,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
activeViewlet.focus();
}
break;
case Parts.ACTIVITYBAR_PART:
this.activityBarService.focusActivityBar();
break;
default:
// Status Bar, Activity Bar and Title Bar simply pass focus to container
const container = this.getContainer(part);
-3
View File
@@ -10,7 +10,6 @@
.monaco-workbench .part > .drop-block-overlay.visible {
visibility: visible;
opacity: 1;
}
.monaco-workbench .part > .drop-block-overlay {
@@ -18,10 +17,8 @@
top: 0;
width: 100%;
height: 100%;
backdrop-filter: brightness(97%) blur(2px);
visibility: hidden;
opacity: 0;
transition: opacity .5s, visibility .5s;
z-index: 10;
}
@@ -168,6 +168,10 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.registerListeners();
}
focusActivityBar(): void {
this.compositeBar.focus();
}
private registerListeners(): void {
// View Container Changes
@@ -66,8 +66,6 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
if (targetCompositeId) {
this.moveComposite(currentContainer.id, targetCompositeId, before);
}
this.openComposite(currentContainer.id, true);
}
}
@@ -255,6 +253,12 @@ export class CompositeBar extends Widget implements ICompositeBar {
return actionBarDiv;
}
focus(): void {
if (this.compositeSwitcherBar) {
this.compositeSwitcherBar.focus();
}
}
layout(dimension: Dimension): void {
this.dimension = dimension;
if (dimension.height === 0 || dimension.width === 0) {
@@ -275,8 +279,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
// Add to the model
if (this.model.add(id, name, order)) {
this.computeSizes([this.model.findItem(id)]);
// Set timeout helps prevent flicker
setTimeout(() => this.updateCompositeSwitcher(), 0);
this.updateCompositeSwitcher();
}
}
@@ -548,11 +548,8 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
if (e.eventData.dataTransfer) {
e.eventData.dataTransfer.effectAllowed = 'move';
}
// Trigger the action even on drag start to prevent clicks from failing that started a drag
if (!this.getAction().checked) {
this.getAction().run();
}
// Remove focus indicator when dragging
this.blur();
}
}));
@@ -19,6 +19,7 @@ import { MementoObject } from 'vs/workbench/common/memento';
import { isEqualOrParent, joinPath } from 'vs/base/common/resources';
import { isLinux } from 'vs/base/common/platform';
import { indexOfPath } from 'vs/base/common/extpath';
import { IDisposable } from 'vs/base/common/lifecycle';
/**
* The base class of editors in the workbench. Editors register themselves for specific editor inputs.
@@ -171,6 +172,7 @@ interface MapGroupToMemento<T> {
export class EditorMemento<T> implements IEditorMemento<T> {
private cache: LRUCache<string, MapGroupToMemento<T>> | undefined;
private cleanedUp = false;
private editorDisposables: Map<EditorInput, IDisposable> | undefined;
constructor(
public readonly id: string,
@@ -200,9 +202,18 @@ export class EditorMemento<T> implements IEditorMemento<T> {
// Automatically clear when editor input gets disposed if any
if (resourceOrEditor instanceof EditorInput) {
Event.once(resourceOrEditor.onDispose)(() => {
const editor = resourceOrEditor;
if (!this.editorDisposables) {
this.editorDisposables = new Map<EditorInput, IDisposable>();
}
if (!this.editorDisposables.has(editor)) {
this.editorDisposables.set(editor, Event.once(resourceOrEditor.onDispose)(() => {
this.clearEditorState(resource);
});
this.editorDisposables?.delete(editor);
}));
}
}
}
@@ -7,7 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import * as nls from 'vs/nls';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext, EditorPinnedContext, EditorGroupEditorsCountContext } from 'vs/workbench/common/editor';
import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext, EditorPinnedContext, EditorGroupEditorsCountContext, EditorStickyContext } from 'vs/workbench/common/editor';
import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor';
import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
@@ -433,6 +433,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCo
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '1_close', order: 40 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '1_close', order: 50 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.KEEP_EDITOR_COMMAND_ID, title: nls.localize('keepOpen', "Keep Open"), precondition: EditorPinnedContext.toNegated() }, group: '3_preview', order: 10, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.PIN_EDITOR_COMMAND_ID, title: nls.localize('pin', "Pin") }, group: '3_preview', order: 20, when: ContextKeyExpr.and(EditorStickyContext.toNegated(), ContextKeyExpr.has('config.workbench.editor.showTabs')) });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.UNPIN_EDITOR_COMMAND_ID, title: nls.localize('unpin', "Unpin") }, group: '3_preview', order: 20, when: ContextKeyExpr.and(EditorStickyContext, ContextKeyExpr.has('config.workbench.editor.showTabs')) });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_UP, title: nls.localize('splitUp', "Split Up") }, group: '5_split', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_DOWN, title: nls.localize('splitDown', "Split Down") }, group: '5_split', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_LEFT, title: nls.localize('splitLeft', "Split Left") }, group: '5_split', order: 30 });
@@ -579,6 +581,8 @@ appendEditorToolItem(
// Editor Commands for Command Palette
const viewCategory = { value: nls.localize('view', "View"), original: 'View' };
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.KEEP_EDITOR_COMMAND_ID, title: { value: nls.localize('keepEditor', "Keep Editor"), original: 'Keep Editor' }, category: viewCategory }, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.PIN_EDITOR_COMMAND_ID, title: { value: nls.localize('pinEditor', "Pin Editor"), original: 'Pin Editor' }, category: viewCategory }, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.UNPIN_EDITOR_COMMAND_ID, title: { value: nls.localize('unpinEditor', "Unpin Editor"), original: 'Unpin Editor' }, category: viewCategory }, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: { value: nls.localize('closeEditorsInGroup', "Close All Editors in Group"), original: 'Close All Editors in Group' }, category: viewCategory } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: { value: nls.localize('closeSavedEditors', "Close Saved Editors in Group"), original: 'Close Saved Editors in Group' }, category: viewCategory } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: { value: nls.localize('closeOtherEditors', "Close Other Editors in Group"), original: 'Close Other Editors in Group' }, category: viewCategory } });
@@ -500,7 +500,7 @@ export class CloseLeftEditorsInGroupAction extends Action {
async run(context?: IEditorIdentifier): Promise<void> {
const { group, editor } = getTarget(this.editorService, this.editorGroupService, context);
if (group && editor) {
return group.closeEditors({ direction: CloseDirection.LEFT, except: editor });
return group.closeEditors({ direction: CloseDirection.LEFT, except: editor, excludeSticky: true });
}
}
}
@@ -514,7 +514,7 @@ function getTarget(editorService: IEditorService, editorGroupService: IEditorGro
return { group: editorGroupService.activeGroup, editor: editorGroupService.activeGroup.activeEditor };
}
export abstract class BaseCloseAllAction extends Action {
abstract class BaseCloseAllAction extends Action {
constructor(
id: string,
@@ -554,7 +554,7 @@ export abstract class BaseCloseAllAction extends Action {
// to bring each dirty editor to the front so that the user
// can review if the files should be changed or not.
await Promise.all(this.groupsToClose.map(async groupToClose => {
for (const editor of groupToClose.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE)) {
for (const editor of groupToClose.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE, { excludeSticky: this.excludeSticky })) {
if (editor.isDirty() && !editor.isSaving() /* ignore editors that are being saved */) {
return groupToClose.openEditor(editor);
}
@@ -566,7 +566,7 @@ export abstract class BaseCloseAllAction extends Action {
const dirtyEditorsToConfirm = new Set<string>();
const dirtyEditorsToAutoSave = new Set<IEditorInput>();
for (const editor of this.editorService.editors) {
for (const editor of this.editorService.getEditors(EditorsOrder.SEQUENTIAL, { excludeSticky: this.excludeSticky }).map(({ editor }) => editor)) {
if (!editor.isDirty() || editor.isSaving()) {
continue; // only interested in dirty editors (unless in the process of saving)
}
@@ -601,21 +601,29 @@ export abstract class BaseCloseAllAction extends Action {
confirmation = ConfirmResult.DONT_SAVE;
}
if (confirmation === ConfirmResult.CANCEL) {
// Handle result from asking user
let result: boolean | undefined = undefined;
switch (confirmation) {
case ConfirmResult.CANCEL:
return;
case ConfirmResult.DONT_SAVE:
result = await this.editorService.revertAll({ soft: true, includeUntitled: true, excludeSticky: this.excludeSticky });
break;
case ConfirmResult.SAVE:
result = await this.editorService.saveAll({ reason: saveReason, includeUntitled: true, excludeSticky: this.excludeSticky });
break;
}
if (confirmation === ConfirmResult.DONT_SAVE) {
await this.editorService.revertAll({ soft: true, includeUntitled: true });
} else {
await this.editorService.saveAll({ reason: saveReason, includeUntitled: true });
}
if (!this.workingCopyService.hasDirty) {
// Only continue to close editors if we either have no more dirty
// editors or the result from the save/revert was successful
if (!this.workingCopyService.hasDirty || result) {
return this.doCloseAll();
}
}
protected abstract get excludeSticky(): boolean;
protected abstract doCloseAll(): Promise<void>;
}
@@ -636,8 +644,12 @@ export class CloseAllEditorsAction extends BaseCloseAllAction {
super(id, label, Codicon.closeAll.classNames, workingCopyService, fileDialogService, editorGroupService, editorService, filesConfigurationService);
}
protected get excludeSticky(): boolean {
return true;
}
protected async doCloseAll(): Promise<void> {
await Promise.all(this.groupsToClose.map(g => g.closeAllEditors()));
await Promise.all(this.groupsToClose.map(group => group.closeAllEditors({ excludeSticky: true })));
}
}
@@ -658,6 +670,10 @@ export class CloseAllEditorGroupsAction extends BaseCloseAllAction {
super(id, label, undefined, workingCopyService, fileDialogService, editorGroupService, editorService, filesConfigurationService);
}
protected get excludeSticky(): boolean {
return false;
}
protected async doCloseAll(): Promise<void> {
await Promise.all(this.groupsToClose.map(group => group.closeAllEditors()));
@@ -680,12 +696,12 @@ export class CloseEditorsInOtherGroupsAction extends Action {
async run(context?: IEditorIdentifier): Promise<void> {
const groupToSkip = context ? this.editorGroupService.getGroup(context.groupId) : this.editorGroupService.activeGroup;
await Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(async g => {
if (groupToSkip && g.id === groupToSkip.id) {
await Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(async group => {
if (groupToSkip && group.id === groupToSkip.id) {
return;
}
return g.closeAllEditors();
return group.closeAllEditors({ excludeSticky: true });
}));
}
}
@@ -707,7 +723,7 @@ export class CloseEditorInAllGroupsAction extends Action {
async run(): Promise<void> {
const activeEditor = this.editorService.activeEditor;
if (activeEditor) {
await Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(g => g.closeEditor(activeEditor)));
await Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(group => group.closeEditor(activeEditor)));
}
}
}
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import * as types from 'vs/base/common/types';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane } from 'vs/workbench/common/editor';
import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, EditorStickyContext, EditorsOrder } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
@@ -37,6 +37,9 @@ export const LAYOUT_EDITOR_GROUPS_COMMAND_ID = 'layoutEditorGroups';
export const KEEP_EDITOR_COMMAND_ID = 'workbench.action.keepEditor';
export const SHOW_EDITORS_IN_GROUP = 'workbench.action.showEditorsInGroup';
export const PIN_EDITOR_COMMAND_ID = 'workbench.action.pinEditor';
export const UNPIN_EDITOR_COMMAND_ID = 'workbench.action.unpinEditor';
export const TOGGLE_DIFF_SIDE_BY_SIDE = 'toggle.diff.renderSideBySide';
export const GOTO_NEXT_CHANGE = 'workbench.action.compareEditor.nextChange';
export const GOTO_PREVIOUS_CHANGE = 'workbench.action.compareEditor.previousChange';
@@ -258,7 +261,7 @@ function registerDiffEditorCommands(): void {
function navigateInDiffEditor(accessor: ServicesAccessor, next: boolean): void {
const editorService = accessor.get(IEditorService);
const candidates = [editorService.activeEditorPane, ...editorService.visibleEditorPanes].filter(e => e instanceof TextDiffEditor);
const candidates = [editorService.activeEditorPane, ...editorService.visibleEditorPanes].filter(editor => editor instanceof TextDiffEditor);
if (candidates.length > 0) {
const navigator = (<TextDiffEditor>candidates[0]).getDiffNavigator();
@@ -491,7 +494,7 @@ function registerCloseEditorCommands() {
return Promise.all(distinct(contexts.map(c => c.groupId)).map(async groupId => {
const group = editorGroupService.getGroup(groupId);
if (group) {
return group.closeEditors({ savedOnly: true });
return group.closeEditors({ savedOnly: true, excludeSticky: true });
}
}));
}
@@ -514,7 +517,7 @@ function registerCloseEditorCommands() {
return Promise.all(distinctGroupIds.map(async groupId => {
const group = editorGroupService.getGroup(groupId);
if (group) {
return group.closeAllEditors();
return group.closeAllEditors({ excludeSticky: true });
}
}));
}
@@ -596,7 +599,8 @@ function registerCloseEditorCommands() {
const editors = contexts
.filter(context => context.groupId === groupId)
.map(context => typeof context.editorIndex === 'number' ? group.getEditorByIndex(context.editorIndex) : group.activeEditor);
const editorsToClose = group.editors.filter(e => editors.indexOf(e) === -1);
const editorsToClose = group.getEditors(EditorsOrder.SEQUENTIAL, { excludeSticky: true }).filter(editor => editors.indexOf(editor) === -1);
if (group.activeEditor) {
group.pinEditor(group.activeEditor);
@@ -622,7 +626,7 @@ function registerCloseEditorCommands() {
group.pinEditor(group.activeEditor);
}
return group.closeEditors({ direction: CloseDirection.RIGHT, except: editor });
return group.closeEditors({ direction: CloseDirection.RIGHT, except: editor, excludeSticky: true });
}
}
});
@@ -642,6 +646,36 @@ function registerCloseEditorCommands() {
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: PIN_EDITOR_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(EditorStickyContext.toNegated(), ContextKeyExpr.has('config.workbench.editor.showTabs')),
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.Enter),
handler: async (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
const { group, editor } = resolveCommandsContext(editorGroupService, getCommandsContext(resourceOrContext, context));
if (group && editor) {
return group.stickEditor(editor);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: UNPIN_EDITOR_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(EditorStickyContext, ContextKeyExpr.has('config.workbench.editor.showTabs')),
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.Enter),
handler: async (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
const { group, editor } = resolveCommandsContext(editorGroupService, getCommandsContext(resourceOrContext, context));
if (group && editor) {
return group.unstickEditor(editor);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: SHOW_EDITORS_IN_GROUP,
weight: KeybindingWeight.WorkbenchContrib,
@@ -266,7 +266,10 @@ class DropOverlay extends Themable {
}
// Open in target group
const options = getActiveTextEditorOptions(sourceGroup, draggedEditor.editor, EditorOptions.create({ pinned: true }));
const options = getActiveTextEditorOptions(sourceGroup, draggedEditor.editor, EditorOptions.create({
pinned: true, // always pin dropped editor
sticky: sourceGroup.isSticky(draggedEditor.editor) // preserve sticky state
}));
targetGroup.openEditor(draggedEditor.editor, options);
// Ensure target has focus
@@ -17,7 +17,7 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler';
import { IThemeService, registerThemingParticipant, Themable } from 'vs/platform/theme/common/themeService';
import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_FOCUSED_EMPTY_BORDER, EDITOR_GROUP_HEADER_BORDER } from 'vs/workbench/common/theme';
import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, GroupsOrder, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions } from 'vs/workbench/services/editor/common/editorGroupsService';
import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleControl';
import { EditorControl } from 'vs/workbench/browser/parts/editor/editorControl';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
@@ -441,6 +441,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
options.pinned = this._group.isPinned(activeEditor); // preserve pinned state
options.sticky = this._group.isSticky(activeEditor); // preserve sticky state
options.preserveFocus = true; // handle focus after editor is opened
const activeElement = document.activeElement;
@@ -732,6 +733,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this._group.count;
}
get stickyCount(): number {
return this._group.stickyCount;
}
get activeEditorPane(): IVisibleEditorPane | undefined {
return this.editorControl ? withNullAsUndefined(this.editorControl.activeEditorPane) : undefined;
}
@@ -748,12 +753,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this._group.isPinned(editor);
}
isSticky(editorOrIndex: EditorInput | number): boolean {
return this._group.isSticky(editorOrIndex);
}
isActive(editor: EditorInput): boolean {
return this._group.isActive(editor);
}
getEditors(order: EditorsOrder): EditorInput[] {
return this._group.getEditors(order);
getEditors(order: EditorsOrder, options?: { excludeSticky?: boolean }): EditorInput[] {
return this._group.getEditors(order, options);
}
getEditorByIndex(index: number): EditorInput | undefined {
@@ -794,6 +803,43 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
}
stickEditor(candidate: EditorInput | undefined = this.activeEditor || undefined): void {
this.doStickEditor(candidate, true);
}
unstickEditor(candidate: EditorInput | undefined = this.activeEditor || undefined): void {
this.doStickEditor(candidate, false);
}
private doStickEditor(candidate: EditorInput | undefined, sticky: boolean): void {
if (candidate && this._group.isSticky(candidate) !== sticky) {
const oldIndexOfEditor = this.getIndexOfEditor(candidate);
// Update model
const editor = sticky ? this._group.stick(candidate) : this._group.unstick(candidate);
if (!editor) {
return;
}
// If the index of the editor changed, we need to forward this to
// title control and also make sure to emit this as an event
const newIndexOfEditor = this.getIndexOfEditor(editor);
if (newIndexOfEditor !== oldIndexOfEditor) {
this.titleAreaControl.moveEditor(editor, oldIndexOfEditor, newIndexOfEditor);
// Event
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_MOVE, editor });
}
// Forward sticky state to title control
if (sticky) {
this.titleAreaControl.stickEditor(editor);
} else {
this.titleAreaControl.unstickEditor(editor);
}
}
}
invokeWithinContext<T>(fn: (accessor: ServicesAccessor) => T): T {
return this.scopedInstantiationService.invokeFunction(fn);
}
@@ -833,11 +879,19 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Determine options
const openEditorOptions: IEditorOpenOptions = {
index: options ? options.index : undefined,
pinned: !this.accessor.partOptions.enablePreview || editor.isDirty() || (options?.pinned ?? typeof options?.index === 'number'), // unless specified, prefer to pin when opening with index
pinned: options?.sticky || !this.accessor.partOptions.enablePreview || editor.isDirty() || (options?.pinned ?? typeof options?.index === 'number' /* unless specified, prefer to pin when opening with index */) || (typeof options?.index === 'number' && this._group.isSticky(options.index)),
sticky: options?.sticky || (typeof options?.index === 'number' && this._group.isSticky(options.index)),
active: this._group.count === 0 || !options || !options.inactive
};
if (!openEditorOptions.active && !openEditorOptions.pinned && this._group.activeEditor && this._group.isPreview(this._group.activeEditor)) {
if (options?.sticky && typeof options?.index === 'number' && !this._group.isSticky(options.index)) {
// Special case: we are to open an editor sticky but at an index that is not sticky
// In that case we prefer to open the editor at the index but not sticky. This enables
// to drag a sticky editor to an index that is not sticky to unstick it.
openEditorOptions.sticky = false;
}
if (!openEditorOptions.active && !openEditorOptions.pinned && this._group.activeEditor && !this._group.isPinned(this._group.activeEditor)) {
// Special case: we are to open an editor inactive and not pinned, but the current active
// editor is also not pinned, which means it will get replaced with this one. As such,
// the editor can only be active.
@@ -1095,8 +1149,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// When moving an editor, try to preserve as much view state as possible by checking
// for the editor to be a text editor and creating the options accordingly if so
const options = getActiveTextEditorOptions(this, editor, EditorOptions.create(moveOptions));
options.pinned = true; // always pin moved editor
const options = getActiveTextEditorOptions(this, editor, EditorOptions.create({
...moveOptions,
pinned: true, // always pin moved editor
sticky: this._group.isSticky(editor) // preserve sticky state
}));
// A move to another group is an open first...
target.openEditor(editor, options);
@@ -1377,7 +1434,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return;
}
const editors = this.getEditorsToClose(args);
const editors = this.doGetEditorsToClose(args);
// Check for dirty and veto
const veto = await this.handleDirtyClosing(editors.slice(0));
@@ -1389,31 +1446,31 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this.doCloseEditors(editors, options);
}
private getEditorsToClose(editors: EditorInput[] | ICloseEditorsFilter): EditorInput[] {
if (Array.isArray(editors)) {
return editors;
private doGetEditorsToClose(args: EditorInput[] | ICloseEditorsFilter): EditorInput[] {
if (Array.isArray(args)) {
return args;
}
const filter = editors;
const filter = args;
const hasDirection = typeof filter.direction === 'number';
let editorsToClose = this._group.getEditors(hasDirection ? EditorsOrder.SEQUENTIAL : EditorsOrder.MOST_RECENTLY_ACTIVE); // in MRU order only if direction is not specified
let editorsToClose = this._group.getEditors(hasDirection ? EditorsOrder.SEQUENTIAL : EditorsOrder.MOST_RECENTLY_ACTIVE, filter); // in MRU order only if direction is not specified
// Filter: saved or saving only
if (filter.savedOnly) {
editorsToClose = editorsToClose.filter(e => !e.isDirty() || e.isSaving());
editorsToClose = editorsToClose.filter(editor => !editor.isDirty() || editor.isSaving());
}
// Filter: direction (left / right)
else if (hasDirection && filter.except) {
editorsToClose = (filter.direction === CloseDirection.LEFT) ?
editorsToClose.slice(0, this._group.indexOf(filter.except)) :
editorsToClose.slice(this._group.indexOf(filter.except) + 1);
editorsToClose.slice(0, this._group.indexOf(filter.except, editorsToClose)) :
editorsToClose.slice(this._group.indexOf(filter.except, editorsToClose) + 1);
}
// Filter: except
else if (filter.except) {
editorsToClose = editorsToClose.filter(e => !e.matches(filter.except));
editorsToClose = editorsToClose.filter(editor => !editor.matches(filter.except));
}
return editorsToClose;
@@ -1444,7 +1501,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region closeAllEditors()
async closeAllEditors(): Promise<void> {
async closeAllEditors(options?: ICloseAllEditorsOptions): Promise<void> {
if (this.isEmpty) {
// If the group is empty and the request is to close all editors, we still close
@@ -1458,30 +1515,34 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
// Check for dirty and veto
const editors = this._group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE);
const veto = await this.handleDirtyClosing(editors.slice(0));
const veto = await this.handleDirtyClosing(this._group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE, options));
if (veto) {
return;
}
// Do close
this.doCloseAllEditors();
this.doCloseAllEditors(options);
}
private doCloseAllEditors(): void {
private doCloseAllEditors(options?: ICloseAllEditorsOptions): void {
// Close all inactive editors first
this.editors.forEach(editor => {
const editorsToClose: EditorInput[] = [];
this._group.getEditors(EditorsOrder.SEQUENTIAL, options).forEach(editor => {
if (!this.isActive(editor)) {
this.doCloseInactiveEditor(editor);
}
editorsToClose.push(editor);
});
// Close active editor last
// Close active editor last (unless we skip it, e.g. because it is sticky)
if (this.activeEditor && editorsToClose.includes(this.activeEditor)) {
this.doCloseActiveEditor();
}
// Forward to title control
this.titleAreaControl.closeAllEditors();
this.titleAreaControl.closeEditors(editorsToClose);
}
//#endregion
@@ -48,7 +48,7 @@ export class EditorsObserver extends Disposable {
}
get editors(): IEditorIdentifier[] {
return [...this.mostRecentEditorsMap.values()];
return this.mostRecentEditorsMap.values();
}
hasEditor(resource: URI): boolean {
@@ -283,7 +283,7 @@ export class EditorsObserver extends Disposable {
// Across all editor groups
else {
await this.doEnsureOpenedEditorsLimit(limit, [...this.mostRecentEditorsMap.values()], exclude);
await this.doEnsureOpenedEditorsLimit(limit, this.mostRecentEditorsMap.values(), exclude);
}
}
@@ -302,6 +302,10 @@ export class EditorsObserver extends Disposable {
return false; // never the editor that should be excluded
}
if (this.editorGroupsService.getGroup(groupId)?.isSticky(editor)) {
return false; // never sticky editors
}
return true;
});
@@ -342,7 +346,7 @@ export class EditorsObserver extends Disposable {
private serialize(): ISerializedEditorsList {
const registry = Registry.as<IEditorInputFactoryRegistry>(Extensions.EditorInputFactories);
const entries = [...this.mostRecentEditorsMap.values()];
const entries = this.mostRecentEditorsMap.values();
const mapGroupToSerializableEditorsOfGroup = new Map<IEditorGroup, IEditorInput[]>();
return {
@@ -63,8 +63,8 @@
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon-theme.close-button-right,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon-theme.close-button-off {
padding-left: 5px; /* reduce padding when we show icons and are in shrinking mode and tab close button is not left */
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon-theme.close-button-off:not(.sticky) {
padding-left: 5px; /* reduce padding when we show icons and are in shrinking mode and tab close button is not left (unless sticky) */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit {
@@ -82,6 +82,30 @@
max-width: -moz-fit-content;
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit.sticky,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.sticky {
/** Sticky tabs do not scroll in case of overflow and are always above unsticky tabs which scroll under */
position: sticky;
z-index: 1;
/** Sticky tabs are even and never grow */
flex-basis: 0;
flex-grow: 0;
/** Sticky tabs have a fixed width of 38px */
width: 38px;
min-width: 38px;
max-width: 38px;
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-fit.sticky,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.disable-sticky-tabs > .tab.sizing-shrink.sticky {
/** Disable sticky positions for sticky tabs if the available space is too little */
position: static;
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-left .action-label {
margin-right: 4px !important;
}
@@ -174,6 +198,10 @@
opacity: 0; /* when tab has the focus this shade breaks the tab border (fixes https://github.com/Microsoft/vscode/issues/57819) */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sticky:not(.has-icon-theme) .monaco-icon-label {
text-align: center; /* ensure that sticky tabs without icon have label centered */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit .monaco-icon-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit .monaco-icon-label > .monaco-icon-label-container {
overflow: visible; /* fixes https://github.com/Microsoft/vscode/issues/20182 */
@@ -210,8 +238,9 @@
overflow: visible; /* ...but still show the close button on hover, focus and when dirty */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off:not(.dirty) > .tab-close {
display: none; /* hide the close action bar when we are configured to hide it */
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off:not(.dirty) > .tab-close,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.sticky > .tab-close {
display: none; /* hide the close action bar when we are configured to hide it (unless dirty, but always when sticky) */
}
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.active > .tab-close .action-label, /* always show it for active tab */
@@ -257,8 +286,8 @@
padding-right: 10px; /* give a little bit more room if close button is off */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-off {
padding-right: 5px; /* we need less room when sizing is shrink */
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-off:not(.sticky) {
padding-right: 5px; /* we need less room when sizing is shrink (unless tab is sticky) */
}
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty-border-top > .tab-close,
@@ -136,10 +136,6 @@ export class NoTabsTitleControl extends TitleControl {
this.ifActiveEditorChanged(() => this.redraw());
}
closeAllEditors(): void {
this.redraw();
}
moveEditor(editor: IEditorInput, fromIndex: number, targetIndex: number): void {
this.ifActiveEditorChanged(() => this.redraw());
}
@@ -148,6 +144,14 @@ export class NoTabsTitleControl extends TitleControl {
this.ifEditorIsActive(editor, () => this.redraw());
}
stickEditor(editor: IEditorInput): void {
// Sticky editors are not presented any different with tabs disabled
}
unstickEditor(editor: IEditorInput): void {
// Sticky editors are not presented any different with tabs disabled
}
setActive(isActive: boolean): void {
this.redraw();
}
@@ -219,7 +223,6 @@ export class NoTabsTitleControl extends TitleControl {
}
}
private ifEditorIsActive(editor: IEditorInput, fn: () => void): void {
if (this.group.isActive(editor)) {
fn(); // only run if editor is current active
@@ -27,7 +27,7 @@ import { getOrSet } from 'vs/base/common/map';
import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService';
import { TAB_INACTIVE_BACKGROUND, TAB_ACTIVE_BACKGROUND, TAB_ACTIVE_FOREGROUND, TAB_INACTIVE_FOREGROUND, TAB_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND, TAB_UNFOCUSED_INACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_BACKGROUND, TAB_UNFOCUSED_ACTIVE_BORDER, TAB_ACTIVE_BORDER, TAB_HOVER_BACKGROUND, TAB_HOVER_BORDER, TAB_UNFOCUSED_HOVER_BACKGROUND, TAB_UNFOCUSED_HOVER_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, WORKBENCH_BACKGROUND, TAB_ACTIVE_BORDER_TOP, TAB_UNFOCUSED_ACTIVE_BORDER_TOP, TAB_ACTIVE_MODIFIED_BORDER, TAB_INACTIVE_MODIFIED_BORDER, TAB_UNFOCUSED_ACTIVE_MODIFIED_BORDER, TAB_UNFOCUSED_INACTIVE_MODIFIED_BORDER, TAB_UNFOCUSED_INACTIVE_BACKGROUND, TAB_HOVER_FOREGROUND, TAB_UNFOCUSED_HOVER_FOREGROUND, EDITOR_GROUP_HEADER_TABS_BORDER } from 'vs/workbench/common/theme';
import { activeContrastBorder, contrastBorder, editorBackground, breadcrumbsBackground } from 'vs/platform/theme/common/colorRegistry';
import { ResourcesDropHandler, fillResourceDataTransfers, DraggedEditorIdentifier, DraggedEditorGroupIdentifier, DragAndDropObserver } from 'vs/workbench/browser/dnd';
import { ResourcesDropHandler, DraggedEditorIdentifier, DraggedEditorGroupIdentifier, DragAndDropObserver } from 'vs/workbench/browser/dnd';
import { Color } from 'vs/base/common/color';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -67,6 +67,11 @@ export class TabsTitleControl extends TitleControl {
large: 10
};
private static readonly TAB_SIZES = {
sticky: 38,
fit: 120
};
private titleContainer: HTMLElement | undefined;
private tabsAndActionsContainer: HTMLElement | undefined;
private tabsContainer: HTMLElement | undefined;
@@ -392,10 +397,6 @@ export class TabsTitleControl extends TitleControl {
this.handleClosedEditors();
}
closeAllEditors(): void {
this.handleClosedEditors();
}
private handleClosedEditors(): void {
// There are tabs to show
@@ -453,7 +454,24 @@ export class TabsTitleControl extends TitleControl {
}
pinEditor(editor: IEditorInput): void {
this.withTab(editor, (editor, index, tabContainer, tabLabelWidget, tabLabel) => this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel));
this.withTab(editor, (editor, index, tabContainer, tabLabelWidget, tabLabel) => this.redrawLabel(editor, index, tabContainer, tabLabelWidget, tabLabel));
}
stickEditor(editor: IEditorInput): void {
this.doHandleStickyEditorChange(editor);
}
unstickEditor(editor: IEditorInput): void {
this.doHandleStickyEditorChange(editor);
}
private doHandleStickyEditorChange(editor: IEditorInput): void {
// Update tab
this.withTab(editor, (editor, index, tabContainer, tabLabelWidget, tabLabel) => this.redrawTab(editor, index, tabContainer, tabLabelWidget, tabLabel));
// A change to the sticky state requires a layout to keep the active editor visible
this.layout(this.dimension);
}
setActive(isGroupActive: boolean): void {
@@ -487,7 +505,7 @@ export class TabsTitleControl extends TitleControl {
// As such we need to redraw each label
this.forEachTab((editor, index, tabContainer, tabLabelWidget, tabLabel) => {
this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel);
this.redrawLabel(editor, index, tabContainer, tabLabelWidget, tabLabel);
});
// A change to a label requires a layout to keep the active editor visible
@@ -745,10 +763,7 @@ export class TabsTitleControl extends TitleControl {
}
// Apply some datatransfer types to allow for dragging the element outside of the application
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
if (resource) {
this.instantiationService.invokeFunction(fillResourceDataTransfers, [resource], e);
}
this.doFillResourceDataTransfers(editor, e);
// Fixes https://github.com/Microsoft/vscode/issues/18733
addClass(tab, 'dragged');
@@ -1010,7 +1025,7 @@ export class TabsTitleControl extends TitleControl {
private redrawTab(editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel): void {
// Label
this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel);
this.redrawLabel(editor, index, tabContainer, tabLabelWidget, tabLabel);
// Borders / Outline
const borderRightColor = (this.getColor(TAB_BORDER) || this.getColor(contrastBorder));
@@ -1018,10 +1033,12 @@ export class TabsTitleControl extends TitleControl {
tabContainer.style.outlineColor = this.getColor(activeContrastBorder) || '';
// Settings
const isTabSticky = this.group.isSticky(index);
const options = this.accessor.partOptions;
const tabCloseButton = isTabSticky ? 'off' /* treat sticky tabs as tabCloseButton: 'off' */ : options.tabCloseButton;
['off', 'left', 'right'].forEach(option => {
const domAction = options.tabCloseButton === option ? addClass : removeClass;
const domAction = tabCloseButton === option ? addClass : removeClass;
domAction(tabContainer, `close-button-${option}`);
});
@@ -1036,13 +1053,37 @@ export class TabsTitleControl extends TitleControl {
removeClass(tabContainer, 'has-icon-theme');
}
// Sticky Tabs need a position to remain at their location
// when scrolling to stay in view (requirement for position: sticky)
if (isTabSticky) {
addClass(tabContainer, 'sticky');
tabContainer.style.left = `${index * TabsTitleControl.TAB_SIZES.sticky}px`;
} else {
removeClass(tabContainer, 'sticky');
tabContainer.style.left = 'auto';
}
// Active / dirty state
this.redrawEditorActiveAndDirty(this.accessor.activeGroup === this.group, editor, tabContainer, tabLabelWidget);
}
private redrawLabel(editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel): void {
const name = tabLabel.name;
const description = tabLabel.description || '';
private redrawLabel(editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel): void {
const isTabSticky = this.group.isSticky(index);
// Unless tabs are sticky, show the full label and description
// Sticky tabs will only show an icon if icons are enabled
// or their first character of the name otherwise
let name: string | undefined;
let description: string;
if (isTabSticky) {
const isShowingIcons = this.accessor.partOptions.showIcons && !!this.accessor.partOptions.iconTheme;
name = isShowingIcons ? '' : tabLabel.name?.charAt(0).toUpperCase();
description = '';
} else {
name = tabLabel.name;
description = tabLabel.description || '';
}
const title = tabLabel.title || '';
if (tabLabel.ariaLabel) {
@@ -1056,7 +1097,7 @@ export class TabsTitleControl extends TitleControl {
// Label
tabLabelWidget.setResource(
{ name, description, resource: toResource(editor, { supportSideBySide: SideBySideEditor.BOTH }) },
{ title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) }
{ title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor), forceLabel: isTabSticky }
);
this.setEditorTabColor(editor, tabContainer, this.group.isActive(editor)); // {{SQL CARBON EDIT}} -- Display the editor's tab color
@@ -1173,8 +1214,8 @@ export class TabsTitleControl extends TitleControl {
layout(dimension: Dimension | undefined): void {
this.dimension = dimension;
const activeTab = this.group.activeEditor ? this.getTab(this.group.activeEditor) : undefined;
if (!activeTab || !this.dimension) {
const activeTabAndIndex = this.group.activeEditor ? this.getTabAndIndex(this.group.activeEditor) : undefined;
if (!activeTabAndIndex || !this.dimension) {
return;
}
@@ -1192,20 +1233,66 @@ export class TabsTitleControl extends TitleControl {
}
private doLayout(dimension: Dimension): void {
const activeTab = this.group.activeEditor ? this.getTab(this.group.activeEditor) : undefined;
if (!activeTab) {
return;
const activeTabAndIndex = this.group.activeEditor ? this.getTabAndIndex(this.group.activeEditor) : undefined;
if (!activeTabAndIndex) {
return; // nothing to do if not editor opened
}
const [tabsContainer, tabsScrollbar] = assertAllDefined(this.tabsContainer, this.tabsScrollbar);
// Breadcrumbs
this.doLayoutBreadcrumbs(dimension);
// Tabs
const [activeTab, activeIndex] = activeTabAndIndex;
this.doLayoutTabs(activeTab, activeIndex);
}
private doLayoutBreadcrumbs(dimension: Dimension): void {
if (this.breadcrumbsControl && !this.breadcrumbsControl.isHidden()) {
const tabsScrollbar = assertIsDefined(this.tabsScrollbar);
this.breadcrumbsControl.layout({ width: dimension.width, height: BreadcrumbsControl.HEIGHT });
tabsScrollbar.getDomNode().style.height = `${dimension.height - BreadcrumbsControl.HEIGHT}px`;
}
}
const visibleContainerWidth = tabsContainer.offsetWidth;
const totalContainerWidth = tabsContainer.scrollWidth;
private doLayoutTabs(activeTab: HTMLElement, activeIndex: number): void {
const [tabsContainer, tabsScrollbar] = assertAllDefined(this.tabsContainer, this.tabsScrollbar);
//
// Synopsis
// - allTabsWidth: sum of all tab widths
// - stickyTabsWidth: sum of all sticky tab widths
// - visibleContainerWidth: size of tab container
// - availableContainerWidth: size of tab container minus size of sticky tabs
//
// [------------------------------ All tabs width ---------------------------------------]
// [------------------- Visible container width -------------------]
// [------ Available container width ------]
// [ Sticky A ][ Sticky B ][ Tab C ][ Tab D ][ Tab E ][ Tab F ][ Tab G ][ Tab H ][ Tab I ]
// Active Tab Width [-------]
// [------- Active Tab Pos X -------]
// [-- Sticky Tabs Width --]
//
const visibleTabsContainerWidth = tabsContainer.offsetWidth;
const allTabsWidth = tabsContainer.scrollWidth;
let stickyTabsWidth = this.group.stickyCount * TabsTitleControl.TAB_SIZES.sticky;
let activeTabSticky = this.group.isSticky(activeIndex);
let availableTabsContainerWidth = visibleTabsContainerWidth - stickyTabsWidth;
// Special case: we have sticky tabs but the available space for showing tabs
// is little enough that we need to disable sticky tabs sticky positioning
// so that tabs can be scrolled at naturally.
if (this.group.stickyCount > 0 && availableTabsContainerWidth < TabsTitleControl.TAB_SIZES.fit) {
addClass(tabsContainer, 'disable-sticky-tabs');
availableTabsContainerWidth = visibleTabsContainerWidth;
stickyTabsWidth = 0;
activeTabSticky = false;
} else {
removeClass(tabsContainer, 'disable-sticky-tabs');
}
let activeTabPosX: number | undefined;
let activeTabWidth: number | undefined;
@@ -1217,42 +1304,78 @@ export class TabsTitleControl extends TitleControl {
// Update scrollbar
tabsScrollbar.setScrollDimensions({
width: visibleContainerWidth,
scrollWidth: totalContainerWidth
width: visibleTabsContainerWidth,
scrollWidth: allTabsWidth
});
// Return now if we are blocked to reveal the active tab and clear flag
if (this.blockRevealActiveTab || typeof activeTabPosX !== 'number' || typeof activeTabWidth !== 'number') {
// We also return if the active tab is sticky because this means it is
// always visible anyway.
if (this.blockRevealActiveTab || typeof activeTabPosX !== 'number' || typeof activeTabWidth !== 'number' || activeTabSticky) {
this.blockRevealActiveTab = false;
return;
}
// Reveal the active one
const containerScrollPosX = tabsScrollbar.getScrollPosition().scrollLeft;
const activeTabFits = activeTabWidth <= visibleContainerWidth;
const tabsContainerScrollPosX = tabsScrollbar.getScrollPosition().scrollLeft;
const activeTabFits = activeTabWidth <= availableTabsContainerWidth;
const adjustedActiveTabPosX = activeTabPosX - stickyTabsWidth;
//
// Synopsis
// - adjustedActiveTabPosX: the adjusted tabPosX takes the width of sticky tabs into account
// conceptually the scrolling only begins after sticky tabs so in order to reveal a tab fully
// the actual position needs to be adjusted for sticky tabs.
//
// Tab is overflowing to the right: Scroll minimally until the element is fully visible to the right
// Note: only try to do this if we actually have enough width to give to show the tab fully!
if (activeTabFits && containerScrollPosX + visibleContainerWidth < activeTabPosX + activeTabWidth) {
//
// Example: Tab G should be made active and needs to be fully revealed as such.
//
// [-------------------------------- All tabs width -----------------------------------------]
// [-------------------- Visible container width --------------------]
// [----- Available container width -------]
// [ Sticky A ][ Sticky B ][ Tab C ][ Tab D ][ Tab E ][ Tab F ][ Tab G ][ Tab H ][ Tab I ]
// Active Tab Width [-------]
// [------- Active Tab Pos X -------]
// [-------- Adjusted Tab Pos X -------]
// [-- Sticky Tabs Width --]
//
//
if (activeTabFits && tabsContainerScrollPosX + availableTabsContainerWidth < adjustedActiveTabPosX + activeTabWidth) {
tabsScrollbar.setScrollPosition({
scrollLeft: containerScrollPosX + ((activeTabPosX + activeTabWidth) /* right corner of tab */ - (containerScrollPosX + visibleContainerWidth) /* right corner of view port */)
scrollLeft: tabsContainerScrollPosX + ((adjustedActiveTabPosX + activeTabWidth) /* right corner of tab */ - (tabsContainerScrollPosX + availableTabsContainerWidth) /* right corner of view port */)
});
}
// Tab is overlflowng to the left or does not fit: Scroll it into view to the left
else if (containerScrollPosX > activeTabPosX || !activeTabFits) {
//
// Tab is overlflowing to the left or does not fit: Scroll it into view to the left
//
// Example: Tab C should be made active and needs to be fully revealed as such.
//
// [----------------------------- All tabs width ----------------------------------------]
// [------------------ Visible container width ------------------]
// [----- Available container width -------]
// [ Sticky A ][ Sticky B ][ Tab C ][ Tab D ][ Tab E ][ Tab F ][ Tab G ][ Tab H ][ Tab I ]
// Active Tab Width [-------]
// [------- Active Tab Pos X -------]
// Adjusted Tab Pos X []
// [-- Sticky Tabs Width --]
//
//
else if (tabsContainerScrollPosX > adjustedActiveTabPosX || !activeTabFits) {
tabsScrollbar.setScrollPosition({
scrollLeft: activeTabPosX
scrollLeft: adjustedActiveTabPosX
});
}
}
private getTab(editor: IEditorInput): HTMLElement | undefined {
private getTabAndIndex(editor: IEditorInput): [HTMLElement, number /* index */] | undefined {
const editorIndex = this.group.getIndexOfEditor(editor);
if (editorIndex >= 0) {
const tabsContainer = assertIsDefined(this.tabsContainer);
return tabsContainer.children[editorIndex] as HTMLElement;
return [tabsContainer.children[editorIndex] as HTMLElement, editorIndex];
}
return undefined;
@@ -1494,11 +1617,11 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
// Adjust gradient for focused and unfocused hover background
const makeTabHoverBackgroundRule = (color: Color, colorDrag: Color, hasFocus = false) => `
.monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container${hasFocus ? '.active' : ''} > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
.monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container${hasFocus ? '.active' : ''} > .title .tabs-container > .tab.sizing-shrink:not(.dragged):not(.sticky):hover > .tab-label::after {
background: linear-gradient(to left, ${color}, transparent) !important;
}
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container${hasFocus ? '.active' : ''} > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container${hasFocus ? '.active' : ''} > .title .tabs-container > .tab.sizing-shrink:not(.dragged):not(.sticky):hover > .tab-label::after {
background: linear-gradient(to left, ${colorDrag}, transparent) !important;
}
`;
@@ -1521,19 +1644,19 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
if (editorDragAndDropBackground && adjustedTabDragBackground) {
const adjustedColorDrag = editorDragAndDropBackground.flatten(adjustedTabDragBackground);
collector.addRule(`
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink.dragged-over:not(.active):not(.dragged) > .tab-label::after,
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container:not(.active) > .title .tabs-container > .tab.sizing-shrink.dragged-over:not(.dragged) > .tab-label::after {
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink.dragged-over:not(.active):not(.dragged):not(.sticky) > .tab-label::after,
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container:not(.active) > .title .tabs-container > .tab.sizing-shrink.dragged-over:not(.dragged):not(.sticky) > .tab-label::after {
background: linear-gradient(to left, ${adjustedColorDrag}, transparent) !important;
}
`);
}
const makeTabBackgroundRule = (color: Color, colorDrag: Color, focused: boolean, active: boolean) => `
.monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container${focused ? '.active' : ':not(.active)'} > .title .tabs-container > .tab.sizing-shrink${active ? '.active' : ''}:not(.dragged) > .tab-label::after {
.monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container${focused ? '.active' : ':not(.active)'} > .title .tabs-container > .tab.sizing-shrink${active ? '.active' : ''}:not(.dragged):not(.sticky) > .tab-label::after {
background: linear-gradient(to left, ${color}, transparent);
}
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container${focused ? '.active' : ':not(.active)'} > .title .tabs-container > .tab.sizing-shrink${active ? '.active' : ''}:not(.dragged) > .tab-label::after {
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container${focused ? '.active' : ':not(.active)'} > .title .tabs-container > .tab.sizing-shrink${active ? '.active' : ''}:not(.dragged):not(.sticky) > .tab-label::after {
background: linear-gradient(to left, ${colorDrag}, transparent);
}
`;
@@ -181,7 +181,12 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
// because we are triggering another openEditor() call
// and do not control the initial intent that resulted
// in us now opening as binary.
const preservingOptions: IEditorOptions = { activation: EditorActivation.PRESERVE, pinned: this.group?.isPinned(input) };
const preservingOptions: IEditorOptions = {
activation: EditorActivation.PRESERVE,
pinned: this.group?.isPinned(input),
sticky: this.group?.isSticky(input)
};
if (options) {
options.overwrite(preservingOptions);
} else {
@@ -237,7 +242,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
if (isArray(error)) {
const errors = <Error[]>error;
return errors.some(e => this.isFileBinaryError(e));
return errors.some(error => this.isFileBinaryError(error));
}
return (<TextFileOperationError>error).textFileOperationResult === TextFileOperationResult.FILE_IS_BINARY;
@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/titlecontrol';
import { applyDragImage, DataTransfers } from 'vs/base/browser/dnd';
import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
@@ -12,8 +13,7 @@ import { IAction, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecut
import * as arrays from 'vs/base/common/arrays';
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { dispose, DisposableStore } from 'vs/base/common/lifecycle';
import 'vs/css!./media/titlecontrol';
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
import { getCodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { localize } from 'vs/nls';
import { createActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ExecuteCommandAction, IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
@@ -32,13 +32,14 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs';
import { BreadcrumbsControl, IBreadcrumbsControlOptions } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
import { EDITOR_TITLE_HEIGHT, IEditorGroupsAccessor, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
import { EditorCommandsContextActionRunner, IEditorCommandsContext, IEditorInput, toResource, IEditorPartOptions, SideBySideEditor, EditorPinnedContext } from 'vs/workbench/common/editor';
import { EditorCommandsContextActionRunner, IEditorCommandsContext, IEditorInput, toResource, IEditorPartOptions, SideBySideEditor, EditorPinnedContext, EditorStickyContext } from 'vs/workbench/common/editor';
import { ResourceContextKey } from 'vs/workbench/common/resources';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { IFileService } from 'vs/platform/files/common/files';
import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types';
import { isFirefox } from 'vs/base/browser/browser';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
export interface IToolbarActions {
primary: IAction[];
@@ -59,6 +60,7 @@ export abstract class TitleControl extends Themable {
private resourceContext: ResourceContextKey;
private editorPinnedContext: IContextKey<boolean>;
private editorStickyContext: IContextKey<boolean>;
private readonly editorToolBarMenuDisposables = this._register(new DisposableStore());
@@ -86,6 +88,7 @@ export abstract class TitleControl extends Themable {
this.resourceContext = this._register(instantiationService.createInstance(ResourceContextKey));
this.editorPinnedContext = EditorPinnedContext.bindTo(contextKeyService);
this.editorStickyContext = EditorStickyContext.bindTo(contextKeyService);
this.contextMenu = this._register(this.menuService.createMenu(MenuId.EditorTitleContext, this.contextKeyService));
@@ -222,6 +225,7 @@ export abstract class TitleControl extends Themable {
// Update contexts
this.resourceContext.set(this.group.activeEditor ? withUndefinedAsNull(toResource(this.group.activeEditor, { supportSideBySide: SideBySideEditor.MASTER })) : null);
this.editorPinnedContext.set(this.group.activeEditor ? this.group.isPinned(this.group.activeEditor) : false);
this.editorStickyContext.set(this.group.activeEditor ? this.group.isSticky(this.group.activeEditor) : false);
// Editor actions require the editor control to be there, so we retrieve it via service
const activeEditorPane = this.group.activeEditorPane;
@@ -266,10 +270,8 @@ export abstract class TitleControl extends Themable {
// If tabs are disabled, treat dragging as if an editor tab was dragged
let hasDataTransfer = false;
if (!this.accessor.partOptions.showTabs) {
const resource = this.group.activeEditor ? toResource(this.group.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null;
if (resource) {
this.instantiationService.invokeFunction(fillResourceDataTransfers, [resource], e);
hasDataTransfer = true;
if (this.group.activeEditor) {
hasDataTransfer = this.doFillResourceDataTransfers(this.group.activeEditor, e);
}
}
@@ -295,6 +297,31 @@ export abstract class TitleControl extends Themable {
}));
}
protected doFillResourceDataTransfers(editor: IEditorInput, e: DragEvent): boolean {
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
if (!resource) {
return false;
}
const editorOptions: ITextEditorOptions = {
viewState: (() => {
if (this.group.activeEditor === editor) {
const activeControl = this.group.activeEditorPane?.getControl();
if (isCodeEditor(activeControl)) {
return withNullAsUndefined(activeControl.saveViewState());
}
}
return undefined;
})(),
sticky: this.group.isSticky(editor)
};
this.instantiationService.invokeFunction(fillResourceDataTransfers, [resource], () => editorOptions, e);
return true;
}
protected onContextMenu(editor: IEditorInput, e: Event, node: HTMLElement): void {
// Update contexts based on editor picked and remember previous to restore
@@ -302,6 +329,8 @@ export abstract class TitleControl extends Themable {
this.resourceContext.set(withUndefinedAsNull(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER })));
const currentPinnedContext = !!this.editorPinnedContext.get();
this.editorPinnedContext.set(this.group.isPinned(editor));
const currentStickyContext = !!this.editorStickyContext.get();
this.editorStickyContext.set(this.group.isSticky(editor));
// Find target anchor
let anchor: HTMLElement | { x: number, y: number } = node;
@@ -325,6 +354,7 @@ export abstract class TitleControl extends Themable {
// restore previous contexts
this.resourceContext.set(currentResourceContext || null);
this.editorPinnedContext.set(currentPinnedContext);
this.editorStickyContext.set(currentStickyContext);
// restore focus to active group
this.accessor.activeGroup.focus();
@@ -351,12 +381,14 @@ export abstract class TitleControl extends Themable {
abstract closeEditors(editors: IEditorInput[]): void;
abstract closeAllEditors(): void;
abstract moveEditor(editor: IEditorInput, fromIndex: number, targetIndex: number): void;
abstract pinEditor(editor: IEditorInput): void;
abstract stickEditor(editor: IEditorInput): void;
abstract unstickEditor(editor: IEditorInput): void;
abstract setActive(isActive: boolean): void;
abstract updateEditorLabel(editor: IEditorInput): void;
@@ -207,7 +207,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
if (isActive) {
if (!activePanel) {
// Only try to open the panel if it has been created and visible
if (!activePanel && this.element && this.layoutService.isVisible(Parts.PANEL_PART)) {
this.doOpenPanel(panel.id);
}
@@ -22,7 +22,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { isThemeColor } from 'vs/editor/common/editorCommon';
import { Color } from 'vs/base/common/color';
import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, removeClass, EventType, hide, show, removeClasses } from 'vs/base/browser/dom';
import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, removeClass, EventType, hide, show, removeClasses, isAncestor } from 'vs/base/browser/dom';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
@@ -35,6 +35,11 @@ import { assertIsDefined } from 'vs/base/common/types';
import { Emitter } from 'vs/base/common/event';
import { Command } from 'vs/editor/common/modes';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
interface IPendingStatusbarEntry {
id: string;
@@ -51,8 +56,11 @@ interface IStatusbarViewModelEntry {
alignment: StatusbarAlignment;
priority: number;
container: HTMLElement;
labelContainer: HTMLElement;
}
const CONTEXT_STATUS_BAR_FOCUSED = new RawContextKey<boolean>('statusBarFocused', false);
class StatusbarViewModel extends Disposable {
static readonly HIDDEN_ENTRIES_KEY = 'workbench.statusbar.hidden';
@@ -188,6 +196,40 @@ class StatusbarViewModel extends Disposable {
return this._entries.filter(entry => entry.alignment === alignment);
}
focusNextEntry(): void {
this.focusEntry(+1, 0);
}
focusPreviousEntry(): void {
this.focusEntry(-1, this.entries.length - 1);
}
private focusEntry(delta: number, restartPosition: number): void {
const getVisibleEntry = (start: number) => {
let indexToFocus = start;
let entry = (indexToFocus >= 0 && indexToFocus < this._entries.length) ? this._entries[indexToFocus] : undefined;
while (entry && this.isHidden(entry.id)) {
indexToFocus += delta;
entry = (indexToFocus >= 0 && indexToFocus < this._entries.length) ? this._entries[indexToFocus] : undefined;
}
return entry;
};
const focused = this._entries.find(entry => isAncestor(document.activeElement, entry.container));
if (focused) {
const entry = getVisibleEntry(this._entries.indexOf(focused) + delta);
if (entry) {
entry.labelContainer.focus();
return;
}
}
const entry = getVisibleEntry(restartPosition);
if (entry) {
entry.labelContainer.focus();
}
}
private updateVisibility(id: string, trigger: boolean): void;
private updateVisibility(entry: IStatusbarViewModelEntry, trigger: boolean): void;
private updateVisibility(arg1: string | IStatusbarViewModelEntry, trigger: boolean): void {
@@ -355,6 +397,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
@IStorageService private readonly storageService: IStorageService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
) {
super(Parts.STATUSBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
@@ -415,7 +458,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
this.appendOneStatusbarEntry(itemContainer, alignment, priority);
// Add to view model
const viewModelEntry: IStatusbarViewModelEntry = { id, name, alignment, priority, container: itemContainer };
const viewModelEntry: IStatusbarViewModelEntry = { id, name, alignment, priority, container: itemContainer, labelContainer: item.labelContainer };
const viewModelEntryDispose = this.viewModel.add(viewModelEntry);
return {
@@ -442,9 +485,21 @@ export class StatusbarPart extends Part implements IStatusbarService {
}
}
focusNextEntry(): void {
this.viewModel.focusNextEntry();
}
focusPreviousEntry(): void {
this.viewModel.focusPreviousEntry();
}
createContentArea(parent: HTMLElement): HTMLElement {
this.element = parent;
// Track focus within container
const scopedContextKeyService = this.contextKeyService.createScoped(this.element);
CONTEXT_STATUS_BAR_FOCUSED.bindTo(scopedContextKeyService).set(true);
// Left items container
this.leftItemsContainer = document.createElement('div');
addClasses(this.leftItemsContainer, 'left-items', 'items-container');
@@ -645,13 +700,14 @@ class StatusbarEntryItem extends Disposable {
private entry!: IStatusbarEntry;
private labelContainer!: HTMLElement;
labelContainer!: HTMLElement;
private label!: CodiconLabel;
private readonly foregroundListener = this._register(new MutableDisposable());
private readonly backgroundListener = this._register(new MutableDisposable());
private readonly commandListener = this._register(new MutableDisposable());
private readonly commandMouseListener = this._register(new MutableDisposable());
private readonly commandKeyboardListener = this._register(new MutableDisposable());
constructor(
private container: HTMLElement,
@@ -711,11 +767,18 @@ class StatusbarEntryItem extends Disposable {
// Update: Command
if (!this.entry || entry.command !== this.entry.command) {
this.commandListener.clear();
this.commandMouseListener.clear();
this.commandKeyboardListener.clear();
const command = entry.command;
if (command) {
this.commandListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command));
this.commandMouseListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command));
this.commandKeyboardListener.value = addDisposableListener(this.labelContainer, EventType.KEY_UP, e => {
const event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {
this.executeCommand(command);
}
});
removeClass(this.labelContainer, 'disabled');
} else {
@@ -814,7 +877,8 @@ class StatusbarEntryItem extends Disposable {
dispose(this.foregroundListener);
dispose(this.backgroundListener);
dispose(this.commandListener);
dispose(this.commandMouseListener);
dispose(this.commandKeyboardListener);
}
}
@@ -822,6 +886,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND);
if (statusBarItemHoverBackground) {
collector.addRule(`.monaco-workbench .part.statusbar > .items-container > .statusbar-item a:hover { background-color: ${statusBarItemHoverBackground}; }`);
collector.addRule(`.monaco-workbench .part.statusbar > .items-container > .statusbar-item a:focus { background-color: ${statusBarItemHoverBackground}; }`);
}
const statusBarItemActiveBackground = theme.getColor(STATUS_BAR_ITEM_ACTIVE_BACKGROUND);
@@ -846,3 +911,27 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
});
registerSingleton(IStatusbarService, StatusbarPart);
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.statusBar.focusPrevious',
weight: KeybindingWeight.WorkbenchContrib,
primary: KeyCode.LeftArrow,
secondary: [KeyCode.UpArrow],
when: CONTEXT_STATUS_BAR_FOCUSED,
handler: (accessor: ServicesAccessor) => {
const statusBarService = accessor.get(IStatusbarService);
statusBarService.focusPreviousEntry();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.statusBar.focusNext',
weight: KeybindingWeight.WorkbenchContrib,
primary: KeyCode.RightArrow,
secondary: [KeyCode.DownArrow],
when: CONTEXT_STATUS_BAR_FOCUSED,
handler: (accessor: ServicesAccessor) => {
const statusBarService = accessor.get(IStatusbarService);
statusBarService.focusNextEntry();
}
});
@@ -934,17 +934,21 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
getContextMenuActions(viewDescriptor?: IViewDescriptor): IAction[] {
const result: IAction[] = [];
let showHide = true;
if (!viewDescriptor && this.isViewMergedWithContainer()) {
viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.panes[0].id) || undefined;
showHide = false;
}
if (viewDescriptor) {
if (showHide) {
result.push(<IAction>{
id: `${viewDescriptor.id}.removeView`,
label: nls.localize('hideView', "Hide"),
enabled: viewDescriptor.canToggleVisibility,
run: () => this.toggleViewVisibility(viewDescriptor!.id)
});
}
const view = this.getView(viewDescriptor.id);
if (view) {
result.push(...view.getContextMenuActions());
@@ -955,7 +959,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
id: `${viewDescriptor.id}.toggleVisibility`,
label: viewDescriptor.name,
checked: this.viewContainerModel.isVisible(viewDescriptor.id),
enabled: viewDescriptor.canToggleVisibility,
enabled: viewDescriptor.canToggleVisibility && (!this.viewContainerModel.isVisible(viewDescriptor.id) || this.viewContainerModel.visibleViewDescriptors.length > 1),
run: () => this.toggleViewVisibility(viewDescriptor.id)
}));

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