Merge remote-tracking branch 'origin/main' into tyriar/116467_2
This commit is contained in:
commit
6d01ad952a
|
@ -985,7 +985,8 @@
|
||||||
"CustomEditorProvider",
|
"CustomEditorProvider",
|
||||||
"CustomReadonlyEditorProvider",
|
"CustomReadonlyEditorProvider",
|
||||||
"TerminalLinkProvider",
|
"TerminalLinkProvider",
|
||||||
"AuthenticationProvider"
|
"AuthenticationProvider",
|
||||||
|
"NotebookContentProvider"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
41
SECURITY.md
Normal file
41
SECURITY.md
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||||
|
|
||||||
|
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
|
||||||
|
|
||||||
|
## Reporting Security Issues
|
||||||
|
|
||||||
|
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||||
|
|
||||||
|
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
|
||||||
|
|
||||||
|
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
|
||||||
|
|
||||||
|
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||||
|
|
||||||
|
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||||
|
|
||||||
|
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||||
|
* Full paths of source file(s) related to the manifestation of the issue
|
||||||
|
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||||
|
* Any special configuration required to reproduce the issue
|
||||||
|
* Step-by-step instructions to reproduce the issue
|
||||||
|
* Proof-of-concept or exploit code (if possible)
|
||||||
|
* Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
|
||||||
|
This information will help us triage your report more quickly.
|
||||||
|
|
||||||
|
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
|
||||||
|
|
||||||
|
## Preferred Languages
|
||||||
|
|
||||||
|
We prefer all communications to be in English.
|
||||||
|
|
||||||
|
## Policy
|
||||||
|
|
||||||
|
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
||||||
|
|
||||||
|
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
|
@ -77,9 +77,9 @@ jsonc-parser@^2.3.0:
|
||||||
integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==
|
integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==
|
||||||
|
|
||||||
vscode-emmet-helper@^2.3.0:
|
vscode-emmet-helper@^2.3.0:
|
||||||
version "2.4.0"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.4.0.tgz#12f82fd05fb1df11ef7e78f85df63724de54a05b"
|
resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.4.1.tgz#7e020f66cbd72cf8e107b0ac7235cb806a728126"
|
||||||
integrity sha512-aMbUL3oHBWM/Ux/C035a6KKLgIV8+GNGuu1b7ztuHXM6VmrdFFLNI5+tfFjfYQ3GBpD+Q7ZQU7CX/JaGlBbBiA==
|
integrity sha512-Sz3QbEgD1h05+sK3ltVLOUl2KKqwFVGUFSLS7ZlVqZoKPCWiFnd0dgf3miyipt6lGOadrsqvn7mCRbiSXJAMqA==
|
||||||
dependencies:
|
dependencies:
|
||||||
emmet "^2.3.0"
|
emmet "^2.3.0"
|
||||||
jsonc-parser "^2.3.0"
|
jsonc-parser "^2.3.0"
|
||||||
|
|
|
@ -1240,6 +1240,12 @@ suite('Notebook API tests', function () {
|
||||||
assert.strictEqual(document.cells[0].metadata.executionOrder, executionOrder);
|
assert.strictEqual(document.cells[0].metadata.executionOrder, executionOrder);
|
||||||
assert.strictEqual(document.cells[0].metadata.runState, vscode.NotebookCellRunState.Success);
|
assert.strictEqual(document.cells[0].metadata.runState, vscode.NotebookCellRunState.Success);
|
||||||
});
|
});
|
||||||
|
test('Opening a notebook should fire activeNotebook event changed only once', async function () {
|
||||||
|
const openedEditor = asPromise(vscode.window.onDidChangeActiveNotebookEditor);
|
||||||
|
const resource = await createRandomFile('', undefined, '.vsctestnb');
|
||||||
|
await vscode.notebook.openNotebookDocument(resource);
|
||||||
|
assert.ok(await openedEditor);
|
||||||
|
});
|
||||||
|
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,22 @@
|
||||||
},
|
},
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"languages": [
|
"languages": [
|
||||||
|
{
|
||||||
|
"id": "dockercompose",
|
||||||
|
"aliases": [
|
||||||
|
"Compose",
|
||||||
|
"compose"
|
||||||
|
],
|
||||||
|
"filenamePatterns": [
|
||||||
|
"compose.yml",
|
||||||
|
"compose.yaml",
|
||||||
|
"compose.*.yml",
|
||||||
|
"compose.*.yaml",
|
||||||
|
"*docker*compose*.yml",
|
||||||
|
"*docker*compose*.yaml"
|
||||||
|
],
|
||||||
|
"configuration": "./language-configuration.json"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "yaml",
|
"id": "yaml",
|
||||||
"aliases": [
|
"aliases": [
|
||||||
|
@ -30,6 +46,11 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"grammars": [
|
"grammars": [
|
||||||
|
{
|
||||||
|
"language": "dockercompose",
|
||||||
|
"scopeName": "source.yaml",
|
||||||
|
"path": "./syntaxes/yaml.tmLanguage.json"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"language": "yaml",
|
"language": "yaml",
|
||||||
"scopeName": "source.yaml",
|
"scopeName": "source.yaml",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "code-oss-dev",
|
"name": "code-oss-dev",
|
||||||
"version": "1.55.0",
|
"version": "1.55.0",
|
||||||
"distro": "17365b1560dc5051788f2ec8b388b44b67ec1365",
|
"distro": "0a442d49008152919d1ca15e5d21c03a1536c80d",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Microsoft Corporation"
|
"name": "Microsoft Corporation"
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,6 +9,7 @@ description: |
|
||||||
architectures:
|
architectures:
|
||||||
- build-on: amd64
|
- build-on: amd64
|
||||||
run-on: @@ARCHITECTURE@@
|
run-on: @@ARCHITECTURE@@
|
||||||
|
compression: lzo
|
||||||
|
|
||||||
grade: stable
|
grade: stable
|
||||||
confinement: classic
|
confinement: classic
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
outline-offset: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-pane-view .pane > .pane-header .monaco-action-bar .action-item.select-container {
|
.monaco-pane-view .pane > .pane-header .monaco-action-bar .action-item.select-container {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import * as processes from 'vs/base/node/processes';
|
||||||
* shell that the terminal uses by default.
|
* shell that the terminal uses by default.
|
||||||
* @param p The platform to detect the shell of.
|
* @param p The platform to detect the shell of.
|
||||||
*/
|
*/
|
||||||
export async function getSystemShell(p: platform.Platform, env = process.env as platform.IProcessEnvironment): Promise<string> {
|
export async function getSystemShell(p: platform.Platform, env: platform.IProcessEnvironment): Promise<string> {
|
||||||
if (p === platform.Platform.Windows) {
|
if (p === platform.Platform.Windows) {
|
||||||
if (platform.isWindows) {
|
if (platform.isWindows) {
|
||||||
return getSystemShellWindows();
|
return getSystemShellWindows();
|
||||||
|
@ -25,7 +25,7 @@ export async function getSystemShell(p: platform.Platform, env = process.env as
|
||||||
return getSystemShellUnixLike(p, env);
|
return getSystemShellUnixLike(p, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSystemShellSync(p: platform.Platform, env = process.env as platform.IProcessEnvironment): string {
|
export function getSystemShellSync(p: platform.Platform, env: platform.IProcessEnvironment): string {
|
||||||
if (p === platform.Platform.Windows) {
|
if (p === platform.Platform.Windows) {
|
||||||
if (platform.isWindows) {
|
if (platform.isWindows) {
|
||||||
return getSystemShellWindowsSync(env);
|
return getSystemShellWindowsSync(env);
|
||||||
|
|
|
@ -53,6 +53,7 @@ export interface IssueReporterConfiguration extends IWindowConfiguration {
|
||||||
commit: string | undefined;
|
commit: string | undefined;
|
||||||
date: string | undefined;
|
date: string | undefined;
|
||||||
reportIssueUrl: string | undefined;
|
reportIssueUrl: string | undefined;
|
||||||
|
reportMarketplaceIssueUrl: string | undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +84,7 @@ export class IssueReporter extends Disposable {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.initServices(configuration);
|
this.initServices(configuration);
|
||||||
|
console.log(configuration);
|
||||||
|
|
||||||
const targetExtension = configuration.data.extensionId ? configuration.data.enabledExtensions.find(extension => extension.id === configuration.data.extensionId) : undefined;
|
const targetExtension = configuration.data.extensionId ? configuration.data.enabledExtensions.find(extension => extension.id === configuration.data.extensionId) : undefined;
|
||||||
this.issueReporterModel = new IssueReporterModel({
|
this.issueReporterModel = new IssueReporterModel({
|
||||||
|
@ -353,7 +355,8 @@ export class IssueReporter extends Disposable {
|
||||||
this.addEventListener('issue-title', 'input', (e: Event) => {
|
this.addEventListener('issue-title', 'input', (e: Event) => {
|
||||||
const title = (<HTMLInputElement>e.target).value;
|
const title = (<HTMLInputElement>e.target).value;
|
||||||
const lengthValidationMessage = this.getElementById('issue-title-length-validation-error');
|
const lengthValidationMessage = this.getElementById('issue-title-length-validation-error');
|
||||||
if (title && this.getIssueUrlWithTitle(title).length > MAX_URL_LENGTH) {
|
const issueUrl = this.getIssueUrl();
|
||||||
|
if (title && this.getIssueUrlWithTitle(title, issueUrl).length > MAX_URL_LENGTH) {
|
||||||
show(lengthValidationMessage);
|
show(lengthValidationMessage);
|
||||||
} else {
|
} else {
|
||||||
hide(lengthValidationMessage);
|
hide(lengthValidationMessage);
|
||||||
|
@ -468,6 +471,10 @@ export class IssueReporter extends Disposable {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (issueType === IssueType.Marketplace) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,11 +640,18 @@ export class IssueReporter extends Disposable {
|
||||||
|
|
||||||
const typeSelect = this.getElementById('issue-type')! as HTMLSelectElement;
|
const typeSelect = this.getElementById('issue-type')! as HTMLSelectElement;
|
||||||
const { issueType } = this.issueReporterModel.getData();
|
const { issueType } = this.issueReporterModel.getData();
|
||||||
reset(typeSelect,
|
this.configuration.product.reportMarketplaceIssueUrl
|
||||||
makeOption(IssueType.Bug, localize('bugReporter', "Bug Report")),
|
? reset(typeSelect,
|
||||||
makeOption(IssueType.FeatureRequest, localize('featureRequest', "Feature Request")),
|
makeOption(IssueType.Bug, localize('bugReporter', "Bug Report")),
|
||||||
makeOption(IssueType.PerformanceIssue, localize('performanceIssue', "Performance Issue"))
|
makeOption(IssueType.FeatureRequest, localize('featureRequest', "Feature Request")),
|
||||||
);
|
makeOption(IssueType.PerformanceIssue, localize('performanceIssue', "Performance Issue")),
|
||||||
|
makeOption(IssueType.Marketplace, localize('marketplaceIssue', "Extensions Marketplace Issue"))
|
||||||
|
)
|
||||||
|
: reset(typeSelect,
|
||||||
|
makeOption(IssueType.Bug, localize('bugReporter', "Bug Report")),
|
||||||
|
makeOption(IssueType.FeatureRequest, localize('featureRequest', "Feature Request")),
|
||||||
|
makeOption(IssueType.PerformanceIssue, localize('performanceIssue', "Performance Issue")),
|
||||||
|
);
|
||||||
|
|
||||||
typeSelect.value = issueType.toString();
|
typeSelect.value = issueType.toString();
|
||||||
|
|
||||||
|
@ -751,6 +765,9 @@ export class IssueReporter extends Disposable {
|
||||||
if (fileOnExtension) {
|
if (fileOnExtension) {
|
||||||
show(extensionSelector);
|
show(extensionSelector);
|
||||||
}
|
}
|
||||||
|
} else if (issueType === IssueType.Marketplace) {
|
||||||
|
reset(descriptionTitle, localize('description', "Description"), $('span.required-input', undefined, '*'));
|
||||||
|
reset(descriptionSubtitle, localize('marketplaceDescription', "Please describe the feature you would like added to the marketplace, or steps to reliably reproduce the problem if you are reporting a bug. We support GitHub-flavored Markdown. You will be able to edit your issue and add screenshots when we preview it on GitHub."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,10 +787,14 @@ export class IssueReporter extends Disposable {
|
||||||
|
|
||||||
private validateInputs(): boolean {
|
private validateInputs(): boolean {
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
['issue-title', 'description', 'issue-source'].forEach(elementId => {
|
['issue-title', 'description'].forEach(elementId => {
|
||||||
isValid = this.validateInput(elementId) && isValid;
|
isValid = this.validateInput(elementId) && isValid;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.issueReporterModel.getData().issueType !== IssueType.Marketplace) {
|
||||||
|
isValid = this.validateInput('issue-source') && isValid;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.issueReporterModel.fileOnExtension()) {
|
if (this.issueReporterModel.fileOnExtension()) {
|
||||||
isValid = this.validateInput('extension-selector') && isValid;
|
isValid = this.validateInput('extension-selector') && isValid;
|
||||||
}
|
}
|
||||||
|
@ -845,13 +866,13 @@ export class IssueReporter extends Disposable {
|
||||||
const issueTitle = (<HTMLInputElement>this.getElementById('issue-title')).value;
|
const issueTitle = (<HTMLInputElement>this.getElementById('issue-title')).value;
|
||||||
const issueBody = this.issueReporterModel.serialize();
|
const issueBody = this.issueReporterModel.serialize();
|
||||||
|
|
||||||
const issueUrl = this.issueReporterModel.fileOnExtension() ? this.getExtensionGitHubUrl() : this.configuration.product.reportIssueUrl!;
|
const issueUrl = this.getIssueUrl();
|
||||||
const gitHubDetails = this.parseGitHubUrl(issueUrl);
|
const gitHubDetails = this.parseGitHubUrl(issueUrl);
|
||||||
if (this.configuration.data.githubAccessToken && gitHubDetails) {
|
if (this.configuration.data.githubAccessToken && gitHubDetails) {
|
||||||
return this.submitToGitHub(issueTitle, issueBody, gitHubDetails);
|
return this.submitToGitHub(issueTitle, issueBody, gitHubDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseUrl = this.getIssueUrlWithTitle((<HTMLInputElement>this.getElementById('issue-title')).value);
|
const baseUrl = this.getIssueUrlWithTitle((<HTMLInputElement>this.getElementById('issue-title')).value, issueUrl);
|
||||||
let url = baseUrl + `&body=${encodeURIComponent(issueBody)}`;
|
let url = baseUrl + `&body=${encodeURIComponent(issueBody)}`;
|
||||||
|
|
||||||
if (url.length > MAX_URL_LENGTH) {
|
if (url.length > MAX_URL_LENGTH) {
|
||||||
|
@ -881,6 +902,14 @@ export class IssueReporter extends Disposable {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getIssueUrl(): string {
|
||||||
|
return this.issueReporterModel.fileOnExtension()
|
||||||
|
? this.getExtensionGitHubUrl()
|
||||||
|
: this.issueReporterModel.getData().issueType === IssueType.Marketplace
|
||||||
|
? this.configuration.product.reportMarketplaceIssueUrl!
|
||||||
|
: this.configuration.product.reportIssueUrl!;
|
||||||
|
}
|
||||||
|
|
||||||
private parseGitHubUrl(url: string): undefined | { repositoryName: string, owner: string } {
|
private parseGitHubUrl(url: string): undefined | { repositoryName: string, owner: string } {
|
||||||
// Assumes a GitHub url to a particular repo, https://github.com/repositoryName/owner.
|
// Assumes a GitHub url to a particular repo, https://github.com/repositoryName/owner.
|
||||||
// Repository name and owner cannot contain '/'
|
// Repository name and owner cannot contain '/'
|
||||||
|
@ -909,16 +938,12 @@ export class IssueReporter extends Disposable {
|
||||||
return repositoryUrl;
|
return repositoryUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getIssueUrlWithTitle(issueTitle: string): string {
|
private getIssueUrlWithTitle(issueTitle: string, repositoryUrl: string): string {
|
||||||
let repositoryUrl = this.configuration.product.reportIssueUrl;
|
|
||||||
if (this.issueReporterModel.fileOnExtension()) {
|
if (this.issueReporterModel.fileOnExtension()) {
|
||||||
const extensionGitHubUrl = this.getExtensionGitHubUrl();
|
repositoryUrl = repositoryUrl + '/issues/new';
|
||||||
if (extensionGitHubUrl) {
|
|
||||||
repositoryUrl = extensionGitHubUrl + '/issues/new';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryStringPrefix = this.configuration.product.reportIssueUrl && this.configuration.product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&';
|
const queryStringPrefix = repositoryUrl.indexOf('?') === -1 ? '?' : '&';
|
||||||
return `${repositoryUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
|
return `${repositoryUrl}${queryStringPrefix}title=${encodeURIComponent(issueTitle)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1156,7 +1181,7 @@ export class IssueReporter extends Disposable {
|
||||||
),
|
),
|
||||||
...extensions.map(extension => $('tr', undefined,
|
...extensions.map(extension => $('tr', undefined,
|
||||||
$('td', undefined, extension.name),
|
$('td', undefined, extension.name),
|
||||||
$('td', undefined, extension.publisher.substr(0, 3)),
|
$('td', undefined, extension.publisher?.substr(0, 3) ?? 'N/A'),
|
||||||
$('td', undefined, extension.version),
|
$('td', undefined, extension.version),
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -238,7 +238,7 @@ ${this._data.experimentInfo}
|
||||||
const tableHeader = `Extension|Author (truncated)|Version
|
const tableHeader = `Extension|Author (truncated)|Version
|
||||||
---|---|---`;
|
---|---|---`;
|
||||||
const table = this._data.enabledNonThemeExtesions.map(e => {
|
const table = this._data.enabledNonThemeExtesions.map(e => {
|
||||||
return `${e.name}|${e.publisher.substr(0, 3)}|${e.version}`;
|
return `${e.name}|${e.publisher?.substr(0, 3) ?? 'N/A'}|${e.version}`;
|
||||||
}).join('\n');
|
}).join('\n');
|
||||||
|
|
||||||
return `<details><summary>Extensions (${this._data.enabledNonThemeExtesions.length})</summary>
|
return `<details><summary>Extensions (${this._data.enabledNonThemeExtesions.length})</summary>
|
||||||
|
|
|
@ -121,9 +121,9 @@ export class RangeUtil {
|
||||||
startChildIndex = Math.min(max, Math.max(min, startChildIndex));
|
startChildIndex = Math.min(max, Math.max(min, startChildIndex));
|
||||||
endChildIndex = Math.min(max, Math.max(min, endChildIndex));
|
endChildIndex = Math.min(max, Math.max(min, endChildIndex));
|
||||||
|
|
||||||
if (startChildIndex === endChildIndex && startOffset === endOffset && startOffset === 0) {
|
if (startChildIndex === endChildIndex && startOffset === endOffset && startOffset === 0 && !domNode.children[startChildIndex].firstChild) {
|
||||||
// We must find the position at the beginning of a <span>
|
// We must find the position at the beginning of a <span>
|
||||||
// To cover cases of empty <span>s, aboid using a range and use the <span>'s bounding box
|
// To cover cases of empty <span>s, avoid using a range and use the <span>'s bounding box
|
||||||
const clientRects = domNode.children[startChildIndex].getClientRects();
|
const clientRects = domNode.children[startChildIndex].getClientRects();
|
||||||
return this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft);
|
return this._createHorizontalRangesFromClientRects(clientRects, clientRectDeltaLeft);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,10 +90,10 @@ class CodeLensContentWidget implements IContentWidget {
|
||||||
if (lens.command) {
|
if (lens.command) {
|
||||||
const title = renderLabelWithIcons(lens.command.title.trim());
|
const title = renderLabelWithIcons(lens.command.title.trim());
|
||||||
if (lens.command.id) {
|
if (lens.command.id) {
|
||||||
children.push(dom.$('a', { id: String(i) }, ...title));
|
children.push(dom.$('a', { id: String(i), title: lens.command.tooltip }, ...title));
|
||||||
this._commands.set(String(i), lens.command);
|
this._commands.set(String(i), lens.command);
|
||||||
} else {
|
} else {
|
||||||
children.push(dom.$('span', undefined, ...title));
|
children.push(dom.$('span', { title: lens.command.tooltip }, ...title));
|
||||||
}
|
}
|
||||||
if (i + 1 < lenses.length) {
|
if (i + 1 < lenses.length) {
|
||||||
children.push(dom.$('span', undefined, '\u00a0|\u00a0'));
|
children.push(dom.$('span', undefined, '\u00a0|\u00a0'));
|
||||||
|
|
|
@ -79,7 +79,7 @@ async function doResolveUnixShellEnv(logService: ILogService): Promise<typeof pr
|
||||||
logService.trace('getUnixShellEnvironment#env', env);
|
logService.trace('getUnixShellEnvironment#env', env);
|
||||||
logService.trace('getUnixShellEnvironment#spawn', command);
|
logService.trace('getUnixShellEnvironment#spawn', command);
|
||||||
|
|
||||||
const systemShellUnix = await getSystemShell(platform);
|
const systemShellUnix = await getSystemShell(platform, env);
|
||||||
const child = spawn(systemShellUnix, ['-ilc', command], {
|
const child = spawn(systemShellUnix, ['-ilc', command], {
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: ['ignore', 'pipe', process.stderr],
|
stdio: ['ignore', 'pipe', process.stderr],
|
||||||
|
|
|
@ -17,7 +17,8 @@ export interface WindowData {
|
||||||
export const enum IssueType {
|
export const enum IssueType {
|
||||||
Bug,
|
Bug,
|
||||||
PerformanceIssue,
|
PerformanceIssue,
|
||||||
FeatureRequest
|
FeatureRequest,
|
||||||
|
Marketplace
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IssueReporterStyles extends WindowStyles {
|
export interface IssueReporterStyles extends WindowStyles {
|
||||||
|
@ -40,7 +41,7 @@ export interface IssueReporterStyles extends WindowStyles {
|
||||||
|
|
||||||
export interface IssueReporterExtensionData {
|
export interface IssueReporterExtensionData {
|
||||||
name: string;
|
name: string;
|
||||||
publisher: string;
|
publisher: string | undefined;
|
||||||
version: string;
|
version: string;
|
||||||
id: string;
|
id: string;
|
||||||
isTheme: boolean;
|
isTheme: boolean;
|
||||||
|
|
|
@ -414,7 +414,8 @@ export class IssueMainService implements ICommonIssueService {
|
||||||
version: !!product.darwinUniversalAssetId ? `${product.version} (Universal)` : product.version,
|
version: !!product.darwinUniversalAssetId ? `${product.version} (Universal)` : product.version,
|
||||||
commit: product.commit,
|
commit: product.commit,
|
||||||
date: product.date,
|
date: product.date,
|
||||||
reportIssueUrl: product.reportIssueUrl
|
reportIssueUrl: product.reportIssueUrl,
|
||||||
|
reportMarketplaceIssueUrl: product.reportMarketplaceIssueUrl
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,7 @@ export interface IProductConfiguration {
|
||||||
readonly twitterUrl?: string;
|
readonly twitterUrl?: string;
|
||||||
readonly requestFeatureUrl?: string;
|
readonly requestFeatureUrl?: string;
|
||||||
readonly reportIssueUrl?: string;
|
readonly reportIssueUrl?: string;
|
||||||
|
readonly reportMarketplaceIssueUrl?: string;
|
||||||
readonly licenseUrl?: string;
|
readonly licenseUrl?: string;
|
||||||
readonly privacyStatementUrl?: string;
|
readonly privacyStatementUrl?: string;
|
||||||
readonly telemetryOptOutUrl?: string;
|
readonly telemetryOptOutUrl?: string;
|
||||||
|
|
|
@ -27,7 +27,7 @@ const WRITE_INTERVAL_MS = 5;
|
||||||
|
|
||||||
const enum ShutdownConstants {
|
const enum ShutdownConstants {
|
||||||
/**
|
/**
|
||||||
* The amount of time that must pass between data events after exit is queued before the actual
|
* The amount of ms that must pass between data events after exit is queued before the actual
|
||||||
* kill call is triggered. This data flush mechanism works around an [issue in node-pty][1]
|
* kill call is triggered. This data flush mechanism works around an [issue in node-pty][1]
|
||||||
* where not all data is flushed which causes problems for task problem matchers. Additionally
|
* where not all data is flushed which causes problems for task problem matchers. Additionally
|
||||||
* on Windows under conpty, killing a process while data is being output will cause the [conhost
|
* on Windows under conpty, killing a process while data is being output will cause the [conhost
|
||||||
|
@ -39,7 +39,7 @@ const enum ShutdownConstants {
|
||||||
*/
|
*/
|
||||||
DataFlushTimeout = 250,
|
DataFlushTimeout = 250,
|
||||||
/**
|
/**
|
||||||
* The maximum time to allow after dispose is called because forcefully killing the process.
|
* The maximum ms to allow after dispose is called because forcefully killing the process.
|
||||||
*/
|
*/
|
||||||
MaximumShutdownTime = 5000
|
MaximumShutdownTime = 5000
|
||||||
}
|
}
|
||||||
|
|
28
src/vs/vscode.proposed.d.ts
vendored
28
src/vs/vscode.proposed.d.ts
vendored
|
@ -700,7 +700,7 @@ declare module 'vscode' {
|
||||||
export interface InlineValueContext {
|
export interface InlineValueContext {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug Adapter Protocol ID of the the stack frame.
|
* The stack frame (as a DAP Id) where the execution has stopped.
|
||||||
*/
|
*/
|
||||||
readonly frameId: number;
|
readonly frameId: number;
|
||||||
|
|
||||||
|
@ -1555,27 +1555,27 @@ declare module 'vscode' {
|
||||||
readonly backupId?: string;
|
readonly backupId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo@API use openNotebookDOCUMENT to align with openCustomDocument etc?
|
||||||
export interface NotebookContentProvider {
|
export interface NotebookContentProvider {
|
||||||
|
|
||||||
readonly options?: NotebookDocumentContentOptions;
|
readonly options?: NotebookDocumentContentOptions;
|
||||||
readonly onDidChangeNotebookContentOptions?: Event<NotebookDocumentContentOptions>;
|
readonly onDidChangeNotebookContentOptions?: Event<NotebookDocumentContentOptions>;
|
||||||
|
|
||||||
|
// todo@API remove! against separation of data provider and renderer
|
||||||
|
// eslint-disable-next-line vscode-dts-cancellation
|
||||||
|
resolveNotebook(document: NotebookDocument, webview: NotebookCommunication): Thenable<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content providers should always use [file system providers](#FileSystemProvider) to
|
* Content providers should always use [file system providers](#FileSystemProvider) to
|
||||||
* resolve the raw content for `uri` as the resouce is not necessarily a file on disk.
|
* resolve the raw content for `uri` as the resouce is not necessarily a file on disk.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line vscode-dts-provider-naming
|
openNotebook(uri: Uri, openContext: NotebookDocumentOpenContext, token: CancellationToken): NotebookData | Thenable<NotebookData>;
|
||||||
openNotebook(uri: Uri, openContext: NotebookDocumentOpenContext): NotebookData | Thenable<NotebookData>;
|
|
||||||
// eslint-disable-next-line vscode-dts-provider-naming
|
|
||||||
// eslint-disable-next-line vscode-dts-cancellation
|
|
||||||
resolveNotebook(document: NotebookDocument, webview: NotebookCommunication): Thenable<void>;
|
|
||||||
// eslint-disable-next-line vscode-dts-provider-naming
|
|
||||||
saveNotebook(document: NotebookDocument, cancellation: CancellationToken): Thenable<void>;
|
|
||||||
// eslint-disable-next-line vscode-dts-provider-naming
|
|
||||||
saveNotebookAs(targetResource: Uri, document: NotebookDocument, cancellation: CancellationToken): Thenable<void>;
|
|
||||||
// eslint-disable-next-line vscode-dts-provider-naming
|
|
||||||
backupNotebook(document: NotebookDocument, context: NotebookDocumentBackupContext, cancellation: CancellationToken): Thenable<NotebookDocumentBackup>;
|
|
||||||
|
|
||||||
// ???
|
saveNotebook(document: NotebookDocument, token: CancellationToken): Thenable<void>;
|
||||||
// provideKernels(document: NotebookDocument, token: CancellationToken): ProviderResult<T[]>;
|
|
||||||
|
saveNotebookAs(targetResource: Uri, document: NotebookDocument, token: CancellationToken): Thenable<void>;
|
||||||
|
|
||||||
|
backupNotebook(document: NotebookDocument, context: NotebookDocumentBackupContext, token: CancellationToken): Thenable<NotebookDocumentBackup>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace notebook {
|
export namespace notebook {
|
||||||
|
|
|
@ -403,8 +403,8 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
|
||||||
contentOptions.transientOutputs = newOptions.transientOutputs;
|
contentOptions.transientOutputs = newOptions.transientOutputs;
|
||||||
},
|
},
|
||||||
viewOptions: options.viewOptions,
|
viewOptions: options.viewOptions,
|
||||||
openNotebook: async (viewType: string, uri: URI, backupId?: string) => {
|
openNotebook: async (viewType: string, uri: URI, backupId: string | undefined, token: CancellationToken) => {
|
||||||
const data = await this._proxy.$openNotebook(viewType, uri, backupId);
|
const data = await this._proxy.$openNotebook(viewType, uri, backupId, token);
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
transientOptions: contentOptions
|
transientOptions: contentOptions
|
||||||
|
|
|
@ -1863,7 +1863,7 @@ export interface ExtHostNotebookShape {
|
||||||
$executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
|
$executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
|
||||||
$cancelNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
|
$cancelNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
|
||||||
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
|
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
|
||||||
$openNotebook(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto>;
|
$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, token: CancellationToken): Promise<NotebookDataDto>;
|
||||||
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
|
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
|
||||||
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
|
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
|
||||||
$backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string>;
|
$backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string>;
|
||||||
|
|
|
@ -114,7 +114,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||||
this._proxy.$sendDidChangeSessions(id, {
|
this._proxy.$sendDidChangeSessions(id, {
|
||||||
added: e.added ?? [],
|
added: e.added ?? [],
|
||||||
changed: e.changed ?? [],
|
changed: e.changed ?? [],
|
||||||
removed: e.changed ?? []
|
removed: e.removed ?? []
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -497,9 +497,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
||||||
|
|
||||||
// --- open, save, saveAs, backup
|
// --- open, save, saveAs, backup
|
||||||
|
|
||||||
async $openNotebook(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto> {
|
async $openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, token: CancellationToken): Promise<NotebookDataDto> {
|
||||||
const { provider } = this._getProviderData(viewType);
|
const { provider } = this._getProviderData(viewType);
|
||||||
const data = await provider.openNotebook(URI.revive(uri), { backupId });
|
const data = await provider.openNotebook(URI.revive(uri), { backupId }, token);
|
||||||
return {
|
return {
|
||||||
metadata: {
|
metadata: {
|
||||||
...notebookDocumentMetadataDefaults,
|
...notebookDocumentMetadataDefaults,
|
||||||
|
@ -776,7 +776,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
||||||
} else if (delta.newActiveEditor) {
|
} else if (delta.newActiveEditor) {
|
||||||
this._activeNotebookEditor = this._editors.get(delta.newActiveEditor)?.editor;
|
this._activeNotebookEditor = this._editors.get(delta.newActiveEditor)?.editor;
|
||||||
}
|
}
|
||||||
this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor?.editor);
|
if (delta.newActiveEditor !== undefined) {
|
||||||
|
this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor?.editor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createNotebookCellStatusBarItemInternal(cell: vscode.NotebookCell, alignment: extHostTypes.NotebookCellStatusBarAlignment | undefined, priority: number | undefined) {
|
createNotebookCellStatusBarItemInternal(cell: vscode.NotebookCell, alignment: extHostTypes.NotebookCellStatusBarAlignment | undefined, priority: number | undefined) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||||
// Getting the SystemShell is an async operation, however, the ExtHost terminal service is mostly synchronous
|
// Getting the SystemShell is an async operation, however, the ExtHost terminal service is mostly synchronous
|
||||||
// and the API `vscode.env.shell` is also synchronous. The default shell _should_ be set when extensions are
|
// and the API `vscode.env.shell` is also synchronous. The default shell _should_ be set when extensions are
|
||||||
// starting up but if not, we run getSystemShellSync below which gets a sane default.
|
// starting up but if not, we run getSystemShellSync below which gets a sane default.
|
||||||
getSystemShell(platform.platform).then(s => this._defaultShell = s);
|
getSystemShell(platform.platform, process.env as platform.IProcessEnvironment).then(s => this._defaultShell = s);
|
||||||
|
|
||||||
this._updateLastActiveWorkspace();
|
this._updateLastActiveWorkspace();
|
||||||
this._updateVariableResolver();
|
this._updateVariableResolver();
|
||||||
|
@ -83,7 +83,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||||
return terminalEnvironment.getDefaultShell(
|
return terminalEnvironment.getDefaultShell(
|
||||||
fetchSetting,
|
fetchSetting,
|
||||||
this._isWorkspaceShellAllowed,
|
this._isWorkspaceShellAllowed,
|
||||||
this._defaultShell ?? getSystemShellSync(platform.platform),
|
this._defaultShell ?? getSystemShellSync(platform.platform, process.env as platform.IProcessEnvironment),
|
||||||
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
|
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
|
||||||
process.env.windir,
|
process.env.windir,
|
||||||
terminalEnvironment.createVariableResolver(this._lastActiveWorkspace, this._variableResolver),
|
terminalEnvironment.createVariableResolver(this._lastActiveWorkspace, this._variableResolver),
|
||||||
|
|
|
@ -384,12 +384,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||||
weight: KeybindingWeight.WorkbenchContrib,
|
weight: KeybindingWeight.WorkbenchContrib,
|
||||||
primary: KeyCode.F5,
|
primary: KeyCode.F5,
|
||||||
when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))),
|
when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))),
|
||||||
handler: async (accessor: ServicesAccessor, debugStartOptions?: { noDebug: boolean }) => {
|
handler: async (accessor: ServicesAccessor, debugStartOptions: { config?: Partial<IConfig>; noDebug?: boolean } = {}) => {
|
||||||
const debugService = accessor.get(IDebugService);
|
const debugService = accessor.get(IDebugService);
|
||||||
let { launch, name, getConfig } = debugService.getConfigurationManager().selectedConfiguration;
|
let { launch, name, getConfig } = debugService.getConfigurationManager().selectedConfiguration;
|
||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
const clonedConfig = deepClone(config);
|
const configOrName = config ? Object.assign(deepClone(config), debugStartOptions.config) : name;
|
||||||
await debugService.startDebugging(launch, clonedConfig || name, { noDebug: debugStartOptions && debugStartOptions.noDebug });
|
await debugService.startDebugging(launch, configOrName, { noDebug: debugStartOptions.noDebug });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -374,6 +374,10 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||||
let type = config?.type;
|
let type = config?.type;
|
||||||
if (name && names.indexOf(name) >= 0) {
|
if (name && names.indexOf(name) >= 0) {
|
||||||
this.setSelectedLaunchName(name);
|
this.setSelectedLaunchName(name);
|
||||||
|
if (!config && name && launch) {
|
||||||
|
config = launch.getConfiguration(name);
|
||||||
|
type = config?.type;
|
||||||
|
}
|
||||||
} else if (dynamicConfig && dynamicConfig.type) {
|
} else if (dynamicConfig && dynamicConfig.type) {
|
||||||
// We could not find the previously used name and config is not passed. We should get all dynamic configurations from providers
|
// We could not find the previously used name and config is not passed. We should get all dynamic configurations from providers
|
||||||
// And potentially auto select the previously used dynamic configuration #96293
|
// And potentially auto select the previously used dynamic configuration #96293
|
||||||
|
|
|
@ -852,14 +852,12 @@ registerAction2(class extends ViewAction<Repl> {
|
||||||
const stopppedChildSession = debugService.getModel().getSessions().find(s => s.parentSession === session && s.state === State.Stopped);
|
const stopppedChildSession = debugService.getModel().getSessions().find(s => s.parentSession === session && s.state === State.Stopped);
|
||||||
if (stopppedChildSession) {
|
if (stopppedChildSession) {
|
||||||
session = stopppedChildSession;
|
session = stopppedChildSession;
|
||||||
} else {
|
|
||||||
await view.selectSession(session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await debugService.focusStackFrame(undefined, undefined, session, true);
|
await debugService.focusStackFrame(undefined, undefined, session, true);
|
||||||
} else {
|
|
||||||
await view.selectSession(session);
|
|
||||||
}
|
}
|
||||||
|
// Need to select the session in the view since the focussed session might not have changed
|
||||||
|
await view.selectSession(session);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,7 @@ export class ExtensionsTree extends WorkbenchAsyncDataTree<IExtensionData, IExte
|
||||||
accessibilityProvider: <IListAccessibilityProvider<IExtensionData>>{
|
accessibilityProvider: <IListAccessibilityProvider<IExtensionData>>{
|
||||||
getAriaLabel(extensionData: IExtensionData): string {
|
getAriaLabel(extensionData: IExtensionData): string {
|
||||||
const extension = extensionData.extension;
|
const extension = extensionData.extension;
|
||||||
return localize('extension-arialabel', "{0}, {1}, {2}, {3}", extension.displayName, extension.version, extension.publisherDisplayName, extension.description);
|
return localize('extension.arialabel', "{0}, {1}, {2}, {3}", extension.displayName, extension.version, extension.publisherDisplayName, extension.description);
|
||||||
},
|
},
|
||||||
getWidgetAriaLabel(): string {
|
getWidgetAriaLabel(): string {
|
||||||
return localize('extensions', "Extensions");
|
return localize('extensions', "Extensions");
|
||||||
|
|
|
@ -165,7 +165,7 @@ export class ExtensionsListView extends ViewPane {
|
||||||
horizontalScrolling: false,
|
horizontalScrolling: false,
|
||||||
accessibilityProvider: <IListAccessibilityProvider<IExtension | null>>{
|
accessibilityProvider: <IListAccessibilityProvider<IExtension | null>>{
|
||||||
getAriaLabel(extension: IExtension | null): string {
|
getAriaLabel(extension: IExtension | null): string {
|
||||||
return extension ? localize('extension-arialabel', "{0}, {1}, {2}, {3}", extension.displayName, extension.version, extension.publisherDisplayName, extension.description) : '';
|
return extension ? localize('extension.arialabel', "{0}, {1}, {2}, {3}", extension.displayName, extension.version, extension.publisherDisplayName, extension.description) : '';
|
||||||
},
|
},
|
||||||
getWidgetAriaLabel(): string {
|
getWidgetAriaLabel(): string {
|
||||||
return localize('extensions', "Extensions");
|
return localize('extensions', "Extensions");
|
||||||
|
|
|
@ -109,7 +109,7 @@ export class OutputElement extends Disposable {
|
||||||
|
|
||||||
if (result.type !== RenderOutputType.Mainframe) {
|
if (result.type !== RenderOutputType.Mainframe) {
|
||||||
// this.viewCell.selfSizeMonitoring = true;
|
// this.viewCell.selfSizeMonitoring = true;
|
||||||
this._notebookEditor.createInset(
|
this._notebookEditor.createOutput(
|
||||||
this._diffElementViewModel,
|
this._diffElementViewModel,
|
||||||
this._nestedCell,
|
this._nestedCell,
|
||||||
result,
|
result,
|
||||||
|
|
|
@ -33,7 +33,7 @@ export interface INotebookTextDiffEditor extends ICommonNotebookEditor {
|
||||||
getLayoutInfo(): NotebookLayoutInfo;
|
getLayoutInfo(): NotebookLayoutInfo;
|
||||||
layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void;
|
layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void;
|
||||||
getOutputRenderer(): OutputRenderer;
|
getOutputRenderer(): OutputRenderer;
|
||||||
createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void;
|
createOutput(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void;
|
||||||
showInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, displayOutput: ICellOutputViewModel, diffSide: DiffSide): void;
|
showInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, displayOutput: ICellOutputViewModel, diffSide: DiffSide): void;
|
||||||
removeInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: ICellOutputViewModel, diffSide: DiffSide): void;
|
removeInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: ICellOutputViewModel, diffSide: DiffSide): void;
|
||||||
hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: ICellOutputViewModel): void;
|
hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: ICellOutputViewModel): void;
|
||||||
|
|
|
@ -590,7 +590,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD
|
||||||
this._list.triggerScrollFromMouseWheelEvent(event);
|
this._list.triggerScrollFromMouseWheelEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void {
|
createOutput(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void {
|
||||||
this._insetModifyQueueByOutputId.queue(output.source.model.outputId + (diffSide === DiffSide.Modified ? '-right' : 'left'), async () => {
|
this._insetModifyQueueByOutputId.queue(output.source.model.outputId + (diffSide === DiffSide.Modified ? '-right' : 'left'), async () => {
|
||||||
const activeWebview = diffSide === DiffSide.Modified ? this._modifiedWebview : this._originalWebview;
|
const activeWebview = diffSide === DiffSide.Modified ? this._modifiedWebview : this._originalWebview;
|
||||||
if (!activeWebview) {
|
if (!activeWebview) {
|
||||||
|
@ -599,7 +599,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD
|
||||||
|
|
||||||
if (!activeWebview.insetMapping.has(output.source)) {
|
if (!activeWebview.insetMapping.has(output.source)) {
|
||||||
const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel);
|
const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel);
|
||||||
await activeWebview.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset());
|
await activeWebview.createOutput({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset());
|
||||||
} else {
|
} else {
|
||||||
const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel);
|
const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel);
|
||||||
const scrollTop = this._list.scrollTop;
|
const scrollTop = this._list.scrollTop;
|
||||||
|
|
|
@ -479,7 +479,7 @@ export interface INotebookEditor extends ICommonNotebookEditor {
|
||||||
/**
|
/**
|
||||||
* Render the output in webview layer
|
* Render the output in webview layer
|
||||||
*/
|
*/
|
||||||
createInset(cell: ICellViewModel, output: IInsetRenderOutput, offset: number): Promise<void>;
|
createOutput(cell: ICellViewModel, output: IInsetRenderOutput, offset: number): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the output from the webview layer
|
* Remove the output from the webview layer
|
||||||
|
@ -748,7 +748,8 @@ export enum CellRevealType {
|
||||||
|
|
||||||
export enum CellRevealPosition {
|
export enum CellRevealPosition {
|
||||||
Top,
|
Top,
|
||||||
Center
|
Center,
|
||||||
|
Bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CellEditState {
|
export enum CellEditState {
|
||||||
|
|
|
@ -1693,7 +1693,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||||
await this._webview?.updateMarkdownPreviewSelectionState(cell.id, isSelected);
|
await this._webview?.updateMarkdownPreviewSelectionState(cell.id, isSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createInset(cell: CodeCellViewModel, output: IInsetRenderOutput, offset: number): Promise<void> {
|
async createOutput(cell: CodeCellViewModel, output: IInsetRenderOutput, offset: number): Promise<void> {
|
||||||
this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => {
|
this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => {
|
||||||
if (!this._webview) {
|
if (!this._webview) {
|
||||||
return;
|
return;
|
||||||
|
@ -1703,7 +1703,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||||
|
|
||||||
if (!this._webview!.insetMapping.has(output.source)) {
|
if (!this._webview!.insetMapping.has(output.source)) {
|
||||||
const cellTop = this._list.getAbsoluteTopOfElement(cell);
|
const cellTop = this._list.getAbsoluteTopOfElement(cell);
|
||||||
await this._webview!.createInset({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset);
|
await this._webview!.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset);
|
||||||
} else {
|
} else {
|
||||||
const cellTop = this._list.getAbsoluteTopOfElement(cell);
|
const cellTop = this._list.getAbsoluteTopOfElement(cell);
|
||||||
const scrollTop = this._list.scrollTop;
|
const scrollTop = this._list.scrollTop;
|
||||||
|
|
|
@ -512,12 +512,12 @@ export class NotebookService extends Disposable implements INotebookService, IEd
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchNotebookRawData(viewType: string, uri: URI, backupId?: string): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions }> {
|
async fetchNotebookRawData(viewType: string, uri: URI, backupId: string | undefined, token: CancellationToken): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions }> {
|
||||||
if (!await this.canResolve(viewType)) {
|
if (!await this.canResolve(viewType)) {
|
||||||
throw new Error(`CANNOT fetch notebook data, there is NO provider for '${viewType}'`);
|
throw new Error(`CANNOT fetch notebook data, there is NO provider for '${viewType}'`);
|
||||||
}
|
}
|
||||||
const provider = this._withProvider(viewType)!;
|
const provider = this._withProvider(viewType)!;
|
||||||
return await provider.controller.openNotebook(viewType, uri, backupId);
|
return await provider.controller.openNotebook(viewType, uri, backupId, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
async save(viewType: string, resource: URI, token: CancellationToken): Promise<boolean> {
|
async save(viewType: string, resource: URI, token: CancellationToken): Promise<boolean> {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/
|
||||||
import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, ICellRange, NOTEBOOK_EDITOR_CURSOR_BEGIN_END, cellRangesToIndexes, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, ICellRange, NOTEBOOK_EDITOR_CURSOR_BEGIN_END, cellRangesToIndexes, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { clamp } from 'vs/base/common/numbers';
|
import { clamp } from 'vs/base/common/numbers';
|
||||||
import { SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants';
|
import { SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||||
|
import { ISplice } from 'vs/base/common/sequence';
|
||||||
|
|
||||||
export interface IFocusNextPreviousDelegate {
|
export interface IFocusNextPreviousDelegate {
|
||||||
onFocusNext(applyFocusNext: () => void): void;
|
onFocusNext(applyFocusNext: () => void): void;
|
||||||
|
@ -313,53 +314,14 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||||
});
|
});
|
||||||
|
|
||||||
if (e.synchronous) {
|
if (e.synchronous) {
|
||||||
viewDiffs.reverse().forEach((diff) => {
|
this._updateElementsInWebview(viewDiffs);
|
||||||
// remove output in the webview
|
|
||||||
const hideOutputs: ICellOutputViewModel[] = [];
|
|
||||||
const deletedOutputs: ICellOutputViewModel[] = [];
|
|
||||||
|
|
||||||
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
|
|
||||||
const cell = this.element(i);
|
|
||||||
if (cell.cellKind === CellKind.Code) {
|
|
||||||
if (this._viewModel!.hasCell(cell.handle)) {
|
|
||||||
hideOutputs.push(...cell?.outputsViewModels);
|
|
||||||
} else {
|
|
||||||
deletedOutputs.push(...cell?.outputsViewModels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.splice2(diff.start, diff.deleteCount, diff.toInsert);
|
|
||||||
|
|
||||||
hideOutputs.forEach(output => this._onDidHideOutput.fire(output));
|
|
||||||
deletedOutputs.forEach(output => this._onDidRemoveOutput.fire(output));
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this._viewModelStore.add(DOM.scheduleAtNextAnimationFrame(() => {
|
this._viewModelStore.add(DOM.scheduleAtNextAnimationFrame(() => {
|
||||||
if (this._isDisposed) {
|
if (this._isDisposed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewDiffs.reverse().forEach((diff) => {
|
this._updateElementsInWebview(viewDiffs);
|
||||||
const hideOutputs: ICellOutputViewModel[] = [];
|
|
||||||
const deletedOutputs: ICellOutputViewModel[] = [];
|
|
||||||
|
|
||||||
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
|
|
||||||
const cell = this.element(i);
|
|
||||||
if (cell.cellKind === CellKind.Code) {
|
|
||||||
if (this._viewModel!.hasCell(cell.handle)) {
|
|
||||||
hideOutputs.push(...cell?.outputsViewModels);
|
|
||||||
} else {
|
|
||||||
deletedOutputs.push(...cell?.outputsViewModels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.splice2(diff.start, diff.deleteCount, diff.toInsert);
|
|
||||||
|
|
||||||
hideOutputs.forEach(output => this._onDidHideOutput.fire(output));
|
|
||||||
deletedOutputs.forEach(output => this._onDidRemoveOutput.fire(output));
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -393,6 +355,33 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||||
this.splice2(0, 0, viewCells);
|
this.splice2(0, 0, viewCells);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _updateElementsInWebview(viewDiffs: ISplice<CellViewModel>[]) {
|
||||||
|
viewDiffs.reverse().forEach((diff) => {
|
||||||
|
const hideOutputs: ICellOutputViewModel[] = [];
|
||||||
|
const deletedOutputs: ICellOutputViewModel[] = [];
|
||||||
|
const removedMarkdownCells: ICellViewModel[] = [];
|
||||||
|
|
||||||
|
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
|
||||||
|
const cell = this.element(i);
|
||||||
|
if (cell.cellKind === CellKind.Code) {
|
||||||
|
if (this._viewModel!.hasCell(cell.handle)) {
|
||||||
|
hideOutputs.push(...cell?.outputsViewModels);
|
||||||
|
} else {
|
||||||
|
deletedOutputs.push(...cell?.outputsViewModels);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removedMarkdownCells.push(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.splice2(diff.start, diff.deleteCount, diff.toInsert);
|
||||||
|
|
||||||
|
hideOutputs.forEach(output => this._onDidHideOutput.fire(output));
|
||||||
|
deletedOutputs.forEach(output => this._onDidRemoveOutput.fire(output));
|
||||||
|
removedMarkdownCells.forEach(cell => this._onDidRemoveCellFromView.fire(cell));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
super.splice(0, this.length);
|
super.splice(0, this.length);
|
||||||
}
|
}
|
||||||
|
@ -473,31 +462,7 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||||
return oldViewCellMapping.has(a.uri.toString());
|
return oldViewCellMapping.has(a.uri.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
viewDiffs.reverse().forEach((diff) => {
|
this._updateElementsInWebview(viewDiffs);
|
||||||
// remove output in the webview
|
|
||||||
const hideOutputs: ICellOutputViewModel[] = [];
|
|
||||||
const deletedOutputs: ICellOutputViewModel[] = [];
|
|
||||||
const removedMarkdownCells: ICellViewModel[] = [];
|
|
||||||
|
|
||||||
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
|
|
||||||
const cell = this.element(i);
|
|
||||||
if (cell.cellKind === CellKind.Code) {
|
|
||||||
if (this._viewModel!.hasCell(cell.handle)) {
|
|
||||||
hideOutputs.push(...cell?.outputsViewModels);
|
|
||||||
} else {
|
|
||||||
deletedOutputs.push(...cell?.outputsViewModels);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
removedMarkdownCells.push(cell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.splice2(diff.start, diff.deleteCount, diff.toInsert);
|
|
||||||
|
|
||||||
hideOutputs.forEach(output => this._onDidHideOutput.fire(output));
|
|
||||||
deletedOutputs.forEach(output => this._onDidRemoveOutput.fire(output));
|
|
||||||
removedMarkdownCells.forEach(cell => this._onDidRemoveCellFromView.fire(cell));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
splice2(start: number, deleteCount: number, elements: CellViewModel[] = []): void {
|
splice2(start: number, deleteCount: number, elements: CellViewModel[] = []): void {
|
||||||
|
@ -698,7 +663,7 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const endIndex = this._getViewIndexUpperBound2(range.end);
|
const endIndex = this._getViewIndexUpperBound2(range.end - 1);
|
||||||
|
|
||||||
const scrollTop = this.getViewScrollTop();
|
const scrollTop = this.getViewScrollTop();
|
||||||
const wrapperBottom = this.getViewScrollBottom();
|
const wrapperBottom = this.getViewScrollBottom();
|
||||||
|
@ -1074,18 +1039,31 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// first render
|
switch (revealPosition) {
|
||||||
const viewItemOffset = revealPosition === CellRevealPosition.Top ? elementTop : (elementTop - this.view.renderHeight / 2);
|
case CellRevealPosition.Top:
|
||||||
this.view.setScrollTop(viewItemOffset);
|
this.view.setScrollTop(elementTop);
|
||||||
|
this.view.setScrollTop(this.view.elementTop(viewIndex));
|
||||||
// second scroll as markdown cell is dynamic
|
break;
|
||||||
const newElementTop = this.view.elementTop(viewIndex);
|
case CellRevealPosition.Center:
|
||||||
const newViewItemOffset = revealPosition === CellRevealPosition.Top ? newElementTop : (newElementTop - this.view.renderHeight / 2);
|
this.view.setScrollTop(elementTop - this.view.renderHeight / 2);
|
||||||
this.view.setScrollTop(newViewItemOffset);
|
this.view.setScrollTop(this.view.elementTop(viewIndex) - this.view.renderHeight / 2);
|
||||||
|
break;
|
||||||
|
case CellRevealPosition.Bottom:
|
||||||
|
this.view.setScrollTop(elementBottom - this.view.renderHeight);
|
||||||
|
this.view.setScrollTop(this.view.elementTop(viewIndex) + this.view.elementHeight(viewIndex) - this.view.renderHeight);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _revealInView(viewIndex: number) {
|
private _revealInView(viewIndex: number) {
|
||||||
this._revealInternal(viewIndex, true, CellRevealPosition.Top);
|
const firstIndex = this.view.firstVisibleIndex;
|
||||||
|
if (viewIndex < firstIndex) {
|
||||||
|
this._revealInternal(viewIndex, true, CellRevealPosition.Top);
|
||||||
|
} else {
|
||||||
|
this._revealInternal(viewIndex, true, CellRevealPosition.Bottom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _revealInCenter(viewIndex: number) {
|
private _revealInCenter(viewIndex: number) {
|
||||||
|
|
|
@ -1163,7 +1163,7 @@ var requirejs = (function() {
|
||||||
await p;
|
await p;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createInset(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number) {
|
async createOutput(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number) {
|
||||||
if (this._disposed) {
|
if (this._disposed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ export class CellOutputElement extends Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (renderResult.type !== RenderOutputType.Mainframe) {
|
if (renderResult.type !== RenderOutputType.Mainframe) {
|
||||||
this.notebookEditor.createInset(this.viewCell, renderResult, this.viewCell.getOutputOffset(index));
|
this.notebookEditor.createOutput(this.viewCell, renderResult, this.viewCell.getOutputOffset(index));
|
||||||
this.domNode.classList.add('background');
|
this.domNode.classList.add('background');
|
||||||
} else {
|
} else {
|
||||||
this.domNode.classList.add('foreground', 'output-element');
|
this.domNode.classList.add('foreground', 'output-element');
|
||||||
|
@ -388,7 +388,7 @@ export class CellOutputContainer extends Disposable {
|
||||||
const renderedOutput = this.outputEntries.get(currOutput);
|
const renderedOutput = this.outputEntries.get(currOutput);
|
||||||
if (renderedOutput && renderedOutput.renderResult) {
|
if (renderedOutput && renderedOutput.renderResult) {
|
||||||
if (renderedOutput.renderResult.type !== RenderOutputType.Mainframe) {
|
if (renderedOutput.renderResult.type !== RenderOutputType.Mainframe) {
|
||||||
this.notebookEditor.createInset(this.viewCell, renderedOutput.renderResult as IInsetRenderOutput, this.viewCell.getOutputOffset(index));
|
this.notebookEditor.createOutput(this.viewCell, renderedOutput.renderResult as IInsetRenderOutput, this.viewCell.getOutputOffset(index));
|
||||||
} else {
|
} else {
|
||||||
this.viewCell.updateOutputHeight(index, renderedOutput.domClientHeight);
|
this.viewCell.updateOutputHeight(index, renderedOutput.domClientHeight);
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,7 +276,6 @@ export class StatefulMarkdownCell extends Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this.notebookEditor.removeMarkdownPreview(this.viewCell);
|
|
||||||
this.localDisposables.dispose();
|
this.localDisposables.dispose();
|
||||||
this.viewCell.detachTextEditor();
|
this.viewCell.detachTextEditor();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
|
@ -170,7 +170,7 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM
|
||||||
|
|
||||||
private async _loadFromProvider(backupId: string | undefined): Promise<void> {
|
private async _loadFromProvider(backupId: string | undefined): Promise<void> {
|
||||||
|
|
||||||
const data = await this._notebookService.fetchNotebookRawData(this.viewType, this.resource, backupId);
|
const data = await this._notebookService.fetchNotebookRawData(this.viewType, this.resource, backupId, CancellationToken.None);
|
||||||
this._lastResolvedFileStat = await this._resolveStats(this.resource);
|
this._lastResolvedFileStat = await this._resolveStats(this.resource);
|
||||||
|
|
||||||
if (this.isDisposed()) {
|
if (this.isDisposed()) {
|
||||||
|
|
|
@ -22,9 +22,10 @@ export const INotebookService = createDecorator<INotebookService>('notebookServi
|
||||||
export interface IMainNotebookController {
|
export interface IMainNotebookController {
|
||||||
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
|
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
|
||||||
options: { transientOutputs: boolean; transientMetadata: TransientMetadata; };
|
options: { transientOutputs: boolean; transientMetadata: TransientMetadata; };
|
||||||
openNotebook(viewType: string, uri: URI, backupId?: string): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions; }>;
|
|
||||||
resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise<void>;
|
resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise<void>;
|
||||||
onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: any): void;
|
onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: any): void;
|
||||||
|
|
||||||
|
openNotebook(viewType: string, uri: URI, backupId: string | undefined, token: CancellationToken): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions; }>;
|
||||||
save(uri: URI, token: CancellationToken): Promise<boolean>;
|
save(uri: URI, token: CancellationToken): Promise<boolean>;
|
||||||
saveAs(uri: URI, target: URI, token: CancellationToken): Promise<boolean>;
|
saveAs(uri: URI, target: URI, token: CancellationToken): Promise<boolean>;
|
||||||
backup(uri: URI, token: CancellationToken): Promise<string>;
|
backup(uri: URI, token: CancellationToken): Promise<string>;
|
||||||
|
@ -66,7 +67,7 @@ export interface INotebookService {
|
||||||
getNotebookProviderResourceRoots(): URI[];
|
getNotebookProviderResourceRoots(): URI[];
|
||||||
destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void;
|
destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void;
|
||||||
|
|
||||||
fetchNotebookRawData(viewType: string, uri: URI, backupId?: string): Promise<INotebookRawData>;
|
fetchNotebookRawData(viewType: string, uri: URI, backupId: string | undefined, token: CancellationToken): Promise<INotebookRawData>;
|
||||||
save(viewType: string, resource: URI, token: CancellationToken): Promise<boolean>;
|
save(viewType: string, resource: URI, token: CancellationToken): Promise<boolean>;
|
||||||
saveAs(viewType: string, resource: URI, target: URI, token: CancellationToken): Promise<boolean>;
|
saveAs(viewType: string, resource: URI, target: URI, token: CancellationToken): Promise<boolean>;
|
||||||
backup(viewType: string, uri: URI, token: CancellationToken): Promise<string | undefined>;
|
backup(viewType: string, uri: URI, token: CancellationToken): Promise<string | undefined>;
|
||||||
|
|
|
@ -309,7 +309,7 @@ export class TestNotebookEditor implements INotebookEditor {
|
||||||
// throw new Error('Method not implemented.');
|
// throw new Error('Method not implemented.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
createInset(cell: CellViewModel, output: IInsetRenderOutput, offset: number): Promise<void> {
|
createOutput(cell: CellViewModel, output: IInsetRenderOutput, offset: number): Promise<void> {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
createMarkdownPreview(cell: ICellViewModel): Promise<void> {
|
createMarkdownPreview(cell: ICellViewModel): Promise<void> {
|
||||||
|
|
|
@ -303,10 +303,6 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-workbench .search-view a.prominent {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Theming */
|
/* Theming */
|
||||||
|
|
||||||
.monaco-workbench.vs .search-view .search-widget .toggle-replace-button:hover {
|
.monaco-workbench.vs .search-view .search-widget .toggle-replace-button:hover {
|
||||||
|
|
|
@ -255,6 +255,7 @@ export class ExcludePatternInputWidget extends PatternInputWidget {
|
||||||
|
|
||||||
setUseExcludesAndIgnoreFiles(value: boolean) {
|
setUseExcludesAndIgnoreFiles(value: boolean) {
|
||||||
this.useExcludesAndIgnoreFilesBox.checked = value;
|
this.useExcludesAndIgnoreFilesBox.checked = value;
|
||||||
|
this._onChangeIgnoreBoxEmitter.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getSubcontrolsWidth(): number {
|
protected getSubcontrolsWidth(): number {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import * as errors from 'vs/base/common/errors';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { Iterable } from 'vs/base/common/iterator';
|
import { Iterable } from 'vs/base/common/iterator';
|
||||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
|
||||||
import * as env from 'vs/base/common/platform';
|
import * as env from 'vs/base/common/platform';
|
||||||
import * as strings from 'vs/base/common/strings';
|
import * as strings from 'vs/base/common/strings';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
@ -45,7 +45,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { IProgress, IProgressService, IProgressStep } from 'vs/platform/progress/common/progress';
|
import { IProgress, IProgressService, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, editorFindMatchHighlight, editorFindMatchHighlightBorder, foreground, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry';
|
import { diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, editorFindMatchHighlight, editorFindMatchHighlightBorder, foreground, listActiveSelectionForeground, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||||
import { OpenFileFolderAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions';
|
import { OpenFileFolderAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions';
|
||||||
|
@ -118,7 +118,7 @@ export class SearchView extends ViewPane {
|
||||||
private treeLabels!: ResourceLabels;
|
private treeLabels!: ResourceLabels;
|
||||||
private viewletState: MementoObject;
|
private viewletState: MementoObject;
|
||||||
private messagesElement!: HTMLElement;
|
private messagesElement!: HTMLElement;
|
||||||
private messageDisposables: IDisposable[] = [];
|
private readonly messageDisposables: DisposableStore = new DisposableStore();
|
||||||
private searchWidgetsContainerElement!: HTMLElement;
|
private searchWidgetsContainerElement!: HTMLElement;
|
||||||
private searchWidget!: SearchWidget;
|
private searchWidget!: SearchWidget;
|
||||||
private size!: dom.Dimension;
|
private size!: dom.Dimension;
|
||||||
|
@ -680,8 +680,7 @@ export class SearchView extends ViewPane {
|
||||||
const wasHidden = this.messagesElement.style.display === 'none';
|
const wasHidden = this.messagesElement.style.display === 'none';
|
||||||
dom.clearNode(this.messagesElement);
|
dom.clearNode(this.messagesElement);
|
||||||
dom.show(this.messagesElement);
|
dom.show(this.messagesElement);
|
||||||
dispose(this.messageDisposables);
|
this.messageDisposables.clear();
|
||||||
this.messageDisposables = [];
|
|
||||||
|
|
||||||
const newMessage = dom.append(this.messagesElement, $('.message'));
|
const newMessage = dom.append(this.messagesElement, $('.message'));
|
||||||
if (wasHidden) {
|
if (wasHidden) {
|
||||||
|
@ -1478,32 +1477,23 @@ export class SearchView extends ViewPane {
|
||||||
const p = dom.append(messageEl, $('p', undefined, message));
|
const p = dom.append(messageEl, $('p', undefined, message));
|
||||||
|
|
||||||
if (!completed) {
|
if (!completed) {
|
||||||
const searchAgainLink = dom.append(p, $('a.pointer.prominent', undefined, nls.localize('rerunSearch.message', "Search again")));
|
const searchAgainButton = this.messageDisposables.add(new SearchLinkButton(
|
||||||
this.messageDisposables.push(dom.addDisposableListener(searchAgainLink, dom.EventType.CLICK, (e: MouseEvent) => {
|
nls.localize('rerunSearch.message', "Search again"),
|
||||||
dom.EventHelper.stop(e, false);
|
() => this.triggerQueryChange({ preserveFocus: false })));
|
||||||
this.triggerQueryChange({ preserveFocus: false });
|
dom.append(p, searchAgainButton.element);
|
||||||
}));
|
|
||||||
} else if (hasIncludes || hasExcludes) {
|
} else if (hasIncludes || hasExcludes) {
|
||||||
const searchAgainLink = dom.append(p, $('a.pointer.prominent', { tabindex: 0 }, nls.localize('rerunSearchInAll.message', "Search again in all files")));
|
const searchAgainButton = this.messageDisposables.add(new SearchLinkButton(nls.localize('rerunSearchInAll.message', "Search again in all files"), this.onSearchAgain.bind(this)));
|
||||||
this.messageDisposables.push(dom.addDisposableListener(searchAgainLink, dom.EventType.CLICK, (e: MouseEvent) => {
|
dom.append(p, searchAgainButton.element);
|
||||||
dom.EventHelper.stop(e, false);
|
|
||||||
|
|
||||||
this.inputPatternExcludes.setValue('');
|
|
||||||
this.inputPatternIncludes.setValue('');
|
|
||||||
this.inputPatternIncludes.setOnlySearchInOpenEditors(false);
|
|
||||||
|
|
||||||
this.triggerQueryChange({ preserveFocus: false });
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
const openSettingsLink = dom.append(p, $('a.pointer.prominent', { tabindex: 0 }, nls.localize('openSettings.message', "Open Settings")));
|
const openSettingsButton = this.messageDisposables.add(new SearchLinkButton(nls.localize('openSettings.message', "Open Settings"), this.onOpenSettings.bind(this)));
|
||||||
this.addClickEvents(openSettingsLink, this.onOpenSettings);
|
dom.append(p, openSettingsButton.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completed) {
|
if (completed) {
|
||||||
dom.append(p, $('span', undefined, ' - '));
|
dom.append(p, $('span', undefined, ' - '));
|
||||||
|
|
||||||
const learnMoreLink = dom.append(p, $('a.pointer.prominent', { tabindex: 0 }, nls.localize('openSettings.learnMore', "Learn More")));
|
const learnMoreButton = this.messageDisposables.add(new SearchLinkButton(nls.localize('openSettings.learnMore', "Learn More"), this.onLearnMore.bind(this)));
|
||||||
this.addClickEvents(learnMoreLink, this.onLearnMore);
|
dom.append(p, learnMoreButton.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
|
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
|
||||||
|
@ -1555,30 +1545,10 @@ export class SearchView extends ViewPane {
|
||||||
.then(onComplete, onError);
|
.then(onComplete, onError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private addClickEvents = (element: HTMLElement, handler: (event: any) => void): void => {
|
private onOpenSettings(e: dom.EventLike): void {
|
||||||
this.messageDisposables.push(dom.addDisposableListener(element, dom.EventType.CLICK, handler));
|
|
||||||
this.messageDisposables.push(dom.addDisposableListener(element, dom.EventType.KEY_DOWN, e => {
|
|
||||||
const event = new StandardKeyboardEvent(e);
|
|
||||||
let eventHandled = true;
|
|
||||||
|
|
||||||
if (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {
|
|
||||||
handler(e);
|
|
||||||
} else {
|
|
||||||
eventHandled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventHandled) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
private onOpenSettings = (e: dom.EventLike): void => {
|
|
||||||
dom.EventHelper.stop(e, false);
|
dom.EventHelper.stop(e, false);
|
||||||
|
this.openSettings('@id:files.exclude,search.exclude,search.useGlobalIgnoreFiles,search.useIgnoreFiles');
|
||||||
this.openSettings('.exclude');
|
}
|
||||||
};
|
|
||||||
|
|
||||||
private openSettings(query: string): Promise<IEditorPane | undefined> {
|
private openSettings(query: string): Promise<IEditorPane | undefined> {
|
||||||
const options: ISettingsEditorOptions = { query };
|
const options: ISettingsEditorOptions = { query };
|
||||||
|
@ -1587,11 +1557,22 @@ export class SearchView extends ViewPane {
|
||||||
this.preferencesService.openGlobalSettings(undefined, options);
|
this.preferencesService.openGlobalSettings(undefined, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onLearnMore = (e: MouseEvent): void => {
|
private onLearnMore(): void {
|
||||||
dom.EventHelper.stop(e, false);
|
|
||||||
|
|
||||||
this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=853977'));
|
this.openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=853977'));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
private onSearchAgain(): void {
|
||||||
|
this.inputPatternExcludes.setValue('');
|
||||||
|
this.inputPatternIncludes.setValue('');
|
||||||
|
this.inputPatternIncludes.setOnlySearchInOpenEditors(false);
|
||||||
|
|
||||||
|
this.triggerQueryChange({ preserveFocus: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
private onEnableExcludes(): void {
|
||||||
|
this.toggleQueryDetails(false, true);
|
||||||
|
this.searchExcludePattern.setUseExcludesAndIgnoreFiles(true);
|
||||||
|
}
|
||||||
|
|
||||||
private updateSearchResultCount(disregardExcludesAndIgnores?: boolean): void {
|
private updateSearchResultCount(disregardExcludesAndIgnores?: boolean): void {
|
||||||
const fileCount = this.viewModel.searchResult.fileCount();
|
const fileCount = this.viewModel.searchResult.fileCount();
|
||||||
|
@ -1600,26 +1581,27 @@ export class SearchView extends ViewPane {
|
||||||
const msgWasHidden = this.messagesElement.style.display === 'none';
|
const msgWasHidden = this.messagesElement.style.display === 'none';
|
||||||
|
|
||||||
const messageEl = this.clearMessage();
|
const messageEl = this.clearMessage();
|
||||||
let resultMsg = this.buildResultCountMessage(this.viewModel.searchResult.count(), fileCount);
|
const resultMsg = this.buildResultCountMessage(this.viewModel.searchResult.count(), fileCount);
|
||||||
this.tree.ariaLabel = resultMsg + nls.localize('forTerm', " - Search: {0}", this.searchResult.query?.contentPattern.pattern ?? '');
|
this.tree.ariaLabel = resultMsg + nls.localize('forTerm', " - Search: {0}", this.searchResult.query?.contentPattern.pattern ?? '');
|
||||||
|
dom.append(messageEl, resultMsg);
|
||||||
|
|
||||||
if (fileCount > 0) {
|
if (fileCount > 0) {
|
||||||
if (disregardExcludesAndIgnores) {
|
if (disregardExcludesAndIgnores) {
|
||||||
resultMsg += nls.localize('useIgnoresAndExcludesDisabled', " - exclude settings and ignore files are disabled");
|
const excludesDisabledMessage = ' - ' + nls.localize('useIgnoresAndExcludesDisabled', "exclude settings and ignore files are disabled") + ' ';
|
||||||
|
const enableExcludesButton = this.messageDisposables.add(new SearchLinkButton(nls.localize('excludes.enable', "enable"), this.onEnableExcludes.bind(this), nls.localize('useExcludesAndIgnoreFilesDescription', "Use Exclude Settings and Ignore Files")));
|
||||||
|
dom.append(messageEl, $('span', undefined, excludesDisabledMessage, '(', enableExcludesButton.element, ')'));
|
||||||
}
|
}
|
||||||
|
|
||||||
dom.append(messageEl, $('span', undefined, resultMsg + ' - '));
|
dom.append(messageEl, ' - ');
|
||||||
const span = dom.append(messageEl, $('span'));
|
|
||||||
const openInEditorLink = dom.append(span, $('a.pointer.prominent', undefined, nls.localize('openInEditor.message', "Open in editor")));
|
|
||||||
|
|
||||||
openInEditorLink.title = appendKeyBindingLabel(
|
const openInEditorTooltip = appendKeyBindingLabel(
|
||||||
nls.localize('openInEditor.tooltip', "Copy current search results to an editor"),
|
nls.localize('openInEditor.tooltip', "Copy current search results to an editor"),
|
||||||
this.keybindingService.lookupKeybinding(Constants.OpenInEditorCommandId), this.keybindingService);
|
this.keybindingService.lookupKeybinding(Constants.OpenInEditorCommandId), this.keybindingService);
|
||||||
|
const openInEditorButton = this.messageDisposables.add(new SearchLinkButton(
|
||||||
this.messageDisposables.push(dom.addDisposableListener(openInEditorLink, dom.EventType.CLICK, (e: MouseEvent) => {
|
nls.localize('openInEditor.message', "Open in editor"),
|
||||||
dom.EventHelper.stop(e, false);
|
() => this.instantiationService.invokeFunction(createEditorFromSearchResult, this.searchResult, this.searchIncludePattern.getValue(), this.searchExcludePattern.getValue(), this.searchIncludePattern.onlySearchInOpenEditors()),
|
||||||
this.instantiationService.invokeFunction(createEditorFromSearchResult, this.searchResult, this.searchIncludePattern.getValue(), this.searchExcludePattern.getValue(), this.searchIncludePattern.onlySearchInOpenEditors());
|
openInEditorTooltip));
|
||||||
}));
|
dom.append(messageEl, openInEditorButton.element);
|
||||||
|
|
||||||
this.reLayout();
|
this.reLayout();
|
||||||
} else if (!msgWasHidden) {
|
} else if (!msgWasHidden) {
|
||||||
|
@ -1645,24 +1627,22 @@ export class SearchView extends ViewPane {
|
||||||
const textEl = dom.append(this.searchWithoutFolderMessageElement,
|
const textEl = dom.append(this.searchWithoutFolderMessageElement,
|
||||||
$('p', undefined, nls.localize('searchWithoutFolder', "You have not opened or specified a folder. Only open files are currently searched - ")));
|
$('p', undefined, nls.localize('searchWithoutFolder', "You have not opened or specified a folder. Only open files are currently searched - ")));
|
||||||
|
|
||||||
const openFolderLink = dom.append(textEl,
|
const actionRunner = this.messageDisposables.add(new ActionRunner());
|
||||||
$('a.pointer.prominent', { tabindex: 0 }, nls.localize('openFolder', "Open Folder")));
|
const openFolderButton = this.messageDisposables.add(new SearchLinkButton(
|
||||||
|
nls.localize('openFolder', "Open Folder"),
|
||||||
|
() => {
|
||||||
|
const action = env.isMacintosh ?
|
||||||
|
this.instantiationService.createInstance(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL) :
|
||||||
|
this.instantiationService.createInstance(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL);
|
||||||
|
|
||||||
const actionRunner = new ActionRunner();
|
actionRunner.run(action).then(() => {
|
||||||
this.messageDisposables.push(dom.addDisposableListener(openFolderLink, dom.EventType.CLICK, (e: MouseEvent) => {
|
action.dispose();
|
||||||
dom.EventHelper.stop(e, false);
|
}, err => {
|
||||||
|
action.dispose();
|
||||||
const action = env.isMacintosh ?
|
errors.onUnexpectedError(err);
|
||||||
this.instantiationService.createInstance(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL) :
|
});
|
||||||
this.instantiationService.createInstance(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL);
|
}));
|
||||||
|
dom.append(textEl, openFolderButton.element);
|
||||||
actionRunner.run(action).then(() => {
|
|
||||||
action.dispose();
|
|
||||||
}, err => {
|
|
||||||
action.dispose();
|
|
||||||
errors.onUnexpectedError(err);
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showEmptyStage(forceHideMessages = false): void {
|
private showEmptyStage(forceHideMessages = false): void {
|
||||||
|
@ -1930,4 +1910,42 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||||
collector.addRule(`.search-view .message { color: ${fgWithOpacity}; }`);
|
collector.addRule(`.search-view .message { color: ${fgWithOpacity}; }`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const link = theme.getColor(textLinkForeground);
|
||||||
|
if (link) {
|
||||||
|
collector.addRule(`.monaco-workbench .search-view .message a { color: ${link}; }`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeLink = theme.getColor(textLinkActiveForeground);
|
||||||
|
if (activeLink) {
|
||||||
|
collector.addRule(`.monaco-workbench .search-view .message a:hover,
|
||||||
|
.monaco-workbench .search-view .message a:active { color: ${activeLink}; }`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class SearchLinkButton extends Disposable {
|
||||||
|
public readonly element: HTMLElement;
|
||||||
|
|
||||||
|
constructor(label: string, handler: (e: dom.EventLike) => unknown, tooltip?: string) {
|
||||||
|
super();
|
||||||
|
this.element = $('a.pointer', { tabindex: 0, title: tooltip }, label);
|
||||||
|
this.addEventHandlers(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private addEventHandlers(handler: (e: dom.EventLike) => unknown): void {
|
||||||
|
const wrappedHandler = (e: dom.EventLike) => {
|
||||||
|
dom.EventHelper.stop(e, false);
|
||||||
|
handler(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
this._register(dom.addDisposableListener(this.element, dom.EventType.CLICK, wrappedHandler));
|
||||||
|
this._register(dom.addDisposableListener(this.element, dom.EventType.KEY_DOWN, e => {
|
||||||
|
const event = new StandardKeyboardEvent(e);
|
||||||
|
if (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {
|
||||||
|
wrappedHandler(e);
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -364,6 +364,8 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setupPtyHostListeners(offProcessTerminalService: IOffProcessTerminalService) {
|
private _setupPtyHostListeners(offProcessTerminalService: IOffProcessTerminalService) {
|
||||||
|
// Mark the process as disconnected is the pty host is unresponsive, the responsive event
|
||||||
|
// will fire only when the pty host was already unresponsive
|
||||||
this._register(offProcessTerminalService.onPtyHostUnresponsive(() => {
|
this._register(offProcessTerminalService.onPtyHostUnresponsive(() => {
|
||||||
this.isDisconnected = true;
|
this.isDisconnected = true;
|
||||||
this._onPtyDisconnect.fire();
|
this._onPtyDisconnect.fire();
|
||||||
|
@ -373,6 +375,9 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
|
||||||
this._onPtyReconnect.fire();
|
this._onPtyReconnect.fire();
|
||||||
});
|
});
|
||||||
this._register(toDisposable(() => this._ptyResponsiveListener?.dispose()));
|
this._register(toDisposable(() => this._ptyResponsiveListener?.dispose()));
|
||||||
|
|
||||||
|
// When the pty host restarts, reconnect is no longer possible so dispose the responsive
|
||||||
|
// listener
|
||||||
this._register(offProcessTerminalService.onPtyHostRestart(() => {
|
this._register(offProcessTerminalService.onPtyHostRestart(() => {
|
||||||
// When the pty host restarts, reconnect is no longer possible
|
// When the pty host restarts, reconnect is no longer possible
|
||||||
if (!this.isDisconnected) {
|
if (!this.isDisconnected) {
|
||||||
|
|
|
@ -13,6 +13,8 @@ import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/co
|
||||||
import { getTerminalShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalConfiguration';
|
import { getTerminalShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalConfiguration';
|
||||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||||
import { getSystemShell } from 'vs/base/node/shell';
|
import { getSystemShell } from 'vs/base/node/shell';
|
||||||
|
import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||||
|
import { Platform } from 'vs/base/common/platform';
|
||||||
|
|
||||||
// This file contains additional desktop-only contributions on top of those in browser/
|
// This file contains additional desktop-only contributions on top of those in browser/
|
||||||
|
|
||||||
|
@ -25,4 +27,5 @@ workbenchRegistry.registerWorkbenchContribution(TerminalNativeContribution, Life
|
||||||
// Register configurations
|
// Register configurations
|
||||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||||
|
|
||||||
getTerminalShellConfiguration(getSystemShell).then(config => configurationRegistry.registerConfiguration(config));
|
const systemShell = async (p: Platform) => getSystemShell(p, await process.getShellEnv());
|
||||||
|
getTerminalShellConfiguration(systemShell).then(config => configurationRegistry.registerConfiguration(config));
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
|
||||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||||
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
||||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||||
|
import { IShellEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentService';
|
||||||
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||||
import type { Terminal as XTermTerminal } from 'xterm';
|
import type { Terminal as XTermTerminal } from 'xterm';
|
||||||
import type { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
|
import type { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
|
||||||
|
@ -34,7 +35,8 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
|
||||||
@IConfigurationResolverService private readonly _configurationResolverService: IConfigurationResolverService,
|
@IConfigurationResolverService private readonly _configurationResolverService: IConfigurationResolverService,
|
||||||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
||||||
@IHistoryService private readonly _historyService: IHistoryService,
|
@IHistoryService private readonly _historyService: IHistoryService,
|
||||||
@ILogService private readonly _logService: ILogService
|
@ILogService private readonly _logService: ILogService,
|
||||||
|
@IShellEnvironmentService private readonly _shellEnvironmentService: IShellEnvironmentService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -76,10 +78,11 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
|
||||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
|
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
|
||||||
let lastActiveWorkspace = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : undefined;
|
let lastActiveWorkspace = activeWorkspaceRootUri ? this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) : undefined;
|
||||||
lastActiveWorkspace = lastActiveWorkspace === null ? undefined : lastActiveWorkspace;
|
lastActiveWorkspace = lastActiveWorkspace === null ? undefined : lastActiveWorkspace;
|
||||||
|
|
||||||
const shell = getDefaultShell(
|
const shell = getDefaultShell(
|
||||||
(key) => this._configurationService.inspect(key),
|
(key) => this._configurationService.inspect(key),
|
||||||
isWorkspaceShellAllowed,
|
isWorkspaceShellAllowed,
|
||||||
await getSystemShell(platformOverride),
|
await getSystemShell(platformOverride, await this._shellEnvironmentService.getShellEnv()),
|
||||||
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
|
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
|
||||||
process.env.windir,
|
process.env.windir,
|
||||||
createVariableResolver(lastActiveWorkspace, this._configurationResolverService),
|
createVariableResolver(lastActiveWorkspace, this._configurationResolverService),
|
||||||
|
@ -87,6 +90,7 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
|
||||||
useAutomationShell,
|
useAutomationShell,
|
||||||
platformOverride
|
platformOverride
|
||||||
);
|
);
|
||||||
|
|
||||||
const args = getDefaultShellArgs(
|
const args = getDefaultShellArgs(
|
||||||
(key) => this._configurationService.inspect(key),
|
(key) => this._configurationService.inspect(key),
|
||||||
isWorkspaceShellAllowed,
|
isWorkspaceShellAllowed,
|
||||||
|
@ -95,6 +99,7 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
|
||||||
this._logService,
|
this._logService,
|
||||||
platformOverride
|
platformOverride
|
||||||
);
|
);
|
||||||
|
|
||||||
return Promise.resolve({ shell, args });
|
return Promise.resolve({ shell, args });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,16 @@
|
||||||
|
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { registerAction2 } from 'vs/platform/actions/common/actions';
|
import { registerAction2 } from 'vs/platform/actions/common/actions';
|
||||||
|
import { EditorOverride, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor';
|
import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor';
|
||||||
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||||
|
import { Extensions as EditorInputExtensions, IEditorInput, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
||||||
|
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||||
|
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||||
import { HideWebViewEditorFindCommand, ReloadWebviewAction, ShowWebViewEditorFindWidgetAction, WebViewEditorFindNextCommand, WebViewEditorFindPreviousCommand } from './webviewCommands';
|
import { HideWebViewEditorFindCommand, ReloadWebviewAction, ShowWebViewEditorFindWidgetAction, WebViewEditorFindNextCommand, WebViewEditorFindPreviousCommand } from './webviewCommands';
|
||||||
import { WebviewEditor } from './webviewEditor';
|
import { WebviewEditor } from './webviewEditor';
|
||||||
import { WebviewInput } from './webviewEditorInput';
|
import { WebviewInput } from './webviewEditorInput';
|
||||||
|
@ -22,6 +27,53 @@ import { IWebviewWorkbenchService, WebviewEditorService } from './webviewWorkben
|
||||||
localize('webview.editor.label', "webview editor")),
|
localize('webview.editor.label', "webview editor")),
|
||||||
[new SyncDescriptor(WebviewInput)]);
|
[new SyncDescriptor(WebviewInput)]);
|
||||||
|
|
||||||
|
class WebviewPanelContribution implements IWorkbenchContribution {
|
||||||
|
constructor(
|
||||||
|
@IEditorService private readonly editorService: IEditorService,
|
||||||
|
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
|
||||||
|
) {
|
||||||
|
this.editorService.overrideOpenEditor({
|
||||||
|
open: (editor, options, group) => this.onEditorOpening(editor, options, group)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private onEditorOpening(
|
||||||
|
editor: IEditorInput,
|
||||||
|
options: ITextEditorOptions | undefined,
|
||||||
|
group: IEditorGroup
|
||||||
|
): IOpenEditorOverride | undefined {
|
||||||
|
if (!(editor instanceof WebviewInput) || editor.getTypeId() !== WebviewInput.typeId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group.isOpened(editor)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let previousGroup: IEditorGroup | undefined;
|
||||||
|
const groups = this.editorGroupService.groups;
|
||||||
|
for (const group of groups) {
|
||||||
|
if (group.isOpened(editor)) {
|
||||||
|
previousGroup = group;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!previousGroup) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
previousGroup.closeEditor(editor);
|
||||||
|
|
||||||
|
return {
|
||||||
|
override: this.editorService.openEditor(editor, { ...options, override: EditorOverride.DISABLED }, group)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||||
|
workbenchContributionsRegistry.registerWorkbenchContribution(WebviewPanelContribution, LifecyclePhase.Starting);
|
||||||
|
|
||||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(
|
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(
|
||||||
WebviewEditorInputFactory.ID,
|
WebviewEditorInputFactory.ID,
|
||||||
WebviewEditorInputFactory);
|
WebviewEditorInputFactory);
|
||||||
|
|
|
@ -353,4 +353,40 @@ suite('NotebookCell#Document', function () {
|
||||||
assert.strictEqual(event.changes[0].items[0].document.isClosed, false);
|
assert.strictEqual(event.changes[0].items[0].document.isClosed, false);
|
||||||
assert.strictEqual(event.changes[0].items[1].document.isClosed, false);
|
assert.strictEqual(event.changes[0].items[1].document.isClosed, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('Opening a notebook results in VS Code firing the event onDidChangeActiveNotebookEditor twice #118470', function () {
|
||||||
|
let count = 0;
|
||||||
|
extHostNotebooks.onDidChangeActiveNotebookEditor(() => count += 1);
|
||||||
|
|
||||||
|
extHostNotebooks.$acceptDocumentAndEditorsDelta({
|
||||||
|
addedEditors: [{
|
||||||
|
documentUri: notebookUri,
|
||||||
|
id: '_notebook_editor_2',
|
||||||
|
selections: [{ start: 0, end: 1 }],
|
||||||
|
visibleRanges: []
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
extHostNotebooks.$acceptDocumentAndEditorsDelta({
|
||||||
|
newActiveEditor: '_notebook_editor_2'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(count, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('unset active notebook editor', function () {
|
||||||
|
|
||||||
|
const editor = extHostNotebooks.activeNotebookEditor;
|
||||||
|
assert.ok(editor !== undefined);
|
||||||
|
|
||||||
|
extHostNotebooks.$acceptDocumentAndEditorsDelta({ newActiveEditor: undefined });
|
||||||
|
assert.ok(extHostNotebooks.activeNotebookEditor === editor);
|
||||||
|
|
||||||
|
extHostNotebooks.$acceptDocumentAndEditorsDelta({});
|
||||||
|
assert.ok(extHostNotebooks.activeNotebookEditor === editor);
|
||||||
|
|
||||||
|
extHostNotebooks.$acceptDocumentAndEditorsDelta({ newActiveEditor: null });
|
||||||
|
assert.ok(extHostNotebooks.activeNotebookEditor === undefined);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,10 +24,6 @@ export class Extensions extends Viewlet {
|
||||||
await this.code.waitForActiveElement(SEARCH_BOX);
|
await this.code.waitForActiveElement(SEARCH_BOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForExtensionsViewlet(): Promise<any> {
|
|
||||||
await this.code.waitForElement(SEARCH_BOX);
|
|
||||||
}
|
|
||||||
|
|
||||||
async searchForExtension(id: string): Promise<any> {
|
async searchForExtension(id: string): Promise<any> {
|
||||||
await this.code.waitAndClick(SEARCH_BOX);
|
await this.code.waitAndClick(SEARCH_BOX);
|
||||||
await this.code.waitForActiveElement(SEARCH_BOX);
|
await this.code.waitForActiveElement(SEARCH_BOX);
|
||||||
|
@ -40,6 +36,10 @@ export class Extensions extends Viewlet {
|
||||||
await this.code.waitAndClick(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[data-extension-id="${id}"]`);
|
await this.code.waitAndClick(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[data-extension-id="${id}"]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async closeExtension(title: string): Promise<any> {
|
||||||
|
await this.code.waitAndClick(`.tabs-container div.tab[title="Extension: ${title}"] div.tab-actions a.action-label.codicon.codicon-close`);
|
||||||
|
}
|
||||||
|
|
||||||
async installExtension(id: string, waitUntilEnabled: boolean): Promise<void> {
|
async installExtension(id: string, waitUntilEnabled: boolean): Promise<void> {
|
||||||
await this.searchForExtension(id);
|
await this.searchForExtension(id);
|
||||||
await this.code.waitAndClick(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[data-extension-id="${id}"] .extension-list-item .monaco-action-bar .action-item:not(.disabled) .extension-action.install`);
|
await this.code.waitAndClick(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[data-extension-id="${id}"] .extension-list-item .monaco-action-bar .action-item:not(.disabled) .extension-action.install`);
|
||||||
|
|
|
@ -7,35 +7,22 @@ import { Application, Quality } from '../../../../automation';
|
||||||
|
|
||||||
export function setup() {
|
export function setup() {
|
||||||
describe('Extensions', () => {
|
describe('Extensions', () => {
|
||||||
it(`install and activate vscode-smoketest-check extension`, async function () {
|
it(`install and enable vscode-smoketest-check extension`, async function () {
|
||||||
const app = this.app as Application;
|
const app = this.app as Application;
|
||||||
|
|
||||||
if (app.quality === Quality.Dev || app.web /* https://github.com/microsoft/vscode/issues/118443 */) {
|
if (app.quality === Quality.Dev) {
|
||||||
this.skip();
|
this.skip();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!app.web) {
|
|
||||||
await app.workbench.settingsEditor.addUserSetting('webview.experimental.useIframes', 'true');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await app.workbench.extensions.openExtensionsViewlet();
|
await app.workbench.extensions.openExtensionsViewlet();
|
||||||
|
|
||||||
await app.workbench.extensions.installExtension('michelkaporin.vscode-smoketest-check', true);
|
await app.workbench.extensions.installExtension('michelkaporin.vscode-smoketest-check', true);
|
||||||
|
|
||||||
await app.workbench.extensions.waitForExtensionsViewlet();
|
// Close extension editor because keybindings dispatch is not working when web views are opened and focused
|
||||||
|
// https://github.com/microsoft/vscode/issues/110276
|
||||||
|
await app.workbench.extensions.closeExtension('vscode-smoketest-check');
|
||||||
|
|
||||||
await app.workbench.quickaccess.runCommand('Smoke Test Check');
|
await app.workbench.quickaccess.runCommand('Smoke Test Check');
|
||||||
await app.workbench.statusbar.waitForStatusbarText('smoke test', 'VS Code Smoke Test Check');
|
|
||||||
});
|
|
||||||
|
|
||||||
after(async function () {
|
|
||||||
const app = this.app as Application;
|
|
||||||
if (app.web) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await app.workbench.settingsEditor.clearUserSettings();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,7 +35,7 @@ export function setup() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://github.com/microsoft/vscode/issues/115244
|
// https://github.com/microsoft/vscode/issues/115244
|
||||||
it('dismisses result & checks for correct result number', async function () {
|
it.skip('dismisses result & checks for correct result number', async function () {
|
||||||
const app = this.app as Application;
|
const app = this.app as Application;
|
||||||
await app.workbench.search.searchFor('body');
|
await app.workbench.search.searchFor('body');
|
||||||
await app.workbench.search.removeFileMatch('app.js');
|
await app.workbench.search.removeFileMatch('app.js');
|
||||||
|
|
Loading…
Reference in a new issue