mirror of
https://github.com/Microsoft/vscode
synced 2024-10-05 19:02:54 +00:00
Merge branch 'main' into tyriar/120077
This commit is contained in:
commit
2584b60112
|
@ -16,6 +16,7 @@
|
|||
"eqeqeq": "warn",
|
||||
"no-buffer-constructor": "warn",
|
||||
"no-caller": "warn",
|
||||
"no-case-declarations": "warn",
|
||||
"no-debugger": "warn",
|
||||
"no-duplicate-case": "warn",
|
||||
"no-duplicate-imports": "warn",
|
||||
|
|
|
@ -219,6 +219,14 @@ steps:
|
|||
timeoutInMinutes: 7
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
|
||||
yarn smoketest-no-compile --web --headless
|
||||
timeoutInMinutes: 10
|
||||
displayName: Run smoke tests (Browser, Chromium)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)
|
||||
|
@ -238,14 +246,6 @@ steps:
|
|||
displayName: Run smoke tests (Remote)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-darwin" \
|
||||
yarn smoketest-no-compile --web --headless
|
||||
timeoutInMinutes: 10
|
||||
displayName: Run smoke tests (Browser, Chromium)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: crash-dump-macos-$(VSCODE_ARCH)
|
||||
|
|
|
@ -217,6 +217,14 @@ steps:
|
|||
timeoutInMinutes: 7
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \
|
||||
yarn smoketest-no-compile --web --headless --electronArgs="--disable-dev-shm-usage --use-gl=swiftshader"
|
||||
timeoutInMinutes: 10
|
||||
displayName: Run smoke tests (Browser, Chromium)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
APP_PATH=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)
|
||||
|
@ -234,14 +242,6 @@ steps:
|
|||
displayName: Run smoke tests (Remote)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_REMOTE_SERVER_PATH="$(agent.builddirectory)/vscode-reh-web-linux-$(VSCODE_ARCH)" \
|
||||
yarn smoketest-no-compile --web --headless --electronArgs="--disable-dev-shm-usage --use-gl=swiftshader"
|
||||
timeoutInMinutes: 10
|
||||
displayName: Run smoke tests (Browser, Chromium)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: crash-dump-linux-$(VSCODE_ARCH)
|
||||
|
|
|
@ -206,6 +206,15 @@ steps:
|
|||
displayName: Compile smoke tests
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"
|
||||
exec { yarn smoketest-no-compile --web --headless }
|
||||
displayName: Run smoke tests (Browser, Chromium)
|
||||
timeoutInMinutes: 10
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
@ -225,15 +234,6 @@ steps:
|
|||
timeoutInMinutes: 10
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-reh-web-win32-$(VSCODE_ARCH)"
|
||||
exec { yarn smoketest-no-compile --web --headless }
|
||||
displayName: Run smoke tests (Browser, Chromium)
|
||||
timeoutInMinutes: 10
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64'))
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
exec {.\build\azure-pipelines\win32\listprocesses.bat }
|
||||
|
|
|
@ -29,6 +29,7 @@ const extensionsPath = path.join(path.dirname(__dirname), 'extensions');
|
|||
// ignore: ['**/out/**', '**/node_modules/**']
|
||||
// });
|
||||
const compilations = [
|
||||
'authentication-proxy/tsconfig.json',
|
||||
'configuration-editing/build/tsconfig.json',
|
||||
'configuration-editing/tsconfig.json',
|
||||
'css-language-features/client/tsconfig.json',
|
||||
|
|
|
@ -223,6 +223,8 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa
|
|||
return true; // web: ship all extensions for now
|
||||
}
|
||||
|
||||
// Skip shipping UI extensions because the client side will have them anyways
|
||||
// and they'd just increase the download without being used
|
||||
const manifest = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, extensionPath)).toString());
|
||||
return !isUIExtension(manifest);
|
||||
}).map((extensionPath) => path.basename(path.dirname(extensionPath)))
|
||||
|
|
|
@ -54,14 +54,14 @@
|
|||
integrity sha1-Rs/+oRmgoAMxKiHC2bVijLX81EI=
|
||||
|
||||
"@types/node@14.x":
|
||||
version "14.17.27"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.27.tgz#5054610d37bb5f6e21342d0e6d24c494231f3b85"
|
||||
integrity sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==
|
||||
version "14.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.0.tgz#98df2397f6936bfbff4f089e40e06fa5dd88d32a"
|
||||
integrity sha512-0GeIl2kmVMXEnx8tg1SlG6Gg8vkqirrW752KqolYo1PHevhhZN3bhJ67qHj+bQaINhX0Ra3TlWwRvMCd9iEfNQ==
|
||||
|
||||
"@vscode/emmet-helper@^2.3.0":
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@vscode/emmet-helper/-/emmet-helper-2.8.2.tgz#9b2ce4fdd62cf3fda45cf8af67c012cfce55edc9"
|
||||
integrity sha512-A/+pkBYQq2JTow1A2flfTmEOmiF780KpdkoX7VBjQ7wujeA+CFUPd17YdeIa9aim20+J5Jp7SFujPDwVFiQucQ==
|
||||
version "2.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@vscode/emmet-helper/-/emmet-helper-2.8.3.tgz#f7c2b4a4751d03bcf2b421f0fce5b521a0f64a18"
|
||||
integrity sha512-dkTSL+BaBBS8gFgPm/GMOU+XfxaMyI+Fl1IUYxEi8Iv24RfHf9/q2eCpV2hs7sncLcoKWEbMYe5gv4Ppmp2Oxw==
|
||||
dependencies:
|
||||
emmet "^2.3.0"
|
||||
jsonc-parser "^2.3.0"
|
||||
|
@ -71,9 +71,9 @@
|
|||
vscode-uri "^2.1.2"
|
||||
|
||||
emmet@^2.3.0:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/emmet/-/emmet-2.3.4.tgz#5ba0d7a5569a68c7697dfa890c772e4f3179d123"
|
||||
integrity sha512-3IqSwmO+N2ZGeuhDyhV/TIOJFUbkChi53bcasSNRE7Yd+4eorbbYz4e53TpMECt38NtYkZNupQCZRlwdAYA42A==
|
||||
version "2.3.5"
|
||||
resolved "https://registry.yarnpkg.com/emmet/-/emmet-2.3.5.tgz#7f80f9c3db6831d1ee2b458717b9c36a074b1a47"
|
||||
integrity sha512-LcWfTamJnXIdMfLvJEC5Ld3hY5/KHXgv1L1bp6I7eEvB0ZhacHZ1kX0BYovJ8FroEsreLcq7n7kZhRMsf6jkXQ==
|
||||
dependencies:
|
||||
"@emmetio/abbreviation" "^2.2.2"
|
||||
"@emmetio/css-abbreviation" "^2.1.4"
|
||||
|
@ -103,9 +103,9 @@ queue@6.0.2:
|
|||
inherits "~2.0.3"
|
||||
|
||||
vscode-languageserver-textdocument@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.2.tgz#2f9f6bd5b5eb3d8e21424c0c367009216f016236"
|
||||
integrity sha512-T7uPC18+f8mYE4lbVZwb3OSmvwTZm3cuFhrdx9Bn2l11lmp3SvSuSVjy2JtvrghzjAo4G6Trqny2m9XGnFnWVA==
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.3.tgz#879f2649bfa5a6e07bc8b392c23ede2dfbf43eff"
|
||||
integrity sha512-ynEGytvgTb6HVSUwPJIAZgiHQmPCx8bZ8w5um5Lz+q5DjP0Zj8wTFhQpyg8xaMvefDytw2+HH5yzqS+FhsR28A==
|
||||
|
||||
vscode-languageserver-types@^3.15.1:
|
||||
version "3.16.0"
|
||||
|
|
|
@ -2821,7 +2821,7 @@ export class CommandCenter {
|
|||
type = 'warning';
|
||||
options.modal = false;
|
||||
break;
|
||||
case GitErrorCodes.AuthenticationFailed:
|
||||
case GitErrorCodes.AuthenticationFailed: {
|
||||
const regex = /Authentication failed for '(.*)'/i;
|
||||
const match = regex.exec(err.stderr || String(err));
|
||||
|
||||
|
@ -2829,12 +2829,13 @@ export class CommandCenter {
|
|||
? localize('auth failed specific', "Failed to authenticate to git remote:\n\n{0}", match[1])
|
||||
: localize('auth failed', "Failed to authenticate to git remote.");
|
||||
break;
|
||||
}
|
||||
case GitErrorCodes.NoUserNameConfigured:
|
||||
case GitErrorCodes.NoUserEmailConfigured:
|
||||
message = localize('missing user info', "Make sure you configure your 'user.name' and 'user.email' in git.");
|
||||
choices.set(localize('learn more', "Learn More"), () => commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup')));
|
||||
break;
|
||||
default:
|
||||
default: {
|
||||
const hint = (err.stderr || err.message || String(err))
|
||||
.replace(/^error: /mi, '')
|
||||
.replace(/^> husky.*$/mi, '')
|
||||
|
@ -2847,6 +2848,7 @@ export class CommandCenter {
|
|||
: localize('git error', "Git error");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
|
|
|
@ -1196,7 +1196,7 @@ export class Repository {
|
|||
break;
|
||||
|
||||
// Rename contains two paths, the second one is what the file is renamed/copied to.
|
||||
case 'R':
|
||||
case 'R': {
|
||||
if (index >= entries.length) {
|
||||
break;
|
||||
}
|
||||
|
@ -1215,7 +1215,7 @@ export class Repository {
|
|||
});
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
default:
|
||||
// Unknown status
|
||||
break entriesLoop;
|
||||
|
|
|
@ -664,7 +664,7 @@ class ResourceCommandResolver {
|
|||
case Status.MODIFIED:
|
||||
case Status.UNTRACKED:
|
||||
case Status.IGNORED:
|
||||
case Status.INTENT_TO_ADD:
|
||||
case Status.INTENT_TO_ADD: {
|
||||
const uriString = resource.resourceUri.toString();
|
||||
const [indexStatus] = this.repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
|
||||
|
||||
|
@ -673,7 +673,7 @@ class ResourceCommandResolver {
|
|||
}
|
||||
|
||||
return resource.resourceUri;
|
||||
|
||||
}
|
||||
case Status.BOTH_ADDED:
|
||||
case Status.BOTH_MODIFIED:
|
||||
return resource.resourceUri;
|
||||
|
|
18
extensions/github-authentication/src/common/env.ts
Normal file
18
extensions/github-authentication/src/common/env.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Uri } from 'vscode';
|
||||
|
||||
const VALID_DESKTOP_CALLBACK_SCHEMES = [
|
||||
'vscode',
|
||||
'vscode-insiders',
|
||||
'code-oss',
|
||||
'vscode-wsl',
|
||||
'vscode-exploration'
|
||||
];
|
||||
|
||||
// This comes from the GitHub Authentication server
|
||||
export function isSupportedEnvironment(url: Uri): boolean {
|
||||
return VALID_DESKTOP_CALLBACK_SCHEMES.includes(url.scheme) || url.authority.endsWith('vscode.dev') || url.authority.endsWith('github.dev');
|
||||
}
|
|
@ -43,7 +43,11 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid
|
|||
this._telemetryReporter = new ExperimentationTelemetry(context, new TelemetryReporter(name, version, aiKey));
|
||||
|
||||
if (this.type === AuthProviderType.github) {
|
||||
this._githubServer = new GitHubServer(this._logger, this._telemetryReporter);
|
||||
this._githubServer = new GitHubServer(
|
||||
// We only can use the Device Code flow when we are running with a remote extension host.
|
||||
context.extension.extensionKind === vscode.ExtensionKind.Workspace,
|
||||
this._logger,
|
||||
this._telemetryReporter);
|
||||
} else {
|
||||
this._githubServer = new GitHubEnterpriseServer(this._logger, this._telemetryReporter);
|
||||
}
|
||||
|
@ -216,7 +220,7 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid
|
|||
return session;
|
||||
} catch (e) {
|
||||
// If login was cancelled, do not notify user.
|
||||
if (e === 'Cancelled') {
|
||||
if (e === 'Cancelled' || e.message === 'Cancelled') {
|
||||
/* __GDPR__
|
||||
"loginCancelled" : { }
|
||||
*/
|
||||
|
|
|
@ -11,8 +11,10 @@ import { PromiseAdapter, promiseFromEvent } from './common/utils';
|
|||
import { ExperimentationTelemetry } from './experimentationService';
|
||||
import { AuthProviderType } from './github';
|
||||
import { Log } from './common/logger';
|
||||
import { isSupportedEnvironment } from './common/env';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
const CLIENT_ID = '01ab8ac9400c4e429b23';
|
||||
|
||||
const NETWORK_ERROR = 'network error';
|
||||
const AUTH_RELAY_SERVER = 'vscode-auth.github.com';
|
||||
|
@ -45,6 +47,13 @@ export interface IGitHubServer extends vscode.Disposable {
|
|||
type: AuthProviderType;
|
||||
}
|
||||
|
||||
interface IGitHubDeviceCodeResponse {
|
||||
device_code: string;
|
||||
user_code: string;
|
||||
verification_uri: string;
|
||||
interval: number;
|
||||
}
|
||||
|
||||
async function getScopes(token: string, serverUri: vscode.Uri, logger: Log): Promise<string[]> {
|
||||
try {
|
||||
logger.info('Getting token scopes...');
|
||||
|
@ -105,7 +114,7 @@ export class GitHubServer implements IGitHubServer {
|
|||
private _disposable: vscode.Disposable;
|
||||
private _uriHandler = new UriEventHandler(this._logger);
|
||||
|
||||
constructor(private readonly _logger: Log, private readonly _telemetryReporter: ExperimentationTelemetry) {
|
||||
constructor(private readonly _supportDeviceCodeFlow: boolean, private readonly _logger: Log, private readonly _telemetryReporter: ExperimentationTelemetry) {
|
||||
this._disposable = vscode.Disposable.from(
|
||||
vscode.commands.registerCommand(this._statusBarCommandId, () => this.manuallyProvideUri()),
|
||||
vscode.window.registerUriHandler(this._uriHandler));
|
||||
|
@ -115,10 +124,6 @@ export class GitHubServer implements IGitHubServer {
|
|||
this._disposable.dispose();
|
||||
}
|
||||
|
||||
private isTestEnvironment(url: vscode.Uri): boolean {
|
||||
return /\.azurewebsites\.net$/.test(url.authority) || url.authority.startsWith('localhost:');
|
||||
}
|
||||
|
||||
// TODO@joaomoreno TODO@TylerLeonhardt
|
||||
private async isNoCorsEnvironment(): Promise<boolean> {
|
||||
const uri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/dummy`));
|
||||
|
@ -130,9 +135,12 @@ export class GitHubServer implements IGitHubServer {
|
|||
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
|
||||
|
||||
if (this.isTestEnvironment(callbackUri)) {
|
||||
const token = await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true });
|
||||
if (!token) { throw new Error('Sign in failed: No token provided'); }
|
||||
if (!isSupportedEnvironment(callbackUri)) {
|
||||
const token = this._supportDeviceCodeFlow
|
||||
? await this.doDeviceCodeFlow(scopes)
|
||||
: await vscode.window.showInputBox({ prompt: 'GitHub Personal Access Token', ignoreFocusOut: true });
|
||||
|
||||
if (!token) { throw new Error('No token provided'); }
|
||||
|
||||
const tokenScopes = await getScopes(token, this.getServerUri('/'), this._logger); // Example: ['repo', 'user']
|
||||
const scopesList = scopes.split(' '); // Example: 'read:user repo user:email'
|
||||
|
@ -187,6 +195,96 @@ export class GitHubServer implements IGitHubServer {
|
|||
});
|
||||
}
|
||||
|
||||
private async doDeviceCodeFlow(scopes: string): Promise<string> {
|
||||
// Get initial device code
|
||||
const uri = `https://github.com/login/device/code?client_id=${CLIENT_ID}&scope=${scopes}`;
|
||||
const result = await fetch(uri, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
}
|
||||
});
|
||||
if (!result.ok) {
|
||||
throw new Error(`Failed to get one-time code: ${await result.text()}`);
|
||||
}
|
||||
|
||||
const json = await result.json() as IGitHubDeviceCodeResponse;
|
||||
|
||||
await vscode.env.clipboard.writeText(json.user_code);
|
||||
|
||||
const modalResult = await vscode.window.showInformationMessage(
|
||||
localize('code.title', "Your Code: {0}", json.user_code),
|
||||
{
|
||||
modal: true,
|
||||
detail: localize('code.detail', "The above one-time code has been copied to your clipboard. To finish authenticating, paste it on GitHub.")
|
||||
}, 'Continue to GitHub');
|
||||
|
||||
if (modalResult !== 'Continue to GitHub') {
|
||||
throw new Error('Cancelled');
|
||||
}
|
||||
|
||||
const uriToOpen = await vscode.env.asExternalUri(vscode.Uri.parse(json.verification_uri));
|
||||
await vscode.env.openExternal(uriToOpen);
|
||||
|
||||
return await vscode.window.withProgress<string>({
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
cancellable: true,
|
||||
title: localize(
|
||||
'progress',
|
||||
"Open [{0}]({0}) in a new tab and paste your one-time code: {1}",
|
||||
json.verification_uri,
|
||||
json.user_code)
|
||||
}, async (_, token) => {
|
||||
return await this.waitForDeviceCodeAccessToken(json, token);
|
||||
});
|
||||
}
|
||||
|
||||
private async waitForDeviceCodeAccessToken(
|
||||
json: IGitHubDeviceCodeResponse,
|
||||
token: vscode.CancellationToken
|
||||
): Promise<string> {
|
||||
|
||||
const refreshTokenUri = `https://github.com/login/oauth/access_token?client_id=${CLIENT_ID}&device_code=${json.device_code}&grant_type=urn:ietf:params:oauth:grant-type:device_code`;
|
||||
|
||||
// Try for 2 minutes
|
||||
const attempts = 120 / json.interval;
|
||||
for (let i = 0; i < attempts; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, json.interval * 1000));
|
||||
if (token.isCancellationRequested) {
|
||||
throw new Error('Cancelled');
|
||||
}
|
||||
let accessTokenResult;
|
||||
try {
|
||||
accessTokenResult = await fetch(refreshTokenUri, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
}
|
||||
});
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!accessTokenResult.ok) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const accessTokenJson = await accessTokenResult.json();
|
||||
|
||||
if (accessTokenJson.error === 'authorization_pending') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (accessTokenJson.error) {
|
||||
throw new Error(accessTokenJson.error_description);
|
||||
}
|
||||
|
||||
return accessTokenJson.access_token;
|
||||
}
|
||||
|
||||
throw new Error('Cancelled');
|
||||
}
|
||||
|
||||
private exchangeCodeForToken: (scopes: string) => PromiseAdapter<vscode.Uri, string> =
|
||||
(scopes) => async (uri, resolve, reject) => {
|
||||
const query = parseQuery(uri);
|
||||
|
|
|
@ -126,14 +126,14 @@
|
|||
"explorer/context": [
|
||||
{
|
||||
"command": "markdown.showPreview",
|
||||
"when": "resourceLangId == markdown",
|
||||
"when": "resourceLangId == markdown && !hasCustomMarkdownPreview",
|
||||
"group": "navigation"
|
||||
}
|
||||
],
|
||||
"editor/title/context": [
|
||||
{
|
||||
"command": "markdown.showPreview",
|
||||
"when": "resourceLangId == markdown",
|
||||
"when": "resourceLangId == markdown && !hasCustomMarkdownPreview",
|
||||
"group": "1_open"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -124,7 +124,7 @@ window.addEventListener('message', async event => {
|
|||
}
|
||||
return;
|
||||
|
||||
case 'updateContent':
|
||||
case 'updateContent': {
|
||||
const root = document.querySelector('.markdown-body')!;
|
||||
|
||||
const parser = new DOMParser();
|
||||
|
@ -216,6 +216,7 @@ window.addEventListener('message', async event => {
|
|||
|
||||
window.dispatchEvent(new CustomEvent('vscode.markdown.updateContent'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ export function createServer(nonce: string) {
|
|||
const server = http.createServer(function (req, res) {
|
||||
const reqUrl = url.parse(req.url!, /* parseQueryString */ true);
|
||||
switch (reqUrl.pathname) {
|
||||
case '/signin':
|
||||
case '/signin': {
|
||||
const receivedNonce = ((reqUrl.query.nonce as string) || '').replace(/ /g, '+');
|
||||
if (receivedNonce === nonce) {
|
||||
deferredRedirect.resolve({ req, res });
|
||||
|
@ -129,6 +129,7 @@ export function createServer(nonce: string) {
|
|||
deferredRedirect.resolve({ err, res });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '/':
|
||||
sendFile(res, path.join(__dirname, '../media/auth.html'), 'text/html; charset=utf-8');
|
||||
break;
|
||||
|
|
|
@ -69,11 +69,12 @@ export class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLens
|
|||
}
|
||||
|
||||
switch (item.kind) {
|
||||
case PConst.Kind.function:
|
||||
case PConst.Kind.function: {
|
||||
const showOnAllFunctions = vscode.workspace.getConfiguration(this.modeId).get<boolean>('referencesCodeLens.showOnAllFunctions');
|
||||
if (showOnAllFunctions) {
|
||||
return getSymbolRange(document, item);
|
||||
}
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case PConst.Kind.const:
|
||||
|
|
|
@ -816,10 +816,10 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<
|
|||
case '#': // Workaround for https://github.com/microsoft/TypeScript/issues/36367
|
||||
return this.client.apiVersion.lt(API.v381) ? undefined : '#';
|
||||
|
||||
case ' ':
|
||||
case ' ': {
|
||||
const space: Proto.CompletionsTriggerCharacter = ' ';
|
||||
return this.client.apiVersion.gte(API.v430) ? space : undefined;
|
||||
|
||||
}
|
||||
case '.':
|
||||
case '"':
|
||||
case '\'':
|
||||
|
|
|
@ -167,7 +167,7 @@ class BufferSynchronizer {
|
|||
|
||||
private updatePending(resource: vscode.Uri, op: BufferOperation): boolean {
|
||||
switch (op.type) {
|
||||
case BufferOperationType.Close:
|
||||
case BufferOperationType.Close: {
|
||||
const existing = this._pending.get(resource);
|
||||
switch (existing?.type) {
|
||||
case BufferOperationType.Open:
|
||||
|
@ -175,6 +175,7 @@ class BufferSynchronizer {
|
|||
return false; // Open then close. No need to do anything
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._pending.has(resource)) {
|
||||
|
|
|
@ -148,7 +148,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe
|
|||
}
|
||||
break;
|
||||
|
||||
case 'event':
|
||||
case 'event': {
|
||||
const event = message as Proto.Event;
|
||||
if (event.event === 'requestCompleted') {
|
||||
const seq = (event as Proto.RequestCompletedEvent).body.request_seq;
|
||||
|
@ -162,7 +162,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe
|
|||
this._onEvent.fire(event);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unknown message type ${message.type} received`);
|
||||
}
|
||||
|
|
|
@ -866,7 +866,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
|||
switch (event.event) {
|
||||
case EventName.syntaxDiag:
|
||||
case EventName.semanticDiag:
|
||||
case EventName.suggestionDiag:
|
||||
case EventName.suggestionDiag: {
|
||||
// This event also roughly signals that projects have been loaded successfully (since the TS server is synchronous)
|
||||
this.loadingIndicator.reset();
|
||||
|
||||
|
@ -879,34 +879,32 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
|||
});
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case EventName.configFileDiag:
|
||||
this._onConfigDiagnosticsReceived.fire(event as Proto.ConfigFileDiagnosticEvent);
|
||||
break;
|
||||
|
||||
case EventName.telemetry:
|
||||
{
|
||||
const body = (event as Proto.TelemetryEvent).body;
|
||||
this.dispatchTelemetryEvent(body);
|
||||
break;
|
||||
case EventName.telemetry: {
|
||||
const body = (event as Proto.TelemetryEvent).body;
|
||||
this.dispatchTelemetryEvent(body);
|
||||
break;
|
||||
}
|
||||
case EventName.projectLanguageServiceState: {
|
||||
const body = (event as Proto.ProjectLanguageServiceStateEvent).body!;
|
||||
if (this.serverState.type === ServerState.Type.Running) {
|
||||
this.serverState.updateLanguageServiceEnabled(body.languageServiceEnabled);
|
||||
}
|
||||
case EventName.projectLanguageServiceState:
|
||||
{
|
||||
const body = (event as Proto.ProjectLanguageServiceStateEvent).body!;
|
||||
if (this.serverState.type === ServerState.Type.Running) {
|
||||
this.serverState.updateLanguageServiceEnabled(body.languageServiceEnabled);
|
||||
}
|
||||
this._onProjectLanguageServiceStateChanged.fire(body);
|
||||
break;
|
||||
}
|
||||
case EventName.projectsUpdatedInBackground:
|
||||
this._onProjectLanguageServiceStateChanged.fire(body);
|
||||
break;
|
||||
}
|
||||
case EventName.projectsUpdatedInBackground: {
|
||||
this.loadingIndicator.reset();
|
||||
|
||||
const body = (event as Proto.ProjectsUpdatedInBackgroundEvent).body;
|
||||
const resources = body.openFiles.map(file => this.toResource(file));
|
||||
this.bufferSyncSupport.getErr(resources);
|
||||
break;
|
||||
|
||||
}
|
||||
case EventName.beginInstallTypes:
|
||||
this._onDidBeginInstallTypings.fire((event as Proto.BeginInstallTypesEvent).body);
|
||||
break;
|
||||
|
@ -936,7 +934,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
|||
private dispatchTelemetryEvent(telemetryData: Proto.TelemetryEventBody): void {
|
||||
const properties: { [key: string]: string } = Object.create(null);
|
||||
switch (telemetryData.telemetryEventName) {
|
||||
case 'typingsInstalled':
|
||||
case 'typingsInstalled': {
|
||||
const typingsInstalledPayload: Proto.TypingsInstalledTelemetryEventPayload = (telemetryData.payload as Proto.TypingsInstalledTelemetryEventPayload);
|
||||
properties['installedPackages'] = typingsInstalledPayload.installedPackages;
|
||||
|
||||
|
@ -947,8 +945,8 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
|||
properties['typingsInstallerVersion'] = typingsInstalledPayload.typingsInstallerVersion;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
const payload = telemetryData.payload;
|
||||
if (payload) {
|
||||
Object.keys(payload).forEach((key) => {
|
||||
|
@ -962,6 +960,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
|||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (telemetryData.telemetryEventName === 'projectInfo') {
|
||||
if (this.serverState.type === ServerState.Type.Running) {
|
||||
|
|
|
@ -49,7 +49,7 @@ function getTagBodyText(
|
|||
|
||||
const text = convertLinkTags(tag.text, filePathConverter);
|
||||
switch (tag.name) {
|
||||
case 'example':
|
||||
case 'example': {
|
||||
// check for caption tags, fix for #79704
|
||||
const captionTagMatches = text.match(/<caption>(.*?)<\/caption>\s*(\r\n|\n)/);
|
||||
if (captionTagMatches && captionTagMatches.index === 0) {
|
||||
|
@ -57,7 +57,8 @@ function getTagBodyText(
|
|||
} else {
|
||||
return makeCodeblock(text);
|
||||
}
|
||||
case 'author':
|
||||
}
|
||||
case 'author': {
|
||||
// fix obsucated email address, #80898
|
||||
const emailMatch = text.match(/(.+)\s<([-.\w]+@[-.\w]+)>/);
|
||||
|
||||
|
@ -66,6 +67,7 @@ function getTagBodyText(
|
|||
} else {
|
||||
return `${emailMatch[1]} ${emailMatch[2]}`;
|
||||
}
|
||||
}
|
||||
case 'default':
|
||||
return makeCodeblock(text);
|
||||
}
|
||||
|
@ -81,7 +83,7 @@ function getTagDocumentation(
|
|||
case 'augments':
|
||||
case 'extends':
|
||||
case 'param':
|
||||
case 'template':
|
||||
case 'template': {
|
||||
const body = (convertLinkTags(tag.text, filePathConverter)).split(/^(\S+)\s*-?\s*/);
|
||||
if (body?.length === 3) {
|
||||
const param = body[1];
|
||||
|
@ -92,6 +94,7 @@ function getTagDocumentation(
|
|||
}
|
||||
return label + (doc.match(/\r\n|\n/g) ? ' \n' + processInlineTags(doc) : ` \u2014 ${processInlineTags(doc)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generic tag
|
||||
|
|
|
@ -981,7 +981,7 @@ suite('vscode API - workspace', () => {
|
|||
assert.strictEqual(document.getText(), expected);
|
||||
});
|
||||
|
||||
test('Should send a single FileWillRenameEvent instead of separate events when moving multiple files at once#111867', async function () {
|
||||
test('Should send a single FileWillRenameEvent instead of separate events when moving multiple files at once#111867, 1/3', async function () {
|
||||
|
||||
const file1 = await createRandomFile();
|
||||
const file2 = await createRandomFile();
|
||||
|
@ -1008,7 +1008,7 @@ suite('vscode API - workspace', () => {
|
|||
assert.strictEqual(e.files[1].oldUri.toString(), file2.toString());
|
||||
});
|
||||
|
||||
test('Should send a single FileWillRenameEvent instead of separate events when moving multiple files at once#111867', async function () {
|
||||
test('Should send a single FileWillRenameEvent instead of separate events when moving multiple files at once#111867, 2/3', async function () {
|
||||
|
||||
const event = new Promise<vscode.FileWillCreateEvent>(resolve => {
|
||||
let sub = vscode.workspace.onWillCreateFiles(e => {
|
||||
|
@ -1032,7 +1032,7 @@ suite('vscode API - workspace', () => {
|
|||
assert.strictEqual(e.files[1].toString(), file2.toString());
|
||||
});
|
||||
|
||||
test('Should send a single FileWillRenameEvent instead of separate events when moving multiple files at once#111867', async function () {
|
||||
test('Should send a single FileWillRenameEvent instead of separate events when moving multiple files at once#111867, 3/3', async function () {
|
||||
|
||||
const file1 = await createRandomFile();
|
||||
const file2 = await createRandomFile();
|
||||
|
|
|
@ -5,11 +5,12 @@
|
|||
|
||||
import * as assert from 'assert';
|
||||
import { EOL } from 'os';
|
||||
import * as crypto from 'crypto';
|
||||
import * as vscode from 'vscode';
|
||||
import { TestFS } from './memfs';
|
||||
|
||||
export function rndName() {
|
||||
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10);
|
||||
return crypto.randomBytes(8).toString('hex');
|
||||
}
|
||||
|
||||
export const testFs = new TestFS('fake-fs', true);
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@microsoft/applicationinsights-web": "^2.6.4",
|
||||
"@parcel/watcher": "2.0.4",
|
||||
"@parcel/watcher": "2.0.5",
|
||||
"@vscode/sqlite3": "4.0.12",
|
||||
"@vscode/sudo-prompt": "9.3.1",
|
||||
"@vscode/vscode-languagedetection": "1.0.21",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"private": true,
|
||||
"dependencies": {
|
||||
"@microsoft/applicationinsights-web": "^2.6.4",
|
||||
"@parcel/watcher": "2.0.4",
|
||||
"@parcel/watcher": "2.0.5",
|
||||
"@vscode/vscode-languagedetection": "1.0.21",
|
||||
"applicationinsights": "1.4.2",
|
||||
"cookie": "^0.4.0",
|
||||
|
|
|
@ -83,10 +83,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.4.tgz#40e1c0ad20743fcee1604a7df2c57faf0aa1af87"
|
||||
integrity sha512-Ot53G927ykMF8cQ3/zq4foZtdk+Tt1YpX7aUTHxBU7UHNdkEiBvBfZSq+rnlUmKCJ19VatwPG4mNzvcGpBj4og==
|
||||
|
||||
"@parcel/watcher@2.0.4":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.4.tgz#f300fef4cc38008ff4b8c29d92588eced3ce014b"
|
||||
integrity sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==
|
||||
"@parcel/watcher@2.0.5":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.5.tgz#f913a54e1601b0aac972803829b0eece48de215b"
|
||||
integrity sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw==
|
||||
dependencies:
|
||||
node-addon-api "^3.2.1"
|
||||
node-gyp-build "^4.3.0"
|
||||
|
|
|
@ -215,6 +215,23 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
|
|||
dom.EventHelper.stop(e);
|
||||
}));
|
||||
|
||||
// Intercept touch events
|
||||
// The following implementation is slightly different from the mouse event handlers above.
|
||||
// Use the following helper variable, otherwise the list flickers.
|
||||
let listIsVisibleOnTouchStart: boolean;
|
||||
this._register(dom.addDisposableListener(this.selectElement, 'touchstart', (e) => {
|
||||
listIsVisibleOnTouchStart = this._isVisible;
|
||||
}));
|
||||
this._register(dom.addDisposableListener(this.selectElement, 'touchend', (e) => {
|
||||
dom.EventHelper.stop(e);
|
||||
|
||||
if (listIsVisibleOnTouchStart) {
|
||||
this.hideSelectDropDown(true);
|
||||
} else {
|
||||
this.showSelectDropDown();
|
||||
}
|
||||
}));
|
||||
|
||||
// Intercept keyboard handling
|
||||
|
||||
this._register(dom.addDisposableListener(this.selectElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
|
@ -761,10 +778,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
|
|||
|
||||
// SetUp list mouse controller - control navigation, disabled items, focus
|
||||
|
||||
const onMouseUp = this._register(new DomEmitter(this.selectList.getHTMLElement(), 'mouseup'));
|
||||
this._register(Event.chain(onMouseUp.event)
|
||||
.filter(() => this.selectList.length > 0)
|
||||
.on(e => this.onMouseUp(e), this));
|
||||
this._register(dom.addDisposableListener(this.selectList.getHTMLElement(), dom.EventType.POINTER_DOWN, e => this.onPointerDown(e)));
|
||||
|
||||
this._register(this.selectList.onMouseOver(e => typeof e.index !== 'undefined' && this.selectList.setFocus([e.index])));
|
||||
this._register(this.selectList.onDidChangeFocus(e => this.onListFocus(e)));
|
||||
|
@ -785,7 +799,12 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
|
|||
// List methods
|
||||
|
||||
// List mouse controller - active exit, select option, fire onDidSelect if change, return focus to parent select
|
||||
private onMouseUp(e: MouseEvent): void {
|
||||
// Also takes in touchend events
|
||||
private onPointerDown(e: PointerEvent): void {
|
||||
|
||||
if (!this.selectList.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
dom.EventHelper.stop(e);
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ function parseRegExp(pattern: string): string {
|
|||
inBrackets = true;
|
||||
continue;
|
||||
|
||||
case '}':
|
||||
case '}': {
|
||||
const choices = splitGlobAware(braceVal, ',');
|
||||
|
||||
// Converts {foo,bar} => [foo|bar]
|
||||
|
@ -189,7 +189,7 @@ function parseRegExp(pattern: string): string {
|
|||
braceVal = '';
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
case ']':
|
||||
regEx += ('[' + bracketVal + ']');
|
||||
|
||||
|
|
|
@ -332,7 +332,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON
|
|||
case CharacterCodes.t:
|
||||
result += '\t';
|
||||
break;
|
||||
case CharacterCodes.u:
|
||||
case CharacterCodes.u: {
|
||||
const ch3 = scanHexDigits(4);
|
||||
if (ch3 >= 0) {
|
||||
result += String.fromCharCode(ch3);
|
||||
|
@ -340,6 +340,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON
|
|||
scanError = ScanError.InvalidUnicode;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
scanError = ScanError.InvalidEscapeCharacter;
|
||||
}
|
||||
|
@ -425,7 +426,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON
|
|||
return token = SyntaxKind.StringLiteral;
|
||||
|
||||
// comments
|
||||
case CharacterCodes.slash:
|
||||
case CharacterCodes.slash: {
|
||||
const start = pos - 1;
|
||||
// Single-line comment
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.slash) {
|
||||
|
@ -471,7 +472,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON
|
|||
value += String.fromCharCode(code);
|
||||
pos++;
|
||||
return token = SyntaxKind.Unknown;
|
||||
|
||||
}
|
||||
// numbers
|
||||
case CharacterCodes.minus:
|
||||
value += String.fromCharCode(code);
|
||||
|
@ -1016,7 +1017,7 @@ export function getNodeValue(node: Node): any {
|
|||
switch (node.type) {
|
||||
case 'array':
|
||||
return node.children!.map(getNodeValue);
|
||||
case 'object':
|
||||
case 'object': {
|
||||
const obj = Object.create(null);
|
||||
for (let prop of node.children!) {
|
||||
const valueNode = prop.children![1];
|
||||
|
@ -1025,6 +1026,7 @@ export function getNodeValue(node: Node): any {
|
|||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
case 'null':
|
||||
case 'string':
|
||||
case 'number':
|
||||
|
@ -1162,7 +1164,7 @@ export function visit(text: string, visitor: JSONVisitor, options: ParseOptions
|
|||
|
||||
function parseLiteral(): boolean {
|
||||
switch (_scanner.getToken()) {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.NumericLiteral: {
|
||||
let value = 0;
|
||||
try {
|
||||
value = JSON.parse(_scanner.getTokenValue());
|
||||
|
@ -1175,6 +1177,7 @@ export function visit(text: string, visitor: JSONVisitor, options: ParseOptions
|
|||
}
|
||||
onLiteralValue(value);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.NullKeyword:
|
||||
onLiteralValue(null);
|
||||
break;
|
||||
|
|
|
@ -119,10 +119,11 @@ export function guessMimeTypes(resource: URI | null, firstLine?: string): string
|
|||
case Schemas.file:
|
||||
path = resource.fsPath;
|
||||
break;
|
||||
case Schemas.data:
|
||||
case Schemas.data: {
|
||||
const metadata = DataUri.parseMetaData(resource);
|
||||
path = metadata.get(DataUri.META_DATA_LABEL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
path = resource.path;
|
||||
}
|
||||
|
|
|
@ -565,14 +565,14 @@ export class ChannelClient implements IChannelClient, IDisposable {
|
|||
c(response.data);
|
||||
break;
|
||||
|
||||
case ResponseType.PromiseError:
|
||||
case ResponseType.PromiseError: {
|
||||
this.handlers.delete(id);
|
||||
const error = new Error(response.data.message);
|
||||
(<any>error).stack = response.data.stack;
|
||||
error.name = response.data.name;
|
||||
e(error);
|
||||
break;
|
||||
|
||||
}
|
||||
case ResponseType.PromiseErrorObj:
|
||||
this.handlers.delete(id);
|
||||
e(response.data);
|
||||
|
|
|
@ -303,18 +303,20 @@ export class QuickInputList {
|
|||
this.list.setFocus(range(this.list.length));
|
||||
}
|
||||
break;
|
||||
case KeyCode.UpArrow:
|
||||
case KeyCode.UpArrow: {
|
||||
const focus1 = this.list.getFocus();
|
||||
if (focus1.length === 1 && focus1[0] === 0) {
|
||||
this._onLeave.fire();
|
||||
}
|
||||
break;
|
||||
case KeyCode.DownArrow:
|
||||
}
|
||||
case KeyCode.DownArrow: {
|
||||
const focus2 = this.list.getFocus();
|
||||
if (focus2.length === 1 && focus2[0] === this.list.length - 1) {
|
||||
this._onLeave.fire();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._onKeyDown.fire(event);
|
||||
|
|
|
@ -10,7 +10,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
|||
import * as platform from 'vs/base/common/platform';
|
||||
import { HitTestContext, IViewZoneData, MouseTarget, MouseTargetFactory, PointerHandlerLastRenderData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import { IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { ClientCoordinates, EditorMouseEvent, EditorMouseEventFactory, GlobalEditorMouseMoveMonitor, createEditorPagePosition } from 'vs/editor/browser/editorDom';
|
||||
import { ClientCoordinates, EditorMouseEvent, EditorMouseEventFactory, GlobalEditorMouseMoveMonitor, createEditorPagePosition, createCoordinatesRelativeToEditor } from 'vs/editor/browser/editorDom';
|
||||
import { ViewController } from 'vs/editor/browser/view/viewController';
|
||||
import { EditorZoom } from 'vs/editor/common/config/editorZoom';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
|
@ -172,7 +172,8 @@ export class MouseHandler extends ViewEventHandler {
|
|||
return null;
|
||||
}
|
||||
|
||||
return this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), editorPos, pos, null);
|
||||
const relativePos = createCoordinatesRelativeToEditor(this.viewHelper.viewDomNode, editorPos, pos);
|
||||
return this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), editorPos, pos, relativePos, null);
|
||||
}
|
||||
|
||||
protected _createMouseTarget(e: EditorMouseEvent, testEventTarget: boolean): IMouseTarget {
|
||||
|
@ -185,11 +186,11 @@ export class MouseHandler extends ViewEventHandler {
|
|||
);
|
||||
}
|
||||
}
|
||||
return this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, testEventTarget ? target : null);
|
||||
return this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, e.relativePos, testEventTarget ? target : null);
|
||||
}
|
||||
|
||||
private _getMouseColumn(e: EditorMouseEvent): number {
|
||||
return this.mouseTargetFactory.getMouseColumn(e.editorPos, e.pos);
|
||||
return this.mouseTargetFactory.getMouseColumn(e.relativePos);
|
||||
}
|
||||
|
||||
protected _onContextMenu(e: EditorMouseEvent, testEventTarget: boolean): void {
|
||||
|
@ -476,7 +477,7 @@ class MouseDownOperation extends Disposable {
|
|||
}
|
||||
|
||||
if (e.posy > editorContent.y + editorContent.height) {
|
||||
const verticalOffset = viewLayout.getCurrentScrollTop() + (e.posy - editorContent.y);
|
||||
const verticalOffset = viewLayout.getCurrentScrollTop() + e.relativePos.y;
|
||||
const viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset);
|
||||
if (viewZoneData) {
|
||||
const newPosition = this._helpPositionJumpOverViewZone(viewZoneData);
|
||||
|
@ -489,7 +490,7 @@ class MouseDownOperation extends Disposable {
|
|||
return new MouseTarget(null, MouseTargetType.OUTSIDE_EDITOR, mouseColumn, new Position(belowLineNumber, model.getLineMaxColumn(belowLineNumber)));
|
||||
}
|
||||
|
||||
const possibleLineNumber = viewLayout.getLineNumberAtVerticalOffset(viewLayout.getCurrentScrollTop() + (e.posy - editorContent.y));
|
||||
const possibleLineNumber = viewLayout.getLineNumberAtVerticalOffset(viewLayout.getCurrentScrollTop() + e.relativePos.y);
|
||||
|
||||
if (e.posx < editorContent.x) {
|
||||
return new MouseTarget(null, MouseTargetType.OUTSIDE_EDITOR, mouseColumn, new Position(possibleLineNumber, 1));
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler';
|
||||
import { IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { ClientCoordinates, EditorMouseEvent, EditorPagePosition, PageCoordinates } from 'vs/editor/browser/editorDom';
|
||||
import { ClientCoordinates, EditorMouseEvent, EditorPagePosition, PageCoordinates, CoordinatesRelativeToEditor } from 'vs/editor/browser/editorDom';
|
||||
import { PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart';
|
||||
import { ViewLine } from 'vs/editor/browser/viewParts/lines/viewLine';
|
||||
import { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/viewCursor';
|
||||
|
@ -374,6 +374,7 @@ abstract class BareHitTestRequest {
|
|||
|
||||
public readonly editorPos: EditorPagePosition;
|
||||
public readonly pos: PageCoordinates;
|
||||
public readonly relativePos: CoordinatesRelativeToEditor;
|
||||
public readonly mouseVerticalOffset: number;
|
||||
public readonly isInMarginArea: boolean;
|
||||
public readonly isInContentArea: boolean;
|
||||
|
@ -381,13 +382,14 @@ abstract class BareHitTestRequest {
|
|||
|
||||
protected readonly mouseColumn: number;
|
||||
|
||||
constructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates) {
|
||||
constructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor) {
|
||||
this.editorPos = editorPos;
|
||||
this.pos = pos;
|
||||
this.relativePos = relativePos;
|
||||
|
||||
this.mouseVerticalOffset = Math.max(0, ctx.getCurrentScrollTop() + pos.y - editorPos.y);
|
||||
this.mouseContentHorizontalOffset = ctx.getCurrentScrollLeft() + pos.x - editorPos.x - ctx.layoutInfo.contentLeft;
|
||||
this.isInMarginArea = (pos.x - editorPos.x < ctx.layoutInfo.contentLeft && pos.x - editorPos.x >= ctx.layoutInfo.glyphMarginLeft);
|
||||
this.mouseVerticalOffset = Math.max(0, ctx.getCurrentScrollTop() + this.relativePos.y);
|
||||
this.mouseContentHorizontalOffset = ctx.getCurrentScrollLeft() + this.relativePos.x - ctx.layoutInfo.contentLeft;
|
||||
this.isInMarginArea = (this.relativePos.x < ctx.layoutInfo.contentLeft && this.relativePos.x >= ctx.layoutInfo.glyphMarginLeft);
|
||||
this.isInContentArea = !this.isInMarginArea;
|
||||
this.mouseColumn = Math.max(0, MouseTargetFactory._getMouseColumn(this.mouseContentHorizontalOffset, ctx.typicalHalfwidthCharacterWidth));
|
||||
}
|
||||
|
@ -398,8 +400,8 @@ class HitTestRequest extends BareHitTestRequest {
|
|||
public readonly target: Element | null;
|
||||
public readonly targetPath: Uint8Array;
|
||||
|
||||
constructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, target: Element | null) {
|
||||
super(ctx, editorPos, pos);
|
||||
constructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: Element | null) {
|
||||
super(ctx, editorPos, pos, relativePos);
|
||||
this._ctx = ctx;
|
||||
|
||||
if (target) {
|
||||
|
@ -412,7 +414,7 @@ class HitTestRequest extends BareHitTestRequest {
|
|||
}
|
||||
|
||||
public override toString(): string {
|
||||
return `pos(${this.pos.x},${this.pos.y}), editorPos(${this.editorPos.x},${this.editorPos.y}), mouseVerticalOffset: ${this.mouseVerticalOffset}, mouseContentHorizontalOffset: ${this.mouseContentHorizontalOffset}\n\ttarget: ${this.target ? (<HTMLElement>this.target).outerHTML : null}`;
|
||||
return `pos(${this.pos.x},${this.pos.y}), editorPos(${this.editorPos.x},${this.editorPos.y}), relativePos(${this.relativePos.x},${this.relativePos.y}), mouseVerticalOffset: ${this.mouseVerticalOffset}, mouseContentHorizontalOffset: ${this.mouseContentHorizontalOffset}\n\ttarget: ${this.target ? (<HTMLElement>this.target).outerHTML : null}`;
|
||||
}
|
||||
|
||||
public fulfill(type: MouseTargetType.UNKNOWN, position?: Position | null, range?: EditorRange | null): MouseTarget;
|
||||
|
@ -436,7 +438,7 @@ class HitTestRequest extends BareHitTestRequest {
|
|||
}
|
||||
|
||||
public withTarget(target: Element | null): HitTestRequest {
|
||||
return new HitTestRequest(this._ctx, this.editorPos, this.pos, target);
|
||||
return new HitTestRequest(this._ctx, this.editorPos, this.pos, this.relativePos, target);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,9 +482,9 @@ export class MouseTargetFactory {
|
|||
return false;
|
||||
}
|
||||
|
||||
public createMouseTarget(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, target: HTMLElement | null): IMouseTarget {
|
||||
public createMouseTarget(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null): IMouseTarget {
|
||||
const ctx = new HitTestContext(this._context, this._viewHelper, lastRenderData);
|
||||
const request = new HitTestRequest(ctx, editorPos, pos, target);
|
||||
const request = new HitTestRequest(ctx, editorPos, pos, relativePos, target);
|
||||
try {
|
||||
const r = MouseTargetFactory._createMouseTarget(ctx, request, false);
|
||||
// console.log(r.toString());
|
||||
|
@ -632,7 +634,7 @@ export class MouseTargetFactory {
|
|||
if (request.isInMarginArea) {
|
||||
const res = ctx.getFullLineRangeAtCoord(request.mouseVerticalOffset);
|
||||
const pos = res.range.getStartPosition();
|
||||
let offset = Math.abs(request.pos.x - request.editorPos.x);
|
||||
let offset = Math.abs(request.relativePos.x);
|
||||
const detail: IMarginData = {
|
||||
isAfterLines: res.isAfterLines,
|
||||
glyphMarginLeft: ctx.layoutInfo.glyphMarginLeft,
|
||||
|
@ -745,10 +747,10 @@ export class MouseTargetFactory {
|
|||
return null;
|
||||
}
|
||||
|
||||
public getMouseColumn(editorPos: EditorPagePosition, pos: PageCoordinates): number {
|
||||
public getMouseColumn(relativePos: CoordinatesRelativeToEditor): number {
|
||||
const options = this._context.configuration.options;
|
||||
const layoutInfo = options.get(EditorOption.layoutInfo);
|
||||
const mouseContentHorizontalOffset = this._context.viewLayout.getCurrentScrollLeft() + pos.x - editorPos.x - layoutInfo.contentLeft;
|
||||
const mouseContentHorizontalOffset = this._context.viewLayout.getCurrentScrollLeft() + relativePos.x - layoutInfo.contentLeft;
|
||||
return MouseTargetFactory._getMouseColumn(mouseContentHorizontalOffset, options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth);
|
||||
}
|
||||
|
||||
|
@ -834,8 +836,8 @@ export class MouseTargetFactory {
|
|||
if (adjustedPageY <= request.editorPos.y) {
|
||||
adjustedPageY = request.editorPos.y + 1;
|
||||
}
|
||||
if (adjustedPageY >= request.editorPos.y + ctx.layoutInfo.height) {
|
||||
adjustedPageY = request.editorPos.y + ctx.layoutInfo.height - 1;
|
||||
if (adjustedPageY >= request.editorPos.y + request.editorPos.height) {
|
||||
adjustedPageY = request.editorPos.y + request.editorPos.height - 1;
|
||||
}
|
||||
|
||||
const adjustedPage = new PageCoordinates(request.pos.x, adjustedPageY);
|
||||
|
|
|
@ -62,11 +62,45 @@ export class EditorPagePosition {
|
|||
) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Coordinates relative to the the (top;left) of the editor that can be used safely with other internal editor metrics.
|
||||
* **NOTE**: This position is obtained by taking page coordinates and transforming them relative to the
|
||||
* editor's (top;left) position in a way in which scale transformations are taken into account.
|
||||
* **NOTE**: These coordinates could be negative if the mouse position is outside the editor.
|
||||
*/
|
||||
export class CoordinatesRelativeToEditor {
|
||||
_positionRelativeToEditorBrand: void = undefined;
|
||||
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
public readonly y: number
|
||||
) { }
|
||||
}
|
||||
|
||||
export function createEditorPagePosition(editorViewDomNode: HTMLElement): EditorPagePosition {
|
||||
const editorPos = dom.getDomNodePagePosition(editorViewDomNode);
|
||||
return new EditorPagePosition(editorPos.left, editorPos.top, editorPos.width, editorPos.height);
|
||||
}
|
||||
|
||||
export function createCoordinatesRelativeToEditor(editorViewDomNode: HTMLElement, editorPagePosition: EditorPagePosition, pos: PageCoordinates) {
|
||||
// The editor's page position is read from the DOM using getBoundingClientRect().
|
||||
//
|
||||
// getBoundingClientRect() returns the actual dimensions, while offsetWidth and offsetHeight
|
||||
// reflect the unscaled size. We can use this difference to detect a transform:scale()
|
||||
// and we will apply the transformation in inverse to get mouse coordinates that make sense inside the editor.
|
||||
//
|
||||
// This could be expanded to cover rotation as well maybe by walking the DOM up from `editorViewDomNode`
|
||||
// and computing the effective transformation matrix using getComputedStyle(element).transform.
|
||||
//
|
||||
const scaleX = editorPagePosition.width / editorViewDomNode.offsetWidth;
|
||||
const scaleY = editorPagePosition.height / editorViewDomNode.offsetHeight;
|
||||
|
||||
// Adjust mouse offsets if editor appears to be scaled via transforms
|
||||
const relativeX = (pos.x - editorPagePosition.x) / scaleX;
|
||||
const relativeY = (pos.y - editorPagePosition.y) / scaleY;
|
||||
return new CoordinatesRelativeToEditor(relativeX, relativeY);
|
||||
}
|
||||
|
||||
export class EditorMouseEvent extends StandardMouseEvent {
|
||||
_editorMouseEventBrand: void = undefined;
|
||||
|
||||
|
@ -80,10 +114,18 @@ export class EditorMouseEvent extends StandardMouseEvent {
|
|||
*/
|
||||
public readonly editorPos: EditorPagePosition;
|
||||
|
||||
/**
|
||||
* Coordinates relative to the (top;left) of the editor.
|
||||
* *NOTE*: These coordinates are preferred because they take into account transformations applied to the editor.
|
||||
* *NOTE*: These coordinates could be negative if the mouse position is outside the editor.
|
||||
*/
|
||||
public readonly relativePos: CoordinatesRelativeToEditor;
|
||||
|
||||
constructor(e: MouseEvent, editorViewDomNode: HTMLElement) {
|
||||
super(e);
|
||||
this.pos = new PageCoordinates(this.posx, this.posy);
|
||||
this.editorPos = createEditorPagePosition(editorViewDomNode);
|
||||
this.relativePos = createCoordinatesRelativeToEditor(editorViewDomNode, this.editorPos, this.pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ export class RangeUtil {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static _createHorizontalRangesFromClientRects(clientRects: DOMRectList | null, clientRectDeltaLeft: number): FloatHorizontalRange[] | null {
|
||||
private static _createHorizontalRangesFromClientRects(clientRects: DOMRectList | null, clientRectDeltaLeft: number, clientRectScale: number): FloatHorizontalRange[] | null {
|
||||
if (!clientRects || clientRects.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -80,13 +80,13 @@ export class RangeUtil {
|
|||
const result: FloatHorizontalRange[] = [];
|
||||
for (let i = 0, len = clientRects.length; i < len; i++) {
|
||||
const clientRect = clientRects[i];
|
||||
result[i] = new FloatHorizontalRange(Math.max(0, clientRect.left - clientRectDeltaLeft), clientRect.width);
|
||||
result[i] = new FloatHorizontalRange(Math.max(0, (clientRect.left - clientRectDeltaLeft) / clientRectScale), clientRect.width / clientRectScale);
|
||||
}
|
||||
|
||||
return this._mergeAdjacentRanges(result);
|
||||
}
|
||||
|
||||
public static readHorizontalRanges(domNode: HTMLElement, startChildIndex: number, startOffset: number, endChildIndex: number, endOffset: number, clientRectDeltaLeft: number, endNode: HTMLElement): FloatHorizontalRange[] | null {
|
||||
public static readHorizontalRanges(domNode: HTMLElement, startChildIndex: number, startOffset: number, endChildIndex: number, endOffset: number, clientRectDeltaLeft: number, clientRectScale: number, endNode: HTMLElement): FloatHorizontalRange[] | null {
|
||||
// Panic check
|
||||
const min = 0;
|
||||
const max = domNode.children.length - 1;
|
||||
|
@ -100,7 +100,7 @@ export class RangeUtil {
|
|||
// We must find the position at the beginning of a <span>
|
||||
// To cover cases of empty <span>s, avoid using a range and use the <span>'s bounding box
|
||||
const clientRects = domNode.children[startChildIndex].getClientRects();
|
||||
return this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft);
|
||||
return this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft, clientRectScale);
|
||||
}
|
||||
|
||||
// If crossing over to a span only to select offset 0, then use the previous span's maximum offset
|
||||
|
@ -135,6 +135,6 @@ export class RangeUtil {
|
|||
endOffset = Math.min(endElement.textContent!.length, Math.max(0, endOffset));
|
||||
|
||||
const clientRects = this._readClientRects(startElement, startOffset, endElement, endOffset, endNode);
|
||||
return this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft);
|
||||
return this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft, clientRectScale);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,21 +48,39 @@ export class DomReadingContext {
|
|||
|
||||
private readonly _domNode: HTMLElement;
|
||||
private _clientRectDeltaLeft: number;
|
||||
private _clientRectDeltaLeftRead: boolean;
|
||||
private _clientRectScale: number;
|
||||
private _clientRectRead: boolean;
|
||||
|
||||
private readClientRect(): void {
|
||||
if (!this._clientRectRead) {
|
||||
this._clientRectRead = true;
|
||||
const rect = this._domNode.getBoundingClientRect();
|
||||
this._clientRectDeltaLeft = rect.left;
|
||||
this._clientRectScale = rect.width / this._domNode.offsetWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public get clientRectDeltaLeft(): number {
|
||||
if (!this._clientRectDeltaLeftRead) {
|
||||
this._clientRectDeltaLeftRead = true;
|
||||
this._clientRectDeltaLeft = this._domNode.getBoundingClientRect().left;
|
||||
if (!this._clientRectRead) {
|
||||
this.readClientRect();
|
||||
}
|
||||
return this._clientRectDeltaLeft;
|
||||
}
|
||||
|
||||
public get clientRectScale(): number {
|
||||
if (!this._clientRectRead) {
|
||||
this.readClientRect();
|
||||
}
|
||||
return this._clientRectScale;
|
||||
}
|
||||
|
||||
public readonly endNode: HTMLElement;
|
||||
|
||||
constructor(domNode: HTMLElement, endNode: HTMLElement) {
|
||||
this._domNode = domNode;
|
||||
this._clientRectDeltaLeft = 0;
|
||||
this._clientRectDeltaLeftRead = false;
|
||||
this._clientRectScale = 1;
|
||||
this._clientRectRead = false;
|
||||
this.endNode = endNode;
|
||||
}
|
||||
|
||||
|
@ -587,7 +605,7 @@ class RenderedViewLine implements IRenderedViewLine {
|
|||
private _actualReadPixelOffset(domNode: FastDomNode<HTMLElement>, lineNumber: number, column: number, context: DomReadingContext): number {
|
||||
if (this._characterMapping.length === 0) {
|
||||
// This line has no content
|
||||
const r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), 0, 0, 0, 0, context.clientRectDeltaLeft, context.endNode);
|
||||
const r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), 0, 0, 0, 0, context.clientRectDeltaLeft, context.clientRectScale, context.endNode);
|
||||
if (!r || r.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -601,7 +619,7 @@ class RenderedViewLine implements IRenderedViewLine {
|
|||
|
||||
const domPosition = this._characterMapping.getDomPosition(column);
|
||||
|
||||
const r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), domPosition.partIndex, domPosition.charIndex, domPosition.partIndex, domPosition.charIndex, context.clientRectDeltaLeft, context.endNode);
|
||||
const r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), domPosition.partIndex, domPosition.charIndex, domPosition.partIndex, domPosition.charIndex, context.clientRectDeltaLeft, context.clientRectScale, context.endNode);
|
||||
if (!r || r.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -627,7 +645,7 @@ class RenderedViewLine implements IRenderedViewLine {
|
|||
const startDomPosition = this._characterMapping.getDomPosition(startColumn);
|
||||
const endDomPosition = this._characterMapping.getDomPosition(endColumn);
|
||||
|
||||
return RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), startDomPosition.partIndex, startDomPosition.charIndex, endDomPosition.partIndex, endDomPosition.charIndex, context.clientRectDeltaLeft, context.endNode);
|
||||
return RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), startDomPosition.partIndex, startDomPosition.charIndex, endDomPosition.partIndex, endDomPosition.charIndex, context.clientRectDeltaLeft, context.clientRectScale, context.endNode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1593,11 +1593,12 @@ class InnerMinimap extends Disposable {
|
|||
this.renderDecorationOnLine(canvasContext, lineOffsetMap, decoration.range, decorationColor, layout, line, lineHeight, lineHeight, tabSize, characterWidth, canvasInnerWidth);
|
||||
continue;
|
||||
|
||||
case MinimapPosition.Gutter:
|
||||
case MinimapPosition.Gutter: {
|
||||
const y = (line - layout.startLineNumber) * lineHeight;
|
||||
const x = 2;
|
||||
this.renderDecoration(canvasContext, decorationColor, x, y, GUTTER_DECORATION_WIDTH, lineHeight);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ class Parser {
|
|||
case TokenKind.Text:
|
||||
return token.astNode as TextAstNode;
|
||||
|
||||
case TokenKind.OpeningBracket:
|
||||
case TokenKind.OpeningBracket: {
|
||||
const set = openedBracketIds.merge(token.bracketIds);
|
||||
const child = this.parseList(set);
|
||||
|
||||
|
@ -154,7 +154,7 @@ class Parser {
|
|||
null
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
default:
|
||||
throw new Error('unexpected');
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens
|
|||
const charCode = text.charCodeAt(charIndex);
|
||||
|
||||
switch (charCode) {
|
||||
case CharCode.Tab:
|
||||
case CharCode.Tab: {
|
||||
let insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize;
|
||||
tabsCharDelta += insertSpacesCount - 1;
|
||||
while (insertSpacesCount > 0) {
|
||||
|
@ -58,7 +58,7 @@ export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens
|
|||
insertSpacesCount--;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case CharCode.LessThan:
|
||||
partContent += '<';
|
||||
prevIsSpace = false;
|
||||
|
|
|
@ -103,10 +103,10 @@ export class UnicodeTextModelHighlighter {
|
|||
case SimpleHighlightReason.Invisible:
|
||||
return { kind: UnicodeHighlighterReasonKind.Invisible };
|
||||
|
||||
case SimpleHighlightReason.Ambiguous:
|
||||
case SimpleHighlightReason.Ambiguous: {
|
||||
const primaryConfusable = strings.AmbiguousCharacters.getPrimaryConfusable(char.codePointAt(0)!)!;
|
||||
return { kind: UnicodeHighlighterReasonKind.Ambiguous, confusableWith: String.fromCodePoint(primaryConfusable) };
|
||||
|
||||
}
|
||||
case SimpleHighlightReason.NonBasicASCII:
|
||||
return { kind: UnicodeHighlighterReasonKind.NonBasicAscii };
|
||||
}
|
||||
|
|
|
@ -449,11 +449,11 @@ export class FindController extends CommonFindController implements IFindControl
|
|||
case 'never':
|
||||
updateSearchScope = false;
|
||||
break;
|
||||
case 'multiline':
|
||||
case 'multiline': {
|
||||
const isSelectionMultipleLine = !!selection && selection.startLineNumber !== selection.endLineNumber;
|
||||
updateSearchScope = isSelectionMultipleLine;
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -506,11 +506,11 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
|
|||
case 'never':
|
||||
this._toggleSelectionFind.checked = false;
|
||||
break;
|
||||
case 'multiline':
|
||||
case 'multiline': {
|
||||
const isSelectionMultipleLine = !!selection && selection.startLineNumber !== selection.endLineNumber;
|
||||
this._toggleSelectionFind.checked = isSelectionMultipleLine;
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -396,7 +396,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
|||
const range = e.target.range;
|
||||
let iconClicked = false;
|
||||
switch (e.target.type) {
|
||||
case MouseTargetType.GUTTER_LINE_DECORATIONS:
|
||||
case MouseTargetType.GUTTER_LINE_DECORATIONS: {
|
||||
const data = e.target.detail as IMarginData;
|
||||
const offsetLeftInGutter = (e.target.element as HTMLElement).offsetLeft;
|
||||
const gutterOffsetX = data.offsetX - offsetLeftInGutter;
|
||||
|
@ -410,6 +410,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
|||
|
||||
iconClicked = true;
|
||||
break;
|
||||
}
|
||||
case MouseTargetType.CONTENT_EMPTY: {
|
||||
if (this._unfoldOnClickAfterEndOfLine && this.hiddenRangeModel.hasRanges()) {
|
||||
const data = e.target.detail as IEmptyContentData;
|
||||
|
|
|
@ -137,6 +137,10 @@
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label {
|
||||
color: var(--vscode-editorSuggestWidget-foreground);
|
||||
}
|
||||
|
||||
.monaco-editor .suggest-widget:not(.frozen) .monaco-highlighted-label .highlight {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -326,7 +326,9 @@ export function setColorMap(colorMap: string[] | null): void {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the tokens provider for a language (manual implementation).
|
||||
* Set the tokens provider for a language (manual implementation). This tokenizer will be exclusive
|
||||
* with a tokenizer created using `setMonarchTokensProvider`, but will work together with a tokens provider
|
||||
* set using `registerDocumentSemanticTokensProvider` or `registerDocumentRangeSemanticTokensProvider`.
|
||||
*/
|
||||
export function setTokensProvider(languageId: string, provider: TokensProvider | EncodedTokensProvider | Thenable<TokensProvider | EncodedTokensProvider>): IDisposable {
|
||||
const validLanguageId = StaticServices.languageService.get().validateLanguageId(languageId);
|
||||
|
@ -353,7 +355,9 @@ export function setTokensProvider(languageId: string, provider: TokensProvider |
|
|||
|
||||
|
||||
/**
|
||||
* Set the tokens provider for a language (monarch implementation).
|
||||
* Set the tokens provider for a language (monarch implementation). This tokenizer will be exclusive
|
||||
* with a tokenizer set using `setTokensProvider`, but will work together with a tokens provider
|
||||
* set using `registerDocumentSemanticTokensProvider` or `registerDocumentRangeSemanticTokensProvider`.
|
||||
*/
|
||||
export function setMonarchTokensProvider(languageId: string, languageDef: IMonarchLanguage | Thenable<IMonarchLanguage>): IDisposable {
|
||||
const create = (languageDef: IMonarchLanguage) => {
|
||||
|
@ -539,14 +543,22 @@ export function registerSelectionRangeProvider(languageId: string, provider: mod
|
|||
}
|
||||
|
||||
/**
|
||||
* Register a document semantic tokens provider
|
||||
* Register a document semantic tokens provider. A semantic tokens provider will complement and enhance a
|
||||
* simple top-down tokenizer. Simple top-down tokenizers can be set either via `setMonarchTokensProvider`
|
||||
* or `setTokensProvider`.
|
||||
*
|
||||
* For the best user experience, register both a semantic tokens provider and a top-down tokenizer.
|
||||
*/
|
||||
export function registerDocumentSemanticTokensProvider(languageId: string, provider: modes.DocumentSemanticTokensProvider): IDisposable {
|
||||
return modes.DocumentSemanticTokensProviderRegistry.register(languageId, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a document range semantic tokens provider
|
||||
* Register a document range semantic tokens provider. A semantic tokens provider will complement and enhance a
|
||||
* simple top-down tokenizer. Simple top-down tokenizers can be set either via `setMonarchTokensProvider`
|
||||
* or `setTokensProvider`.
|
||||
*
|
||||
* For the best user experience, register both a semantic tokens provider and a top-down tokenizer.
|
||||
*/
|
||||
export function registerDocumentRangeSemanticTokensProvider(languageId: string, provider: modes.DocumentRangeSemanticTokensProvider): IDisposable {
|
||||
return modes.DocumentRangeSemanticTokensProviderRegistry.register(languageId, provider);
|
||||
|
|
20
src/vs/monaco.d.ts
vendored
20
src/vs/monaco.d.ts
vendored
|
@ -5351,12 +5351,16 @@ declare namespace monaco.languages {
|
|||
export function setColorMap(colorMap: string[] | null): void;
|
||||
|
||||
/**
|
||||
* Set the tokens provider for a language (manual implementation).
|
||||
* Set the tokens provider for a language (manual implementation). This tokenizer will be exclusive
|
||||
* with a tokenizer created using `setMonarchTokensProvider`, but will work together with a tokens provider
|
||||
* set using `registerDocumentSemanticTokensProvider` or `registerDocumentRangeSemanticTokensProvider`.
|
||||
*/
|
||||
export function setTokensProvider(languageId: string, provider: TokensProvider | EncodedTokensProvider | Thenable<TokensProvider | EncodedTokensProvider>): IDisposable;
|
||||
|
||||
/**
|
||||
* Set the tokens provider for a language (monarch implementation).
|
||||
* Set the tokens provider for a language (monarch implementation). This tokenizer will be exclusive
|
||||
* with a tokenizer set using `setTokensProvider`, but will work together with a tokens provider
|
||||
* set using `registerDocumentSemanticTokensProvider` or `registerDocumentRangeSemanticTokensProvider`.
|
||||
*/
|
||||
export function setMonarchTokensProvider(languageId: string, languageDef: IMonarchLanguage | Thenable<IMonarchLanguage>): IDisposable;
|
||||
|
||||
|
@ -5466,12 +5470,20 @@ declare namespace monaco.languages {
|
|||
export function registerSelectionRangeProvider(languageId: string, provider: SelectionRangeProvider): IDisposable;
|
||||
|
||||
/**
|
||||
* Register a document semantic tokens provider
|
||||
* Register a document semantic tokens provider. A semantic tokens provider will complement and enhance a
|
||||
* simple top-down tokenizer. Simple top-down tokenizers can be set either via `setMonarchTokensProvider`
|
||||
* or `setTokensProvider`.
|
||||
*
|
||||
* For the best user experience, register both a semantic tokens provider and a top-down tokenizer.
|
||||
*/
|
||||
export function registerDocumentSemanticTokensProvider(languageId: string, provider: DocumentSemanticTokensProvider): IDisposable;
|
||||
|
||||
/**
|
||||
* Register a document range semantic tokens provider
|
||||
* Register a document range semantic tokens provider. A semantic tokens provider will complement and enhance a
|
||||
* simple top-down tokenizer. Simple top-down tokenizers can be set either via `setMonarchTokensProvider`
|
||||
* or `setTokensProvider`.
|
||||
*
|
||||
* For the best user experience, register both a semantic tokens provider and a top-down tokenizer.
|
||||
*/
|
||||
export function registerDocumentRangeSemanticTokensProvider(languageId: string, provider: DocumentRangeSemanticTokensProvider): IDisposable;
|
||||
|
||||
|
|
|
@ -245,6 +245,8 @@ export class DialogMainService implements IDialogMainService {
|
|||
// we figure this out by `hashing` the configuration
|
||||
// options for the dialog to prevent duplicates
|
||||
|
||||
this.logService.trace('[DialogMainService]: request to acquire file dialog lock', options);
|
||||
|
||||
let windowFileDialogLocks = this.windowFileDialogLocks.get(window.id);
|
||||
if (!windowFileDialogLocks) {
|
||||
windowFileDialogLocks = new Set();
|
||||
|
@ -256,9 +258,13 @@ export class DialogMainService implements IDialogMainService {
|
|||
return undefined; // prevent duplicates, return
|
||||
}
|
||||
|
||||
this.logService.trace('[DialogMainService]: new file dialog lock created', options);
|
||||
|
||||
windowFileDialogLocks.add(optionsHash);
|
||||
|
||||
return toDisposable(() => {
|
||||
this.logService.trace('[DialogMainService]: file dialog lock disposed', options);
|
||||
|
||||
windowFileDialogLocks?.delete(optionsHash);
|
||||
|
||||
// if the window has no more dialog locks, delete it from the set of locks
|
||||
|
|
|
@ -414,6 +414,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
|
|||
throw new ExtensionManagementError(nls.localize('notFoundCompatibleDependency', "Can't install '{0}' extension because it is not compatible with the current version of {1} (version {2}).", extension.identifier.id, this.productService.nameLong, this.productService.version), ExtensionManagementErrorCode.Incompatible);
|
||||
}
|
||||
|
||||
this.logService.info('Getting Manifest...', compatibleExtension.identifier.id);
|
||||
const manifest = await this.galleryService.getManifest(compatibleExtension, CancellationToken.None);
|
||||
if (manifest === null) {
|
||||
throw new ExtensionManagementError(`Missing manifest for extension ${extension.identifier.id}`, ExtensionManagementErrorCode.Invalid);
|
||||
|
|
|
@ -175,15 +175,17 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
|
|||
case RecommendationsNotificationResult.Ignored:
|
||||
this.highImportanceTipsByExe.delete(exeName);
|
||||
break;
|
||||
case RecommendationsNotificationResult.IncompatibleWindow:
|
||||
case RecommendationsNotificationResult.IncompatibleWindow: {
|
||||
// Recommended in incompatible window. Schedule the prompt after active window change
|
||||
const onActiveWindowChange = Event.once(Event.latch(Event.any(this.nativeHostService.onDidOpenWindow, this.nativeHostService.onDidFocusWindow)));
|
||||
this._register(onActiveWindowChange(() => this.promptHighImportanceExeBasedTip()));
|
||||
break;
|
||||
case RecommendationsNotificationResult.TooMany:
|
||||
}
|
||||
case RecommendationsNotificationResult.TooMany: {
|
||||
// Too many notifications. Schedule the prompt after one hour
|
||||
const disposable = this._register(disposableTimeout(() => { disposable.dispose(); this.promptHighImportanceExeBasedTip(); }, 60 * 60 * 1000 /* 1 hour */));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -209,7 +211,7 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
|
|||
this.promptExeRecommendations(tips)
|
||||
.then(result => {
|
||||
switch (result) {
|
||||
case RecommendationsNotificationResult.Accepted:
|
||||
case RecommendationsNotificationResult.Accepted: {
|
||||
// Accepted: Update the last prompted time and caches.
|
||||
this.updateLastPromptedMediumExeTime(Date.now());
|
||||
this.mediumImportanceTipsByExe.delete(exeName);
|
||||
|
@ -218,23 +220,24 @@ export class ExtensionTipsService extends BaseExtensionTipsService {
|
|||
// Schedule the next recommendation for next internval
|
||||
const disposable1 = this._register(disposableTimeout(() => { disposable1.dispose(); this.promptMediumImportanceExeBasedTip(); }, promptInterval));
|
||||
break;
|
||||
|
||||
}
|
||||
case RecommendationsNotificationResult.Ignored:
|
||||
// Ignored: Remove from the cache and prompt next recommendation
|
||||
this.mediumImportanceTipsByExe.delete(exeName);
|
||||
this.promptMediumImportanceExeBasedTip();
|
||||
break;
|
||||
|
||||
case RecommendationsNotificationResult.IncompatibleWindow:
|
||||
case RecommendationsNotificationResult.IncompatibleWindow: {
|
||||
// Recommended in incompatible window. Schedule the prompt after active window change
|
||||
const onActiveWindowChange = Event.once(Event.latch(Event.any(this.nativeHostService.onDidOpenWindow, this.nativeHostService.onDidFocusWindow)));
|
||||
this._register(onActiveWindowChange(() => this.promptMediumImportanceExeBasedTip()));
|
||||
break;
|
||||
|
||||
case RecommendationsNotificationResult.TooMany:
|
||||
}
|
||||
case RecommendationsNotificationResult.TooMany: {
|
||||
// Too many notifications. Schedule the prompt after one hour
|
||||
const disposable2 = this._register(disposableTimeout(() => { disposable2.dispose(); this.promptMediumImportanceExeBasedTip(); }, 60 * 60 * 1000 /* 1 hour */));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ export interface IRecursiveWatcher {
|
|||
readonly onDidLogMessage: Event<ILogMessage>;
|
||||
|
||||
/**
|
||||
* An event to indicate an error occured from the watcher
|
||||
* An event to indicate an error occurred from the watcher
|
||||
* that is unrecoverable. Listeners should restart the
|
||||
* watcher if possible.
|
||||
*/
|
||||
|
|
|
@ -397,13 +397,10 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple
|
|||
} catch (error) {
|
||||
throw this.toFileSystemProviderError(error);
|
||||
} finally {
|
||||
|
||||
// Release any known lock for the file handle
|
||||
// since the handle has been closed and is invalid
|
||||
const lockForHandle = this.mapHandleToLock.get(fd);
|
||||
if (lockForHandle) {
|
||||
lockForHandle.dispose();
|
||||
this.mapHandleToLock.delete(fd);
|
||||
lockForHandle.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -323,7 +323,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
|
|||
await Promises.unlink(source);
|
||||
} catch (error) {
|
||||
switch (error.code) {
|
||||
case 'EACCES':
|
||||
case 'EACCES': {
|
||||
const { response } = await this.showMessageBox(windowId, {
|
||||
title: this.productService.nameLong,
|
||||
type: 'info',
|
||||
|
@ -346,6 +346,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'ENOENT':
|
||||
break; // ignore file not found
|
||||
default:
|
||||
|
|
|
@ -298,7 +298,7 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
|
|||
case TriggerAction.REFRESH_PICKER:
|
||||
updatePickerItems();
|
||||
break;
|
||||
case TriggerAction.REMOVE_ITEM:
|
||||
case TriggerAction.REMOVE_ITEM: {
|
||||
const index = picker.items.indexOf(item);
|
||||
if (index !== -1) {
|
||||
const items = picker.items.slice();
|
||||
|
@ -313,6 +313,7 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
|
|||
picker.keepScrollPosition = keepScrollPositionBefore;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -473,11 +473,13 @@ export class PersistentTerminalProcess extends Disposable {
|
|||
get fixedDimensions(): IFixedTerminalDimensions | undefined { return this._fixedDimensions; }
|
||||
|
||||
setTitle(title: string, titleSource: TitleEventSource): void {
|
||||
this._hasWrittenData = true;
|
||||
this._title = title;
|
||||
this._titleSource = titleSource;
|
||||
}
|
||||
|
||||
setIcon(icon: TerminalIcon, color?: string): void {
|
||||
this._hasWrittenData = true;
|
||||
this._icon = icon;
|
||||
this._color = color;
|
||||
}
|
||||
|
|
|
@ -399,20 +399,22 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
|
|||
|
||||
async refreshProperty<T extends ProcessPropertyType>(type: T): Promise<IProcessPropertyMap[T]> {
|
||||
switch (type) {
|
||||
case ProcessPropertyType.Cwd:
|
||||
case ProcessPropertyType.Cwd: {
|
||||
const newCwd = await this.getCwd();
|
||||
if (newCwd !== this._properties.cwd) {
|
||||
this._properties.cwd = newCwd;
|
||||
this._onDidChangeProperty.fire({ type: ProcessPropertyType.Cwd, value: this._properties.cwd });
|
||||
}
|
||||
return newCwd as IProcessPropertyMap[T];
|
||||
case ProcessPropertyType.InitialCwd:
|
||||
}
|
||||
case ProcessPropertyType.InitialCwd: {
|
||||
const initialCwd = await this.getInitialCwd();
|
||||
if (initialCwd !== this._properties.initialCwd) {
|
||||
this._properties.initialCwd = initialCwd;
|
||||
this._onDidChangeProperty.fire({ type: ProcessPropertyType.InitialCwd, value: this._properties.initialCwd });
|
||||
}
|
||||
return initialCwd as IProcessPropertyMap[T];
|
||||
}
|
||||
case ProcessPropertyType.Title:
|
||||
return this.currentTitle as IProcessPropertyMap[T];
|
||||
default:
|
||||
|
|
|
@ -555,7 +555,7 @@ export function executeTransform(transform: ColorTransform, theme: IColorTheme)
|
|||
case ColorTransformType.IfDefinedThenElse:
|
||||
return resolveColorValue(theme.defines(transform.if) ? transform.then : transform.else, theme);
|
||||
|
||||
case ColorTransformType.LessProminent:
|
||||
case ColorTransformType.LessProminent: {
|
||||
const from = resolveColorValue(transform.value, theme);
|
||||
if (!from) {
|
||||
return undefined;
|
||||
|
@ -569,6 +569,7 @@ export function executeTransform(transform: ColorTransform, theme: IColorTheme)
|
|||
return from.isDarkerThan(backgroundColor)
|
||||
? Color.getLighterColor(from, backgroundColor, transform.factor).transparent(transform.transparency)
|
||||
: Color.getDarkerColor(from, backgroundColor, transform.factor).transparent(transform.transparency);
|
||||
}
|
||||
default:
|
||||
throw assertNever(transform);
|
||||
}
|
||||
|
|
|
@ -839,7 +839,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
|||
case 'one':
|
||||
case 'all':
|
||||
case 'preserve':
|
||||
case 'folders':
|
||||
case 'folders': {
|
||||
|
||||
// Collect previously opened windows
|
||||
const lastSessionWindows: IWindowState[] = [];
|
||||
|
@ -876,6 +876,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
|||
}
|
||||
|
||||
return pathsToOpen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtHostContext, IExtHostEditorTabsShape, IExtHostContext, MainContext, IEditorTabDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { EditorResourceAccessor, IUntypedEditorInput, SideBySideEditor, GroupChangeKind } from 'vs/workbench/common/editor';
|
||||
import { EditorResourceAccessor, IUntypedEditorInput, SideBySideEditor, GroupModelChangeKind } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { isGroupEditorCloseEvent, isGroupEditorMoveEvent, isGroupEditorOpenEvent } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
|
@ -157,7 +157,7 @@ export class MainThreadEditorTabs {
|
|||
}
|
||||
|
||||
private _onDidGroupActivate(event: IEditorsChangeEvent): void {
|
||||
if (event.kind !== GroupChangeKind.GROUP_INDEX && event.kind !== GroupChangeKind.EDITOR_ACTIVE) {
|
||||
if (event.kind !== GroupModelChangeKind.GROUP_INDEX && event.kind !== GroupModelChangeKind.EDITOR_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
this._findAndUpdateActiveTab();
|
||||
|
@ -188,15 +188,15 @@ export class MainThreadEditorTabs {
|
|||
// let eventString = '[';
|
||||
// events.forEach(event => {
|
||||
// switch (event.kind) {
|
||||
// case GroupChangeKind.GROUP_INDEX: eventString += 'GROUP_INDEX, '; break;
|
||||
// case GroupChangeKind.EDITOR_ACTIVE: eventString += 'EDITOR_ACTIVE, '; break;
|
||||
// case GroupChangeKind.EDITOR_PIN: eventString += 'EDITOR_PIN, '; break;
|
||||
// case GroupChangeKind.EDITOR_OPEN: eventString += 'EDITOR_OPEN, '; break;
|
||||
// case GroupChangeKind.EDITOR_CLOSE: eventString += 'EDITOR_CLOSE, '; break;
|
||||
// case GroupChangeKind.EDITOR_MOVE: eventString += 'EDITOR_MOVE, '; break;
|
||||
// case GroupChangeKind.EDITOR_LABEL: eventString += 'EDITOR_LABEL, '; break;
|
||||
// case GroupChangeKind.GROUP_ACTIVE: eventString += 'GROUP_ACTIVE, '; break;
|
||||
// case GroupChangeKind.GROUP_LOCKED: eventString += 'GROUP_LOCKED, '; break;
|
||||
// case GroupModelChangeKind.GROUP_INDEX: eventString += 'GROUP_INDEX, '; break;
|
||||
// case GroupModelChangeKind.EDITOR_ACTIVE: eventString += 'EDITOR_ACTIVE, '; break;
|
||||
// case GroupModelChangeKind.EDITOR_PIN: eventString += 'EDITOR_PIN, '; break;
|
||||
// case GroupModelChangeKind.EDITOR_OPEN: eventString += 'EDITOR_OPEN, '; break;
|
||||
// case GroupModelChangeKind.EDITOR_CLOSE: eventString += 'EDITOR_CLOSE, '; break;
|
||||
// case GroupModelChangeKind.EDITOR_MOVE: eventString += 'EDITOR_MOVE, '; break;
|
||||
// case GroupModelChangeKind.EDITOR_LABEL: eventString += 'EDITOR_LABEL, '; break;
|
||||
// case GroupModelChangeKind.GROUP_ACTIVE: eventString += 'GROUP_ACTIVE, '; break;
|
||||
// case GroupModelChangeKind.GROUP_LOCKED: eventString += 'GROUP_LOCKED, '; break;
|
||||
// default: eventString += 'UNKNOWN, '; break;
|
||||
// }
|
||||
// });
|
||||
|
@ -212,24 +212,24 @@ export class MainThreadEditorTabs {
|
|||
events.forEach(event => {
|
||||
// Call the correct function for the change type
|
||||
switch (event.kind) {
|
||||
case GroupChangeKind.EDITOR_OPEN:
|
||||
case GroupModelChangeKind.EDITOR_OPEN:
|
||||
this._onDidTabOpen(event);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_CLOSE:
|
||||
case GroupModelChangeKind.EDITOR_CLOSE:
|
||||
this._onDidTabClose(event);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_ACTIVE:
|
||||
case GroupChangeKind.GROUP_ACTIVE:
|
||||
case GroupModelChangeKind.EDITOR_ACTIVE:
|
||||
case GroupModelChangeKind.GROUP_ACTIVE:
|
||||
if (this._editorGroupsService.activeGroup.id !== event.groupId) {
|
||||
return;
|
||||
}
|
||||
this._onDidGroupActivate(event);
|
||||
break;
|
||||
case GroupChangeKind.GROUP_INDEX:
|
||||
case GroupModelChangeKind.GROUP_INDEX:
|
||||
this._createTabsModel();
|
||||
// Here we stop the loop as no need to process other events
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_MOVE:
|
||||
case GroupModelChangeKind.EDITOR_MOVE:
|
||||
this._onDidTabMove(event);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -247,9 +247,10 @@ class SaveWorkspaceAsAction extends Action2 {
|
|||
if (configPathUri && hasWorkspaceFileExtension(configPathUri)) {
|
||||
switch (contextService.getWorkbenchState()) {
|
||||
case WorkbenchState.EMPTY:
|
||||
case WorkbenchState.FOLDER:
|
||||
case WorkbenchState.FOLDER: {
|
||||
const folders = contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri }));
|
||||
return workspaceEditingService.createAndEnterWorkspace(folders, configPathUri);
|
||||
}
|
||||
case WorkbenchState.WORKSPACE:
|
||||
return workspaceEditingService.saveAndEnterWorkspace(configPathUri);
|
||||
}
|
||||
|
|
|
@ -963,29 +963,32 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||
case Parts.EDITOR_PART:
|
||||
this.editorGroupService.activeGroup.focus();
|
||||
break;
|
||||
case Parts.PANEL_PART:
|
||||
case Parts.PANEL_PART: {
|
||||
const activePanel = this.paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel);
|
||||
if (activePanel) {
|
||||
activePanel.focus();
|
||||
}
|
||||
break;
|
||||
case Parts.SIDEBAR_PART:
|
||||
}
|
||||
case Parts.SIDEBAR_PART: {
|
||||
const activeViewlet = this.paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar);
|
||||
if (activeViewlet) {
|
||||
activeViewlet.focus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Parts.ACTIVITYBAR_PART:
|
||||
(this.getPart(Parts.ACTIVITYBAR_PART) as ActivitybarPart).focus();
|
||||
break;
|
||||
case Parts.STATUSBAR_PART:
|
||||
this.statusBarService.focus();
|
||||
default:
|
||||
default: {
|
||||
// Title Bar & Banner simply pass focus to container
|
||||
const container = this.getContainer(part);
|
||||
if (container) {
|
||||
container.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/editorgroupview';
|
||||
import { EditorGroupModel, IEditorOpenOptions, IGroupChangeEvent, IGroupEditorCloseEvent, IGroupEditorMoveEvent, IGroupEditorOpenEvent, ISerializedEditorGroupModel, isGroupEditorCloseEvent, isGroupEditorMoveEvent, isGroupEditorOpenEvent, isSerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { GroupIdentifier, CloseDirection, IEditorCloseEvent, ActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, ActiveEditorStickyContext, ActiveEditorPinnedContext, EditorResourceAccessor, EditorInputCapabilities, IUntypedEditorInput, DEFAULT_EDITOR_ASSOCIATION, ActiveEditorGroupLockedContext, SideBySideEditor, EditorCloseContext, IEditorWillMoveEvent, IEditorWillOpenEvent, IMatchEditorOptions, GroupChangeKind } from 'vs/workbench/common/editor';
|
||||
import { EditorGroupModel, IEditorOpenOptions, IGroupModelChangeEvent, ISerializedEditorGroupModel, isGroupEditorCloseEvent, isGroupEditorOpenEvent, isSerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { GroupIdentifier, CloseDirection, IEditorCloseEvent, ActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, ActiveEditorStickyContext, ActiveEditorPinnedContext, EditorResourceAccessor, EditorInputCapabilities, IUntypedEditorInput, DEFAULT_EDITOR_ASSOCIATION, ActiveEditorGroupLockedContext, SideBySideEditor, EditorCloseContext, IEditorWillMoveEvent, IEditorWillOpenEvent, IMatchEditorOptions, GroupModelChangeKind, IActiveEditorChangeEvent } from 'vs/workbench/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
import { Event, Emitter, Relay } from 'vs/base/common/event';
|
||||
|
@ -87,12 +87,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
private readonly _onWillDispose = this._register(new Emitter<void>());
|
||||
readonly onWillDispose = this._onWillDispose.event;
|
||||
|
||||
private readonly _onDidGroupChange = this._register(new Emitter<IGroupChangeEvent>());
|
||||
readonly onDidGroupChange = this._onDidGroupChange.event;
|
||||
|
||||
private readonly _onDidModelChange = this._register(new Emitter<IGroupChangeEvent>());
|
||||
private readonly _onDidModelChange = this._register(new Emitter<IGroupModelChangeEvent>());
|
||||
readonly onDidModelChange = this._onDidModelChange.event;
|
||||
|
||||
private readonly _onDidActiveEditorChange = this._register(new Emitter<IActiveEditorChangeEvent>());
|
||||
readonly onDidActiveEditorChange = this._onDidActiveEditorChange.event;
|
||||
|
||||
private readonly _onDidOpenEditorFail = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidOpenEditorFail = this._onDidOpenEditorFail.event;
|
||||
|
||||
|
@ -266,32 +266,33 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
};
|
||||
|
||||
// Update group contexts based on group changes
|
||||
this._register(this.onDidGroupChange(e => {
|
||||
this._register(this.onDidModelChange(e => {
|
||||
switch (e.kind) {
|
||||
case GroupChangeKind.EDITOR_ACTIVE:
|
||||
// Track the active editor and update context key that reflects
|
||||
// the dirty state of this editor
|
||||
observeActiveEditor();
|
||||
case GroupModelChangeKind.GROUP_LOCKED:
|
||||
groupLockedContext.set(this.isLocked);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_PIN:
|
||||
case GroupModelChangeKind.EDITOR_PIN:
|
||||
if (e.editor && e.editor === this.model.activeEditor) {
|
||||
groupActiveEditorPinnedContext.set(this.model.isPinned(this.model.activeEditor));
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_STICKY:
|
||||
case GroupModelChangeKind.EDITOR_STICKY:
|
||||
if (e.editor && e.editor === this.model.activeEditor) {
|
||||
groupActiveEditorStickyContext.set(this.model.isSticky(this.model.activeEditor));
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.GROUP_LOCKED:
|
||||
groupLockedContext.set(this.isLocked);
|
||||
break;
|
||||
}
|
||||
|
||||
// Group editors count context
|
||||
groupEditorsCountContext.set(this.count);
|
||||
}));
|
||||
|
||||
// Track the active editor and update context key that reflects
|
||||
// the dirty state of this editor
|
||||
this._register(this.onDidActiveEditorChange(() => {
|
||||
observeActiveEditor();
|
||||
}));
|
||||
|
||||
observeActiveEditor();
|
||||
}
|
||||
|
||||
|
@ -535,76 +536,40 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
this._register(this.accessor.onDidVisibilityChange(e => this.onDidVisibilityChange(e)));
|
||||
}
|
||||
|
||||
private onDidGroupModelChange(e: IGroupChangeEvent): void {
|
||||
private onDidGroupModelChange(e: IGroupModelChangeEvent): void {
|
||||
|
||||
// Re-emit to outside
|
||||
this._onDidModelChange.fire(e);
|
||||
|
||||
// Handle within
|
||||
|
||||
if (e.kind === GroupChangeKind.GROUP_LOCKED) {
|
||||
this.onDidChangeGroupLocked();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.kind) {
|
||||
case GroupChangeKind.EDITOR_PIN:
|
||||
this.onDidChangeEditorPinned(e.editor);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_STICKY:
|
||||
this.onDidChangeEditorSticky(e.editor);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_MOVE:
|
||||
if (isGroupEditorMoveEvent(e)) {
|
||||
this.onDidMoveEditor(e.editor, e.oldEditorIndex, e.editorIndex);
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_OPEN:
|
||||
case GroupModelChangeKind.EDITOR_OPEN:
|
||||
if (isGroupEditorOpenEvent(e)) {
|
||||
this.onDidOpenEditor(e.editor, e.editorIndex);
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_CLOSE:
|
||||
case GroupModelChangeKind.EDITOR_CLOSE:
|
||||
if (isGroupEditorCloseEvent(e)) {
|
||||
this.handleOnDidCloseEditor(e.editor, e.editorIndex, e.context, e.sticky);
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_WILL_DISPOSE:
|
||||
case GroupModelChangeKind.EDITOR_WILL_DISPOSE:
|
||||
this.onWillDisposeEditor(e.editor);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_DIRTY:
|
||||
case GroupModelChangeKind.EDITOR_DIRTY:
|
||||
this.onDidChangeEditorDirty(e.editor);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_LABEL:
|
||||
case GroupModelChangeKind.EDITOR_LABEL:
|
||||
this.onDidChangeEditorLabel(e.editor);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_CAPABILITIES:
|
||||
this.onDidChangeEditorCapabilities(e.editor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeGroupLocked(): void {
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.GROUP_LOCKED });
|
||||
}
|
||||
|
||||
private onDidChangeEditorPinned(editor: EditorInput): void {
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_PIN, editor });
|
||||
}
|
||||
|
||||
private onDidChangeEditorSticky(editor: EditorInput): void {
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_STICKY, editor });
|
||||
}
|
||||
|
||||
private onDidMoveEditor(editor: EditorInput, oldEditorIndex: number, editorIndex: number): void {
|
||||
const event: IGroupEditorMoveEvent = { kind: GroupChangeKind.EDITOR_MOVE, editor, oldEditorIndex, editorIndex };
|
||||
this._onDidGroupChange.fire(event);
|
||||
}
|
||||
|
||||
private onDidOpenEditor(editor: EditorInput, editorIndex: number): void {
|
||||
|
||||
/* __GDPR__
|
||||
|
@ -618,10 +583,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
|
||||
// Update container
|
||||
this.updateContainer();
|
||||
|
||||
// Event
|
||||
const event: IGroupEditorOpenEvent = { kind: GroupChangeKind.EDITOR_OPEN, editor, editorIndex };
|
||||
this._onDidGroupChange.fire(event);
|
||||
}
|
||||
|
||||
private handleOnDidCloseEditor(editor: EditorInput, editorIndex: number, context: EditorCloseContext, sticky: boolean): void {
|
||||
|
@ -661,8 +622,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
|
||||
// Event
|
||||
this._onDidCloseEditor.fire({ groupId: this.id, editor, context, index: editorIndex, sticky });
|
||||
const event: IGroupEditorCloseEvent = { kind: GroupChangeKind.EDITOR_CLOSE, editor, editorIndex, context, sticky };
|
||||
this._onDidGroupChange.fire(event);
|
||||
}
|
||||
|
||||
private canDispose(editor: EditorInput): boolean {
|
||||
|
@ -776,24 +735,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
|
||||
// Forward to title control
|
||||
this.titleAreaControl.updateEditorDirty(editor);
|
||||
|
||||
// Event
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_DIRTY, editor });
|
||||
}
|
||||
|
||||
private onDidChangeEditorLabel(editor: EditorInput): void {
|
||||
|
||||
// Forward to title control
|
||||
this.titleAreaControl.updateEditorLabel(editor);
|
||||
|
||||
// Event
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_LABEL, editor });
|
||||
}
|
||||
|
||||
private onDidChangeEditorCapabilities(editor: EditorInput): void {
|
||||
|
||||
// Event
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_CAPABILITIES, editor });
|
||||
}
|
||||
|
||||
private onDidVisibilityChange(visible: boolean): void {
|
||||
|
@ -843,8 +790,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
if (this._index !== newIndex) {
|
||||
this._index = newIndex;
|
||||
this.model.setIndex(newIndex);
|
||||
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.GROUP_INDEX });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -861,8 +806,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
// Update styles
|
||||
this.updateStyles();
|
||||
|
||||
// Event
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.GROUP_ACTIVE });
|
||||
// Update model
|
||||
this.model.setActive(undefined /* entire group got active */);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
@ -1119,7 +1064,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
|
||||
// Editor change event
|
||||
if (changed) {
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_ACTIVE, editor });
|
||||
this._onDidActiveEditorChange.fire({ editor });
|
||||
}
|
||||
|
||||
// Handle errors but do not bubble them up
|
||||
|
@ -1535,7 +1480,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
}
|
||||
|
||||
// Events
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_ACTIVE });
|
||||
this._onDidActiveEditorChange.fire({ editor: undefined });
|
||||
|
||||
// Remove empty group if we should
|
||||
if (closeEmptyGroup) {
|
||||
|
@ -1690,7 +1635,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
|
||||
// Otherwise, handle accordingly
|
||||
switch (confirmation) {
|
||||
case ConfirmResult.SAVE:
|
||||
case ConfirmResult.SAVE: {
|
||||
const result = await editor.save(this.id, { reason: saveReason });
|
||||
if (!result && autoSave) {
|
||||
// Save failed and we need to signal this back to the user, so
|
||||
|
@ -1701,6 +1646,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
}
|
||||
|
||||
return editor.isDirty(); // veto if still dirty
|
||||
}
|
||||
case ConfirmResult.DONT_SAVE:
|
||||
try {
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import { contrastBorder, editorBackground } from 'vs/platform/theme/common/color
|
|||
import { GroupDirection, IAddGroupOptions, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, GroupsOrder, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorGroupsService, IEditorSideGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid';
|
||||
import { GroupIdentifier, EditorInputWithOptions, IEditorPartOptions, IEditorPartOptionsChangeEvent, GroupChangeKind } from 'vs/workbench/common/editor';
|
||||
import { GroupIdentifier, EditorInputWithOptions, IEditorPartOptions, IEditorPartOptionsChangeEvent, GroupModelChangeKind } from 'vs/workbench/common/editor';
|
||||
import { EDITOR_GROUP_BORDER, EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { distinct, coalesce, firstOrDefault } from 'vs/base/common/arrays';
|
||||
import { IEditorGroupsAccessor, IEditorGroupView, getEditorPartOptions, impactsEditorPartOptions, IEditorPartCreationOptions } from 'vs/workbench/browser/parts/editor/editor';
|
||||
|
@ -237,20 +237,21 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
|||
case GroupsOrder.CREATION_TIME:
|
||||
return this.groups;
|
||||
|
||||
case GroupsOrder.MOST_RECENTLY_ACTIVE:
|
||||
case GroupsOrder.MOST_RECENTLY_ACTIVE: {
|
||||
const mostRecentActive = coalesce(this.mostRecentActiveGroups.map(groupId => this.getGroup(groupId)));
|
||||
|
||||
// there can be groups that got never active, even though they exist. in this case
|
||||
// make sure to just append them at the end so that all groups are returned properly
|
||||
return distinct([...mostRecentActive, ...this.groups]);
|
||||
|
||||
case GroupsOrder.GRID_APPEARANCE:
|
||||
}
|
||||
case GroupsOrder.GRID_APPEARANCE: {
|
||||
const views: IEditorGroupView[] = [];
|
||||
if (this.gridWidget) {
|
||||
this.fillGridNodes(views, this.gridWidget.getViews());
|
||||
}
|
||||
|
||||
return views;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,20 +302,22 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
|||
return groups[0];
|
||||
case GroupLocation.LAST:
|
||||
return groups[groups.length - 1];
|
||||
case GroupLocation.NEXT:
|
||||
case GroupLocation.NEXT: {
|
||||
let nextGroup: IEditorGroupView | undefined = groups[index + 1];
|
||||
if (!nextGroup && wrap) {
|
||||
nextGroup = this.doFindGroupByLocation(GroupLocation.FIRST, source);
|
||||
}
|
||||
|
||||
return nextGroup;
|
||||
case GroupLocation.PREVIOUS:
|
||||
}
|
||||
case GroupLocation.PREVIOUS: {
|
||||
let previousGroup: IEditorGroupView | undefined = groups[index - 1];
|
||||
if (!previousGroup && wrap) {
|
||||
previousGroup = this.doFindGroupByLocation(GroupLocation.LAST, source);
|
||||
}
|
||||
|
||||
return previousGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,21 +553,23 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
|||
this.doSetGroupActive(groupView);
|
||||
}));
|
||||
|
||||
// Track editor change
|
||||
groupDisposables.add(groupView.onDidGroupChange(e => {
|
||||
// Track group changes
|
||||
groupDisposables.add(groupView.onDidModelChange(e => {
|
||||
switch (e.kind) {
|
||||
case GroupChangeKind.EDITOR_ACTIVE:
|
||||
this.updateContainer();
|
||||
break;
|
||||
case GroupChangeKind.GROUP_INDEX:
|
||||
this._onDidChangeGroupIndex.fire(groupView);
|
||||
break;
|
||||
case GroupChangeKind.GROUP_LOCKED:
|
||||
case GroupModelChangeKind.GROUP_LOCKED:
|
||||
this._onDidChangeGroupLocked.fire(groupView);
|
||||
break;
|
||||
case GroupModelChangeKind.GROUP_INDEX:
|
||||
this._onDidChangeGroupIndex.fire(groupView);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
||||
// Track active editor change after it occurred
|
||||
groupDisposables.add(groupView.onDidActiveEditorChange(() => {
|
||||
this.updateContainer();
|
||||
}));
|
||||
|
||||
// Track dispose
|
||||
Event.once(groupView.onWillDispose)(() => {
|
||||
dispose(groupDisposables);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IEditorFactoryRegistry, IEditorIdentifier, GroupIdentifier, EditorExtensions, IEditorPartOptionsChangeEvent, EditorsOrder, GroupChangeKind } from 'vs/workbench/common/editor';
|
||||
import { IEditorFactoryRegistry, IEditorIdentifier, GroupIdentifier, EditorExtensions, IEditorPartOptionsChangeEvent, EditorsOrder, GroupModelChangeKind } from 'vs/workbench/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
@ -115,11 +115,11 @@ export class EditorsObserver extends Disposable {
|
|||
|
||||
private registerGroupListeners(group: IEditorGroup): void {
|
||||
const groupDisposables = new DisposableStore();
|
||||
groupDisposables.add(group.onDidGroupChange(e => {
|
||||
groupDisposables.add(group.onDidModelChange(e => {
|
||||
switch (e.kind) {
|
||||
|
||||
// Group gets active: put active editor as most recent
|
||||
case GroupChangeKind.GROUP_ACTIVE: {
|
||||
case GroupModelChangeKind.GROUP_ACTIVE: {
|
||||
if (this.editorGroupsService.activeGroup === group && group.activeEditor) {
|
||||
this.addMostRecentEditor(group, group.activeEditor, true /* is active */, false /* editor already opened */);
|
||||
}
|
||||
|
@ -127,21 +127,11 @@ export class EditorsObserver extends Disposable {
|
|||
break;
|
||||
}
|
||||
|
||||
// Editor gets active: put active editor as most recent
|
||||
// if group is active, otherwise second most recent
|
||||
case GroupChangeKind.EDITOR_ACTIVE: {
|
||||
if (e.editor) {
|
||||
this.addMostRecentEditor(group, e.editor, this.editorGroupsService.activeGroup === group, false /* editor already opened */);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Editor opens: put it as second most recent
|
||||
//
|
||||
// Also check for maximum allowed number of editors and
|
||||
// start to close oldest ones if needed.
|
||||
case GroupChangeKind.EDITOR_OPEN: {
|
||||
case GroupModelChangeKind.EDITOR_OPEN: {
|
||||
if (e.editor) {
|
||||
this.addMostRecentEditor(group, e.editor, false /* is not active */, true /* is new */);
|
||||
this.ensureOpenedEditorsLimit({ groupId: group.id, editor: e.editor }, group.id);
|
||||
|
@ -149,15 +139,19 @@ export class EditorsObserver extends Disposable {
|
|||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// Editor closes: remove from recently opened
|
||||
case GroupChangeKind.EDITOR_CLOSE: {
|
||||
if (e.editor) {
|
||||
this.removeMostRecentEditor(group, e.editor);
|
||||
}
|
||||
// Editor closes: remove from recently opened
|
||||
groupDisposables.add(group.onDidCloseEditor(e => {
|
||||
this.removeMostRecentEditor(group, e.editor);
|
||||
}));
|
||||
|
||||
break;
|
||||
}
|
||||
// Editor gets active: put active editor as most recent
|
||||
// if group is active, otherwise second most recent
|
||||
groupDisposables.add(group.onDidActiveEditorChange(e => {
|
||||
if (e.editor) {
|
||||
this.addMostRecentEditor(group, e.editor, this.editorGroupsService.activeGroup === group, false /* editor already opened */);
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntry
|
|||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IAction, Separator, toAction } from 'vs/base/common/actions';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { STATUS_BAR_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_ITEM_ACTIVE_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND, STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND, STATUS_BAR_BORDER, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER } from 'vs/workbench/common/theme';
|
||||
import { STATUS_BAR_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_ITEM_ACTIVE_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND, STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND, STATUS_BAR_BORDER, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_ITEM_COMPACT_HOVER_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { EventHelper, createStyleSheet, addDisposableListener, EventType, clearNode } from 'vs/base/browser/dom';
|
||||
|
@ -414,8 +414,9 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
|||
// Install mouse listeners to update hover feedback for
|
||||
// all compact entries that belong to each other
|
||||
const statusBarItemHoverBackground = this.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND)?.toString();
|
||||
const statusBarItemCompactHoverBackground = this.getColor(STATUS_BAR_ITEM_COMPACT_HOVER_BACKGROUND)?.toString();
|
||||
this.compactEntriesDisposable.value = new DisposableStore();
|
||||
if (statusBarItemHoverBackground && this.theme.type !== ColorScheme.HIGH_CONTRAST) {
|
||||
if (statusBarItemHoverBackground && statusBarItemCompactHoverBackground && this.theme.type !== ColorScheme.HIGH_CONTRAST) {
|
||||
for (const [, compactEntryGroup] of compactEntryGroups) {
|
||||
for (const compactEntry of compactEntryGroup) {
|
||||
if (!compactEntry.hasCommand) {
|
||||
|
@ -424,6 +425,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
|||
|
||||
this.compactEntriesDisposable.value.add(addDisposableListener(compactEntry.labelContainer, EventType.MOUSE_OVER, () => {
|
||||
compactEntryGroup.forEach(compactEntry => compactEntry.labelContainer.style.backgroundColor = statusBarItemHoverBackground);
|
||||
compactEntry.labelContainer.style.backgroundColor = statusBarItemCompactHoverBackground;
|
||||
}));
|
||||
|
||||
this.compactEntriesDisposable.value.add(addDisposableListener(compactEntry.labelContainer, EventType.MOUSE_OUT, () => {
|
||||
|
|
|
@ -226,7 +226,7 @@ class ViewPaneDropOverlay extends Themable {
|
|||
case DropDirection.RIGHT:
|
||||
this.doPositionOverlay({ top: '0', right: '0', width: '50%', height: '100%' });
|
||||
break;
|
||||
default:
|
||||
default: {
|
||||
// const top = this.bounds?.top || 0;
|
||||
// const left = this.bounds?.bottom || 0;
|
||||
|
||||
|
@ -243,6 +243,7 @@ class ViewPaneDropOverlay extends Themable {
|
|||
}
|
||||
|
||||
this.doPositionOverlay({ top, left, width, height });
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.orientation === Orientation.VERTICAL && paneHeight <= 25) ||
|
||||
|
|
|
@ -785,6 +785,14 @@ export interface IEditorCloseEvent extends IEditorIdentifier {
|
|||
readonly sticky: boolean;
|
||||
}
|
||||
|
||||
export interface IActiveEditorChangeEvent {
|
||||
|
||||
/**
|
||||
* The new active editor or `undefined` if the group is empty.
|
||||
*/
|
||||
editor: EditorInput | undefined;
|
||||
}
|
||||
|
||||
export interface IEditorWillMoveEvent extends IEditorIdentifier {
|
||||
|
||||
/**
|
||||
|
@ -823,7 +831,7 @@ export interface IEditorOpenEvent extends IEditorIdentifier {
|
|||
|
||||
export type GroupIdentifier = number;
|
||||
|
||||
export const enum GroupChangeKind {
|
||||
export const enum GroupModelChangeKind {
|
||||
|
||||
/* Group Changes */
|
||||
GROUP_ACTIVE,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IEditorFactoryRegistry, GroupIdentifier, EditorsOrder, EditorExtensions, IUntypedEditorInput, SideBySideEditor, EditorCloseContext, IMatchEditorOptions, GroupChangeKind } from 'vs/workbench/common/editor';
|
||||
import { IEditorFactoryRegistry, GroupIdentifier, EditorsOrder, EditorExtensions, IUntypedEditorInput, SideBySideEditor, EditorCloseContext, IMatchEditorOptions, GroupModelChangeKind } from 'vs/workbench/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
@ -70,12 +70,12 @@ export interface IMatchOptions {
|
|||
readonly strictEquals?: boolean;
|
||||
}
|
||||
|
||||
export interface IGroupChangeEvent {
|
||||
export interface IGroupModelChangeEvent {
|
||||
|
||||
/**
|
||||
* The kind of change that occured in the group.
|
||||
* The kind of change that occured in the group model.
|
||||
*/
|
||||
readonly kind: GroupChangeKind;
|
||||
readonly kind: GroupModelChangeKind;
|
||||
|
||||
/**
|
||||
* Only applies when editors change providing
|
||||
|
@ -84,13 +84,13 @@ export interface IGroupChangeEvent {
|
|||
readonly editor?: EditorInput;
|
||||
}
|
||||
|
||||
export interface IGroupEditorChangeEvent extends IGroupChangeEvent {
|
||||
export interface IGroupEditorChangeEvent extends IGroupModelChangeEvent {
|
||||
readonly editor: EditorInput;
|
||||
}
|
||||
|
||||
export interface IGroupEditorOpenEvent extends IGroupEditorChangeEvent {
|
||||
|
||||
readonly kind: GroupChangeKind.EDITOR_OPEN;
|
||||
readonly kind: GroupModelChangeKind.EDITOR_OPEN;
|
||||
|
||||
/**
|
||||
* Identifies the index of the editor in the group.
|
||||
|
@ -98,15 +98,15 @@ export interface IGroupEditorOpenEvent extends IGroupEditorChangeEvent {
|
|||
readonly editorIndex: number;
|
||||
}
|
||||
|
||||
export function isGroupEditorOpenEvent(e: IGroupChangeEvent): e is IGroupEditorOpenEvent {
|
||||
export function isGroupEditorOpenEvent(e: IGroupModelChangeEvent): e is IGroupEditorOpenEvent {
|
||||
const candidate = e as IGroupEditorOpenEvent;
|
||||
|
||||
return candidate.kind === GroupChangeKind.EDITOR_OPEN && candidate.editorIndex !== undefined;
|
||||
return candidate.kind === GroupModelChangeKind.EDITOR_OPEN && candidate.editorIndex !== undefined;
|
||||
}
|
||||
|
||||
export interface IGroupEditorMoveEvent extends IGroupEditorChangeEvent {
|
||||
|
||||
readonly kind: GroupChangeKind.EDITOR_MOVE;
|
||||
readonly kind: GroupModelChangeKind.EDITOR_MOVE;
|
||||
|
||||
/**
|
||||
* Identifies the index of the editor in the group.
|
||||
|
@ -121,15 +121,15 @@ export interface IGroupEditorMoveEvent extends IGroupEditorChangeEvent {
|
|||
readonly oldEditorIndex: number;
|
||||
}
|
||||
|
||||
export function isGroupEditorMoveEvent(e: IGroupChangeEvent): e is IGroupEditorMoveEvent {
|
||||
export function isGroupEditorMoveEvent(e: IGroupModelChangeEvent): e is IGroupEditorMoveEvent {
|
||||
const candidate = e as IGroupEditorMoveEvent;
|
||||
|
||||
return candidate.kind === GroupChangeKind.EDITOR_MOVE && candidate.editorIndex !== undefined && candidate.oldEditorIndex !== undefined;
|
||||
return candidate.kind === GroupModelChangeKind.EDITOR_MOVE && candidate.editorIndex !== undefined && candidate.oldEditorIndex !== undefined;
|
||||
}
|
||||
|
||||
export interface IGroupEditorCloseEvent extends IGroupEditorChangeEvent {
|
||||
|
||||
readonly kind: GroupChangeKind.EDITOR_CLOSE;
|
||||
readonly kind: GroupModelChangeKind.EDITOR_CLOSE;
|
||||
|
||||
/**
|
||||
* Identifies the index of the editor in the group.
|
||||
|
@ -151,10 +151,10 @@ export interface IGroupEditorCloseEvent extends IGroupEditorChangeEvent {
|
|||
readonly sticky: boolean;
|
||||
}
|
||||
|
||||
export function isGroupEditorCloseEvent(e: IGroupChangeEvent): e is IGroupEditorCloseEvent {
|
||||
export function isGroupEditorCloseEvent(e: IGroupModelChangeEvent): e is IGroupEditorCloseEvent {
|
||||
const candidate = e as IGroupEditorCloseEvent;
|
||||
|
||||
return candidate.kind === GroupChangeKind.EDITOR_CLOSE && candidate.editorIndex !== undefined && candidate.context !== undefined && candidate.sticky !== undefined;
|
||||
return candidate.kind === GroupModelChangeKind.EDITOR_CLOSE && candidate.editorIndex !== undefined && candidate.context !== undefined && candidate.sticky !== undefined;
|
||||
}
|
||||
|
||||
interface IEditorCloseResult {
|
||||
|
@ -170,7 +170,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
//#region events
|
||||
|
||||
private readonly _onDidModelChange = this._register(new Emitter<IGroupChangeEvent>());
|
||||
private readonly _onDidModelChange = this._register(new Emitter<IGroupModelChangeEvent>());
|
||||
readonly onDidModelChange = this._onDidModelChange.event;
|
||||
|
||||
//#endregion
|
||||
|
@ -351,7 +351,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
// Event
|
||||
const event: IGroupEditorOpenEvent = {
|
||||
kind: GroupChangeKind.EDITOR_OPEN,
|
||||
kind: GroupModelChangeKind.EDITOR_OPEN,
|
||||
editor: newEditor,
|
||||
editorIndex: targetIndex
|
||||
};
|
||||
|
@ -407,7 +407,7 @@ export class EditorGroupModel extends Disposable {
|
|||
listeners.add(Event.once(editor.onWillDispose)(() => {
|
||||
if (this.indexOf(editor) >= 0) {
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_WILL_DISPOSE,
|
||||
kind: GroupModelChangeKind.EDITOR_WILL_DISPOSE,
|
||||
editor
|
||||
});
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ export class EditorGroupModel extends Disposable {
|
|||
// Re-Emit dirty state changes
|
||||
listeners.add(editor.onDidChangeDirty(() => {
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_DIRTY,
|
||||
kind: GroupModelChangeKind.EDITOR_DIRTY,
|
||||
editor
|
||||
});
|
||||
}));
|
||||
|
@ -424,7 +424,7 @@ export class EditorGroupModel extends Disposable {
|
|||
// Re-Emit label changes
|
||||
listeners.add(editor.onDidChangeLabel(() => {
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_LABEL,
|
||||
kind: GroupModelChangeKind.EDITOR_LABEL,
|
||||
editor
|
||||
});
|
||||
}));
|
||||
|
@ -432,14 +432,14 @@ export class EditorGroupModel extends Disposable {
|
|||
// Re-Emit capability changes
|
||||
listeners.add(editor.onDidChangeCapabilities(() => {
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_CAPABILITIES,
|
||||
kind: GroupModelChangeKind.EDITOR_CAPABILITIES,
|
||||
editor
|
||||
});
|
||||
}));
|
||||
|
||||
// Clean up dispose listeners once the editor gets closed
|
||||
listeners.add(this.onDidModelChange(event => {
|
||||
if (event.kind === GroupChangeKind.EDITOR_CLOSE && event.editor?.matches(editor)) {
|
||||
if (event.kind === GroupModelChangeKind.EDITOR_CLOSE && event.editor?.matches(editor)) {
|
||||
dispose(listeners);
|
||||
}
|
||||
}));
|
||||
|
@ -455,7 +455,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
if (closeResult) {
|
||||
const event: IGroupEditorCloseEvent = {
|
||||
kind: GroupChangeKind.EDITOR_CLOSE,
|
||||
kind: GroupModelChangeKind.EDITOR_CLOSE,
|
||||
...closeResult
|
||||
};
|
||||
this._onDidModelChange.fire(event);
|
||||
|
@ -467,7 +467,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
if (closeResult) {
|
||||
const event: IGroupEditorCloseEvent = {
|
||||
kind: GroupChangeKind.EDITOR_CLOSE,
|
||||
kind: GroupModelChangeKind.EDITOR_CLOSE,
|
||||
...closeResult
|
||||
};
|
||||
this._onDidModelChange.fire(event);
|
||||
|
@ -556,7 +556,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
// Event
|
||||
const event: IGroupEditorMoveEvent = {
|
||||
kind: GroupChangeKind.EDITOR_MOVE,
|
||||
kind: GroupModelChangeKind.EDITOR_MOVE,
|
||||
editor,
|
||||
oldEditorIndex: index,
|
||||
editorIndex: toIndex,
|
||||
|
@ -566,7 +566,27 @@ export class EditorGroupModel extends Disposable {
|
|||
return editor;
|
||||
}
|
||||
|
||||
setActive(candidate: EditorInput): EditorInput | undefined {
|
||||
setActive(candidate: EditorInput | undefined): EditorInput | undefined {
|
||||
let result: EditorInput | undefined = undefined;
|
||||
|
||||
if (!candidate) {
|
||||
this.setGroupActive();
|
||||
} else {
|
||||
result = this.setEditorActive(candidate);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private setGroupActive(): void {
|
||||
// We do not really keep the `active` state in our model because
|
||||
// it has no special meaning to us here. But for consistency
|
||||
// we emit a `onDidModelChange` event so that components can
|
||||
// react.
|
||||
this._onDidModelChange.fire({ kind: GroupModelChangeKind.GROUP_ACTIVE });
|
||||
}
|
||||
|
||||
private setEditorActive(candidate: EditorInput): EditorInput | undefined {
|
||||
const res = this.findEditor(candidate);
|
||||
if (!res) {
|
||||
return; // not found
|
||||
|
@ -593,7 +613,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
// Event
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_ACTIVE,
|
||||
kind: GroupModelChangeKind.EDITOR_ACTIVE,
|
||||
editor
|
||||
});
|
||||
}
|
||||
|
@ -603,7 +623,7 @@ export class EditorGroupModel extends Disposable {
|
|||
// it has no special meaning to us here. But for consistency
|
||||
// we emit a `onDidModelChange` event so that components can
|
||||
// react.
|
||||
this._onDidModelChange.fire({ kind: GroupChangeKind.GROUP_INDEX });
|
||||
this._onDidModelChange.fire({ kind: GroupModelChangeKind.GROUP_INDEX });
|
||||
}
|
||||
|
||||
pin(candidate: EditorInput): EditorInput | undefined {
|
||||
|
@ -629,7 +649,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
// Event
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_PIN,
|
||||
kind: GroupModelChangeKind.EDITOR_PIN,
|
||||
editor
|
||||
});
|
||||
}
|
||||
|
@ -658,7 +678,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
// Event
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_PIN,
|
||||
kind: GroupModelChangeKind.EDITOR_PIN,
|
||||
editor
|
||||
});
|
||||
|
||||
|
@ -708,7 +728,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
// Event
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_STICKY,
|
||||
kind: GroupModelChangeKind.EDITOR_STICKY,
|
||||
editor
|
||||
});
|
||||
}
|
||||
|
@ -739,7 +759,7 @@ export class EditorGroupModel extends Disposable {
|
|||
|
||||
// Event
|
||||
this._onDidModelChange.fire({
|
||||
kind: GroupChangeKind.EDITOR_STICKY,
|
||||
kind: GroupModelChangeKind.EDITOR_STICKY,
|
||||
editor
|
||||
});
|
||||
}
|
||||
|
@ -892,7 +912,7 @@ export class EditorGroupModel extends Disposable {
|
|||
if (this.isLocked !== locked) {
|
||||
this.locked = locked;
|
||||
|
||||
this._onDidModelChange.fire({ kind: GroupChangeKind.GROUP_LOCKED });
|
||||
this._onDidModelChange.fire({ kind: GroupModelChangeKind.GROUP_LOCKED });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -400,6 +400,12 @@ export const STATUS_BAR_ITEM_HOVER_BACKGROUND = registerColor('statusBarItem.hov
|
|||
hc: Color.white.transparent(0.12)
|
||||
}, localize('statusBarItemHoverBackground', "Status bar item background color when hovering. The status bar is shown in the bottom of the window."));
|
||||
|
||||
export const STATUS_BAR_ITEM_COMPACT_HOVER_BACKGROUND = registerColor('statusBarItem.compactHoverBackground', {
|
||||
dark: Color.white.transparent(0.20),
|
||||
light: Color.white.transparent(0.20),
|
||||
hc: Color.white.transparent(0.20)
|
||||
}, localize('statusBarItemCompactHoverBackground', "Status bar item background color when hovering an item that contains two hovers. The status bar is shown in the bottom of the window."));
|
||||
|
||||
export const STATUS_BAR_PROMINENT_ITEM_FOREGROUND = registerColor('statusBarItem.prominentForeground', {
|
||||
dark: STATUS_BAR_FOREGROUND,
|
||||
light: STATUS_BAR_FOREGROUND,
|
||||
|
|
|
@ -645,7 +645,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
|||
case 'text':
|
||||
text = iv.text;
|
||||
break;
|
||||
case 'variable':
|
||||
case 'variable': {
|
||||
let va = iv.variableName;
|
||||
if (!va) {
|
||||
const lineContent = model.getLineContent(iv.range.startLineNumber);
|
||||
|
@ -656,7 +656,8 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
|||
text = strings.format(var_value_format, va, value);
|
||||
}
|
||||
break;
|
||||
case 'expression':
|
||||
}
|
||||
case 'expression': {
|
||||
let expr = iv.expression;
|
||||
if (!expr) {
|
||||
const lineContent = model.getLineContent(iv.range.startLineNumber);
|
||||
|
@ -670,6 +671,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (text) {
|
||||
|
|
|
@ -86,12 +86,13 @@ export class LinkDetector {
|
|||
case 'web':
|
||||
container.appendChild(this.createWebLink(part.value));
|
||||
break;
|
||||
case 'path':
|
||||
case 'path': {
|
||||
const path = part.captures[0];
|
||||
const lineNumber = part.captures[1] ? Number(part.captures[1]) : 0;
|
||||
const columnNumber = part.captures[2] ? Number(part.captures[2]) : 0;
|
||||
container.appendChild(this.createPathLink(part.value, path, lineNumber, columnNumber, workspaceFolder));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
container.appendChild(document.createTextNode(part.value));
|
||||
|
|
|
@ -164,7 +164,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
|
|||
this.requestCallback(<DebugProtocol.Request>message);
|
||||
}
|
||||
break;
|
||||
case 'response':
|
||||
case 'response': {
|
||||
const response = <DebugProtocol.Response>message;
|
||||
const clb = this.pendingRequests.get(response.request_seq);
|
||||
if (clb) {
|
||||
|
@ -172,6 +172,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter {
|
|||
clb(response);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ export function convertToVSCPaths(message: DebugProtocol.ProtocolMessage, toUri:
|
|||
function convertPaths(msg: DebugProtocol.ProtocolMessage, fixSourcePath: (toDA: boolean, source: PathContainer | undefined) => void): void {
|
||||
|
||||
switch (msg.type) {
|
||||
case 'event':
|
||||
case 'event': {
|
||||
const event = <DebugProtocol.Event>msg;
|
||||
switch (event.event) {
|
||||
case 'output':
|
||||
|
@ -214,7 +214,8 @@ function convertPaths(msg: DebugProtocol.ProtocolMessage, fixSourcePath: (toDA:
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 'request':
|
||||
}
|
||||
case 'request': {
|
||||
const request = <DebugProtocol.Request>msg;
|
||||
switch (request.command) {
|
||||
case 'setBreakpoints':
|
||||
|
@ -236,7 +237,8 @@ function convertPaths(msg: DebugProtocol.ProtocolMessage, fixSourcePath: (toDA:
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 'response':
|
||||
}
|
||||
case 'response': {
|
||||
const response = <DebugProtocol.Response>msg;
|
||||
if (response.success && response.body) {
|
||||
switch (response.command) {
|
||||
|
@ -260,6 +262,7 @@ function convertPaths(msg: DebugProtocol.ProtocolMessage, fixSourcePath: (toDA:
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ export function prepareCommand(shell: string, args: string[], cwd?: string, env?
|
|||
}
|
||||
break;
|
||||
|
||||
case ShellType.bash:
|
||||
case ShellType.bash: {
|
||||
|
||||
quote = (s: string) => {
|
||||
s = s.replace(/(["'\\\$])/g, '\\$1');
|
||||
|
@ -203,6 +203,7 @@ export function prepareCommand(shell: string, args: string[], cwd?: string, env?
|
|||
command += `${quote(a)} `;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return command;
|
||||
|
|
|
@ -13,7 +13,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
|
|||
import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { Verbosity, EditorResourceAccessor, SideBySideEditor, EditorInputCapabilities, IEditorIdentifier, GroupChangeKind } from 'vs/workbench/common/editor';
|
||||
import { Verbosity, EditorResourceAccessor, SideBySideEditor, EditorInputCapabilities, IEditorIdentifier, GroupModelChangeKind } from 'vs/workbench/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { SaveAllInGroupAction, CloseGroupAction } from 'vs/workbench/contrib/files/browser/fileActions';
|
||||
import { OpenEditorsFocusedContext, ExplorerFocusedContext, IFilesConfiguration, OpenEditor } from 'vs/workbench/contrib/files/common/files';
|
||||
|
@ -138,7 +138,7 @@ export class OpenEditorsView extends ViewPane {
|
|||
|
||||
const groupDisposables = new Map<number, IDisposable>();
|
||||
const addGroupListener = (group: IEditorGroup) => {
|
||||
groupDisposables.set(group.id, group.onDidGroupChange(e => {
|
||||
const groupModelChangeListener = group.onDidModelChange(e => {
|
||||
if (this.listRefreshScheduler.isScheduled()) {
|
||||
return;
|
||||
}
|
||||
|
@ -149,34 +149,31 @@ export class OpenEditorsView extends ViewPane {
|
|||
|
||||
const index = this.getIndex(group, e.editor);
|
||||
switch (e.kind) {
|
||||
case GroupChangeKind.GROUP_INDEX: {
|
||||
case GroupModelChangeKind.EDITOR_ACTIVE:
|
||||
case GroupModelChangeKind.GROUP_ACTIVE:
|
||||
this.focusActiveEditor();
|
||||
break;
|
||||
case GroupModelChangeKind.GROUP_INDEX:
|
||||
if (index >= 0) {
|
||||
this.list.splice(index, 1, [group]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GroupChangeKind.GROUP_ACTIVE:
|
||||
case GroupChangeKind.EDITOR_ACTIVE: {
|
||||
this.focusActiveEditor();
|
||||
break;
|
||||
}
|
||||
case GroupChangeKind.EDITOR_DIRTY:
|
||||
case GroupChangeKind.EDITOR_LABEL:
|
||||
case GroupChangeKind.EDITOR_CAPABILITIES:
|
||||
case GroupChangeKind.EDITOR_STICKY:
|
||||
case GroupChangeKind.EDITOR_PIN: {
|
||||
case GroupModelChangeKind.EDITOR_DIRTY:
|
||||
case GroupModelChangeKind.EDITOR_STICKY:
|
||||
case GroupModelChangeKind.EDITOR_CAPABILITIES:
|
||||
case GroupModelChangeKind.EDITOR_PIN:
|
||||
case GroupModelChangeKind.EDITOR_LABEL:
|
||||
this.list.splice(index, 1, [new OpenEditor(e.editor!, group)]);
|
||||
this.focusActiveEditor();
|
||||
break;
|
||||
}
|
||||
case GroupChangeKind.EDITOR_OPEN:
|
||||
case GroupChangeKind.EDITOR_CLOSE:
|
||||
case GroupChangeKind.EDITOR_MOVE: {
|
||||
case GroupModelChangeKind.EDITOR_OPEN:
|
||||
case GroupModelChangeKind.EDITOR_MOVE:
|
||||
case GroupModelChangeKind.EDITOR_CLOSE:
|
||||
updateWholeList();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
groupDisposables.set(group.id, groupModelChangeListener);
|
||||
this._register(groupDisposables.get(group.id)!);
|
||||
};
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ export class NotebookEditor extends EditorPane {
|
|||
if (group) {
|
||||
this._groupListener.clear();
|
||||
this._groupListener.add(group.onWillCloseEditor(e => this._saveEditorViewState(e.editor)));
|
||||
this._groupListener.add(group.onDidGroupChange(() => {
|
||||
this._groupListener.add(group.onDidModelChange(() => {
|
||||
if (this._editorGroupService.activeGroup !== group) {
|
||||
this._widget?.value?.updateEditorFocus();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { IBorrowValue, INotebookEditorService } from 'vs/workbench/contrib/noteb
|
|||
import { INotebookEditor, INotebookEditorCreationOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { GroupIdentifier, GroupChangeKind } from 'vs/workbench/common/editor';
|
||||
import { GroupIdentifier } from 'vs/workbench/common/editor';
|
||||
|
||||
export class NotebookEditorWidgetService implements INotebookEditorService {
|
||||
|
||||
|
@ -40,9 +40,9 @@ export class NotebookEditorWidgetService implements INotebookEditorService {
|
|||
const onNewGroup = (group: IEditorGroup) => {
|
||||
const { id } = group;
|
||||
const listeners: IDisposable[] = [];
|
||||
listeners.push(group.onDidGroupChange(e => {
|
||||
listeners.push(group.onDidCloseEditor(e => {
|
||||
const widgets = this._borrowableEditors.get(group.id);
|
||||
if (!widgets || e.kind !== GroupChangeKind.EDITOR_CLOSE) {
|
||||
if (!widgets) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -896,6 +896,12 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
|||
this.view.triggerScrollFromMouseWheelEvent(browserEvent);
|
||||
}
|
||||
|
||||
isElementAboveViewport(index: number) {
|
||||
const elementTop = this.view.elementTop(index);
|
||||
const elementBottom = elementTop + this.view.elementHeight(index);
|
||||
|
||||
return elementBottom < this.scrollTop;
|
||||
}
|
||||
|
||||
updateElementHeight2(element: ICellViewModel, size: number): void {
|
||||
const index = this._getViewIndexUpperBound(element);
|
||||
|
@ -903,7 +909,7 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
|||
return;
|
||||
}
|
||||
|
||||
if (index < this.firstVisibleIndex) {
|
||||
if (this.isElementAboveViewport(index)) {
|
||||
// update element above viewport
|
||||
const oldHeight = this.elementHeight(element);
|
||||
const delta = oldHeight - size;
|
||||
|
|
|
@ -630,34 +630,33 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'preload':
|
||||
case 'preload': {
|
||||
const resources = event.data.resources;
|
||||
for (const { uri, originalUri } of resources) {
|
||||
kernelPreloads.load(uri, originalUri);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'focus-output':
|
||||
focusFirstFocusableInCell(event.data.cellId);
|
||||
break;
|
||||
case 'decorations':
|
||||
{
|
||||
let outputContainer = document.getElementById(event.data.cellId);
|
||||
if (!outputContainer) {
|
||||
viewModel.ensureOutputCell(event.data.cellId, -100000, true);
|
||||
outputContainer = document.getElementById(event.data.cellId);
|
||||
}
|
||||
outputContainer?.classList.add(...event.data.addedClassNames);
|
||||
outputContainer?.classList.remove(...event.data.removedClassNames);
|
||||
case 'decorations': {
|
||||
let outputContainer = document.getElementById(event.data.cellId);
|
||||
if (!outputContainer) {
|
||||
viewModel.ensureOutputCell(event.data.cellId, -100000, true);
|
||||
outputContainer = document.getElementById(event.data.cellId);
|
||||
}
|
||||
|
||||
outputContainer?.classList.add(...event.data.addedClassNames);
|
||||
outputContainer?.classList.remove(...event.data.removedClassNames);
|
||||
break;
|
||||
}
|
||||
case 'customKernelMessage':
|
||||
onDidReceiveKernelMessage.fire(event.data.message);
|
||||
break;
|
||||
case 'customRendererMessage':
|
||||
renderers.getRenderer(event.data.rendererId)?.receiveMessage(event.data.message);
|
||||
break;
|
||||
case 'notebookStyles':
|
||||
case 'notebookStyles': {
|
||||
const documentStyle = document.documentElement.style;
|
||||
|
||||
for (let i = documentStyle.length - 1; i >= 0; i--) {
|
||||
|
@ -674,6 +673,7 @@ async function webviewPreloads(ctx: PreloadContext) {
|
|||
documentStyle.setProperty(`--${name}`, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'notebookOptions':
|
||||
currentOptions = event.data.options;
|
||||
viewModel.toggleDragDropEnabled(currentOptions.dragAndDropEnabled);
|
||||
|
|
|
@ -500,7 +500,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
case CellEditType.Replace:
|
||||
this._replaceCells(edit.index, edit.count, edit.cells, synchronous, computeUndoRedo);
|
||||
break;
|
||||
case CellEditType.Output:
|
||||
case CellEditType.Output: {
|
||||
this._assertIndex(cellIndex);
|
||||
const cell = this._cells[cellIndex];
|
||||
if (edit.append) {
|
||||
|
@ -509,6 +509,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
this._spliceNotebookCellOutputs2(cell, edit.outputs.map(op => new NotebookCellOutputTextModel(op)), computeUndoRedo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CellEditType.OutputItems:
|
||||
{
|
||||
this._assertIndex(cellIndex);
|
||||
|
|
|
@ -234,14 +234,14 @@ suite('NotebookCellList', () => {
|
|||
assert.deepStrictEqual(cellList.scrollTop, 55);
|
||||
assert.deepStrictEqual(cellList.getViewScrollBottom(), 265);
|
||||
|
||||
// cellList.updateElementHeight2(viewModel.cellAt(0)!, 50);
|
||||
// assert.deepStrictEqual(cellList.scrollTop, 5);
|
||||
// assert.deepStrictEqual(cellList.getViewScrollBottom(), 215);
|
||||
cellList.updateElementHeight2(viewModel.cellAt(0)!, 50);
|
||||
assert.deepStrictEqual(cellList.scrollTop, 5);
|
||||
assert.deepStrictEqual(cellList.getViewScrollBottom(), 215);
|
||||
|
||||
// focus won't be visible after cell 0 grow to 250, so let's try to keep the focused cell visible
|
||||
// cellList.updateElementHeight2(viewModel.cellAt(0)!, 250);
|
||||
// assert.deepStrictEqual(cellList.scrollTop, 250 + 100 - cellList.renderHeight);
|
||||
// assert.deepStrictEqual(cellList.getViewScrollBottom(), 250 + 100 - cellList.renderHeight + 210);
|
||||
cellList.updateElementHeight2(viewModel.cellAt(0)!, 250);
|
||||
assert.deepStrictEqual(cellList.scrollTop, 250 + 100 - cellList.renderHeight);
|
||||
assert.deepStrictEqual(cellList.getViewScrollBottom(), 250 + 100 - cellList.renderHeight + 210);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ export abstract class AbstractListSettingWidget<TDataItem extends object> extend
|
|||
DOM.append(container, this.renderAddButton());
|
||||
this.renderList();
|
||||
|
||||
this._register(DOM.addDisposableListener(this.listElement, DOM.EventType.CLICK, e => this.onListClick(e)));
|
||||
this._register(DOM.addDisposableListener(this.listElement, DOM.EventType.POINTER_DOWN, e => this.onListClick(e)));
|
||||
this._register(DOM.addDisposableListener(this.listElement, DOM.EventType.DBLCLICK, e => this.onListDoubleClick(e)));
|
||||
|
||||
this._register(DOM.addStandardDisposableListener(this.listElement, 'keydown', (e: StandardKeyboardEvent) => {
|
||||
|
@ -447,7 +447,7 @@ export abstract class AbstractListSettingWidget<TDataItem extends object> extend
|
|||
return rowElement;
|
||||
}
|
||||
|
||||
private onListClick(e: MouseEvent): void {
|
||||
private onListClick(e: PointerEvent): void {
|
||||
const targetIdx = this.getClickedItemIndex(e);
|
||||
if (targetIdx < 0) {
|
||||
return;
|
||||
|
|
|
@ -264,12 +264,13 @@ class OnAutoForwardedAction extends Disposable {
|
|||
break;
|
||||
}
|
||||
case OnPortForward.Silent: break;
|
||||
default:
|
||||
default: {
|
||||
const elapsed = new Date().getTime() - this.lastNotifyTime.getTime();
|
||||
this.logService.trace(`ForwardedPorts: (OnAutoForwardedAction) time elapsed since last notification ${elapsed} ms`);
|
||||
if (elapsed > OnAutoForwardedAction.NOTIFY_COOL_DOWN) {
|
||||
await this.showNotification(tunnel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -293,7 +293,7 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
|
|||
case 'disconnected':
|
||||
this.renderRemoteStatusIndicator(`$(alert) ${nls.localize('disconnectedFrom', "Disconnected from {0}", truncate(hostLabel, RemoteStatusIndicator.REMOTE_STATUS_LABEL_MAX_LENGTH))}`);
|
||||
break;
|
||||
default:
|
||||
default: {
|
||||
const tooltip = new MarkdownString('', { isTrusted: true, supportThemeIcons: true });
|
||||
const hostNameTooltip = this.labelService.getHostTooltip(Schemas.vscodeRemote, this.remoteAuthority);
|
||||
if (hostNameTooltip) {
|
||||
|
@ -302,6 +302,7 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
|
|||
tooltip.appendText(nls.localize({ key: 'host.tooltip', comment: ['{0} is a remote host name, e.g. Dev Container'] }, "Editing on {0}", hostLabel));
|
||||
}
|
||||
this.renderRemoteStatusIndicator(`$(remote) ${truncate(hostLabel, RemoteStatusIndicator.REMOTE_STATUS_LABEL_MAX_LENGTH)}`, tooltip);
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (this.virtualWorkspaceLocation) {
|
||||
|
|
|
@ -675,12 +675,13 @@ export function searchMatchComparer(elementA: RenderableMatch, elementB: Rendera
|
|||
return compareFileExtensions(elementA.name(), elementB.name());
|
||||
case SearchSortOrder.FileNames:
|
||||
return compareFileNames(elementA.name(), elementB.name());
|
||||
case SearchSortOrder.Modified:
|
||||
case SearchSortOrder.Modified: {
|
||||
const fileStatA = elementA.fileStat;
|
||||
const fileStatB = elementB.fileStat;
|
||||
if (fileStatA && fileStatB) {
|
||||
return fileStatB.mtime - fileStatA.mtime;
|
||||
}
|
||||
}
|
||||
// Fall through otherwise
|
||||
default:
|
||||
return comparePaths(elementA.resource.fsPath, elementB.resource.fsPath) || compareFileNames(elementA.name(), elementB.name());
|
||||
|
|
|
@ -2162,7 +2162,7 @@ export function parseExitResult(
|
|||
// Create exit code message
|
||||
let message: string | undefined = undefined;
|
||||
switch (typeof exitCodeOrError) {
|
||||
case 'number':
|
||||
case 'number': {
|
||||
let commandLine: string | undefined = undefined;
|
||||
if (shellLaunchConfig.executable) {
|
||||
commandLine = shellLaunchConfig.executable;
|
||||
|
@ -2187,7 +2187,8 @@ export function parseExitResult(
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 'object':
|
||||
}
|
||||
case 'object': {
|
||||
// Ignore internal errors
|
||||
if (exitCodeOrError.message.toString().includes('Could not find pty with id')) {
|
||||
break;
|
||||
|
@ -2211,6 +2212,7 @@ export function parseExitResult(
|
|||
}
|
||||
message = nls.localize('launchFailed.errorMessage', "The terminal process failed to launch: {0}.", innerMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { code, message };
|
||||
|
|
|
@ -844,7 +844,7 @@ export class PredictionTimeline {
|
|||
const cursor = this.physicalCursor(buffer);
|
||||
const beforeTestReaderIndex = reader.index;
|
||||
switch (prediction.matches(reader, this._lookBehind)) {
|
||||
case MatchResult.Success:
|
||||
case MatchResult.Success: {
|
||||
// if the input character matches what the next prediction expected, undo
|
||||
// the prediction and write the real character out.
|
||||
const eaten = input.slice(beforeTestReaderIndex, reader.index);
|
||||
|
@ -859,13 +859,14 @@ export class PredictionTimeline {
|
|||
this._lookBehind = prediction;
|
||||
this._expected.shift();
|
||||
break;
|
||||
}
|
||||
case MatchResult.Buffer:
|
||||
// on a buffer, store the remaining data and completely read data
|
||||
// to be output as normal.
|
||||
this._inputBuffer = input.slice(beforeTestReaderIndex);
|
||||
reader.index = input.length;
|
||||
break ReadLoop;
|
||||
case MatchResult.Failure:
|
||||
case MatchResult.Failure: {
|
||||
// on a failure, roll back all remaining items in this generation
|
||||
// and clear predictions, since they are no longer valid
|
||||
const rollback = this._expected.filter(p => p.gen === startingGen).reverse();
|
||||
|
@ -878,6 +879,7 @@ export class PredictionTimeline {
|
|||
this._clearPredictionState();
|
||||
this._failedEmitter.fire(prediction);
|
||||
break ReadLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1253,7 +1255,7 @@ class TypeAheadStyle implements IDisposable {
|
|||
return { applyArgs: [4], undoArgs: [24] };
|
||||
case 'inverted':
|
||||
return { applyArgs: [7], undoArgs: [27] };
|
||||
default:
|
||||
default: {
|
||||
let color: Color;
|
||||
try {
|
||||
color = Color.fromHex(style);
|
||||
|
@ -1263,6 +1265,7 @@ class TypeAheadStyle implements IDisposable {
|
|||
|
||||
const { r, g, b } = color.rgba;
|
||||
return { applyArgs: [38, 2, r, g, b], undoArgs: [39] };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,14 @@ class TestTerminalConfigHelper extends TerminalConfigHelper {
|
|||
}
|
||||
}
|
||||
|
||||
suite('Workbench - TerminalConfigHelper', () => {
|
||||
suite('Workbench - TerminalConfigHelper', function () {
|
||||
let fixture: HTMLElement;
|
||||
|
||||
// This suite has retries setup because the font-related tests flake only on GitHub actions, not
|
||||
// ADO. It seems Electron hangs for some reason only on GH actions, so the two options are to
|
||||
// retry or remove the test outright (which would drop coverage).
|
||||
this.retries(3);
|
||||
|
||||
setup(() => {
|
||||
fixture = document.body;
|
||||
});
|
||||
|
|
|
@ -251,13 +251,13 @@ export class TestingPeekOpener extends Disposable implements ITestingPeekOpener
|
|||
// don't show the peek if the user asked to only auto-open peeks for visible tests,
|
||||
// and this test is not in any of the editors' models.
|
||||
switch (cfg) {
|
||||
case AutoOpenPeekViewWhen.FailureVisible:
|
||||
case AutoOpenPeekViewWhen.FailureVisible: {
|
||||
const editorUris = new Set(editors.map(e => e.getModel()?.uri.toString()));
|
||||
if (!Iterable.some(resultItemParents(evt.result, evt.item), i => i.item.uri && editorUris.has(i.item.uri.toString()))) {
|
||||
return;
|
||||
}
|
||||
break; //continue
|
||||
|
||||
}
|
||||
case AutoOpenPeekViewWhen.FailureAnywhere:
|
||||
break; //continue
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ export class SingleUseTestCollection extends Disposable {
|
|||
}
|
||||
break;
|
||||
|
||||
case ExtHostTestItemEventOp.SetProp:
|
||||
case ExtHostTestItemEventOp.SetProp: {
|
||||
const { key, value, previous } = evt;
|
||||
const extId = internal.fullId.toString();
|
||||
switch (key) {
|
||||
|
@ -185,6 +185,7 @@ export class SingleUseTestCollection extends Disposable {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assertNever(evt);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ export class TestingContentProvider implements IWorkbenchContribution, ITextMode
|
|||
if (message?.type === TestMessageType.Error) { text = message.expected; }
|
||||
break;
|
||||
}
|
||||
case TestUriType.ResultMessage:
|
||||
case TestUriType.ResultMessage: {
|
||||
const message = test.tasks[parsed.taskIndex].messages[parsed.messageIndex]?.message;
|
||||
if (typeof message === 'string') {
|
||||
text = message;
|
||||
|
@ -69,6 +69,7 @@ export class TestingContentProvider implements IWorkbenchContribution, ITextMode
|
|||
language = this.languageService.createById('markdown');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (text === undefined) {
|
||||
|
|
|
@ -43,7 +43,7 @@ export const maxPriority = (...states: TestResultState[]) => {
|
|||
return states[0];
|
||||
case 2:
|
||||
return statePriority[states[0]] > statePriority[states[1]] ? states[0] : states[1];
|
||||
default:
|
||||
default: {
|
||||
let max = states[0];
|
||||
for (let i = 1; i < states.length; i++) {
|
||||
if (statePriority[max] < statePriority[states[i]]) {
|
||||
|
@ -52,6 +52,7 @@ export const maxPriority = (...states: TestResultState[]) => {
|
|||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ export async function configureOpenerTrustedDomainsHandler(
|
|||
options: { pinned: true }
|
||||
});
|
||||
return trustedDomains;
|
||||
case 'trust':
|
||||
case 'trust': {
|
||||
const itemToTrust = pickedResult.toTrust;
|
||||
if (trustedDomains.indexOf(itemToTrust) === -1) {
|
||||
storageService.remove(TRUSTED_DOMAINS_CONTENT_STORAGE_KEY, StorageScope.GLOBAL);
|
||||
|
@ -131,6 +131,7 @@ export async function configureOpenerTrustedDomainsHandler(
|
|||
|
||||
return [...trustedDomains, itemToTrust];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class UserDataSyncReportIssueContribution extends Disposable implements IWorkben
|
|||
private onAutoSyncError(error: UserDataSyncError): void {
|
||||
switch (error.code) {
|
||||
case UserDataSyncErrorCode.LocalTooManyRequests:
|
||||
case UserDataSyncErrorCode.TooManyRequests:
|
||||
case UserDataSyncErrorCode.TooManyRequests: {
|
||||
const operationId = error.operationId ? localize('operationId', "Operation Id: {0}", error.operationId) : undefined;
|
||||
const message = localize('too many requests', "Turned off syncing settings on this device because it is making too many requests.");
|
||||
this.notificationService.notify({
|
||||
|
@ -35,6 +35,7 @@ class UserDataSyncReportIssueContribution extends Disposable implements IWorkben
|
|||
message: operationId ? `${message} ${operationId}` : message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ import { EditorResolution } from 'vs/platform/editor/common/editor';
|
|||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
|
||||
const CONTEXT_CONFLICTS_SOURCES = new RawContextKey<string>('conflictsSources', '');
|
||||
|
||||
|
@ -128,6 +129,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
|||
@IUserDataSyncStoreManagementService private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IUserDataInitializationService private readonly userDataInitializationService: IUserDataInitializationService,
|
||||
@IHostService private readonly hostService: IHostService,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -333,7 +335,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
|||
break;
|
||||
case UserDataSyncErrorCode.IncompatibleLocalContent:
|
||||
case UserDataSyncErrorCode.Gone:
|
||||
case UserDataSyncErrorCode.UpgradeRequired:
|
||||
case UserDataSyncErrorCode.UpgradeRequired: {
|
||||
const message = localize('error upgrade required', "Settings sync is disabled because the current version ({0}, {1}) is not compatible with the sync service. Please update before turning on sync.", this.productService.version, this.productService.commit);
|
||||
const operationId = error.operationId ? localize('operationId', "Operation Id: {0}", error.operationId) : undefined;
|
||||
this.notificationService.notify({
|
||||
|
@ -341,6 +343,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
|||
message: operationId ? `${message} ${operationId}` : message,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case UserDataSyncErrorCode.IncompatibleRemoteContent:
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
|
@ -407,12 +410,13 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
|||
case UserDataSyncErrorCode.LocalInvalidContent:
|
||||
this.handleInvalidContentError(source);
|
||||
break;
|
||||
default:
|
||||
default: {
|
||||
const disposable = this.invalidContentErrorDisposables.get(source);
|
||||
if (disposable) {
|
||||
disposable.dispose();
|
||||
this.invalidContentErrorDisposables.delete(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -428,6 +432,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
|||
if (source !== SyncResource.Settings && source !== SyncResource.Keybindings) {
|
||||
return;
|
||||
}
|
||||
if (!this.hostService.hasFocus) {
|
||||
return;
|
||||
}
|
||||
const resource = source === SyncResource.Settings ? this.environmentService.settingsResource : this.environmentService.keybindingsResource;
|
||||
if (isEqual(resource, EditorResourceAccessor.getCanonicalUri(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }))) {
|
||||
// Do not show notification if the file in error is active
|
||||
|
@ -537,7 +544,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
|||
break;
|
||||
case UserDataSyncErrorCode.IncompatibleLocalContent:
|
||||
case UserDataSyncErrorCode.Gone:
|
||||
case UserDataSyncErrorCode.UpgradeRequired:
|
||||
case UserDataSyncErrorCode.UpgradeRequired: {
|
||||
const message = localize('error upgrade required while starting sync', "Settings sync cannot be turned on because the current version ({0}, {1}) is not compatible with the sync service. Please update before turning on sync.", this.productService.version, this.productService.commit);
|
||||
const operationId = e.operationId ? localize('operationId', "Operation Id: {0}", e.operationId) : undefined;
|
||||
this.notificationService.notify({
|
||||
|
@ -545,6 +552,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
|
|||
message: operationId ? `${message} ${operationId}` : message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
case UserDataSyncErrorCode.IncompatibleRemoteContent:
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
|
|
|
@ -47,7 +47,7 @@ class UserDataSyncReportIssueContribution extends Disposable implements IWorkben
|
|||
private onAutoSyncError(error: UserDataSyncError): void {
|
||||
switch (error.code) {
|
||||
case UserDataSyncErrorCode.LocalTooManyRequests:
|
||||
case UserDataSyncErrorCode.TooManyRequests:
|
||||
case UserDataSyncErrorCode.TooManyRequests: {
|
||||
const operationId = error.operationId ? localize('operationId', "Operation Id: {0}", error.operationId) : undefined;
|
||||
const message = localize({ key: 'too many requests', comment: ['Settings Sync is the name of the feature'] }, "Settings sync is disabled because the current device is making too many requests. Please report an issue by providing the sync logs.");
|
||||
this.notificationService.notify({
|
||||
|
@ -62,6 +62,7 @@ class UserDataSyncReportIssueContribution extends Disposable implements IWorkben
|
|||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -757,7 +757,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD
|
|||
}, this._fileService, this._logService, this._resourceLoadingCts.token);
|
||||
|
||||
switch (result.type) {
|
||||
case WebviewResourceResponse.Type.Success:
|
||||
case WebviewResourceResponse.Type.Success: {
|
||||
const { buffer } = await streamToBuffer(result.stream);
|
||||
return {
|
||||
id,
|
||||
|
@ -768,7 +768,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD
|
|||
etag: result.etag,
|
||||
mtime: result.mtime
|
||||
};
|
||||
|
||||
}
|
||||
case WebviewResourceResponse.Type.NotModified:
|
||||
return {
|
||||
id,
|
||||
|
|
|
@ -191,7 +191,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
|
||||
public isCurrentWorkspace(workspaceIdOrFolder: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI): boolean {
|
||||
switch (this.getWorkbenchState()) {
|
||||
case WorkbenchState.FOLDER:
|
||||
case WorkbenchState.FOLDER: {
|
||||
let folderUri: URI | undefined = undefined;
|
||||
if (URI.isUri(workspaceIdOrFolder)) {
|
||||
folderUri = workspaceIdOrFolder;
|
||||
|
@ -200,6 +200,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
}
|
||||
|
||||
return URI.isUri(folderUri) && this.uriIdentityService.extUri.isEqual(folderUri, this.workspace.folders[0].uri);
|
||||
}
|
||||
case WorkbenchState.WORKSPACE:
|
||||
return isWorkspaceIdentifier(workspaceIdOrFolder) && this.workspace.id === workspaceIdOrFolder.id;
|
||||
}
|
||||
|
@ -353,11 +354,11 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
await this.reloadDefaultConfiguration();
|
||||
return;
|
||||
|
||||
case ConfigurationTarget.USER:
|
||||
case ConfigurationTarget.USER: {
|
||||
const { local, remote } = await this.reloadUserConfiguration();
|
||||
await this.loadConfiguration(local, remote);
|
||||
return;
|
||||
|
||||
}
|
||||
case ConfigurationTarget.USER_LOCAL:
|
||||
await this.reloadLocalUserConfiguration();
|
||||
return;
|
||||
|
@ -901,11 +902,12 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
|
|||
return this.reloadRemoteUserConfiguration().then(() => undefined);
|
||||
case EditableConfigurationTarget.WORKSPACE:
|
||||
return this.reloadWorkspaceConfiguration();
|
||||
case EditableConfigurationTarget.WORKSPACE_FOLDER:
|
||||
case EditableConfigurationTarget.WORKSPACE_FOLDER: {
|
||||
const workspaceFolder = overrides && overrides.resource ? this.workspace.getFolder(overrides.resource) : null;
|
||||
if (workspaceFolder) {
|
||||
return this.reloadWorkspaceFolderConfiguration(workspaceFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -358,7 +358,7 @@ export class ConfigurationEditingService {
|
|||
return nls.localize('errorInvalidRemoteConfiguration', "Unable to write into remote user settings. Please open the remote user settings to correct errors/warnings in it and try again.");
|
||||
case EditableConfigurationTarget.WORKSPACE:
|
||||
return nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into workspace settings. Please open the workspace settings to correct errors/warnings in the file and try again.");
|
||||
case EditableConfigurationTarget.WORKSPACE_FOLDER:
|
||||
case EditableConfigurationTarget.WORKSPACE_FOLDER: {
|
||||
let workspaceFolderName: string = '<<unknown>>';
|
||||
if (operation.resource) {
|
||||
const folder = this.contextService.getWorkspaceFolder(operation.resource);
|
||||
|
@ -367,6 +367,7 @@ export class ConfigurationEditingService {
|
|||
}
|
||||
}
|
||||
return nls.localize('errorInvalidConfigurationFolder', "Unable to write into folder settings. Please open the '{0}' folder settings to correct errors/warnings in it and try again.", workspaceFolderName);
|
||||
}
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
@ -385,7 +386,7 @@ export class ConfigurationEditingService {
|
|||
return nls.localize('errorRemoteConfigurationFileDirty', "Unable to write into remote user settings because the file has unsaved changes. Please save the remote user settings file first and then try again.");
|
||||
case EditableConfigurationTarget.WORKSPACE:
|
||||
return nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into workspace settings because the file has unsaved changes. Please save the workspace settings file first and then try again.");
|
||||
case EditableConfigurationTarget.WORKSPACE_FOLDER:
|
||||
case EditableConfigurationTarget.WORKSPACE_FOLDER: {
|
||||
let workspaceFolderName: string = '<<unknown>>';
|
||||
if (operation.resource) {
|
||||
const folder = this.contextService.getWorkspaceFolder(operation.resource);
|
||||
|
@ -394,6 +395,7 @@ export class ConfigurationEditingService {
|
|||
}
|
||||
}
|
||||
return nls.localize('errorConfigurationFileDirtyFolder', "Unable to write into folder settings because the file has unsaved changes. Please save the '{0}' folder settings file first and then try again.", workspaceFolderName);
|
||||
}
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue